)
一、防御清單按性價比排序1.1 根除格式錯位最重要Session 反序列化能成立的前提是寫與讀的 serialize_handler 不一致。只要全鏈路統(tǒng)一就斷掉了錯位解析的物理基礎(chǔ)。統(tǒng)一session.serialize_handler能全站統(tǒng)一就統(tǒng)一推薦統(tǒng)一為php_serialize它格式最規(guī)范、不存在逐鍵|分隔的歧義各入口/各 SAPI/CLI 與 Web 的 php.ini 要一致不要在部分頁面用ini_set(session.serialize_handler, ...)臨時改改了就極易和別的頁面錯位更換 session 存儲后端files→Redis 等時確認(rèn)舊數(shù)據(jù)已清空避免舊格式文件被新后端讀取。1.2 不要讓用戶可控數(shù)據(jù)進(jìn) session或至少別原樣進(jìn)業(yè)務(wù)上少把請求參數(shù)直接$_SESSION[x] $_POST[x];。若必須存做校驗/白名單/轉(zhuǎn)義尤其警惕|與序列化特征串。1.3 收斂任意文件包含面Session 反序列化的兩條實戰(zhàn)鏈路最終都依賴能寫文件 能 include 文件。堵住 LFI/RFI、對 include 路徑做白名單能同時廢掉寫馬鏈路與大部分探測。1.4 會話層面加固session.use_strict_mode 1不接受服務(wù)器不認(rèn)識的 session id增加自定 id 預(yù)測文件名的難度嚴(yán)格控制 session 文件目錄權(quán)限只允許運行用戶讀寫別放在 web 可訪問/可下載的目錄session.save_path不要指向 web 根目錄之類能被直接 URL 訪問的地方。1.5 upload_progress 加固如果確實用不到session.upload_progress.enabled Off ; 或至少 session.upload_progress.cleanup On ; 確保上傳結(jié)束立即清 session.upload_progress.freq 1% session.upload_progress.min_freq 1用不到進(jìn)度條就干脆關(guān)掉能刪掉一個不需要業(yè)務(wù)漏洞的 session 寫點。1.6 代碼層縱深反序列化對象做允許類白名單PHP 7.4 支持在session_start()里配——不對那是unserialize()的allowed_classes選項Session 解碼默認(rèn)不過濾類。若可行用自定義 session handler / 反序列化前做類白名單校驗?zāi)軗踝∥粗愖⑷爰皶r升級 PHP跟進(jìn)官方 session 相關(guān)修復(fù)安全編碼規(guī)范里明確禁止把不可信內(nèi)容無差別寫入 session這條紅線。一句話記住防御核心統(tǒng)一 handler 格式 用戶輸入不進(jìn) session 別給文件包含 關(guān) upload_progress。二、審計視角怎么快速發(fā)現(xiàn)這種洞Step 1 找 session 的寫與讀分別用什么 handler grep serialize_handler / ini_set / session_start([serialize_handler 看不同頁面是否一致 —— 不一致 有戲 ? Step 2 找可控數(shù)據(jù)能否進(jìn) session 文件 a. $_SESSION[...] $_REQUEST/$_POST/$_GET/可拼接串 ... b. 無業(yè)務(wù)寫點 → 看 upload_progress.enabled 是否為 On能否用上傳寫點 ? Step 3 判斷寫點內(nèi)容能否承載 | 序列化對象有沒有過濾/轉(zhuǎn)義 | ? Step 4 找可利用類 / POP 鏈危險 __destruct/__wakeup/__toString/...能 autoload 注意 php_serialize 寫 php 讀 時對象類必須真實存在才會觸發(fā) ? Step 5 構(gòu)造 payload → 寫點提交 → 觸發(fā)讀取 → 驗證CTF 題面上通常給兩條線索幫你走完 Step 1一個文件里ini_set(session.serialize_handler, php_serialize)存了可控值另一個文件/入口只有默認(rèn)的session_start()。只要把兩者用同一個PHPSESSID串起來就是完整攻擊。三、CTF 常見題型套路怎么認(rèn)出來、突破口在哪出題套路特征線索突破口處理器錯位最經(jīng)典頁面 A 用 php_serialize 存用戶可控值頁面 B 默認(rèn) session_start提示詞常出現(xiàn) php_serialize構(gòu)造\|O:...注入對象upload_progress 注入給了上傳點但沒明顯業(yè)務(wù)寫 session或 hint 提 upload_progress文件名/PHP_SESSION_UPLOAD_PROGRESS 字段塞 payloadupload_progress LFI存在include $_GET[file]寫馬 include sess_id getshell反序列化 POP 鏈考察給了好幾個類/危險函數(shù)sink 定位 串鏈組合題全鏈路一個點觸發(fā)反序列化要求最終 RCE從注入對象到代碼執(zhí)行要自己串寫點→錯位→POP→sink做題建議順序不管多花哨的題都適用先讀源碼確認(rèn)session 相關(guān)配置與寫點別一上來就找 POP 鏈先確認(rèn)入口成不成立用本地同版本 PHP 把 payload 打在本地 session上xxd看文件字節(jié)對不對、能不能觸發(fā)再對著遠(yuǎn)程提交利用失敗時先回來查文件字節(jié)是否真寫對了。四、版本與配置差異速查關(guān)注點說明php_serialize處理器PHP ≥ 5.5.4session.upload_progress.*PHP ≥ 5.4默認(rèn) enabledOn解碼失敗行為PHP ≥ 7 報Failed to decode session object. Session has been destroyed.并清空__unserialize()優(yōu)先于__wakeup()PHP ≥ 7.4session id 合法字符A-Z a-z 0-9 - ,實測含下劃線會被拒session 默認(rèn)文件路徑Debian/Ubuntu/var/lib/php/sessions一般發(fā)行版/tmp可用session.save_path改session 文件命名sess_session_id五、推薦資源官方為主PHP 官方手冊中文Session 配置說明https://www.php.net/manual/zh/session.configuration.phpsession.serialize_handlerhttps://www.php.net/manual/zh/session.configuration.php#ini.session.serialize-handler會話上傳進(jìn)度https://www.php.net/manual/zh/session.upload-progress.phpsession_start()https://www.php.net/manual/zh/function.session-start.php魔術(shù)方法、繞過、POP 鏈兩篇。關(guān)于錯位注入 /|分隔的經(jīng)典思路可以搜中文社區(qū)關(guān)鍵字session 反序列化 php_serialize php 豎線注入、upload_progress session 寫馬 LFI結(jié)合多篇 writeup 對照理解不同作者對落盤時機(jī)的描述有出入以自己實測為準(zhǔn)。練習(xí)環(huán)境本地php -S Docker 自建不要用帶非法字符的 session id跑完記得清理 php -S 后臺進(jìn)程。六、最后一張圖全系列知識怎么串成記憶看一個請求/一個頁面 → handler 誰寫的誰讀的 │ 不一致 ▼ 能把可控字符串(含 | )弄進(jìn) session 文件嗎 業(yè)務(wù)寫點? / upload_progress? / LFI 觸發(fā)? │ 能 ▼ 文件里第一個 | 之后的字節(jié) 你的對象序列化 ▼ php_var_unserialize 創(chuàng)建對象 → 魔術(shù)方法 → POP 鏈 → sink(RCE)