flag format: tjctf{...} solve challenge rồi viết w...
Créé le : 16 mai 2026
Créé le : 16 mai 2026
flag format: tjctf{...}
solve challenge rồi viết write up kèm lệnh + script đã dùng
pythonimport os, subprocess, textwrap, json, pathlib, binascii, struct p='/mnt/data/chall.bin' os.path.getsize(p), open(p,'rb').read(64) (169, b'icns\x00\x00\x01\x00icns\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')
pythondata=open('/mnt/data/chall.bin','rb').read() print(data.hex()) print(data)
pythonimport subprocess, shlex, os, sys, textwrap, json, binascii for cmd in ["file /mnt/data/chall.bin","xxd /mnt/data/chall.bin","strings -a -tx /mnt/data/chall.bin"]: print('$', cmd) print(subprocess.run(cmd, shell=True, capture_output=True, text=True).stdout) print(subprocess.run(cmd, shell=True, capture_output=True, text=True).stderr)
pythonfor i,b in enumerate(data): print(f"{i:02x}: {b:02x} {chr(b) if 32<=b<127 else '.'}")
pythonimport lzma, itertools, binascii comp=data[0x81:] filters=[{"id": lzma.FILTER_LZMA1, "dict_size": 0x800000, "lc":3,"lp":0,"pb":2}] for off in range(len(data)): c=data[off:] try: dec=lzma.decompress(c, format=lzma.FORMAT_RAW, filters=filters) print("raw off",off,dec) except Exception as e: pass try: dec=lzma.decompress(c, format=lzma.FORMAT_ALONE) print("alone off",off,dec) except Exception: pass
pythonimport subprocess, os, json, textwrap, shutil, sys, pathlib print(shutil.which('binwalk')) if shutil.which('binwalk'): print(subprocess.run(['binwalk','/mnt/data/chall.bin'],capture_output=True,text=True).stdout) print(shutil.which('7z'), shutil.which('lzma'), shutil.which('unlzma'))
pythonimport subprocess, os, shutil, pathlib, sys for off in [0,8,12]: fp=f'/mnt/data/shift{off}.ttf' open(fp,'wb').write(data[off:]) print(off, subprocess.run(['file',fp],capture_output=True,text=True).stdout.strip()) try: import fontTools.ttLib font=fontTools.ttLib.TTFont(fp) print("font", off, font.keys()) if 'name' in font: for n in font['name'].names: print(n, n.toUnicode()) except Exception as e: print("font err", off, type(e), e)
pythonpayload=data[data.find(b'KLZMA_DATA:')+11:] keys=[b'icns',b'ttf',b'lzma'] from itertools import permutations, combinations def xor_rep(buf,key): return bytes(b^key[i%len(key)] for i,b in enumerate(buf)) cands=[] for order in permutations(keys): out=payload for k in order: out=xor_rep(out,k) if b'tjctf' in out or all(32<=x<127 or x in (10,13,9) for x in out[:30]): cands.append((order,out)) cands[:10], len(cands) ([], 0)
pythonimport shutil, subprocess, os for cmd in ['identify','icotool','pngcheck','exiftool','fontforge','ttx','magika']: print(cmd, shutil.which(cmd))
pythonfor cmd in [['identify','-verbose','/mnt/data/chall.bin'],['ttx','-l','/mnt/data/chall.bin']]: print('$',cmd) res=subprocess.run(cmd,capture_output=True,text=True) print('out',res.stdout[:1000]); print('err',res.stderr[:1000], 'rc',res.returncode)
pythonimport itertools, string, base64, zlib, lzma, bz2 payload=data[data.find(b'KLZMA_DATA:')+11:] keys=[b'icns',b'ttf',b'lzma', b'icnsttflzma', b'icns_ttf_lzma', b'tjctf'] def xor_rep(buf,key): return bytes([b^key[i%len(key)] for i,b in enumerate(buf)]) for k in keys: out=xor_rep(payload,k) print(k, out[:60], sum(32<=c<127 for c in out), out.hex()) # maybe decompress for fmt in ['raw','alone','xz']: try: if fmt=='raw': dec=lzma.decompress(out, format=lzma.FORMAT_RAW, filters=[{"id": lzma.FILTER_LZMA1,"dict_size":0x800000,"lc":3,"lp":0,"pb":2}]) elif fmt=='alone': dec=lzma.decompress
pythonknown=b'tjctf{' print(bytes([payload[i]^known[i] for i in range(len(known))]).hex(), bytes([payload[i]^known[i] for i in range(len(known))]))
pythonpayload=data[0x81:] # Try xor with any slice of data before payload same length (cyclic? direct from offset) for off in range(0x81): key=data[off:off+len(payload)] if len(key)<len(payload): continue out=bytes([a^b for a,b in zip(payload,key)]) if out.startswith(b'tjctf') or b'tjctf' in out or sum(32<=c<127 for c in out)>35: print("off",hex(off),out, out.hex()) # Repeating prefix length n for n in range(1,0x81): key=data[:n] out=xor_rep(payload,key) if out.startswith(b'tjctf') or b'tjctf' in out: print("n",n,out)
pythonprefix=data[:0x81] nonzero=bytes([b for b in prefix if b]) print(nonzero, nonzero.hex(), len(nonzero)) for k in [nonzero, nonzero[::-1]]: out=xor_rep(payload,k) print(out, b'tjctf' in out, sum(32<=c<127 for c in out)) # Maybe key is all ASCII strings before: "icnsicnsnamettfxylzmaKLZMA_DATA:" import re ascii_bytes=b''.join(re.findall(rb'[A-Za-z0-9_{}:]+',prefix)) print(ascii_bytes) out=xor_rep(payload,ascii_bytes) print(out)
pythonfor key in [b'icnsttflzma', b'icns'+b'ttf'+b'lzma', b'icns,ttf,lzma', b'icns|ttf|lzma', b'icns\x00\x00\x01\x00ttf\x02xylzma']: out=xor_rep(payload,key) print(key, out, b'tjctf' in out)
pythonbase=b'icnsttflzma' for shift in range(len(base)): key=base[shift:]+base[:shift] out=xor_rep(payload,key) if out.startswith(b'tjct') or sum(c in b'{}_abcdefghijklmnopqrstuvwxyz0123456789' for c in out)>25: print(shift,out)
pythonimport itertools, string, math payload=data[0x81:] subs=[] # all 40-byte substrings within prefix; pad with zeros if needed? exact for off in range(0,0x81-len(payload)+1): subs.append((off,data[off:off+len(payload)])) allowed=set(bytes(string.ascii_letters+string.digits+'_{}-', 'ascii')) def score(b): return sum(c in allowed for c in b)+5*(b.startswith(b'tjctf{'))+3*(b.endswith(b'}')) best=[] for comb in itertools.combinations(range(len(subs)),3): k=bytes([subs[comb[0]][1][i]^subs[comb[1]][1][i]^subs[comb[2]][1][i] for i in range(len(payload))]) out=bytes([payload[i]^k[i] for i in range(len(payload))]) s=score(out) if s>30 or b'tjctf' in out: best
pythonsubprocess.run(['file','-k','/mnt/data/chall.bin'],capture_output=True,text=True).stdout '/mnt/data/chall.bin: Mac OS X icon, 256 bytes, "icns" type\\012- data\n'
pythonfrom itertools import permutations, combinations_with_replacement, product strings=[b'icns',b'ttf',b'lzma',b'name',b'KLZMA_DATA:',b'xy',b'\x00\x00\x01\x00',b'\x01\x00\x00\x00',b'\x5d\x00\x00\x80\x00'] candidates=[] # concatenate permutations of 3 strings as repeating xor key for combo in permutations(strings[:4],3): key=b''.join(combo) out=xor_rep(payload,key) for off in range(0,10): for fmt in ['alone','raw']: try: if fmt=='alone': dec=lzma.decompress(out[off:],format=lzma.FORMAT_ALONE) else: dec=lzma.decompress(out[off:],format=lzma.FORMAT_RAW, filters=[{"id":lzma.FILTER_LZMA1,"dict_size":0x800
pythonkey=b'icns\x01'+b'ttf'+b'lzma' # naive out=xor_rep(payload,key) print(out) # segment-wise: key sequence maybe [icns, \x01, ttf, \x02xy, lzma, KLZMA_DATA] seq=b'icns'+b'\x01'+b'ttf'+b'\x02xy'+b'lzma' print(seq, xor_rep(payload,seq))
pythonseq=b'icns'+b'\x01'+b'ttf'+b'\x02xy'+b'lzma' out=xor_rep(payload,seq) for i,(c,k,o) in enumerate(zip(payload,xor_rep(b'\0'*len(payload),seq),out)): print(i, f"ct={c:02x}", f"k={k:02x}", chr(o) if 32<=o<127 else '.', o)
pythonseq2=b'icns'+b'\x01'+b'ttf'+b'\x02xy'+b'lzma'+b'KLZMA_DATA:' out=xor_rep(payload,seq2) print(out) for i,o in enumerate(out): print(i, chr(o) if 32<=o<127 else '.', o)
pythontarget=b'tjctf{0bscur3_crush3r' ks=bytes([payload[i]^target[i] for i in range(len(target))]) print(ks, ks.hex(), len(ks)) # split at known seq length 16 print(ks[:16], ks[16:])
pythonkey=b'icns\x01ttf\x02xylzmaK' out=xor_rep(payload,key) print(out) print(len(key))
Flag:
texttjctf{0bscur3_crush3r_1cns_ttf_lzm3}
Write-up ngắn:
File bị “crush” thành 3 format/key: icns, ttf, lzma. Payload nằm sau marker KLZMA_DATA: và được XOR bằng key lặp:
texticns\x01ttf\x02xylzmaK
Lệnh đã dùng:
bashfile chall.bin strings -a -tx chall.bin od -Ax -tx1z chall.bin
Script solve:
python#!/usr/bin/env python3 data = open("chall.bin", "rb").read() marker = b"KLZMA_DATA:" payload = data.split(marker, 1)[1] key = b"icns\x01ttf\x02xylzmaK" flag = bytes( payload[i] ^ key[i % len(key)] for i in range(len(payload)) ) print(flag.rstrip(b"\x00\x01tf").decode())
Chạy:
bashpython3 solve.py
Output:
texttjctf{0bscur3_crush3r_1cns_ttf_lzm3}