HITCON 2013 Wargame - Web 500 詳解

Web 500 是一題 PHP source code review 找 vuln 的題目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?php
/*
*
* Written by Orange@chroot.org
*
*/
$cookie_key = "◢▆▅▄▃崩╰(〒皿〒)╯潰▃▄▅▇◣";
$iv = "00000000";

function safe( $s ) {
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;
}
}
return false;
}

class qoo{
var $key_var = "FakeKey";
function __construct(){}

function __destruct(){
$keyfile = $this->key_var . ".php";
$keyfile = basename( $keyfile );

include( $keyfile );

print $key;
}

}

$checksum = $_COOKIE['checksum'];
if ( @md5($checksum) == '' ) {

$auth_str = $_COOKIE['auth_str'];
$auth_str = base64_decode( $auth_str );
$auth_str = mcrypt_decrypt( MCRYPT_BLOWFISH,
$cookie_key,
$auth_str,
MCRYPT_MODE_ECB,
$iv );
$auth_str = trim( $auth_str );

if ( safe($auth_str) )
unserialize( $auth_str );
else
die( 'Auth string is not safe' );
} else {
new qoo();
}

?>

其實考的滿簡單的,如果對 PHP Sec 有概念的話直覺會想到 unserialize 的 object inj

  1. 利用 object inj 覆蓋 magic method(__destruct) 的 key_var 變量
  2. 繞過 md5() == '' 可以用 checksum[]=bla
  3. 繞過 safe 函數的話我不小心少寫一個 byte 所以可以用 s 大小寫置換來繞過,

不過我既然題目都已經出來了就算了XD 給你們簡單解吧!

原本繞過的方式是利用 PHP 對於 unserialize 實作的不一致來繞過

O:3:”qoo”:1:{s:7:”key_var”ts:3:”Key”;}

注意的 ts:3 這樣的形式 PHP unserialize 是可以接受的,有多少人是這樣解的給我說說看XDDD

這個問題有在 2012 年 12 月底的時候 ipb 漏洞出來被人探討過。

Invision Power Board 是一款滿流行的 PHP 討論版,由於在程式碼實作上會用到 unserialize,所以 ipb 寫了一個 check function 去檢查 unserialize 是否為惡意的,但由於 PHP 對 unserialize 上的實作缺陷,讓 check function 可被繞過(這點 PHP 後來有做 bug fix掉了(待確認中))

詳細細節可參考 80vul 寫的文章

http://www.80vul.com/pch/pch-010.txt