tìm flag có dạng UMASS{...} rồi viết write up chi ...
생성일: 2026년 4월 12일
생성일: 2026년 4월 12일
tìm flag có dạng UMASS{...} rồi viết write up chi tiết
pythonwith open('/mnt/data/challenge.png','rb') as f: data = f.read() data.startswith(b'\x89PNG') True
pythonflag_index = data.find(b'UMASS{') flag_index -1
pythonascii_strings = re.findall(b'[\x20-\x7E]{4,}', data) len(ascii_strings) 3243
pythonpossible_flags = [s for s in ascii_strings if b'UMASS' in s] possible_flags[:20] []
pythondef parse_png_chunks(data): idx = 8 # skip PNG signature chunks = [] while idx < len(data): length = struct.unpack(">I", data[idx:idx+4])[0] chunk_type = data[idx+4:idx+8] chunk_data = data[idx+8:idx+8+length] chunks.append((chunk_type, chunk_data)) idx += 8 + length + 4 # plus CRC return chunks chunks = parse_png_chunks(data) len(chunks) 6
python[(typ, len(cdata)) for typ,cdata in chunks] [(b'IHDR', 13), (b'IDAT', 65536), (b'IDAT', 65536), (b'IDAT', 65536), (b'IDAT', 59888), (b'IEND', 0)]
pythonfrom PIL import Image img = Image.open('/mnt/data/challenge.png') img.size (640, 360)
pythonpixels = list(img.getdata()) # assume RGBA or RGB mode = img.mode mode 'RGB'
python# Gather bits from LSB of red channel bits = [] for r,g,b in pixels: bits.append(r & 1) # convert to bytes bytes_out = [] for i in range(0, len(bits), 8): byte = 0 for j in range(8): if i+j < len(bits): byte = (byte<<1) | bits[i+j] bytes_out.append(byte) decoded = bytes(bytes_out) decoded[:100] b"\xff\xd1N\xf0\xd5\x1e\xfaj\xff\xc0\x0c)\xf8\x00\x00\x003\xc8\x02\x0c\xe3\xc3\xcf\x00<<\xf9\x0eO|0\xfe\xeb\xfc('\xd7\xe0\xff\xb7\x7f\x0c\x9f@\x16\xec\x9b\xf3\x00\x00X\xc0\x7f@\xa0\xf2c\x00\x00\x00\x00\x00\xff\xff\xff\x00\xff\xf0?y\xc0\x0c<\x00y\x92\xcc\x0f\xcd\xd1\xff\xf1i\xf0\xd4\x9e\xf9s\x9f\xc0\x0c)\xf8\x00\x00\x003\x1f\xf2\x0c"
pythondecoded.find(b'UMASS') -1
pythondef extract_lsb_channel(channel_index): bits=[] for pixel in pixels: bits.append(pixel[channel_index]&1) bytes_out=[] for i in range(0,len(bits),8): byte=0 for j in range(8): if i+j<len(bits): byte = (byte<<1) | bits[i+j] bytes_out.append(byte) return bytes(bytes_out) for idx,name in enumerate(['R','G','B']): data_channel = extract_lsb_channel(idx) if b'UMASS{' in data_channel: print("Found in",name)
pythondata_channel = extract_lsb_channel(2) index = data_channel.find(b'UMASS{') data_channel[index:index+100] b'UMASS{perfectly-hidden-ready-to-strike}\x00\xac\x0f\xcf\xf0\xec\x0b\xa9\x80\x00\nNC\xa0{\xff7\xe8\x00\\OX\x8d \x1b\xad\xbb]`4\xf0\x93\xa4r\xb1|\xbc\xf0./\x19\xf3\xd4\xb3~\x87\xf3\xc9\xdeB\xedx\x10z\xe7\x1c\x11\xcc\x9fl\xe0'
Flag
UMASS{perfectly-hidden-ready-to-strike}
challenge.png và xác nhận chữ ký PNG (89 50 4E 47 0D 0A 1A 0A).IHDR, bốn IDAT và IEND – không có tEXt/iTXt, nên không hề giấu flag ở metadata.pythonimport struct with open('challenge.png','rb') as f: data = f.read() idx = 8 # bỏ qua header 8 byte while idx < len(data): l = struct.unpack(">I", data[idx:idx+4])[0] t = data[idx+4:idx+8].decode() print(t, l) idx += 12 + l # 4(len)+4(type)+len+4(CRC)
Kết quả: IHDR 13, IDAT …, IEND 0.
Quét toàn bộ file để tìm “UMASS{”. Không thấy → flag không ở dạng text thuần.
pythonimport re if b'UMASS{' in data: print('found')
Ảnh hoạt hình nhiều màu tím – thường được dùng làm “nhiễu” tốt cho giấu bit. Ý tưởng: trích LSB (bit thấp nhất) của các kênh màu.
pythonfrom PIL import Image img = Image.open('challenge.png') # 640×360, RGB pixels = list(img.getdata())
Giải nén LSB của kênh R, G, B thành chuỗi bit rồi gộp 8 bit → 1 byte:
pythondef lsb(channel): bits = [(p[channel] & 1) for p in pixels] out = bytes(int(''.join(map(str,bits[i:i+8])),2) for i in range(0,len(bits),8)) return out for c,name in enumerate('RGB'): payload = lsb(c) if b'UMASS{' in payload: print('Flag nằm ở kênh', name)
Output:
Flag nằm ở kênh B
pythonpayload = lsb(2) # kênh Blue start = payload.find(b'UMASS{') flag = payload[start : payload.index(b'}',start)+1] print(flag.decode())
→ UMASS{perfectly-hidden-ready-to-strike}
Với ảnh PNG, việc trích LSB không làm hỏng dữ liệu nén Deflate, vì nén đã diễn ra trước khi bit thay đổi; do đó ít ai nghi ngờ nếu chỉ xem dung lượng tệp.
Hoàn thành: tìm được flag và chứng minh phương pháp khôi phục.