[Web 安全] PHP 反序列化漏洞 —— PHP 序列化 反序列化

關注這個專欄的其他相關筆記:[Web 安全] 反序列化漏洞 - 學習筆記-CSDN博客

0x01:PHP 序列化 — Serialize

序列化就是將對象的狀態信息轉化為可以存儲或傳輸的形式的過程,在 PHP 中,通常使用 serialize() 函數來完成序列化的操作。

下面筆者直接簡要點列出各個數據類型序列化之后的結果,不信的崽崽可以自己跑一下:

?echo serialize(null); ? ? ? // N;echo serialize(123); ? ? ? ?// i:123; ? => int 類型的值為 123echo serialize(123.3); ? ? ?// d:123.3; => double 類型的值為 123.3echo serialize(true); ? ? ? // b:1; ? ? => Boolean 類型的值為 Trueecho serialize("Blue17"); ? // s:6:"Blue17"; => String 類型的值為 Blue17echo serialize(array("Blue17", 17, null)); // a:3:{i:0;s:6:"Blue17";i:1;i:17;i:2;N;}

0x0101:序列化結果解析 — Array 類型

這部分筆者就簡單分析一下上面 Array 類型序列化后的結果:

?echo serialize(array("Blue17", 17, null)); // a:3:{i:0;s:6:"Blue17";i:1;i:17;i:2;N;}?/*a:3 ? ? ? ? ? ? ? => array 中有三個元素i:0;s:6:"Blue17"  => index 為 0 的地方是一個長度為 6 的 String 類型的元素,值為 Blue17i:1;i:17; ? ? ? ? => index 為 1 的地方是一個 int 類型的元素,值為 17i:2;N; ? ? ? ? ?  => index 為 2 的地方是一個 Null 類型的元素。*/

0x0102:序列化結果解析 — 類

類的序列化結果基本大差不差,但是不同 “訪問類型” 的變量序列化的結果有很大差異,這部分筆者就按照 “訪問類型” 進行分類,并對每個單獨進行講解。

1. 類序列化結果解析 —— Public 型

這里我們開始進入正規,講講最常見的類的序列化結果,先來一個最常見的試試水:

