對的你沒看錯
還是 PHP
就說它很香了
今天來講的是一個關於物件導向的高牆
其實這種反序列化漏洞不只在 PHP 有
還有偉大的 OOP 大宗 Java
全名 Object-Oriented Programming
是具有物件概念的程式設計
可以包含資料、屬性、程式碼與函數等
整個架構中
就是以一個一個小物件堆疊而成
在 OOP 中有三個重要的概念
帶大家快速認識認識
物件內部資源無法被直接使⽤
須經由物件提供的 "介⾯" 做存取
⼦類別可以繼承及覆寫⽗類別的變數、⽅法
使⽤同⼀抽象介⾯但以不同⽅式實作
在 OOP 中
程式語言如何將一個抽象的物件儲存下來呢
它會將這些抽象的物件轉換成一種固定格式的字串
用來描述該物件的一些特徵
以方便未來可以轉換回去做使用
這個行為就叫做序列化
在 php 中有兩個函數
serialize()
<-> unserialize()
其功能就是
object <-> string
接下來的練習推薦大家可以去 PHP Sandbox 跟著一起動手看看
class Test
{
public $var = 'aaa';
};
$obj = new Test();
echo serialize($obj);
會輸出
最前面的 O
代表物件
而後面的 s
代表字串
要注意的是每一個變數都是由 名稱 + 值
的方式表達
那名稱跟值又會分別以 型態 + 數字 + 值
的格式
如果是物件
後面包的東西是用大括號,且結尾不需要分號
如果是一般變數
會以 名稱 + 分號 + 值 + 分號
的形式
PHP 中有其他種不同的型態
序列化後每一個都有它的代號
代號 | 意義 |
---|---|
a | array |
b | boolean |
d | double |
i | integer |
o | common object |
r | reference |
s | non-escaped string |
C | custom object |
O | class |
N | null |
R | pointer reference |
S | escaped string |
U | unicode string |
在了解基本的序列化格式後
我們來看看在物件導向中的三種不同權限的變數
這三種變數在被 PHP 序列化出來後有非常特別的差異
class Test
{
public $var = 123;
protected $var2 = 123;
private $var3 = 123;
};
echo serialize(new Test);
我們可以發現印出來的三種變數都呈現不一樣的表示方式
O:4:"Test":3:{s:3:"var";i:123;s:7:"*var2";i:123;s:10:"Testvar3";i:123;}
長這樣
權限 | 序列化後的字串 |
---|---|
public | s:3:"var";i:123; |
protected | s:7:"*var2";i:123; |
private | s:10:"Testvar3";i:123; |
public 變數名稱沒有被特別的更動
protected 在變數名稱前面有用一個 * 跟著
private 會有 class 名稱被放在前綴
但這邊的 protected 與 private 有個小陷阱
其實在那個前綴的地方
都有一個 \x00
的字元包覆著
所以你用 sandbox 印出來會長這樣
出現一個問號的字元
所以正確的輸出應該是
權限 | 序列化後的字串 |
---|---|
public | s:3:"var";i:123; |
protected | s:7:"\0*\0var2";i:123; |
private | s:10:"\0Test\0var3";i:123; |