几个月前,我正在计划一个悠长的假期,因此想找一些零花钱。Pornhub的漏洞赏金计划和它高额的奖励成功引起了我的注意。并且,去黑一个像Pornhub的站是一个真的很炫酷的事情。
文章太长,请谨慎阅读。
这是关于我如何成功在www.pronhub.com上执行命令。
我利用视频上传的callback字段,然后能够成功的在多个Pornhub的站点上去执行一个精心构造过形式的对象注入。通过在一个特定的流中使用SimpleXMLElement类,我能够去执行一个OOB(带外数据) XXE攻击,如此一来,我可以获取到服务器上所有私有的,本地的文件全部内容。
除了本地文件泄露而外,通过对已创建类的轻微修改,我也能够去在服务器上达到下列核心的能力:
SSRF
Blind SQL执行(在每一个Pornhub的数据库上执行SQL语句,无命令结果回显)
通过利用这三个点的组合,我最终能够在pornhub.com执行任意的代码。
完整路径的泄露和一些反序列化
Pornhub是一个基于账户的服务网站,作为网站一个重要的特性,它必须可以上传文件到服务器上。在黑客的眼中,文件上传是一种最主要的攻击面,通常来讲是潜在导致利用的点。
我决定去研究下pornhub.com这个允许注册用户上传图片作为个人图片的特性功能。
服务器成功地取消了我大多数操作文件的琐屑尝试。图片一旦被上传,Pornhub会把上传的图片剪切到一个有效的大小(为了适应用户页面的模板)。一旦我上传图片,尝试去剪切图片,我成功的导致了服务器显示如下的异常信息:
{"success":"ERROR","message":"Unable to make handle from: /home/web1/upload.pornhub.com/htdocs/temp/images/1517/avatarOriginal158936891.png"}.
正如你能清晰从这个高度描述性的错误性信息中所看见的那样,这个异常信息泄露了我上传文件的完整路径信息:
/home/web1/upload.pornhub.com/htdocs/temp/images/1517/avatarOriginal158936891.png
既然我能够去使我上传的图片特定的物理路径泄露,我就有了一个在服务器上我可以支配的可写的目录了。悲剧的是,在联系Pornhub团队报告了这个问题后,他们回复说早前已经有另一个研究人员报告了相同的问题了…
在我更加细致深入的去研究pornhub的上传特性后,我成功地发现服务器会接受一个Cookie作为上传的字段。这个Cookie字段默认包含着一个序列化的用户cookies的PHP数组。
显然,负责去处理上传文件的代码最终列举出在列表里面的成员,如果一个特殊的成员不存在于Request的Cookie header中,就添加一个HTTP set-cookie的头。
令我纠结的事情却恰好是一个完全来自于用户输入的实用的反序列化利用。为了去扩宽我的攻击向量 – 我需要一个有__toString方法的类(在PHP中,当一个对象转换为字符串时,会自动去调用)
基于我是处于一个黑盒状态下的利用研究 – 我显然没有源代码 – 所以我丝毫不熟悉pornhub运用了哪些php的类,我只能强行去使用原生PHP的内建类。
不幸的是,我没能找到任何有__toString方法不需要去调用类的构造函数的类。所以,我决定放弃这个点,尽管它有巨大的潜在威胁。
虽然这个点对于我来说一定程度上基本没啥用,但是那些盆友们发现这个非常有用:
https://www.evonide.com/how-we-broke-php-hacked-pornhub-and-earned-20000-dollar/
他们非常幸运!我没能找到如何更好利用这个点的方法,所以我并没有报告这个“来自用户的反序列化”问题。
上传视频以及有趣的callback
作为朝着RCE的下一个台阶,我决定去集中注意力在视频上传功能上,出于和上文所详细介绍的原因一样,我继续关注了上传处。
正如之前的文件上传,我所有去利用上传功能的尝试都遭受了惨痛的失败 – pornhub 确实知道如何在部分程度上保护他们的服务器,避免来自用户上传文件的安全威胁。然而,在我尝试的过程中,我发现一个有趣的字段,这个字段叫“callbackUrl”,更确信的是这个字段里包含着一个相当有趣的URL。自然而然,我尝试去访问这个URL,然后得到了一个异常信息:”job” is invalid。我决定进一步深入去探索下这个job的字段。
我将callbackURL中的URL改为我自己的URL,希望则个字段可以被使用而不是一个白名单字段。令人感到惊喜的是,在改变了这个URL为我自己本地服务器后,我得到了一个连接:
这看上去像一个潜在的SSRF,但是这个请求的源是一个第三方的服务器,并非和pornhub有关的域名或者在Pornhub的IP范围中。这意味着,我可能没办法通过它去访问pornhub内部的服务,而且研究一个第三方的站点有点超出范围了。
无论如何,这个请求给了我关于这个让人期待的job字段的结构的重要信息。似乎job是一个非常长的JSON数组,具体说明了上传文件来提供给更进一步的处理,或许是编码。我的第一次尝试是去操作这个Json来上传一个php shell,但是我失败了,我都几乎准备要放弃这次行动了…直到…
对象注入?
我开始检测这个Json当中的“type”成员,它看上去像一个类的名字。我改变它并发送Json到原有的URL。发现结果相当令人惊喜:
接收到的响应说明了类不存在。这让我得到了一个结论:这是一个类的名称,那么我就有一定可能去执行对象注入。不幸的是,此时此刻一个对象注入事实上是没可能的…
Soapclient:
个人而言,Soapclient是我在处理反序列化数据时最爱的选择:在大部分情况下,它具有暴露关于系统行为的重要信息的潜能(例如:方法名,字段),并且通常允许返回你想获得任何的值,甚至输入那些程序猿从来不打算提供的。
"SoapClient::SoapClient(): $wsdl must be string or null"
这是一个不寻常的错误,因为它是一个构造函数的错误,并不应该在反序列化中调用,这很可能引导我们去相信另一个事实:Pornhub使用着他们自己的反序列化方法。
我尝试着去理解这个不熟悉的反序列化原理是如何去工作的,通过多次不同的尝试,我获得了一些具有提示性的错误,我发现我能够控制所有发送给构造方法的参数。有了这样的发现,我能够创建一个SoapClient设置在我的服务端上的请求,从而取代原有的类。
请求:
我服务端上接收到的请求:
通过使用SoapClient,我现在有能力去:
进行SSRF (服务端请求伪造)
获取到服务端PHP准确的版本信息(返回信息说明服务器PHP的版本为5.6.17)
使用函数来调用原有的类(getResult,无需字段)
我尝试去获得“getResult”的更多的结果,但是每次都失败了。
为了去扩宽我的攻击面,我猜测应该有一种比SoapClient更好的类,所以我试了试使用PHP的默认DirectoryIterator类。
请求和根目录的返回信息:
此时,我本不能访问根目录,但感谢对象注入与DirectoryIterator,我成功的发现了所有“/”下目录的准确列表,并且检测一个目录是否存在。
我尝试将DirectoryIterator放入SoapClient中,但失败了,似乎并不是所有Json当中的成员都会被作为对象进行解码。
SQLite和PDO
我偶然发现SQLite3类,其中存在一个filename的字段。
我尝试去使用在第一个漏洞中发现的可写的路径,这样我就能够创建一个空文件了。
为啥是个空文件呢?简单来说,因为我需要它去执行语句,并在这个文件中插入内容(把它当作一个shell来用)。
我需要去调用一个附加的函数来执行实际的语句,来写入文件之中,但是这没有什么可能。
我又试图从PDO中寻找,作为一个潜在的类注入,然而我意识到它依然和SQLite3的类差不多。
尽管我已经被上面的结果折磨的累觉不爱了,但我继续寻找到PHP中另一个有用的内建类。
SimpleXMLElement
作为最后一个手段,我决定好好的去看看原生的SimpleXMLElement类,
在黑客术语当中,XML是几乎立刻就能和XXE关联起来的。然而,正如我之前成功获取到安装在这台服务器的PHP版本5.6.17,这个版本的SimpleXMLElement的类,已经成功免疫XXE攻击 – 如果一个外部的实体存在,这个类就会抛出异常并且停止XML处理。因此,我机智的认识到一个基本的XXE在现在这个情况下毫无用处了。
除了对于XXE利用到目前为止这点可怜的成功,SimpleXMLElement构造函数包含了一个可选择的字段,叫“options”,它是用来指定额外的Libxml字段。
这其中有一个字段是“LIBXML_DTDLOAD” – 这个在稍后使我能够去加载外部的DTD并且使用XXE带外数据攻击。
在加强了我的XML技能并且实施了无数种的尝试后,我成功的获得了我的第一个文件!!!
我最终运行了两个服务器,一个是XML的,第二个是用来接受文件的(使用了NetCat,因为大多数的文件都太大,对于一般的服务器不能通过URL来接收)
第一个XML包含了两个外部的字段实体:
第一个xml.xml是用来读取远程文件源码的
第二个xml2.xml是得到xml.xml读取到的代码并发起一个请求到本地服务器(这样我们就可以获取到Pornhub的代码了)
总结下,我攻击的步骤:
1.向Pornhub的服务器发送一个Post请求
2.Pornhub的服务器下载第一个xml文件,即:xml.xml
3.Pornhub的服务器下载第二个xml文件,即:xml2.xml
4.Pornhub的服务器发送一个Get请求到第二个服务器的URL,其中带有一个a字段,负责存放base64之后Pornhub服务器上的本地文件
获取配置文件
从此刻开始以后,我的黑盒状态下的研究变成了在白盒状态下研究了,此时,我觉得是时候联系pornhub.com,与他们分享我的发现了。
当我准备把发现报告给Pornhub之时,我下载了他们部分的资源,偶然发现了pornhub的注数据库凭证信息。
PDO的MySQL驱动有个"PDO::MYSQL_ATTR_INIT_COMMAND"选项,它允许我通过PDO的构造方法来执行语句。
在我获取到了连接字符串后,我能够去发送带有PDO类的请求,从而在Pornhub的数据库上执行任何的语句了。这个发现稍后被加入到了第一个报告之中。
www.pornhub.com 代码执行
现在我是有了pornhub全站新鲜代码武装的人了,而且还能够完全访问pornhub的数据库,我猜测对于我去找到一个主站的远程代码执行将会变得相当容易。好吧,还是没那么容易的。
我在GIF产生的原理中找到了调用PHP exec函数的点:
显然,你可以从pornhub.com的任何一个视频中制作一个GIF,并且这个视频的文件路径是从数据库中获得的,并且没有任何形式的转义。
在我成功进行这之前,Pornhub团队已经禁掉了upload.pronhub.com上的URL,从而来暂时避免这个漏洞造成危害(根据我提供给他们的第一份报告),但是www.pornhub.com上的URL还是可以访问的。可是,这个网站禁止了向外部的连接。所以,我不能获取更多的泄露信息。
为了我在pornhub.com上即将到来的RCE的POC,我将数据库中的“filename”改为了’sleep 60’,可是我忽视掉了主数据库有一个30分钟的缓存…
在我耐心的等候更新的时候,我使用最新发现的SQLite和DirectoryIterator原生类注入来寻找可写的路径,但是一无所获。
我一直尝试着去执行一个命令并从数据库得到结果,在我测试的过程中,Pornhub团队封锁了这个URL,因而我只能以一个没有结果的成功的远程代码执行来作为我整个研究的总结(先前写的‘sleep’命令在数据库缓存更新后确实执行了)。
这个远程代码执行的详细细节,也被我添加进了我之前提供给pornhub.com的报告之中。
总结
对象注入,与SQL注入相比,显得相对陌生。开发人员总是没有意识到它们也可能造成危险的漏洞,所以难得去确保他们的代码在此类问题上的安全性。然而,如果被正确的使用,它们可以帮助研究者发现无数的利用点。就我这个例子而言,这个问题给了我充足经费去我一直以来需要的国外度假,但是也帮助我证实了一点 – 如果你全心全意在一个目标上,你就可以实现它!(或者以我的例子来说 – 黑掉这无法无边的pornhub.com)
时间线:
2016-05-10 – 发现反序列化 – 没有报告
2016-05-15 – 报告路径泄露
2016-06-01 – 报告文件泄露
2016-06-02 – 添加:整个数据库控制
2016-06-06 – 添加:代码执行
2016-07-06 – 10,000$ 来自pornhub的奖金
2016-09-12 – Pornhub 修复了问题
2016-10-03 – 报告被公开
发表评论
您还未登录,请先登录。
登录