boolean
<boolean(b)型態> : <值(0或1)>
b:0
或 b:1
int
<interger(i)型態> : <值 -2147483648~2147483647>
i:666
string
<string(s)型態> : <名稱長度> : <名稱>
s:4:"Baba"
array
<array(a)型態> : <array 長度> : { key ; value ; key ; value .....}
a:2:{i:1;s:3:"iam",i:2;s:4:"Baba"}
['A' => 123, 2 => 'aaa']
會變為 a:2:{s:1:"A";i:123;i:2;s:3:"aaa";}
object
Object (o) 型態 : <object 名稱長度> : <properties 數量> : {key; value; key; value; ...}
,其中:
%00*%00<property名稱>
%00<class名稱>%00<property名稱>
Object 的 method 不會被序列化。
e.g.
class Babaobject{
public $iam;
public $Baba = 666;
protected $not = "QAQ";
private $you = True;
}
O:10:"Babaobject":4:{s:3:"iam";N;s:4:"Baba";i:666;s:6:"%00*%00not";s:3:"QAQ";s:15:"%00Babaobject%00you";b:1;}
protected $not = "QAQ";
序列化後,直接印出會看到 s:6:"*not";s:3:"QAQ"
;而 private $you = True;
序列化後,直接印出會看到 s:15:"Babaobjectyou";b:1;
。之所以會看不到 %00
,是因為在 ascii 中 %00
為空字元,因此無法顯示,但在計算長度時仍可看出其確實存在,因而會比顯示的字元多 2 個字。(因此會看到 *not
的長度是 6
)NULL
<Null (n) 型態>
N
常見型
在 PHP 中,有許多 magic method 會在特定條件下自動執行,例如:
__wakeup
:反序列化時觸發__sleep
:序列化時觸發__destruct
:物件刪除時觸發舉例來說,如下的程式碼收到 網址?data=O:4:"Flag":0:{}
時,會反序列化出 Flag 物件,並印出 flag。
<?php
require('secret.php');
class Flag {
function __wakeup() {
global $flag;
echo $flag;
}
}
unserialize($_GET['data']);
有些時候我們可以利用竄改資料來達成目的,例如下方的例子,可以看出正常情況下 Flag
物件中的屬性 u
會是一個 User
實例,但我們反序列化時可以改成 Admin
,像是這樣 O:4:"Flag":1:{s:1:"u";O:5:"Admin":0:{}}
,如此便能拿到 flag。
<?php
require('secret.php');
class Flag {
function __construct() {
$this->u = new User();
}
function __destruct() {
$this->u->flag();
}
}
class User {
function flag() {
echo "No flag for ya~";
}
}
class Admin {
function flag() {
global $flag;
echo "Here you go: {$flag}";
}
}
unserialize($_GET['data']);
原生型
phar 型