
1. 環境準備:
操作系統: Ubuntu 16.04 64位
PHP版本: 5.5.14
gcc編譯組件
編譯PHP: 先到PHP官網下在我們需要的PHP目標版本源文件.
http://php.net/releases/
安裝GCC: apt install gcc make automake libxml2-dev gdb
解壓源碼包: tar xvf php-5.5.14.tar.gz
生成Makefile文件: 進入剛才我們解壓好的源碼目錄執行:./configure --enable-debug --prefix=$HOME/php/php-5.5.14;
prefix表示要安裝的目錄,因為這裡我們是搭建調試環境,建議給不同的版本設定不同的目錄避免衝突; --enable-debug生成debug版本的程序.
編譯安裝:make && make installl
安裝完畢後我們進入安裝目錄: cd $HOME/php/php-5.5.14/; 執行./bin/php -v輸出版本號:
2. 幾個數據結構:
Zval是PHP中最重要的數據結構之一(另一個比較重要的數據結構是hash table),它包含了PHP中的變數值和類型的相關信息,是一個struct,基本結構為:
可以看到zval實際上是_zval_struct結構的一個別名,它包含了四個成員:
value -> zvalue_value類型的一個變數,包含變數的值或引用
refcount__gc -> 變數的引用計數
type -> 變數的類型,類型請查看源文件定義
is_ref__gc -> 標記變數是否是引用變數。對於普通的變數,該值為0,而對於引用型的變數,該值為1。
在源文件中我們可以看到zval.type支持以下幾種類型:
zvalue_value: 它是一個聯合體,保存真實的變數或引用.
Bucket結構:HashTable相當於Array對象,而Bucket相當於Array對象里的某個元素。對於多維數組實際就是HashTable的某個Bucket里存儲著另一個HashTable。
3. PHP對象序列化後的數據
通過下面的腳本我們可以生成一個DateTimeZone的一個對象,並列印這個對象序列化後的數據:
從輸出的部分看:O表示對象, :12為對象標籤的長度, :2表示對象包含兩個鍵值對; 第一個元素鍵為timezone_type,值是一個Int類型的1, 第二個元素鍵為timezone,值是一個字元串.這裡就是一個DateTimeZone對象序列化後的數據.
當PHP在進行反序列化的時候會將上面字元串解析並填充到zval與zvalue_value等數據結構中.
4. 反序列化
PHP中對應的反序列化函數是:unserialize,在原代碼中對應的函數是php_var_unserialize.下面我們通過gdb來看一下,DateTimeZone在內存中的結構.
通過源碼我們可以看出來zend_hash_find從HashTable中找出指向timezone的zval指針然後保存到了z_timezone. 然後timezone_initialize會利用z_timezone對tzobj進行初始化,用gdb來看看內存中的數據: 執行next單步指令,將程序運行到return SUCCESS這一行, 然後觀察兩個參數.
5. 反序列化利用
運行後發現一些有趣的東西, 看到了一些不能識別的字元. 對上反序列化字元串可以發現:s:6:"+08:00"被替換成了i:1123123123,
這個時候應該已經可以猜到了, DataTimeZone在重建的時候把最後一個對象認為是一個指向字元串的指針了(這個值可以隨意修改指向當前進程空間的任何位置). 再看看timezone_initialize函數:
本來i:1123123123應該指向一個合法的表示時區的字元串,但現在指針的值經過修改後指向了一個內存空間,可以看到timelib_parse_zone函數如果解析失敗,php_error_docref就會將原本應該指向一個合法字元串的指針指向的數據給列印到終端.
喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!
本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!
請您繼續閱讀更多來自 全球大搜羅 的精彩文章:
※秋冬裙裝搭配新技能,讓你美完整個秋冬
※多變春天,用一衣多穿完美應對「任性」的溫度
TAG:全球大搜羅 |