当前位置:首页 > HTML技巧 > 正文

Joomla-3.4.6远程代码执行漏洞原理分析和Poc构造

11-16 HTML技巧

上周,意大利安全公司Hacktive Security的研究员AlessandroGroppo公开了影响Joomla内容管理系统老旧版本3.0.0至3.4.6(在2012年9月末至2015年12月中旬发布)的0day详情。该漏洞是一个PHP对象注入漏洞,可导致远程代码执行后果。它尚不存在CVE编号且易于利用,类似于CVE-2015-8562。建议使用就版本的用户更新到安全版本。

在此次漏洞复现和原理分析过程中,学到很多东西,在这里要感谢PHITHON关于Joomla远程代码执行漏洞的总结,让我少走了很多弯路。

浏览器访问安装注意:第3步最终确认哪里,应该选择 不安装示范数据,目前测试的是选择博客风格的示范内容不能成功复现安装成功

可以用NC 监听和菜刀连接 由于我的PHP是Windows环境所以无法反弹只能通过菜刀连接

通过漏洞复现和分析py脚本可以知道,在上传shell的时候有以下几步,之所以有这么手工步骤主要与Joomla的会话机制有关。

利用PHP自带的file_put_contents函数写入webshell到configuration.php中,webshell内容如下:

4.发送带有写入webshell的请求 主要构造username,password,option,task,csrftoken等字段

这个漏洞是和Joomla的会话的运作机制有关,Joomla 会话以 PHP Objects 的形式存储在数据库中且由 PHP 会话函数处理,但是由于Mysql无法保存Null 字节,函数在将session写入数据库和读取时会对象因大小不正确而导致不合法从而溢出。因为未认证用户的会话也可存储,所以该对象注入 (Object Injection) 可以在未登录认证的情况下攻击成功,导致RCE。

当我们在 Joomla中执行 POST 请求时,通常会有303重定向将我们重定向至结果页。这是利用的重要事项,因为第一个请求(含参数)将只会导致 Joomla 执行动作并存储(例如调用write() 函数)会话,之后303重定向将进行检索(如调用read() 函数)并将信息显示给用户。

漏洞利用文件 ‘libraries/joomla/session/storage/database.php’中定义的函数 read()和 write()由session_set_save_handler()设置,作为‘libraries/joomla/session/session.php:__start’session_start() 调用的读和写处理程序。

由于Mysql无法保存Null 字节,libraries/joomla/session/storage/database.php的write函数在将数据存储到数据库之前(write函数)会用‘’替换‘002a00’(chr(0).’’.chr(0)),而在序列化对象中, $protected变量被赋予‘002a00’前缀。

当读取数据库中的数据时, read 函数会用‘002a00’(NN)替换‘’,重构原始对象。

这种替换的主要问题在于它用3个字节替换了6个字节。这种代码在Joomla3.0.0到3.4.6 版本中一直存在。从 3.4.7 版本开始,会话是 base64 编码形式存储在数据库中。

如之前所述,我们能够通过动作参数的读取和写入来操纵该会话对象进行注入将被3个字节替换的‘’,导致对象因大小不正确(字节长度不同)导致不合法,造成溢出。

比如一个登录表单,在 username 字段中放入‘my002a00username’,经过write函数处理后将在数据库中得到如下对象:

当该会话对象被 read 函数中读取时,‘’将被以如上所述方式所替代,得到如下值:s:8:s:usernames:16:myN*Nusername不合法的大小

被替换的字符串只有13个字节长,但生命的字符串长度仍然是16个字节! 就可以愉快地利大神棋牌用这种“溢出”构造一个可以实现 RCE 的一个新的对象,在可以控制反序列化对象以后,我们只需构造一个能够一步步调用的执行链,即可进行一些危险的操作了。 在本次曝光的Poc中就是用username字段进行溢出,password字段进行对象注入,如果插入任意serialize字符串,构造反序列化漏洞了,到这里就和之前的漏洞CVE-2015-8562的比较相似了。

User-Agent:123}__test|O:21:"JDatabaseDriverMysqli":3:{s:4:"000a";O:17:"JSimplepieFactory":0:{}s:21:"000disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5

{}s:5:"cache";b:1;s:19:"cache_name_function";s:6:"assert";s:10:"javascript";i:9999;s:8:"feed_url";s:37:"phpinfo();JFactory::getConfig();exit;";}i:1;s:4:"init";}}s:13:"000connection";i:1;}4

当exp对象反序列化后,将会成为一个JDatabaseDriverMysqli类对象,不管中间如何执行,最后都将会调用__destruct,__destruct将会调用disconnect,disconnect里有一处敏感函

但很明显,这里的call_user_func_array的第二个参数,是我们无法控制的。所以不能直接构造assert+eval来执行任意代码。

于是这里再次调用了一个对象:SimplePie类对象,和它的init方法组成一个回调函数[new SimplePie(), 'init'],传入call_user_func_array。

所以,可以将其中第二个call_user_func的第一个参数cache_name_function,赋值为assert,第二个参数赋值为我需要执行的代码,就构造好了一个『回调后门』。

默认情况下SimplePie是没有定义的,这也是为什么我在调用SimplePie之前先new了一个JSimplepieFactory的原因,因为JSimplepieFactory对象在加载时会调用import函数将SimplePie导入到当前工作环境:

前面讲过由于Joomla的会话机制Post请求会被303重定向到结果页面所以无法回显,这里的phpinfo函数就用不了 选择用file_put_contents函数写入一句话到configuration.php中

免责声明:本文中提到的漏洞利用Poc和脚本仅供研究学习使用,请遵守《网络安全法》等相关法律法规。

版权保护: 转载请保留链接: http://lefkosaemlak.com/html/68.html