文章中反序列化触发点有两处,分别在发布文章和编辑文章的地方,代码相似,以其中之一举例
application/controllers/User.php:475

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 发布文章
function addxinzhi() {
$canpublish = intval ( $this->setting ['publisharticleforexpert'] );
if ($canpublish && $this->user ['grouptype'] != 1) {
if ($this->user ['expert'] == 0) { // 0 不是专家,1是专家
$this->message ( '发布文章只对认证专家开放!', 'topic/default' );
}
}
//省略代码
$outimgurl = $this->input->post ( 'outimgurl' );

if ($_FILES ['image'] ['name'] == null && trim ( $outimgurl ) == '') {
$this->message ( '封面图和外部图片至少填写一个!', 'user/addxinzhi' );

exit ();
}

if (trim ( $outimgurl ) != '' && $_FILES ['image'] ['name'] == null) {
$filepath = '/data/attach/topic/topic' . random ( 6, 0 ) . '.jpg';
//反序列化点
image_resize ( $outimgurl, FCPATH . $filepath, 300, 240 );

上面最后一行代码中的image_resize函数对POST的$outimgurl进行了处理,跟进代码
system/helpers/public_helper.php:2068

1
2
function image_resize($src, $dst, $width, $height, $crop = 0) {
return imagecropper ( $src, $dst, $width, $height );

跟进imagecropper,同文件第1997行

1
2
function imagecropper($source_path, $dst, $target_width, $target_height) {
$source_info = getimagesize ( $source_path );

进入getimagesize函数,众所周知,可以用phar://协议进行反序列化

接着花了很长时间终于构造出一条POP链,最后发现phpggc里面有,气吐血~

Guzzle组件

phpggc给了三条Guzzle组件的POP链,其中两条用到了GuzzleHttp\Psr7\FnStream类,但是该类从1.5.0版本开始添加了__wakeup,限制了利用(php<=5.6.24还是可以绕过的)

而仅剩的这条POP链末端是file_put_contents,这样在反序列化中我们必须指定绝对路径来写入文件

Getshell思考

如何在不知道网站路径的情况下写入文件Getshell呢?我现在几种思路:

  1. 通过报错得到网站路径
  2. Windows下,找利用><猜测路径的点
  3. 尝试使用常见WEB目录
  4. 将shell写入已知目录,再文件包含

对于第1、2两点,翻了下代码没找到,放弃

对于第3点其实就是爆破web目录,Linux基本就是/var/www或者/var/www/html之类的目录,Windows下各种一件集成工具的目录收集一波

对于第4点,我确实找到了,但是该包含点需要跳文件或者不存在的目录,所以只能在Win下进行
代码在application/controllers/Plugin/Plugin_weixin.php:183

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function ajaxrequestresult() {
$message = array ();
$logdir = FCPATH . '/data/logs/';
$yearmonth = gmdate ( 'Ym', $_SERVER ['REQUEST_TIME'] );
//可控点
$logfile = $logdir . $yearmonth . '_' . $_POST ['name'] . '.php';
if (! file_exists ( $logfile )) {
$message ['code'] = 2005;
$message ['logintime'] = time();
$message ['msg'] = "请打开微信扫一扫";
// $message ['filename'] = $logfile;
} else {
//包含点
$message=include ($logfile);
if($message['code']==2000){

Guzzle/FW1利用过程

  1. 一个有文章发布权限的帐号,登录
  2. 猜测WEB目录在D盘
  3. 通过phpggc的Guzzle/FW1链生成phar.jpg
  4. 上传,并获取到上传后的路径
  5. 发布或修改文章,添加外部图片链接为phar://path/to/phar.jpg,提交触发反序列化
  6. 对应D盘根目录生成shell.php
  7. 使用文件包含包含shell.php