分块传输编码在WEB安全中的应用——sql注入用,可以直接复用chunkSplitPostData还原
分块传输编码在WEB安全中的应用
from: https://www.zhihuifly.com/t/topic/1090 讲得非常清晰
分块传输编码在WEB安全中的应用
0x01 分块传输编码概念
维基百科对分块传输编码的描述:
分块传输编码(Chunked transfer encoding)是超文本传输协议(HTTP)中的一种数据传输机制,允许HTTP由网页服务器发送给客户端应用( 通常是网页浏览器)的数据可以分成多个部分。分块传输编码只在HTTP协议1.1版本(HTTP/1.1)中提供。(使用HTTP 1.0协议,服务器会主动放弃chunked编码。)
《HTTP权威指南》P373对分块传输编码的解释:
0x02 分块传输编码格式
标准的分块传输编码格式如下:
php [chunk size][\r\n][chunk data][\r\n][chunk size][\r\n][chunk data][\r\n][chunk size = 0][\r\n][\r\n]
chunk size是以十六进制的ASCII码表示,chunk数据以0长度的chunk块结束,也就是(30 0d 0a 0d 0a
)。
以下格式也可被识别:
php [chunk size;other data][\r\n][chunk data]
其中的分号之后的other data是无关数据。
0x03 分块传输例子
一个简单的分块传输HTTP请求如下:
POST /inject.php HTTP/1.1
Accept-Encoding: gzip,deflate
Transfer-Encoding: chunked
Connection: close
Accept: */*
Host: 172.20.10.2:8011
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 48
6;kxebH
id=123
b;pAo6m
12345678911
0
我们传输的数据主体id=123
+12345678911
分块后分别是6位和11位,上面的6和b就是块数据长度的16进制数,
>>> hex(6)
'0x6'
>>> hex(11)
'0xb'
>>>
我们在服务器输出参数id的值:
HTTP/1.1 200 OK
Date: Fri, 24 May 2019 02:17:07 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.17
Content-Length: 14
Connection: close
Content-Type: text/html
12312345678911
可见块数据被服务器自动解码合并输出。
0x04 分块传输应用
根据分块传输原理,这种发包方式用于Bypass基于流量特征检测的WAF应该会很有作用。
以SQL注入攻击为例,我们来分析下sqlmap最新版(2019.5.24下载的)如何利用分块传输绕过WAF进行SQL注入。
lib/core/common.py
行5160的chunkSplitPostData()
函数实现对数据主体进行分块传输编码:
def chunkSplitPostData(data): """ Convert POST data to chunked transfer-encoded data (Note: splitting done by SQL keywords) >>> random.seed(0) >>> chunkSplitPostData("SELECT username,password FROM users") '5;4Xe90\\r\\nSELEC\\r\\n3;irWlc\\r\\nT u\\r\\n1;eT4zO\\r\\ns\\r\\n5;YB4hM\\r\\nernam\\r\\n9;2pUD8\\r\\ne,passwor\\r\\n3;mp07y\\r\\nd F\\r\\n5;8RKXi\\r\\nROM u\\r\\n4;MvMhO\\r\\nsers\\r\\n0\\r\\n\\r\\n' """ length = len(data) retVal = "" index = 0 while index < length: chunkSize = randomInt(1) if index + chunkSize >= length: chunkSize = length - index salt = randomStr(5, alphabet=string.ascii_letters + string.digits) while chunkSize: candidate = data[index:index + chunkSize] if re.search(r"\b%s\b" % '|'.join(HTTP_CHUNKED_SPLIT_KEYWORDS), candidate, re.I): chunkSize -= 1 else: break index += chunkSize retVal += "%x;%s\r\n" % (chunkSize, salt) retVal += "%s\r\n" % candidate retVal += "0\r\n\r\n" return retVal
如上可见,这里严格按照分块传输编码的规范,并对敏感关键词进行分割,敏感关键词在这里定义:
lib/core/settings.py
行808:
这几个关键词明显不够,我们可以根据自己的需要添加一下。
对了,还需要添加chunked的请求头,在lib/request/connect.py
中:
尝试利用他的--chunked
参数进行分块传输注入:
可见完美注入,再查看TCP流量:
SQLMAP实现得很优雅。已经不需要自己来写tamper。
0x05 分块传输应用场景拓展
基于HTTP的攻击方式怎么能只局限于SQL注入呢,其实绕过WAF进行XSS、CSRF、SSRF、命令注入等攻击都可以通过分块传输来实现。
1. 代理实现
以XSS为例:
使用代理实现请求体更改,已有人实现(https://github.com/4rat/sqlmap\_chunked\_proxy):
运行脚本即监听9999端口,浏览器配置代理127.0.0.1:9999 。
进行XSS:
数据包情况:
服务器解析情况:
2. burp插件
https://github.com/c0ny1/chunked-coding-converter
下图是一个最原始的XSS攻击数据包,这里尝试进行一次最原生的XSS攻击,流量特征非常明显了:
使用插件进行分块传输:‘
完美X进去:
0x06 参考
- 维基百科:《分块传输编码》
- 《HTTP权威指南》
SQL注入利用分块编码传输绕过[该方法可绕某狗]
原理:在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,post请求报文中的数据部分需要改为用一系列分块来传输。每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的,也不包括分块数据结尾的,且最后需要用0独占一行表示结束。1. 开启上个实验中已关闭的content-length自动更新。给post请求包加入Transfer-Encoding: chunked后,将数据部分id=1 and 1=1进行分块编码(注意长度值必须为十六进制数),每一块里长度值独占一行,数据占一行如图八所示。2.将上面图八数据包的id=1 and 1=1改为id=1 and 1=2即将图八中所标的第4块的1改为2。如图九所示没有返回数据,payload生效。注意:分块编码传输需要将关键字and,or,select ,union等关键字拆开编码,不然仍然会被waf拦截。编码过程中长度需包括空格的长度。最后用0表示编码结束,并在0后空两行表示数据包结束,不然点击提交按钮后会看到一直处于waiting状态。