?<?php?class demo {public $var1; ? ? ? ? ? ? ? // 這個變量沒有賦值public $var2 = "Blue17"; ? ?// 這個變量賦予了字符串類型的值var $var3 = 17; ? ? ? ? ?// 雖然修飾符是 var 但其實還是 public 類型的?function printVar($var) {$localVar = $var; ? ?// 類方法中的局部變量echo $localVar;}}?// O:4:"demo":3:{s:4:"var1";N;s:4:"var2";s:6:"Blue17";s:4:"var3";i:17;}echo serialize(new demo(array(123)));

下面我們仔細分析一下結果,可以看到,它序列化的結果基本全是變量,類中方法其實是沒有被序列化的,類中的局部變量也沒有被序列化

?O:4:"demo":3:{s:4:"var1";N;s:4:"var2";s:6:"Blue17";s:4:"var3";i:17;}?// O:4:"demo":3 => Object 對象是一個 4 字的叫 demo,其中有 3 個屬性(變量)// s:4:"var1";N; => 屬性名稱占 4 字節,叫 var1 其值是 Null 類型// s:4:"var2";s:6:"Blue17" => 屬性名稱占 4 字節,叫 var2,其值是 String 類型,長度為 6 內容是 Blue17// s:4:"var3";i:17; => 屬性名稱占 4 字節,叫 var3,其值是 int 類型,值為 17。

2. 類序列化結果解析 —— Protected 型

下面我們來看看如果類的屬性中混入了 Protect 型的變量它序列化的結果長啥樣吧:

?<?php?class demo {protected $var1; ? ? ? ? ? ? ? // 這個變量沒有賦值protected $var2 = "Blue17"; ? ?// 這個變量賦予了字符串類型的值protected $var3 = 17; ? ? ? ? ?// 雖然修飾符是 var 但其實還是 public 類型的}?echo serialize(new demo()) . "\n";// O:4:"demo":3:{s:7:"*var1";N;s:7:"*var2";s:6:"Blue17";s:7:"*var3";i:17;}?echo urlencode(serialize(new demo()));// O%3A4%3A%22demo%22%3A3%3A%7Bs%3A7%3A%22%00%2A%00var1%22%3BN%3Bs%3A7%3A%22%00%2A%00var2%22%3Bs%3A6%3A%22Blue17%22%3Bs%3A7%3A%22%00%2A%00var3%22%3Bi%3A17%3B%7D

下面我們仔細分析一下結果,這里筆者特意對它序列化后的結果做了一個編碼,因為里面其實有一些不可見的字符,不編碼是看不出來的,大部分內容其實與 Public 一致,但是被 protected 修飾的變量序列化后的內容就有很大不同了:

?O:4:"demo":3:{s:7:"*var1";N;s:7:"*var2";s:6:"Blue17";s:7:"*var3";i:17;}?// s:7:"*var1";N; => 屬性名稱占 7 個字節?怎么數著只有 5 個??// 這個是 URL 編碼后的內容:s%3A7%3A%22%00%2A%00var1%22%3BN%3B// 這個是簡單解碼后的樣子:s:7:"%00*%00var1";N;

如上,可以發現,Protected 屬性序列化后明面看只有 *var1 這樣,但其實 * 兩邊其實還藏了兩個 ASCII 碼值為 0 的字符 (這也引出后面一個 Bug,在嘗試構造反序列化值得時候,不建議通過直接復制就篡改被 Protected 或者 Private 修飾的值,因為你復制得內容一般都不全,會丟掉這個特殊的 %00)。

3. 類序列化結果解析 —— Private 型

下面我們來看看如果類的屬性中混入了 Private 型的變量它序列化的結果長啥樣吧:

?<?php?class demo {private $var1; ? ? ? ? ? ? ? // 這個變量沒有賦值private $var2 = "Blue17"; ? ?// 這個變量賦予了字符串類型的值}?echo serialize(new demo()) . "\n";// O:4:"demo":2:{s:10:"demovar1";N;s:10:"demovar2";s:6:"Blue17";}?echo urlencode(serialize(new demo()));// O%3A4%3A%22demo%22%3A2%3A%7Bs%3A10%3A%22%00demo%00var1%22%3BN%3Bs%3A10%3A%22%00demo%00var2%22%3Bs%3A6%3A%22Blue17%22%3B%7D

下面我們仔細分析一下結果,這里筆者特意對它序列化后的結果做了一個編碼,因為里面其實有一些不可見的字符,不編碼是看不出來的,大部分內容其實與 Public 一致,但是被 Private 修飾的變量序列化后的內容就有很大不同了:

?O:4:"demo":2:{s:10:"demovar1";N;s:10:"demovar2";s:6:"Blue17";}?// s:10:"demovar1";N; => 屬性名稱占 10 個字節?怎么數著只有 8 個??// 這個是 URL 編碼后的內容:s%3A10%3A%22%00demo%00var1%22%3BN%3B// 這個是簡單解碼后的樣子:s:10:"%00demo%00var1";N; => %00 算一位,數一數,剛好 10 位

如上,可以發現,Private 屬性序列化后明面看只有 demovar1 這樣,但其實類名兩邊其實還藏了兩個 ASCII 碼值為 0 的字符,所以其真實格式為(URL 編碼后的哈,不編碼的話 ASCII 值為 0 的其實是不可見字符) %00類名%00變量名

0x02:PHP 反序列化 — Unserialize

以下是反序列化相關的幾個特性:

  • 反序列化就是將序列化得到的字符串轉化為一個對象的過程。

  • 反序列化生成的對象成員屬性值由被反序列化的字符串決定,與原來類預定義的值無關。

  • PHP 中通過 unserialize() 函數進行反序列化,序列化使用 serialize() 函數。

  • 反序列化不觸發類的成員方法,需要被調用方法后才會被觸發。(不一定,這個后面講)

下面筆者就以 Public 型的類為例,講解一下反序列化的用處(另外兩種類型,流程一致,但是要特別注意 %00 到底有沒有被復制過去,如果報錯了,一般就是這個的問題)。

0x0201:反序列化 —— 正常流程

首先是比較簡單的 Public 型類的反序列化,我們先創建一個類,假設叫 Note (筆記)類吧,然后我們寫筆記就要實例化這個類,然后往這個類的對象里寫東西,代碼如下:

<?phpclass Note {public $title;   // 筆記標題public $content; // 筆記內容// 記錄標題 & 內容function write($title, $content) {$this -> title = $title;$this -> content = $content;}// 讀取標題 & 內容function read() {echo "Title: " . $this -> title . "\n";echo "Content: " . $this -> content . "\n";}
}// 實例化筆記類
$note = new Note();
// 往筆記里寫東西
$note -> write("Hello, World!!", "Today Is a Nice Day!!");

如上,我們已經往筆記里寫東西了,寫了你要保存吧,可是你是個對象你咋保存?這時就可以使用序列化,把 $note 這個對象里的內容序列化然后存儲在一個文件里:

// 保存 $note 筆記里的東西
echo serialize($note); // O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}

OK,保存了你過段時間得看吧,給你看下面這個東西你又看不懂是不是:

O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}

這個時候就需要用我們軟件進行反序列化然后再調用 read 方法了是吧:

// 保存 $note 筆記里的東西
$save = serialize($note); // O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}// 查看保存的內容
$raw = unserialize($save); // 對序列化的內容進行反序列化
$raw -> read();

如上,可以看到,通過反序列化被保存的值,我們成功還原了用戶筆記里寫的東西。下面是整個測試的源碼(這里筆者特別提醒,反序列化的環境中要有序列化的那個類,不然即使反序列化了也是無法執行類的方法的):

<?php// 創建筆記類
class Note {public $title;   // 筆記標題public $content; // 筆記內容// 記錄標題 & 內容function write($title, $content) {$this -> title = $title;$this -> content = $content;}// 讀取標題 & 內容function read() {echo "Title: " . $this -> title . "\n";echo "Content: " . $this -> content . "\n";}
}// 實例化筆記類
$note = new Note();
// 往筆記里寫東西
$note -> write("Hello, World!!", "Today Is a Nice Day!!");// 保存 $note 筆記里的東西
$save = serialize($note); // O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}// 查看保存的內容
$raw = unserialize($save); // 對序列化的內容進行反序列化
$raw -> read(); // 執行類的成員方法

0x0202:反序列化 —— 異常流程

我們繼續假設,我們剛剛是本地的,假設你寫了筆記,然后你要上傳,那你上傳服務端的序列化的內容就是下面這個:

O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:21:"Today Is a Nice Day!!";}

假設,攻擊者截獲了這個內容,按照 PHP 序列化的格式自己改了一下(主要是改內容和長度):

O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:25:"Today Is NOT a Nice Day!!";}

