[LitCTF2026] Misc+Reverse部分wp

Misc1

[LitCTF2026] lit_lsb_base64

题目描述

组委会发来一张花花绿绿的 PNG,标题里写着三个字母:LSB。这和「崂山煲」可没关系——它指的是 最低有效位(Least Significant Bit) 隐写。

从 stego.png 的 R 通道 LSB 按正常 bit 顺序提取,开头得到:TGl0Q1RGe2xzYl8xc19mdW5fdzF0aF9iNHMzXzY0fQ==

Base64 解码后是:LitCTF{lsb_1s_fun_w1th_b4s3_64}

 

Misc2

[LitCTF2026] lit_rush_qr

题目描述

附件里有一个「闪得很快」的 GIF。有人说自己好像瞥见了 二维码 的一角,但怎么也扫不出来……

这个 GIF 的闪现帧里二维码缺了两个定位块,把第 2 帧按 QR 网格采样,确认是 33x33 模块,补回三个标准定位块和静区后成功解码。

LitCTF{qr_h1gh_3rr_c0r_r3c0v3ry}

 

Misc3

 

[LitCTF2026] lit_sstv

题目描述

你收到一段奇怪的 WAV:听起来像老式调制解调器或短波噪声。它其实不是「坏掉的音频」,而是一种把 图片编码进声音 的协议——SSTV(慢扫描电视)

WAV 开头的 VIS 码是 44,对应 Martin M1 SSTV。按 Martin M1 解调后图片里显示的 flag 是:LitCTF{sstv_p4t13nc3}

 

Misc4

[LitCTF2026] lit_welcome

题目描述

组委会给你发了一张「欢迎」图片,说 flag 就在图里——可你一眼望去好像只有几行普普通通的欢迎语?

图片里只有两种颜色:#ffffff 和几乎看不出的 #feffff。

 

Misc5

[LitCTF2026] lit_pyjail_reader

题目描述

ez_jail

程序核心读取函数:

def safe_read(path: str) -> str:
p = path.strip()
if not p or p.startswith("-") or "\x00" in p:
raise ValueError("invalid path")
with open(p, "r", errors="replace") as f:
return f.read(MAX_FILE)

过滤只有路径不能为空,不能以-开头,不能包含null字节

但最终仍然直接调用 Python 内置 open() 打开用户提供的路径进行读取,而 open() 本身就是标准文件读取接口。存在任意文件读取

 

Misc6

[LitCTF2026] lit_pyjail_unicode

题目描述

ezjail_2

先看关键逻辑:

if banned(line):
conn.sendall(b"disallowed pattern in source\n")
return

out = eval(line, {"__builtins__": __builtins__})

题目会接受一行python代码,先做黑名单过滤,直接eval(),并且给了完整__builtins__

黑名单检测的是原始源码字符串,这里BANNED.search(raw)检测的是输入的文本,Python 解释器处理 Unicode 标识符时,会做 NFKC normalization(兼容规范化)。Python 文档说明 identifiers 会在解析时做 NFKC 归一化。所以可以换成全角来进行输入

 

RE1

[LitCTF2026] lit_rc4_variant

题目描述

程序实现一种 64 字节状态 的流密码式异或:初始化与 RC4 类似但模 64,且输出字节与 S[v7] + S[v10](模 256)异或——与「标准 RC4 输出 S[(S[i]+S[j])&255]」不同。密钥为 ASCII 字符串,放在 .rdata

发现密钥已经明文存放key 为:lit_rc4_key!

在伪代码中发现程序将用户输入加密后与固定数据比较:

g_cipher 为目标密文,长度为 0x1D = 29 字节。

目标密文为cipher = bytes.fromhex(

"7b3d38774e72427d4537760f53534f66371775375f495872747f791f3a"

)

Exp: key = b"lit_rc4_key!"

 

cipher = bytes.fromhex(

"7b3d38774e72427d4537760f53534f66371775375f495872747f791f3a"

)

 

def decrypt(data):

S = list(range(64))

 

# KSA

j = 0

for i in range(64):

j = (j + S[i] + key[i % len(key)]) & 0x3f

S[i], S[j] = S[j], S[i]

 

out = bytearray(data)

 

# PRGA

i = 0

j = 0

for n in range(len(out)):

i = (i + 1) % 64

j = (j + S[i]) % 64

S[i], S[j] = S[j], S[i]

 

k = (S[(S[i] + S[j]) & 0x3f] + S[i]) & 0xff

out[n] ^= k

 

return bytes(out)

 

print(decrypt(cipher))

 

RE2

[LitCTF2026] lit_tea_standard

题目描述

程序把你输入的 flag 做 PKCS#7 填充 到 8 字节倍数,再按 8 字节一块 做 标准 TEA(32 轮,delta = 0x9E3779B9),与内存中的密文逐字节比较。密钥 k[0..3] 以 4×uint32 形式存放在 .rdata

填充后的长度必须是32字节

循环里有sub r8d, 0x61c88647

cmp r8d, 0xc6ef3720其中0x61c88647 == -0x9E3779B9 mod 2^32

0xc6ef3720 == 0x9E3779B9 * 32 mod 2^32这是标准的TEA 32轮加密

从加密公式反推四个常量

k0 = 0xA11CEFAC

k1 = 0xB00B1E00

k2 = 0xCAFEBABE

k3 = 0xDEADBEEF

