这题的灵感来自C3ngH师傅的“你知道pyc的文件头可以推出来吗”,于是就有了这题
前后的部分估计不是很难,那就主要来讲讲构建pyc打明文攻击这一步
关于PYC
https://ctf-wiki.org/misc/other/pyc/
可以参考这个文档

ok回头看我给的压缩包,给了信息
python 3.12.12
Bit Field为00 00 00 00
hash 字段非置空
Magic Number
那已知python版本号就可以推出前四字节
conda create -n ctf-test python=3.12.12
conda activate ctf-test
python
>>>import importlib.util
>>>importlib.util.MAGIC_NUMBER
b'xcbrrn'importlib.util.MAGIC_NUMBER.hex()
'cb0d0d0a'
可以得到前四字节"cb0d0d0a"
Bit Field
在python 3.12.12中,Bit Field只有两种状态
00 00 00 00 ------->后面跟着的是Timestamp和Source Size,然后16位后hash
值置空(就是全0,会被非预期,所以我手动将其改掉了,但是不会影响pyc的正常功能,对此感兴趣师傅可以自己去构建一下)
01 00 00 00------->后面跟着的是hash值
至于Bit Field为00 00 00 00,决定了8-12位是TIMESTAMP or HASH
Timestamp和Source Size
有一个点在ctf-wiki里没写清楚,他说的是.pyc产生的时间,事实上是py文件最后修改的时间,大小也是指py文件的大小,我在压缩包里给了flag.py,可以看到大小,不过只能看到 ZIP entry 的 mtime,而不能看到文件产生的时间。
所以只能获取Source Size

flag.py原始大小是1411字节,转为4字节的16进制表示为:83050000
明文攻击
综上已知CB 0D 0D 0A 00 00 00 00 ?? ?? ?? ?? 83 05 00 00
8+4字节,且偏移量为12。可以进行明文攻击


后面分析flag.py就可以了
exp
from base64 import b64decode
def rc4_bytes(key: bytes, data: bytes) -> bytes:
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) & 0xFF
S[i], S[j] = S[j], S[i]
i = j = 0
out = bytearray()
for byte in data:
i = (i + 1) & 0xFF
j = (j + S[i]) & 0xFF
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) & 0xFF]
out.append(byte ^ K)
return bytes(out)
CIPHER_B64 = "adJts2ab4DvAn9Zu60bNyGrOAWj72B1/kg=="
def step2_unxor(data: bytes, k: int = 0x37) -> bytes:
return bytes(b ^ k for b in data)
def step1_unreverse(s: str) -> str:
return s[::-1]
def solve():
cipher = b64decode(CIPHER_B64)
with open("S3ct3t", "rb") as f:
key = f.read().strip()
inter = rc4_bytes(key, cipher)
b_plain_reversed = step2_unxor(inter, 0x37)
s_plain_reversed = b_plain_reversed.decode("utf-8", errors="ignore")
flag = step1_unreverse(s_plain_reversed)
print("flag:", flag)
if __name__ == "__main__":
solve()
S3ct3t文件在图片尾部的压缩包中,解压获得

S3ct3t:your-secret-key-here
随后获得flag:VNCTF{W3lc0me_T0_V&N2025}
如果本题有哪里有问题,还请师傅们多多包涵,欢迎找我反馈

Comments 3 条评论
偏移量是4?不是12咩
嗷,两端之间的间隔当作偏移量
@Whild-QvQ 不好意思 是12 已严肃更正