题目的名字是justrom,给我求出flag,flag包裹形式是LilacCTF{}
Tạo vào: 25 tháng 1, 2026
Trả lời bằng GPT-5.2 Thinking bởi Chat01
Tạo vào: 25 tháng 1, 2026
Trả lời bằng GPT-5.2 Thinking bởi Chat01
我把你给的 rom.bin 先做了结构分析(还没完全跑到解出 flag 的最后一步,但已经定位到“怎么解”的核心点了):
0x0000 附近看起来像 trap table(大量 ba + nop)。0x4000 开始是一段明显的 SPARC 代码:开头就有典型函数序言 0x9de3bfa0(save %sp, ...)。0x4018 附近能看到 4 个 32-bit 常量:0x61707865 0x3320646e 0x79622d32 0x6b2065740x1000 .. 0x2FFF(8KB)0x13000 .. 0x13FFF(4KB)0xC000 处有一段非常“像 key/nonce”的东西:
11 22 33 44 ... dd ee ff 00 de ad be ef ... 13 37 13 37AAAABBBBCCCCLilacCTF{,所以这段可能是诱饵,或者实现里对 key/nonce 的端序/装载方式做了变化,或者是“先解一段得到真正 key,再解另一段”。这个脚本会:
0x1000 和 0x13000 两段作为候选密文LilacCTF{ 就打印 flag把下面保存成 solve.py,和 rom.bin 放同目录运行:python3 solve.py
python#!/usr/bin/env python3 import struct from pathlib import Path ROM_PATH = "rom.bin" CIPHERS = [ ("cipherA_8k", 0x1000, 0x2000), ("cipherB_4k", 0x13000, 0x1000), ] FLAG_PREFIX = b"LilacCTF{" def rotl32(x, n): return ((x << n) & 0xffffffff) | (x >> (32 - n)) def quarter_round(a, b, c, d): a = (a + b) & 0xffffffff d ^= a; d = rotl32(d, 16) c = (c + d) & 0xffffffff b ^= c; b = rotl32(b, 12) a = (a + b) & 0xffffffff d ^= a; d = rotl32(d, 8) c = (c + d) & 0xffffffff b ^= c; b = rotl32(b, 7) return a, b, c, d CONST_WORDS = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574] # "expand 32-byte k" words def chacha20_block_generic(key32, nonce12, counter, key_word_endian="little", nonce_word_endian="little", out_endian="little"): if key_word_endian == "little": key_words = list(struct.unpack("<8I", key32)) else: key_words = list(struct.unpack(">8I", key32)) if nonce_word_endian == "little": nonce_words = list(struct.unpack("<3I", nonce12)) else: nonce_words = list(struct.unpack(">3I", nonce12)) state = CONST_WORDS + key_words + [counter & 0xffffffff] + nonce_words x = state.copy() for _ in range(10): # 20 rounds # column x[0], x[4], x[8], x[12] = quarter_round(x[0], x[4], x[8], x[12]) x[1], x[5], x[9], x[13] = quarter_round(x[1], x[5], x[9], x[13]) x[2], x[6], x[10], x[14] = quarter_round(x[2], x[6], x[10], x[14]) x[3], x[7], x[11], x[15] = quarter_round(x[3], x[7], x[11], x[15]) # diagonal x[0], x[5], x[10], x[15] = quarter_round(x[0], x[5], x[10], x[15]) x[1], x[6], x[11], x[12] = quarter_round(x[1], x[6], x[11], x[12]) x[2], x[7], x[8], x[13] = quarter_round(x[2], x[7], x[8], x[13]) x[3], x[4], x[9], x[14] = quarter_round(x[3], x[4], x[9], x[14]) out = [(x[i] + state[i]) & 0xffffffff for i in range(16)] if out_endian == "little": return struct.pack("<16I", *out) else: return struct.pack(">16I", *out) def chacha20_crypt_generic(key32, nonce12, counter, data, key_word_endian="little", nonce_word_endian="little", out_endian="little"): out = bytearray() blocks = (len(data) + 63) // 64 for bi in range(blocks): ks = chacha20_block_generic( key32, nonce12, (counter + bi) & 0xffffffff, key_word_endian, nonce_word_endian, out_endian ) chunk = data[bi*64:(bi+1)*64] out.extend(bytes([b ^ ks[i] for i, b in enumerate(chunk)])) return bytes(out) def find_flag(buf: bytes): i = buf.find(FLAG_PREFIX) if i == -1: return None j = buf.find(b"}", i) if j == -1: return None return buf[i:j+1] def main(): rom = Path(ROM_PATH).read_bytes() variants = [] for key_end in ("little", "big"): for nonce_end in ("little", "big"): for out_end in ("little", "big"): variants.append((key_end, nonce_end, out_end)) # 扫描 key(32)+nonce(12),4字节对齐 for off in range(0, len(rom) - (32 + 12), 4): key = rom[off:off+32] nonce = rom[off+32:off+32+12] # 粗略跳过全0/太像空洞的区域 if key.count(0) > 24: continue for (name, c_off, c_len) in CIPHERS: cipher = rom[c_off:c_off+c_len] # 只先解前 512 字节做快速匹配 sample = cipher[:512] for counter in range(0, 9): for (key_end, nonce_end, out_end) in variants: plain = chacha20_crypt_generic( key, nonce, counter, sample, key_end, nonce_end, out_end ) fl = find_flag(plain) if fl: # 命中后解全段 full_plain = chacha20_crypt_generic( key, nonce, counter, cipher, key_end, nonce_end, out_end ) fl2 = find_flag(full_plain) if fl2: print("[+] HIT!") print(f" key/nonce offset: 0x{off:05x}") print(f" cipher: {name} @0x{c_off:x} len=0x{c_len:x}") print(f" counter={counter}, key_end={key_end}, nonce_end={nonce_end}, out_end={out_end}") print(fl2.decode(errors="replace")) return print("[-] No flag found with this scan. 说明:key/nonce 可能不是平铺在 ROM 里,或者不是标准 ChaCha20(IETF) 输出字节序。") if __name__ == "__main__": main()
我已经能确定这是 SPARC ROM +(很大概率)ChaCha/Salsa 系列加密/PRNG,也找到了明显的常量与疑似 key/nonce 区域,但还没把 SPARC 代码完整跑起来(需要一个小 SPARC 解释器或能反汇编 SPARC 的工具环境),所以我这条消息里还没直接给出最终 LilacCTF{...}。
你先跑一下上面脚本: