一、简介
本篇只介绍思路,不做详细注入语句讲解。
二、SQL注入产生原因
用户输入处理不当,用户数据被当做SQL语句执行。
三、注入类型
分类标准 | 分类 |
---|---|
根据请求方式分类 | GET方式注入 POST方式注入 |
根据注入点参数分类 | 整数型注入 字符型注入 搜索型注入 |
根据反馈类型分类 | union联合查询注入 报错注入 布尔盲注 时间盲注 其他类型 (如请求头注入、内联注入、二次编码注入、宽字节注入、堆叠注入、二阶注入等) |
根据数据库类型分类 | Mysql、MSSql、Oracle、Access、MongoDB等 |
四、SQL注入思路
1、发现注入点
注入点
所有存在可变参数且代入数据库中执行的数据
如:url中的?id=、页面中的搜索框、POST数据包中的可变参数、数据头中的UA、X-Forward-For等
判断:
在参数后加单引号、双引号、斜杠'、"、\
,全部加。
若页面异常,则可能存在注入;
若页面无变化,则使用延时函数,判断是否存在时间延时盲注(各大数据库通用);其中,在mysql数据库中,需要额外判断宽字节注入、二次编码注入。若页面存在延时刷新、报错,可能存在sql注入。
2、判断闭合符
使用不报错的闭合符('或"
),加上注释符(不同数据库不同,但-- a
几乎可以通用:mysql中为–空格,mssql和oracle为–,access无注释符号)
注意:
mysql为?id=1' -- a
形式
mssql、oracle、access均为?id=1' and 1=1/1=2 --
形式(1=1正常、1=2异常)
若页面返回正常,则单或双引号即为闭合符;若页面依然异常,则在单或双引号后添加)
,直至页面恢复正常。添加部分与单或双引号组成闭合符。
注意:需要结合语境,判断可能使用的sql语句,更加容易判断闭合符。如搜索型语句处(多存在搜索框处),可能会使用like关键词,需要使用%闭合,构造形如%'and '%'='
的闭合语句进行闭合判断。
3、判断数据库类型
在进行注入前,需要判断数据库类型,从而选择合适的注入语句。使用每个数据库独有的一个或多个语法、函数进行判断。
简单列举,够用即可。
数据库类型 | 注释 | 函数 |
---|---|---|
mysql | – a | version()、@@version、length() |
mssql | – | @@version、len()、?id=1’ and exists (select * from sysobjects)>0 – 返回正常 |
oracle | – | banner from sys.v_$version、length() |
access | 无 | and exists (select * from msysobjects)>0 返回正常 |
注:注释处为两个英文输入法的短横杠,非单横杠(显示问题)
4、选择注入方式
根据页面回显情况,选择通用注入方式:
1>首选union联合查询。要求:有回显位。
2>次选报错注入。要求:页面异常为报错信息。
3>最后是盲注。若页面只有正常和单一异常两种回显,选择布尔盲注;若页面无回显,选择时间盲注。
5、结合WAF确定注入语句
结合4,同一处注入点可以有多重注入手法,若是没有waf,按照优先级进行选择即可。若是有waf,需要结合绕waf选择注入方式。同时,在判断时,也可以尝试绕waf。
1>首先,判断and、or、空格是否存在waf拦截。
2>然后,按照注入手法优先级,将用到的关键词(如:order by、union select等)单独放入注入语句进行判断。
优先绕过waf,其次换可替代的关键词、最后换注入方式。
3>最后,根据waf拦截方式,确定注入语句,依次注出当前数据库名、表名、字段名、数据即可。文末附上常见绕waf方式。
注意:
若为mysql数据库,可进行以下判断
--os-shell可对网站进行getshell,但是存在以下前提条件
1、存在sql注入
2、知道网站绝对路径
3、拥有数据库权限(dba权限),也可以使用sqlmap的--is-dba判断
4、数据库配置文件secure_file_priv未设置或设置为可读写的已知路径
4>其他:
时间延时盲注可用DNS外带节省注入时间,放在其他文章中再做讲述。
五、SQL注入防御
方式 | 说明 |
---|---|
去掉单引号 | 现实场景常用单引号,去掉不合实际 |
转义单引号 | 对数字型无效(数字型不需要引号) 斜杠转义 addslashes()函数转义 php.ini配置文件转义(5.6以下版本开启magic_quotes_gpc = On) |
强制类型转换 | 针对数字型 intval() |
更改数据库连接方式 | POD连接数据库将变量转换成字符串,再写入数据库,无法拼接 |
六、WAF绕过
sql语法特性 + http特性 + waf缺陷 = waf绕过
1、大小写绕过(现今几乎无效)
2、替换关键字
1> 关键字双写(代码级别waf有效)
2> 同价词替换,针对特殊关键词拦截的情况
and --> &&
or --> ||
= --> <、>
空格 --> %20、%09、%0a、%0b、%0c、%0d、%a0、//
3> 特殊字符拼接(mssql支持拼接、mysql不支持拼接)
‘test1’+’test2’
3、编码绕过
常见的sql编码有unicode、hex、url、ascii、base64等
1>url编码(或者二次编码)
2>unicode编码(改/为%)
常见unicode编码
单引号:%u0027
空格:%u0020
左括号:%u0028
右括号:%u0029
4、注释绕过
利用语言函数特性来绕过waf规则
常见注释符://、--、//、#、--+、---、;、--a
1>普通注释
/**/
在构造查询中插入注释,规避对空格的依赖或关键字识别
2>内联注释
/*!*/
表示注释里面的语句会被执行(只有MYSQL能识别)
/*!50001 select * from test*/
表示数据库5.00.01以上版本才会执行该语句
5、参数污染
当同一参数出现多次,不同中间件会解析为不同结果。如果WAF只检测了同名参数中的第一个或最后一个,并且中间件特征正好取与WAF相反的参数,则可成功绕过
服务器中间件 | 解析结果 | 举例 |
---|---|---|
ASP.NET/IIS | 所有出现的参数值用逗号连接 | par1=var1,val2 |
ASP/IIS | 所有出现的参数值用逗号连接 | par1=var1,var2 |
PHP/Apache | 仅最后一次出现的参数值 | par1=var2 |
JSP/Tomcat | 仅最后一次出现的参数值 | par1=val1 |
Perl CGI/Apache | 仅第一次出现参数值 | par1=var1 |
如:
/index.aspx?id=select 1,2,3 from table
-->
/index.aspx?id=select 1&id=,2,3 from table
6、缓冲区溢出
许多WAF是C语言写的,而C语言本身没有缓冲区保护机制,如果WAF在处理测试向量时超出了其缓冲区长度,会引发bug从而实现绕过
如:
?id=1 and (select 1)=(select 0xAAAAAA*1000 more A)+union select 1,2version()-- a
7、整合绕过
绕过技术结合使用
8、分块传输绕过
burpsuite中更实用post传输数据,设置Transfer-encoding: chunked
使用换行分割数据