Joomla 1.5~3.4 session对象注入漏洞
更新时间:
许可信息: 本文采用 自由转载-非商用-非衍生-保持署名 许可协议,作者alpha1e0,转载请注明作者或出处链接。
本文分析Joomla 1.5~3.4 session对象注入漏洞
1 漏洞原理
joomla在处理session时,会将User-Agent X-Forwarded-For存储到$_SESSION中,$_SESSION在加载的时候会反序列化,再加上其他特性最终导致对象注入。
以下的内容以joomla 3.2.1
为例进行分析
1.1 session中存储User-Agent X-Forwarded-For信息
@libraries/joomla/session/session.php #L974
其中,$this->set
会设置$_SESSION
1.2 PHP<5.6.13 中session反序列化机制(session.serialize_handle=php时)
在注入session的过程中,我们使用以下payload
User-Agent: }__test|a:2:{s:4:"talk";a:2:{s:6:"target";s:3:"tom";s:7:"counter";i:100;}s:2:"kk";s:4:"vvvv";}\xd8\x34\xdf\x06
序列化之后变成了
__default|a:8:{s:15:"session.counter";i:1;s:19:"session.timer.start";i:1465956802;s:18:"session.timer.last";i:1465956802;s:17:"session.timer.now";i:1465956802;s:22:"session.client.browser";s:98:"}__test|a:2:{s:4:"talk";a:2:{s:6:"target";s:3:"tom";s:7:"counter";i:100;}s:2:"kk";s:4:"vvvv";}
可以看到,session的序列化数据中,有两个key-value对,_default和_test
,很显然,session[_default]
部分是不可能反序列化的,我们的拼接导致了session[_default]
出错了,并且我们不可能构造正确的session[_default]
。
但是,在PHP<5.6.13版本中,当session中一个key-value反序列化出错后,PHP没有停止反序列化,而是继续下一个key-value的反序列化,而session[_test]
是我们可以控制的,唯一的麻烦是我们需要截断(session[User-Agent]后还有很多内容)
1.3 session存储在mysql数据库中的截断技巧
通过官网介绍
“The character set named utf8 uses a maximum of three bytes per character and contains only BMP characters. ”
mysql在使用utf8的时候,一个字符的大小的上限为3字节,而当出现四个字节的字符时,是需要用使用utf8mb4编码,不使用的话,会将不识别的四字节的字符连同后面的字符串一同舍弃
。
例如,使用特殊字符 进行更新
UPDATE user SET name = 'alice特殊字符some ' WHERE id =1;
则name会被更新为alice,some会被丢弃。
而具体哪些4字节的utf8 word会造成截断需要做fuzzing找
在Joomla中使用 \xd8\x34\xdf\x06 这个utf8 word来做截断
1.4 执行链构造
通过搜索eval/assert/call_user_func可以找到用于构造执行链的类,例如在joomla中找到如下:
@libraries/joomla/database/driver/mysqli.php JDatabaseDriverMysqli类 #L83
disconnect的定义 #L200
这个类唯一的问题是call_user_func_array中的参数部分不能控制,因此没有太大价值,只能做POC
例如控制参数:
$this->disconnectHandlers = array("print_r");
这样可以打印$this,可以构造POC,例如以下的生成payload的代码
@libraries/simplepie/simplepie.php SimplePie类 #L1544,init函数
可以看到,其中$this->cache_name_function和$this->feed_url都可以控制
只是init反序列化时候不能调用,因此需要结合JDatabaseDriverMysqli使用,即:
$this->disconnectHandlers = array(array(SimplePie实例,"init"));
这里还有一个问题,SimpliePie不是自动加载的,因此需要想办法把SimplePie加载一下,这里使用
@/libraries/legacy/simplepie/factory.php JSimplepieFactory类
该类会自动加载,加载的过程中会加载SimplePie
结合以上所有内容就得到了构建对象注入的方法,poc如下:
总结,该漏洞非常精巧,需要同时满足以下条件:
- User-Agent为检测直接存入$_SESSION
- PHP<5.6.13 session处理的小问题
- Mysql4字节urf8 word截断
- 可以构造执行链
2 参考:
- http://drops.wooyun.org/papers/11330
- http://bobao.360.cn/learning/detail/2501.html
- http://xteam.baidu.com/?p=177
- http://lynahex.com/index.php/archives/PHP-Object-Injection.html