首页
社区
课程
招聘
[翻译]PHP反序列化与wordpress一些意外bug的有趣结合
发表于: 2018-3-4 12:07 2554

[翻译]PHP反序列化与wordpress一些意外bug的有趣结合

2018-3-4 12:07
2554

PHP反序列化与wordpress一些意外bug的有趣结合

原作者:Nicky Bloor@nickstadb

原文地址:https://nickbloor.co.uk/2018/02/28/popping-wordpress/



译者按:作者证明这是最新的WordPress 4.9.4版本存在的问题,默认安装,虽然bug有些不值一提,但会导致RCE,作者希望能够多多讨论这些事情的思路和努力,而不是过多地关注漏洞详细信息。PoC视频URL:https://videopress.com/v/tYSsU4Ch

几个月前,我正在编写一篇关于PHP反序列化漏洞的博客文章,决定为这篇文章找一个真实目标,能够让我将测试数据传输给PHP unserialize ()函数来实现演示目的。于是我下载了一批WordPress插件,并开始通过grepping来寻找调用unserialize ()的代码实例:



这个插件的问题在于发送明文HTTP请求,并且将该请求响应传递给了unserialize ()函数。就真实攻击而言,它并不是最佳入口点,但是如果我能通过这种微不足道的方式向unserialize ()函数提供输出来触发代码的话,这就足够了!