如上,我們添加了一個單詞 Not ,然后修改了長度,然后我們 “發送” 到服務端,讓他讀一下,代碼如下:

<?php// 創建筆記類
class Note {public $title;   // 筆記標題public $content; // 筆記內容// 記錄標題 & 內容function write($title, $content) {$this -> title = $title;$this -> content = $content;}// 讀取標題 & 內容function read() {echo "Title: " . $this -> title . "\n";echo "Content: " . $this -> content . "\n";}
}
// 接收的信息
$receive = 'O:4:"Note":2:{s:5:"title";s:14:"Hello, World!!";s:7:"content";s:25:"Today Is NOT a Nice Day!!";}';$raw = unserialize($receive); // 對序列化的內容進行反序列化
$raw -> read(); // 調用讀方法

如上,可以看到,結果就這樣被修改了。這就是前面介紹的反序列化的一個特性 “反序列化生成的對象成員屬性值由被反序列化的字符串決定,與原來類預定義的值無關。”,也是我們后面 “反序列化漏洞的依據”。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/71992.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/71992.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/71992.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

航空裝配自動化神器Ethercat轉profient網關搭配機器人精準控制

生產管理系統通過網關與裝配機器人連接&#xff0c;加快航空器機身的裝配速度&#xff0c;減少人為誤差。 航空制造對裝配線的精度和效率有著極高的要求。某航空制造廠使用的耐達訊Profinet轉EtherCAT協議網關NY-PN-ECATM&#xff0c;將其生產管理系統與裝配機器人連接&#xf…

