芜湖~
题目没有之前那么好玩 有些题目能找到原型
线上赛莫名其妙人性化 中午把网站停了 给选手吃饭时间 没想到
不过 这次不管是附件题 还是web题 每个IP的flag都不一样 挺好的
以下是我自己的一些思路和解析 有什么问题或者建议随时都可以联系我

目录
[Base64 编码 + 异或加密](#Base64 编码 + 异或加密)
[加油各位( •̀ ω •́ )y 期待与君再相逢](#加油各位( •̀ ω •́ )y 期待与君再相逢)
MISC
签到题-损坏的压缩包

dGFoZw==
base64解码
flag{tahg}
迷宫

附件只有一个压缩包

根据题目提示直接解压
layer1 → data2 → secret3 → hidden4 → .config → user → backup5

先用十六进制编辑器查看内容

后面30没有用
ZWE2MzJjNjYwNmJlY2Q5ZTQ2YzFkMzkyZjhiMGU2ZGE==
一看就是base64
直接Base64 解码
ea632c6606becd9e46c1d392f8b0e6da
flag{ea632c6606becd9e46c1d392f8b0e6da}
幻影

依然只有一个zip的附件

只有个bin的文件

老规矩不能直接打开的文件 先看一下源代码

看到这里其实 提示已经非常明显了 这里逐行分析一下
- 第一行的
Rar!:没用干扰信息(但你要知道没有试出来的)。 - 第二行的提示:
REMEMBER: FLAG IS HIDDEN IN BASE64 PLUS XOR!核心提示!翻译过来就是:flag 藏在「Base64 编码 + 异或加密」里!很多小白一开始会看错,把
XOR看成X,以为 x 是文件名的 04,其实不是,这里的XOR是加密算法的名字! - 第三行的假 flag:
FAKE FLAG: flag{00000000-0000-0000-0000-000000000000} - 第四行的警告:
DO NOT TRUST THIS ONE.这行是提醒你!上面那个全是 0 的 flag 是假的!用来迷惑你的!不要信它! - 最后一行的乱码一样的字符串:
+fP++OT+qvup/f6mqrL7/Pmusqv6/K6y/f36qbL5rPum/an9+6qpqqri真正的明=密文
Base64 编码 + 异或加密
先进行Base64 编码 在进行异或解密
这里有两种解决方法
元老级工具了

拿到flag
flag{a5d6ba95-dcf1-4ec1-bbe6-f3d9b6bd5655}
脚本
python
import base64
# 1. 读取我们提取到的加密字符串
encrypted_str = "+fP++OT+qvup/f6mqrL7/Pmusqv6/K6y/f36qbL5rPum/an9+6qpqqri"
encrypted_bytes = encrypted_str.encode('ascii')
# 2. 暴力破解所有可能的密钥x(0~255)
for x in range(256):
try:
# 先把加密字符串做Base64解码
padding = 4 - len(encrypted_bytes) %4
if padding <4:
eb = encrypted_bytes + b'='*padding
else:
eb = encrypted_bytes
decoded = base64.b64decode(eb, validate=False)
# 然后每个字节异或密钥x,解密
temp = bytes([b ^ x for b in decoded])
# 转成字符串,看看是不是flag
res = temp.decode('utf-8', errors='replace')
if 'flag{' in res:
print(f"找到真正的Flag啦!密钥x={x}")
print(f"最终Flag:{res}")
break
except:
continue

也可以得到flag
flag{a5d6ba95-dcf1-4ec1-bbe6-f3d9b6bd5655}
像素中的秘密

只看题目 像素 而且又在 高级里面 就知道又要破脚本里面
附件下载 只有一个图片 不怕附件多 就怕附件只有一个

正常分析 在源代码里面 发现IEND 块后残留 64 字节数据
这是一个正常的思路
读取 PNG 文件,提取 IEND 块后数据,拆分出种子用 LCG 异或解密得到 Base62 字符串,解码后转为 UTF-8 文本即为 flag。、
脚本解读
python
# 导入必要的模块
# string:提供字符串相关工具(如数字/字母字符集)
# struct:用于解析二进制数据(处理PNG块结构、字节序)
# Path:更便捷的文件路径处理(判断文件是否存在、读取文件)
import string
import struct
from pathlib import Path
# ===================== 核心解密参数配置 =====================
# LCG(线性同余生成器)参数 - 该类MISC题的通用标准参数
# A:乘法因子(multiplier),CTF中最常见的Java/glibc标准值
A = 1664525
# C:增量(increment),与A配套的标准值
C = 1013904223
# MASK:32位无符号整数掩码,确保计算结果在32位范围内
MASK = 0xFFFFFFFF
# Base62字符集(CTF通用顺序:数字→小写字母→大写字母)
# Base62是一种编码方式,比Base64少了+和/,常用于隐写题
B62 = string.digits + string.ascii_lowercase + string.ascii_uppercase
# ===================== 核心功能函数 =====================
def cut_after_iend(png_data: bytes) -> bytes:
"""
核心功能:遍历PNG文件结构,找到IEND结束块,返回其之后的所有残留数据
PNG文件结构:文件头(8字节) + 多个块(长度+类型+数据+CRC) + IEND块
IEND块是PNG的最后一个块,隐写数据通常藏在IEND之后
"""
# 第一步:校验PNG文件头(固定为\x89PNG\r\n\x1a\n),排除非PNG文件
if not png_data.startswith(b'\x89PNG\r\n\x1a\n'):
raise RuntimeError("❌ 不是有效的PNG文件(文件头校验失败)")
# offset:当前遍历到的字节偏移量,初始跳过8字节文件头
offset = 8
# data_len:PNG文件总字节长度
data_len = len(png_data)
# 循环遍历所有PNG块,直到找到IEND块
# 每次循环至少需要8字节(4字节长度 + 4字节块类型)
while offset + 8 <= data_len:
# 解析当前块的长度(PNG块长度为大端字节序,用>I解析)
chunk_len = struct.unpack('>I', png_data[offset:offset + 4])[0]
# 解析当前块的类型(如IHDR/IDAT/IEND)
chunk_type = png_data[offset + 4:offset + 8]
# 移动偏移量到下一个块:8字节(长度+类型) + 块数据长度 + 4字节CRC校验位
offset += 8 + chunk_len + 4
# 找到IEND块(PNG的结束块),返回其后的所有数据
if chunk_type == b'IEND':
print(f"✅ 找到IEND块,偏移位置: 0x{offset:08x}") # 打印十六进制偏移,方便调试
return png_data[offset:]
# 遍历完所有块仍未找到IEND,说明文件损坏或非标准PNG
raise RuntimeError("❌ 未找到PNG的IEND结束块")
def lcg_decrypt(raw_data: bytes) -> tuple[int, bytes]:
"""
核心功能:用LCG算法解密IEND后的残留数据
数据结构约定:4字节填充(无用) + 4字节seed(种子) + 剩余为XOR密文
返回值:(提取到的seed, 解密后的字节数据)
"""
# 校验数据长度:至少需要8字节(4填充+4seed),否则无法解密
if len(raw_data) < 8:
raise RuntimeError(f"❌ 尾部数据过短(仅{len(raw_data)}字节),至少需要8字节")
# 提取seed:跳过前4字节填充,取4-8字节,按大端字节序转整数
# 大端字节序(big-endian)是网络/文件存储的通用方式
seed = int.from_bytes(raw_data[4:8], 'big')
print(f"✅ 提取到seed: 0x{seed:08x} (十进制: {seed})") # 打印十六进制+十进制seed,方便调试
# cur_seed:当前LCG生成器的种子值,初始为提取的seed
cur_seed = seed
# decrypted:存储解密后的字节数据,用bytearray更高效
decrypted = bytearray()
# 遍历8字节后的所有密文字节,逐字节异或解密
for idx, b in enumerate(raw_data[8:]):
# 执行LCG公式:下一个种子 = (A*当前种子 + C) % 2^32(用MASK实现)
cur_seed = (A * cur_seed + C) & MASK
# 异或解密:密文字节 ^ LCG生成值的低8位(只取最后1字节)
dec_byte = b ^ (cur_seed & 0xFF)
# 将解密后的字节加入结果
decrypted.append(dec_byte)
# 返回seed和解密后的字节数据(bytearray转bytes)
return seed, bytes(decrypted)
def b62_decode(b62_str: str) -> bytes:
"""
核心功能:将Base62字符串解码为原始字节数据
Base62解码原理:字符串→大整数→字节数组(大端)
"""
# 初始化解码后的整数为0
num = 0
# 遍历Base62字符串的每个字符,逐位计算整数
for c in b62_str:
try:
# 核心公式:num = num * 62 + 字符在B62中的索引
num = num * 62 + B62.index(c)
except ValueError:
# 字符不在B62字符集中,解码失败
raise RuntimeError(f"❌ Base62字符串包含非法字符: {c}(仅支持0-9/a-z/A-Z)")
# 计算需要的字节数:确保至少1字节(避免num=0时返回空)
# bit_length():整数的二进制位数,+7//8 是向上取整到字节数
byte_count = max((num.bit_length() + 7) // 8, 1) if num > 0 else 1
# 将整数转为大端字节序的字节数组
return num.to_bytes(byte_count, 'big')
# ===================== 主函数(一键解密) =====================
def main(png_path: str = "image_10.png"):
"""
主函数:整合所有步骤,一键解密PNG文件中的flag
参数:png_path - PNG文件路径,默认值为同目录的image_10.png
"""
# 将字符串路径转为Path对象,方便文件操作
png_file = Path(png_path)
# 检查文件是否存在,不存在则提示并退出
if not png_file.exists():
print(f"❌ 未找到文件: {png_path}")
return
# 第一步:读取PNG文件的二进制数据
with open(png_file, 'rb') as f: # 'rb'以二进制模式读取,避免编码问题
png_data = f.read()
print(f"✅ 读取PNG文件成功,文件大小: {len(png_data)} 字节")
# 第二步:提取IEND块后的残留数据(捕获异常,避免程序崩溃)
try:
tail_data = cut_after_iend(png_data)
print(f"✅ IEND后提取到 {len(tail_data)} 字节残留数据")
except Exception as e:
print(e) # 打印具体错误信息
return
# 第三步:用LCG算法解密残留数据(捕获异常)
try:
seed, dec_buf = lcg_decrypt(tail_data)
# 去除解密后数据末尾的空字节(\x00),并转为ASCII字符串
b62_str = dec_buf.rstrip(b'\x00').decode('ascii')
print(f"✅ LCG解密完成,Base62字符串: {b62_str}")
except Exception as e:
print(e)
return
# 第四步:Base62解码得到最终flag(捕获异常)
try:
flag_bytes = b62_decode(b62_str)
# 将字节数据转为UTF-8字符串(flag的标准编码)
flag = flag_bytes.decode('utf-8')
# 格式化输出flag,增强可读性
print("\n" + "=" * 50)
print(f"🎉 最终Flag: {flag}")
print("=" * 50)
except Exception as e:
print(e)
return
# ===================== 程序入口 =====================
if __name__ == "__main__":
"""
程序入口:直接运行脚本时,调用main函数
默认解密同目录下的image_10.png,无需传参
"""
main()
运行脚本
✅ 读取PNG文件成功,文件大小: 245 字节
✅ 找到IEND块,偏移位置: 0x000000b5
✅ IEND后提取到 64 字节残留数据
✅ 提取到seed: 0x69cb3446 (十进制: 1774924870)
✅ LCG解密完成,Base62字符串: 16vPI4pqYkxFvJHGGgssbbrGLF7Zqg1YN
==================================================
🎉 最终Flag: flag{final_flag_png_lcg}
==================================================