提取密文cipher = bytes.fromhex(

"edef21feb79b3cb0"

"1e9372e2023e29bc"

"36f70c922e5aae46"

"44fa45251ae58c87"

)

解密脚本from struct import unpack, pack

 

cipher = bytes.fromhex(

"edef21feb79b3cb0"

"1e9372e2023e29bc"

"36f70c922e5aae46"

"44fa45251ae58c87"

)

 

key = [0xA11CEFAC, 0xB00B1E00, 0xCAFEBABE, 0xDEADBEEF]

delta = 0x9E3779B9

 

def tea_decrypt_block(block):

v0, v1 = unpack("<2I", block)

s = (delta * 32) & 0xffffffff

 

for _ in range(32):

v1 = (v1 - ((((v0 << 4) + key[2]) ^ (v0 + s) ^ ((v0 >> 5) + key[3])) & 0xffffffff)) & 0xffffffff

v0 = (v0 - ((((v1 << 4) + key[0]) ^ (v1 + s) ^ ((v1 >> 5) + key[1])) & 0xffffffff)) & 0xffffffff

s = (s - delta) & 0xffffffff

 

return pack("<2I", v0, v1)

 

pt = b"".join(tea_decrypt_block(cipher[i:i+8]) for i in range(0, len(cipher), 8))

 

pad = pt[-1]

flag = pt[:-pad]

 

print(flag.decode())

 

RE3

[LitCTF2026] lit_b64_alphabet

题目描述

程序把你输入的 flag 按标准 Base64 的分组方式编码,但 64 个输出字符的字母表 不是 RFC 默认顺序,而是程序里保存的一串置换。比对对象是内存中的 期望密文字符串

期望密文与自定义字母表

标准的base64表是ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

把自定义密文里的字符,按自定义字母表的下标映射回标准 Base64 表。

import base64

 

cipher = "zjA5lToj9PUAGn2O+v6TRPosgYWB6noyGjhBgjfwyl=="

 

custom = "2KuEphj84USZF67iloxzfYd+MrDgRG9yLwBnHAXcJq3eCN/s1bOQ5TvPa0tVkWmI"

standard = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

 

table = str.maketrans(custom, standard)

 

standard_b64 = cipher.translate(table)

 

flag = base64.b64decode(standard_b64)

print(flag.decode())

 

RE4

[LitCTF2026] lit_xor_chain

题目描述

程序读入一行字符串,对 每个字节 先做异或常数、再加常数,再与内存里的 期望数组 逐字节比较。逻辑与常见逆向入门讲义中的「循环 + xor + add + 数组比对」一致。

140001491: lea rcx, [rsp+20h]        ; 输入

140001496: call strlen

14000149b: cmp rax, 1Eh

14000149f: jne Wrong

输入长度必须是0x1E = 30

1400014c0: movzx edx, byte ptr [rcx]

1400014c3: xor edx, 52h

1400014c6: add edx, 5

1400014c9: cmp dl, byte ptr [r8]

1400014cc: jne Wrong核心循环的逻辑是输入 → XOR 0x52 → +5 → 和数组比较

提取期望数组

expected = bytes.fromhex(

"23 40 2B 16 0B 19 2E 25"

"3C 29 67 68 12 2F 42 25"

"12 2B 3F 3C 41 12 38 3B"

"3B 12 42 3E 78 34"

)

脚本:expected = bytes.fromhex(

"23 40 2B 16 0B 19 2E 25"

"3C 29 67 68 12 2F 42 25"

"12 2B 3F 3C 41 12 38 3B"

"3B 12 42 3E 78 34"

)

 

flag = bytes(((b - 5) & 0xff) ^ 0x52 for b in expected)

 

print(flag.decode())

 

RE5

[LitCTF2026] lit_xtea_tweak

题目描述

流程与「分组 + 填充 + 分块加密」类似 XTEA,但轮常数 delta 被换成 0xDEADBEEF(标准文献里常见的是 0x9E3779B9)。若直接套用网上搜到的 XTEA 脚本而不改 delta,解密会失败。

密钥是key = [

0x11111111,

0x22222222,

0x33333333,

0x44444444

]

密文是cipher = bytes.fromhex(

"e3ee1ee7d3a7966f"

"c6a7b9e1b94e6786"

"5f0304a6dbbbb940"

"563af79eee64d406"

)

解密脚本

import struct

 

cipher = bytes.fromhex(

"e3ee1ee7d3a7966f"

"c6a7b9e1b94e6786"

"5f0304a6dbbbb940"

"563af79eee64d406"

)

 

key = [0x11111111, 0x22222222, 0x33333333, 0x44444444]

delta = 0xDEADBEEF

MASK = 0xffffffff

 

def xtea_decrypt_block(block):

v0, v1 = struct.unpack("<2I", block)

s = (delta * 32) & MASK

 

for _ in range(32):

v1 = (v1 - (((((v0 << 4) ^ (v0 >> 5)) + v0) & MASK) ^ ((s + key[(s >> 11) & 3]) & MASK))) & MASK

s = (s - delta) & MASK

v0 = (v0 - (((((v1 << 4) ^ (v1 >> 5)) + v1) & MASK) ^ ((s + key[s & 3]) & MASK))) & MASK

 

return struct.pack("<2I", v0, v1)

 

pt = b"".join(

xtea_decrypt_block(cipher[i:i+8])

for i in range(0, len(cipher), 8)

)

 

pad = pt[-1]

flag = pt[:-pad]

 

print(flag.decode())

 

点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注