什么是MySql的主從復制(主從同步)?

主頁還有其他面試題總結&#xff0c;有需要的可以去看一下&#xff0c;喜歡的就留個三連再走吧~ 1.什么是MySql的主從復制原理&#xff1f; 主從復制的核心就是二進制binlog&#xff08;DDL&#xff08;數據定義語言&#xff09;語句和DML&#xff08;數據操縱語言&#xff09…

自然語言處理:初識自然語言處理

介紹 大家好&#xff0c;博主又來給大家分享知識了。從這次開始&#xff0c;博主給大家分享自然語言處理這個領域的內容。這也是博主非常感興趣的研究領域。 最開始&#xff0c;博主計劃在自然語言處理系列的第一篇博文中&#xff0c;和大家聊聊文本規范化這個話題。畢竟在自…

【保姆級視頻教程(二)】YOLOv12訓練數據集構建:標簽格式轉換-劃分-YAML 配置 避坑指南 | 小白也能輕松玩轉目標檢測!

【2025全站首發】YOLOv12訓練數據集構建&#xff1a;標簽格式轉換-劃分-YAML 配置 避坑指南 | 小白也能輕松玩轉目標檢測&#xff01; 文章目錄 1. 數據集準備1.1 標簽格式轉換1.2 數據集劃分1.3 yaml配置文件創建 2. 訓練驗證 1. 數據集準備 示例數據集下載鏈接&#xff1a;P…

【人工智能】藍耘智算平臺盛大發布DeepSeek滿血版:開創AI推理體驗新紀元

&#x1f4dd;個人主頁&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的關注 &#x1f339;&#x1f339; ? 藍耘智算平臺 藍耘智算平臺核心技術與突破元生代推理引擎快速入門&#xff1a;三步調用大模型接口&#xff0c;OpenAI SDK無縫兼容實戰用例文…

【網絡編程】幾個常用命令:ping / netstat / xargs / pidof / watch

ping&#xff1a;檢測網絡聯通 1. ping 的基本功能2. ping 的工作原理3. ping 的常見用法4. ping 的輸出解釋5. ping 的應用場景6. 注意事項 netstat&#xff1a;查看網絡狀態 1. netstat 的基本功能2. 常見用法3. 示例4. 輸出字段解釋5. netstat 的替代工具6. 注意事項 xargs&…

【C++】:STL詳解 —— list類

目錄 list的概念 list的構造函數 list的大小 size() resize() empty() list的插入 push_front()和emplace_front() push_back()和emplace_back() insert()和emplace() list的刪除 pop_front() pop_back() erase() remove() remove_if() unique() clear()…

【數據結構】(11) Map 和 Set

一、Map 和 Set 的簡介 1、Set 和 Map Map 和 Set 是集合類框架學習的最后一部分。Map 和 Set 都是接口&#xff0c;需要通過 TreeSet、HashSet 和 TreeMap、HashMap 實例化。注意&#xff0c;Set 實現了 Collection&#xff0c;Map 并沒有。 Set 存放的是鍵&#xff08;Key&a…

關于CanvasRenderer.SyncTransform觸發調用的機制

1&#xff09;關于CanvasRenderer.SyncTransform觸發調用的機制 2&#xff09;小游戲Spine裁剪掉幀問題 3&#xff09;Dedicated Server性能問題 4&#xff09;.mp4視頻放入RT進行渲染的性能分析閉坑指南 這是第421篇UWA技術知識分享的推送&#xff0c;精選了UWA社區的熱門話題…

Kronecker分解(K-FAC):讓自然梯度在深度學習中飛起來

Kronecker分解&#xff08;K-FAC&#xff09;&#xff1a;讓自然梯度在深度學習中飛起來 在深度學習的優化中&#xff0c;自然梯度下降&#xff08;Natural Gradient Descent&#xff09;是一個強大的工具&#xff0c;它利用Fisher信息矩陣&#xff08;FIM&#xff09;調整梯度…

【HTML— 快速入門】HTML 基礎