简单来说,当攻击者能够将他的数据提供给应用程序,而该应用程序将数据转化为运行对象时没有作适当验证的时候就会出现反序列化漏洞。如果攻击者数据被允许去控制运行对象的属性,那么攻击者就可以操纵任何使用这些对象属性的代码执行流程,就有可能使用它发起攻击。这是一种称为面向属性编程(POP)的技术,一个POP小工具是可以通过这种方式控制任何代码片段,开发实现是通过向应用程序提供特制对象,以便在这些对象进行反序列化的时候触发一些有用的行为。如果想了解更多详情的话,可以参阅我的博客文章《Attacking Java Deserialization》(https://nickbloor.co.uk/2017/08/13/attacking-java-deserialization/),其中的一般概念适用于任何基础技术。

在PHP应用程序的现状来看,POP小工具最为人熟知和最可靠的原因在于类的__wakeup()方法(PHP“魔术方法”,unserialize()函数会检查是否存在__wakeup(),如果存在,则会先调用__wakeup()方法,预先准备对象需要的资源),如果一个类定义了__wakeup()方法,那么无论何时该类的某个对象使用了unserialize ()函数进行反序列化都能保证__wakeup()方法被调用,另外一个原因是__destruct ()方法(当创建的对象被销毁或遇到PHP结束标记的时候,比如程序已经执行完毕,对象会自动调用__destruct()执行一些相应的操作,可以自行定义),例如PHP脚本执行完成时(未发生致命错误),当反序列化对象超出范围时仍几乎可以保证__destruct ()方法被调用。

除了__wakeup ()和__destruct ()方法之外, PHP还有其他“魔术方法”,可以在类中定义,也可以在反序列化之后调用,这取决于反序列化对象的使用方式。在一个更大更复杂的应用程序中可能很难追踪到反序列化对象在哪里结束以及如何来使用它或调用那些方法,于是确定那些类可以用于PHP反序列化漏洞利用也很困难,因为相关文件可能未包含在入口点,或者一个类的自动加载器(例如spl_autoload_register()函数)可能以及被注册来进一步混淆。

为了简化这个过程,我编写了一个PHP类,它定义了所有魔术方法并且在调用任何魔术方法时将详细信息写入日志文件。特别有趣的是魔术方法__get()和__call(),如果应用程序尝试获取不存在的属性或调用该类中不存在的方法时就会调用以上魔术方法,前者可以用来识别在payload object上设置的属性,以便操纵并使用这些属性的代码,而后者可以用来识别POP小工具触发使用的非魔术方法(并且可以将它们自身用作POP小工具)。

该类的__wakeup ()方法还使用了get_declared_classes ()函数来检索和记录可以利用exploit payload的已声明类的列表(虽然这不会反映当前未声明但可以自动加载的类)。

将上面的代码保存到一个PHP文件中,我们可以通过这个在其他任何PHP脚本中插入一个include'/path/to/UniversalPOPGadget.php'语句,并使这个类可用。以下Python脚本将查找给定目录中所有PHP文件,并将语句写入文件前端,从而有效地检测应用程序,以便我们可以向为其提供序列化的UniversalPOPGadget对象,来用它们研究反序列化的入口点。

回到刚刚那个调用unserialize()函数的WordPress插件代码片段,我不知道该如何去实际触发unserialize()函数的调用,我所知道的是这个插件应该向http://api.wordpress.org/plugins/info/1.0/发送HTTP请求,于是我使用上面的Python脚本来测试WordPress和插件代码,然后修改了服务器上的hosts文件,将api.wordpress.org指向同一台服务器。以下代码放在Web根目录中的/plugins/info/1.0/index.php文件中,以便提供UniversalPOPGadget payload:

在使用这种手段后,我开始像往常一样使用WordPress实例,特别注意了与目标WordPress插件相关的所有功能,同时查看UniversalPOPGadget日志文件。很快地,生成了一些日志文件,其中包括以下内容(为简洁起见,已将大量可用类删除):

日志文件中显示,在UniversalPOPGadget对象被反序列化之后,用程序试图获取或检查是否存在多个属性(段、版本、作者等等)。首先这就告诉我们,通过这个特定的入口点我们可以使用任何可用类中的任何定义在__get ()或__isset ()方法中的代码来作为POP小工具,其次它揭示了目标应用程序试图获得的几个属性,这些属性几乎保证影响执行流程,因此可能对开发有用处。

上面的日志文件显示,与反序列化对象的首次交互是尝试获取名为sections的属性。

现在来看最初的目标插件,它在调用unserialize ()之后做的第一件事是检查名为rating的属性是否存在,那么这个日志并不是我当初注意的第三方插件产生的!

对WordPress代码进行一次快速grep,对于上面提到的HTTP URL,显示该请求是由wp-admin/includes/plugin-install.php文件中的WordPress插件API发送的。浏览代码时并不清楚反序列化的payload object是如何使用的,或者切确地说这个HTTP请求以及随后对unserialize ()函数的调用是从哪里触发的。我继续点击WordPress管理界面,发现日志是从主控制面板、更新页面和插件页面生成的。重新加载这些页面使我能够触发目标HTTP请求,并向unserialize ()函数提供任意数据。

我记录了一些WordPress发出的HTTP请求并把它们发送到真正的api.wordpress.org以获取实例响应,结果响应的是stdClass类型的序列化对象,更重要的是示例响应给了我一个预期中WordPress会收到的属性的确切列表,其中每个属性都有可能用于操控某些核心WordPress代码的执行流程。我根据捕获到的真实响应修改了伪造的api.wordpress.org用来返回序列化对象。以下是这个的一个简单例子:

我开始修改这些对象的属性并刷新相关的WordPress页面,来测试修改内容对结果页面有何影响(如果有的话)。在有些情况下WordPress使用了HTML编码来防止HTML/JavaScript注入,但是最终我发现了几个可以插入任意HTML和JavaScript的字段。请记住这个情况是发生在管理界面内,如果管理员登录并浏览“更新”或“插件”页面,攻击者就能够对WordPress站点执行MitM攻击或DNS欺骗,也可能会利用此漏洞实现远程代码执行。

在快速尝试一些JavaScript和Python脚本之后我有了假设漏洞的运用证明。这个PoC会导致WordPress管理界面中的“更新和插件”菜单旁显示一个徽章,表示有更新可用(当然即使没有也会显示),这可能会诱导管理员点击这些链接来检查并可能安装这些更新。如果有管理员点击任一链接,那么一个JavaScript payload被注入到该页面中,然后就添加了一个新的管理员账户并将一个基本PHP命令shell注入到现行的WordPress主题的index.php中。

在大多数情况下这种PoC攻击足以实现代码执行,但是我也发现了我可以使用类似方式向WordPress发送一个错误的插件更新来攻击WordPress管理界面的点击更新功能,如果有管理员点击了更新按钮,就会导致下载一个假插件更新的ZIP文件并将其提取至服务器上。

深入挖掘这一点,我注意到即使没有登录,WordPress也会发送了类似对api.wordpress.org的HTTP请求,我开始对WordPress进行代码审计来了解其中发生了什么,以及它是否可能遭受了类似攻击。我在wp-includes/update.php文件中发现了wp_schedule_update_checks()函数。



[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//