代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

  • A+
所属分类:代码审计

公众号:安全客资讯平台(ID:anquanbobao)
作者:osword

前言

前几天审计某cms基于ThinkPHP5.0.24开发,反序列化没有可以较好的利用链,这里分享下挖掘ThinkPHP5.0.24反序列化利用链过程.该POP实现任意文件内容写入,达到getshell的目的

环境搭建

Debian

apache2+mysql+ThinkPHP5.0.24+php5.6

下载地址:http://www.thinkphp.cn/donate/download/id/1279.html

文件:application/index/controller/Index.php

<?php
namespace appindexcontroller;


class Index
{
public function index($input='')
{
echo "Welcome thinkphp 5.0.24";
echo $input;
unserialize($input);
}
}

访问:http://127.0.0.1/cms/tp50/public/index.php

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

简述

Thinkphp 5.0.x反序列化最后触发RCE,要调用的Request__call方法.

但是由于这里self::$hook[$method]不可控,无法成功利用

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

我的思路是在找其他的__call,其他魔术方法搜了一圈没有可以进一步利用.

文件:thinkphp/library/think/console/Output.php

最后选择Output类中的__call方法,这里调用block方法.后续可以当做跳板

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

POP链分析

从头开始分析

反序列化起点:thinkphp/library/think/process/pipes/Windows.php removeFiles方法

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

跟进removeFiles方法

跳板:file_exists方法能够触发__toString魔术方法

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

跳板利用点:thinkphp/library/think/Model.php

Model抽象类的 __toString

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

跟进toJson方法至toArray方法

如下图Model抽象类toArray方法,存在三个地方可以执行__call

但是我们目的是调用Output类__call且能够继续利用,调试后选择第三处当做调板

 $item[$key] = $value ? $value->getAttr($attr) : null;

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

分析下如何达到该行代码

 $item[$key] = $value ? $value->getAttr($attr) : null;

这里直接看else分支

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

溯源$values变量,比较关键是下面两行

$modelRelation = $this->$relation();
$value = $this->getRelationData($modelRelation);

$modelRelation值可以利用Model类中的getError方法

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

跟进getRelationData方法,这里最后传入的$modelRelation需要Relation类型

最后返回值$values需要经过if语句判断

$this->parent && !$modelRelation->isSelfRelation() && get_class($modelRelation->getModel()) == get_class($this->parent)

全局搜索下,可以利用HasOne类

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

最后$attr值,由$bindAttr = $modelRelation->getBindAttr();执行后的结果.

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

跟进OneToOne抽象类getBindAttr方法,binAttr类变量可控.

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

至此代码执行到$item[$key] = $value ? $value->getAttr($attr) : null;就能够执行Output类__call魔术方法

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

跟进Output类block方法

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

继续跟进writelin方法,最后会调用write方法

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

这里$this->handle可控,全局搜索write方法,进一步利用

定位到:thinkphp/library/think/session/driver/Memcached.php

类:Memcached

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

继续搜索可用set方法

定位到:thinkphp/library/think/cache/driver/File.php

类:File

最后可以直接执行file_put_contents方法写入shell

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

$filename可控且可以利用伪协议绕过exit

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

$data值比较棘手,这里有个坑,由于最后调用set方法中的参数来自先前调用的write方法

只能为true,且这里$expire只能为数值,这样文件内容就无法写shell

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

继续执行,跟进下方的setTagItem方法

会再执行一次set方法,且这里文件内容$value通过$name赋值(文件名)

所以可以在文件名上做手脚

示例:php://filter/write=string.rot13/resource=./<?cuc cucvasb();?>

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

 

POP链(图)

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

 

EXP

马赛克

 

复现

写入文件

实战是需要找个可写目录

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

读取文件

代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

结语

感谢@水泡泡师傅解答问题

整条POP分析下来挺有趣,希望师傅们喜欢.

米斯特代码审计小组招新:

要求:练掌握一门及以上如C++/Java/PHP/Python编程语言

           在先知/360cloudbug提交过高危及以上危害漏洞

           简历附带高危漏洞报告投递[email protected]

           抄送[email protected]


安全客:有思想的安全新媒体。
声明:本文经安全客授权发布,转载请联系安全客平台。

本文始发于微信公众号(米斯特安全团队):代码审计 | ThinkPHP v5.0.x 反序列化利用链挖掘

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: