在滲透入侵 VPS 之類的主機常常會有 open_basedir 以及 disable_functions 的保護
常見的繞過方法其實都滿容易防止的不過如果是針對 PHP 本身記憶體上的弱點懂得防禦的管理員相對就少很多了XD
而且對於一般主機,伺服器要求的是穩定所以也不能常常 update PHP 版本
因此抱著練練手感以及增加自己兵器庫的心態來寫寫這個 Exploit
主要參考 PoC 來源
(本想等到這個系列結束再來練不過作者富堅,只好自立自強自己的 Exploit 自己寫XD )
用到的弱點是 CVE-2015-0231
一個 PHP 在處理 unserialize 上所產生的 Use-After-Free ,先利用 O 製作出一個物件,接著清空它,之後再使用 serialize 中 的 R (reference) 去指向已被清空的物件造成 UAF 產生
(PHP 在 serialize / unserialize 上不知道發生過多少次問題了XD)
所以理論上只要是這個版本所影響的 PHP 版本
PHP 5.6 < 5.6.5
PHP 5.5 < 5.5.21
PHP 5.4 < 5.4.36
皆會被這個漏洞所影響
(未測試過所有版本無法保證正確性)
漏洞利用本質上就是 Use-After-Free
簡單修改偽造一個 zval物件去給他引用就可以達到任意地址寫入以及任意地址讀取
(原網址並沒有提供任意寫入的 PoC 要自己研究生XD)
任意跳轉的話把 zval 中 type 的部分設成 IS_OBJECT(0x5) 以及把 reference count 設成 0 就會自動被 GC(?) 掉了 XD
不過在這個 Exploit 中並沒有用到這招
一開始很單純的想法在 IDA pro 裡面看到 php binary 內有用到 popen 以及 fopen
兩個在 PHP 內的呼叫都是
resource popen ( string $command , string $mode )
resource fopen ( string $filename , string $mode [, bool $use_include_path = false [, resource $context ]] )
提供 $filename / $command 以及 $mode
可以直接利用 PHP 內的數據結構將所需的參數放到 popen 內
最後只要呼叫 fopen(‘/bin/id’, ‘r’) 應該就是個輕鬆寫意的利用XD
不過卡了很久最後 strace 發現…
PHP 中 fopen 最後是用 open 來實作,而 fopen 傳進去的第二個參數會被轉成 int oflag …
所以當 popen 在抓取第二個參數的字串時會出現記憶體存取錯誤
所以只好換條思路
找個 PHP 會引用到的 Function 而且兩個參數都為字串型式呢?
仔細觀察了一下 IDA pro 發現剛好有個符合需求 - rename
所以接下來的思路就是
- 讀取 popen 的 GOT 地址
- 寫入到 rename 的 GOT 地址中
- 在 PHP 中使用 rename( ‘ls -alh > /tmp/.xxx’, ‘r’ );
本地利用完美!
接著是遠端利用通用性的問題
遠端利用的情況下雖然有可能知道對方 PHP 的版本,但在無法確保 binary 的細節以及作業系統的情況下做出遠端 Exploit
但由於上面的 Exploit 會使用到 GOT 的位置,雖然可以洩漏任意地址,但在不知道 Image Base 的情況下也不知道該洩漏哪塊
如果是純 PHP CGI 或 FPM 的情況還好
x86 下沒有 PIE 還可以猜固定的 0x08048000 但是比較常見的情況是 Apache + libphp
Apache 加載 libphp5.so 後又會有 ASLR 的問題更難猜XD
不過由於 Apache 在 服務開啟後 create child 是用 prefork 的方式
所以 walk around 的解法是利用任意洩漏地址 brute dump 出 ELF header 後再去抓出 GOT address
(缺點會在 error.log 洗很多 Segmentation fault 就是了XD)
(不過可以先利用 leak heap 上的資訊判斷 library 加載的大致位置,可以確定最前面一個 byte 後 SHIFT 左右掃一下約 8000 次內就可以得到 ELF header 最慘也只好要 65536 次內一定可以取得位置!)