準備工作 vscode下載 百度網盤 Subline Text 下載 Sublime Text下載 百度網盤 vscode 下載 Sublime Text 是一款輕量好用的文本編輯器&#xff0c;我們在寫前端代碼時&#xff0c;使用 Sublime Text 打開比使用記事本打開&#xff0c;得到的代碼體驗更好&#xff0c;比 vscode…

鴻蒙開發深入淺出01(基本環境搭建、頁面模板與TabBar)

鴻蒙開發深入淺出01&#xff08;基本環境搭建、頁面模板與TabBar&#xff09; 1、效果展示2、下載 DevEco Studio3、創建項目4、新建頁面模板5、更改應用信息6、新建以下頁面7、Index.ets8、真機運行9、圖片資源文件 1、效果展示 2、下載 DevEco Studio 訪問官網根據自己的版本…

自動駕駛泊車算法詳解(一)

自動駕駛泊車算法是自動駕駛技術中的重要組成部分&#xff0c;主要用于實現車輛在復雜場景下的自動泊車功能&#xff08;如垂直泊車、側方位泊車、斜列泊車等&#xff09;。其核心目標是通過感知、規劃和控制技術&#xff0c;使車輛在無人工干預的情況下安全、高效地完成泊車動…

鴻蒙next 點擊穿透實現

點擊穿透可以參考華為開發的保留文章,該章節只能在developer preview版本下查看 點擊穿透 主要的方法是hitTestBehavior // xxx.ets Entry Component struct HitTestBehaviorExample {build() {// outer stackStack() {Button(outer button).onTouch((event) > {console.i…

27.[前端開發-JavaScript基礎]Day04-函數基本使用-遞歸-變量作用域-函數式編程

一、JavaScript函數 1 認識JavaScript函數 程序中的foo、bar、baz 認識函數 函數使用的步驟 2 函數的聲明和調用 聲明和調用函數 函數的參數 有參數的函數練習 函數的返回值 函數的練習 arguments參數&#xff08;JS高級再學習&#xff09; 3 函數的遞歸調用 函數中調用函數…

藍橋杯練習代碼

一、最長公共前綴 編寫一個函數來查找字符串數組中的最長公共前綴。 如果不存在公共前綴,返回空字符串 ""。 示例 1: 輸入:strs = ["flower","flow","flight"] 輸出:"fl"示例 2: 輸入:strs = ["dog",&q…

添加成對約束后的標簽傳播算法研究:使用Python語言編寫算法,在空手道數據集下驗證算法的準確性,在一定程度上解決非對齊問題

背景&#xff1a; 輔導的過程中遇到了一個比較新穎的問題&#xff0c;下面是我對這個問題的分析和簡要思路介紹。 思路分析&#xff1a; 這算機器學習下面的無監督學習&#xff0c;標簽傳播算法簡稱LPA&#xff0c;傳統的標簽傳播算法會出現非對齊問題&#xff0c;一句話描述就…

鴻蒙開發第4篇__關于在鴻蒙應用中使用Java語言進行設計

本博文很重要 HarmonyOS從 API8 開始不再支持使用Java作為開發語言&#xff0c;未來的新功能將在ArkTS中實現. API 8對應的是HarmonyOS 3.0.0版本。請看下圖&#xff1a; 因此&#xff0c; 讀者如果看到類似《鴻蒙應用程序開發》(2021年版本 清華大學出版計)書 還使用Java語言…

sklearn機器學習 Python代碼通用模板

以下是一個使用 scikit-learn&#xff08;sklearn&#xff09;進行機器學習的通用 Python 代碼模板。這個模板涵蓋了數據加載、預處理、模型訓練、評估和預測的基本流程&#xff0c;適用于常見的機器學習任務。 python # 導入必要的庫 import numpy as np import pandas as …

P9420 [藍橋杯 2023 國 B] 雙子數--最高效的質數篩【埃拉托斯特尼篩法】

P9420 [藍橋杯 2023 國 B] 雙子數 題目 分析代碼 題目 分析 首先&#xff0c;我們如何找到雙子數&#xff1f; 1&#xff09;找到所有質數滿足范圍內的質數&#xff08;即至少質數^2<23333333333333) 我們看見雙子數x的范圍2333<x<23333333333333&#xff0c;又因為…