本篇Writup讲述作者针对某大公司网站做安全测试时,发现其子域名网站在账户更新时存在漏洞,可以通过构造POST请求,实现从普通用户到管理员的提权,漏洞最终收获了$5000的奖励。

去年年底时候,在学习完DVWA (Damn Vulnerable Web Application) 后,我架设了OWASP Juice Shop和WebGoat继续学习WEB安全,在OWASP Juice Shop的不当输入校验(Improper Input Validation)课程下,有一项名为“注册具有管理员权限用户”的隐患测试任务。

该项任务是在网站用户注册过程中,通过参数变换和构造,赋予“role”角色“admin”值,实现注册具有管理员权限的用户。在学习完该项任务后,在2021年初的1月份,我正好针对某个知名百万美元大公司网站做安全测试,为此,我决定用OWASP Juice Shop中的学习任务实战尝试看看。

漏洞发现

该公司门户下恰好有一个子域名网站,需要注册登录才能使用,为此我就及时进行了注册。在用户注册过程中,一切貌似正常,以下为用户注册的POST请求包:

POST /register HTTP/1.1
Host: www.redacted.com
Content-Type: application/json
{“email”: “user@tld.xyz”, “password”: “password123”}

上述请求发出后,服务端会返回一个跳转到网站主页302请求,当时我觉得应该没啥异常。之后,我深入查看我的注册账户情况,想从中发现CSRF或IDOR漏洞,但可惜的是userID中绑定了CSRF token,所以CSRF或IDOR是根本不可能的。但经过几天后,我在Burp中回看当时的HTTP日志时发现,看到了用户账户更新的请求数据包:

POST /updateUserInfo HTTP/1.1
Host: www.redacted.com
CSRF-Token: XXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/json
{
“User”: {“id”: “123”, “email”: “user@tld.xyz”, “fullName”: “User A”},
“Address”: {“city”: “Some City”}
}

该请求包发出之后,服务端会返回很多内容,部份如下:

HTTP/1.1 200 OK

{
“response”: “success”,
“info”: {
“id”: “123”,
“email”: “user@tld.xyz”,
“fullName”: “User A”,
“companyUser” :“0”

}
}

返回的响应内容中包含了很多值得深入探究的地方,其中“companyUser”值为0,哦太美妙了,那我试试更改其值看看。于是,我尝试把其值更改为1:

POST /updateUserInfo HTTP/1.1
Host: www.redacted.com
CSRF-Token: XXXXXXXXXXXXXXXXXXXXXXX
Content-Type: application/json
{
“User”: {“id”: “123”, “email”: “user@tld.xyz”, “fullName”: “User A”, “companyUser”: “1”},
“Address”: {“city”: “Some City”}
}

但请求发出后,啥情况也没有。那是不是“companyUser”字段不该在“User”里面呢?但用{“companyUser”: { “companyUser”: “1” }}还是不行。之后,我又把其中第一个字母大写,变为 {“CompanyUser”: { “companyUser”: “1” }},请求后,我发现响应回来的内容中“companyUser”字段值终于变为“1”了!成功了!于是,我立马退出并进行了重新登录,但是,登录后却跳出了一个2FA PIN码确认框来!
我不知道该网站的2FA PIN码长度和组合样式,还有可能是符号加数字的方式,所以考虑暴力破解是不可能的。经过反复测试,我在服务端响应内容中发现了“companyUser2FA”字段内容。于是我马上在POST请求中加入了该字段,为{“CompanyUser”: { “companyUser”: “1”, “companyUser2FA”: “1234” }}。好了,退出再登录之后,响应内容中包含了2FA值,但是又遇到了新的麻烦-IP限制:

登录后,服务端跳出告知,我的IP不在白名单范围内,好吧。我又反复测试,发现了与IP关联的响应字段“companyUserIP”,再次把该字段添加进账户更新POST请求中,为{“CompanyUser”: { “companyUser”: “1”, “companyUser2FA”: “1234”, “companyUserIP”: “<My Public IP>” }},请求发出后,我退出并进行重新登录。期待奇迹发生,果然:

我当前的账户已经是管理员权限,可以通过某个路径看到管理员看到的一切!当前的账户身份不仅是该子域名网站下的管理员,还是其它子域名网站的管理员,从中我发现在域名枚举中未发现的其它子域名网站。由于授权原因,我不敢深入测试其它子域名,只能浅尝辄止,立即做了漏洞上报。几个小时后,该公司就修复了该漏洞。几天之后,我的漏洞被评级为P1严重级。

漏洞上报和处理进程

2021.1.22   漏洞上报
2021.1.23   漏洞修复
2021.2.6     漏洞评估为P1级并收获$5000的奖励

参考来源:medium

本文作者:clouds, 转自FreeBuf