flag format: tjctf{...} đây là 2 challenge độc lập...
تم الإنشاء في: ١٧ مايو ٢٠٢٦
تمت الإجابة باستخدام GPT-5.5 Thinking بواسطة Chat01
تم الإنشاء في: ١٧ مايو ٢٠٢٦
تمت الإجابة باستخدام GPT-5.5 Thinking بواسطة Chat01
flag format: tjctf{...}
đây là 2 challenge độc lập, không liên quan tới nhau
tìm ra flag rồi viết write up chi tiết kèm câu lệnh + script đã dùng
forensics/loud-packets
tjctf{v3ry_l0ud_pc4p_file}
misc/glitch
tjctf{D3S1GN+TECH_:)}
Các file/script mình tạo để tái hiện:
[solve_loud_packets.py]
solve_glitch.py
recovered_loud.wav
spectrogram.png
File chall.pcap chứa nhiều packet UDP có payload bắt đầu bằng magic BTAV. Sau BTAV là sequence number 4 byte. Payload còn lại chính là các chunk của một file.
Khi sort theo sequence rồi nối payload lại, byte đầu ra bắt đầu bằng:
textRIFF....WAVE
=> Đây là file WAV. Mở spectrogram của WAV thì thấy flag được vẽ bằng font 5x7.
bashpython3 -m pip install py7zr numpy scipy pillow python3 solve_loud_packets.py
Tạo spectrogram:
bashsox recovered_loud.wav -n spectrogram -x 3000 -y 700 -z 80 -r -m -o spectrogram.png
python#!/usr/bin/env python3 import struct, wave, numpy as np PCAP = "chall.pcap" OUT_WAV = "recovered_loud.wav" with open(PCAP, "rb") as f: gh = f.read(24) endian = ">" if gh[:4] == b"\xa1\xb2\xc3\xd4" else "<" frames = [] with open(PCAP, "rb") as f: f.read(24) while True: ph = f.read(16) if len(ph) < 16: break ts_sec, ts_usec, incl_len, orig_len = struct.unpack(endian + "IIII", ph) pkt = f.read(incl_len) if len(pkt) < 42 or pkt[12:14] != b"\x08\x00": continue ihl = (pkt[14] & 0x0f) * 4 if pkt[23] != 17: continue udp = 14 + ihl sport, dport, ulen, _ = struct.unpack("!HHHH", pkt[udp:udp+8]) payload = pkt[udp+8:udp+ulen] if payload.startswith(b"BTAV"): seq = struct.unpack("!I", payload[4:8])[0] frames.append((seq, payload[8:])) frames.sort() wav_bytes = b"".join(p for _, p in frames) with open(OUT_WAV, "wb") as f: f.write(wav_bytes) print(wav_bytes[:12]) print(f"wrote {OUT_WAV}")
Output quan trọng:
textb'RIFF\x143\x04\x00WAVE'
Sau khi mở spectrogram, text hiện ra là:
texttjctf{v3ry_l0ud_pc4p_file}
Hint “Do not resist” trỏ tới resistor color code:
textblack = 0 brown = 1 red = 2 orange = 3 yellow = 4 green = 5 blue = 6 violet = 7 gray = 8 white = 9
Ảnh là các dải màu bị nhiễu. Sau khi median filter để bỏ noise, mỗi hàng chính có 2 màu lớn ở vùng bên trái/middle. Đổi 2 màu đó thành 2 chữ số rồi parse thành ASCII decimal.
Ví dụ:
textblue gray -> 68 -> 'D' green brown -> 51 -> '3' gray orange -> 83 -> 'S' yellow white -> 49 -> '1' ...
Chuỗi nhận được:
textD3S1GN+TECH_:)
Challenge yêu cầu wrap trong tjctf{} nên flag là:
texttjctf{D3S1GN+TECH_:)}
bashpython3 solve_glitch.py
pythonfrom PIL import Image, ImageFilter import numpy as np IMG = "glitch.png" img = Image.open(IMG).convert("RGB").filter(ImageFilter.MedianFilter(7)) arr = np.array(img).astype(float) refs = { "K": (0, 0, 0), # black 0 "N": (95, 45, 35), # brown 1 "R": (255, 0, 0), # red 2 "O": (255, 125, 0), # orange 3 "Y": (255, 230, 0), # yellow 4 "G": (50, 255, 0), # green 5 "B": (0, 0, 255), # blue 6 "V": (255, 0, 255), # violet 7 "E": (128, 128, 128), # gray 8 "W": (245, 245, 245), # white 9 } keys = list(refs) ref = np.array([refs[k] for k in keys], float) flat = arr.reshape(-1, 3) cls = np.argmin(((flat[:, None, :] - ref[None, :, :]) ** 2).sum(axis=2), axis=1) letters = np.array(keys)[cls].reshape(arr.shape[:2]) def row_pair(y, min_run=350): row = letters[y, :1600] # bỏ phần border đen/vàng bên phải raw = [] cur = str(row[0]) start = 0 for x, c0 in enumerate(row[1:], 1): c = str(c0) if c != cur: if x - start >= 25: raw.append((cur, start, x)) cur, start = c, x if len(row) - start >= 25: raw.append((cur, start, len(row))) merged = [] for c, s, e in raw: if merged and merged[-1][0] == c and s - merged[-1][2] < 120: merged[-1] = (c, merged[-1][1], e) else: merged.append((c, s, e)) major = [(c, s, e) for c, s, e in merged if e - s >= min_run] if len(major) >= 2: return major[0][0] + major[1][0] return None pairs = [] prev = None for y in range(0, letters.shape[0], 3): p = row_pair(y) # same-color pairs chỉ là artifact do glitch/noise split dải màu if p and p[0] != p[1] and p != prev: pairs.append(p) prev = p digit = { "K": "0", "N": "1", "R": "2", "O": "3", "Y": "4", "G": "5", "B": "6", "V": "7", "E": "8", "W": "9", } digits = "".join(digit[c] for p in pairs for c in p) text = "".join(chr(int(digits[i:i+2])) for i in range(0, len(digits), 2)) print("pairs :", pairs) print("digits:", digits) print("text :", text) print("flag :", "tjctf{" + text + "}")
Output:
textpairs : ['BE', 'GN', 'EO', 'YW', 'VN', 'VE', 'YO', 'EY', 'BW', 'BV', 'VR', 'WG', 'GE', 'YN'] digits: 6851834971784384696772955841 text : D3S1GN+TECH_:) flag : tjctf{D3S1GN+TECH_:)}