Sunset
๐ง Kesimpulan Challenge ini menggunakan teknik: PNG โ LSB extraction โ RGB channel split โ hex encoding โ bit interleave (R-G-B) โ ZIP file โ PNG โ flag
๐งฉ Write-Up: Sunset (Forensic / Steganography)
(half slop)
๐ Deskripsi
Diberikan sebuah file gambar PNG (sunset.png). Berdasarkan deskripsi, terdapat pesan tersembunyi di dalam gambar.
๐ Step 1 โ Analisis Awal
Langkah pertama adalah melakukan pengecekan dasar:
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:10:05
โฐโโฏ file sunset.png
sunset.png: PNG image data, 1911 x 955, 8-bit/color RGB, non-interlaced
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:10:22
โฐโโฏ strings sunset.png | head
IHDR
IDATx
%!!Y/b
I-h!
LJ$ @"
.$ fi @)
JDh>
P,4H
gO>%
:F-!
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ PIPE|0 ๎ kali ๏ 06:10:28
โฐโโฏ binwalk sunset.png
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 PNG image, 1911 x 955, 8-bit/color RGB, non-interlaced
41 0x29 Zlib compressed data, default compression
Tidak ditemukan signature mencurigakan atau embedded file.
๐ฌ Step 2 โ Steganografi dengan zsteg
Karena file adalah PNG, pake zsteg juga:
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:10:35
โฐโโฏ zsteg sunset.png
imagedata .. text: ",BLMffIfi@Ye"
b1,r,lsb,xy .. file: Zip archive data, at least v2.0 to extract, compression method=deflate
b1,g,lsb,xy .. file: Zip archive data, at least v2.0 to extract, compression method=deflate
b1,b,lsb,xy .. file: Zip archive data, at least v2.0 to extract, compression method=deflate
b1,rgb,msb,xy .. file: BS image, Version 0, Quantization 64624, (Decompresses to 3640 words)
b1,bgr,lsb,xy .. <wbStego size=0x701c ext="\x1C\x0E?" data="\x00\x00?\x00\x01\xC0\x00q\xC0\x00"... even=false hdr=nil enc=nil mix=nil controlbyte=nil>
b1,bgr,msb,xy .. file: BS image, Version 0, Quantization 64624, (Decompresses to 3640 words)
b2,g,msb,xy .. text: "RU'uJ`s~"
b2,rgb,lsb,xy .. file: mc68k COFF object not stripped
b2,bgr,lsb,xy .. file: mc68k COFF object not stripped
b3,g,msb,xy .. text: "HJ$IR$\t8#"
b4,r,lsb,xy .. file: PDP-11 UNIX/RT ldp
b4,r,msb,xy .. text: "HDDDDLDD\"B\"\""
b4,g,lsb,xy .. file: PDP-11 UNIX/RT ldp
b4,g,msb,xy .. text: "QUUUUUU]5SUSu[5;"
b4,b,lsb,xy .. text: "3\"4R24UR\"3##%$US$UC5UUEEgDUGUefeDTDy"
b4,b,msb,xy .. text: "UU=3Uu7ww"
b4,bgr,msb,xy .. file: Tower/XP rel 3 object not stripped
Ditemukan indikasi data pada channel RGB.
Kemudian dilakukan extract:
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:11:08
โฐโโฏ zsteg -E b1,rgb,lsb,xy sunset.png > raw_bits.bin
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๏ 11s ๎ kali ๏ 06:11:49
โฐโโฏ file raw_bits.bin
raw_bits.bin: data
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:11:52
โฐโโฏ zsteg -E b1,r,lsb,xy sunset.png > raw_bits_r.bin
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๏ 9s ๎ kali ๏ 06:12:35
โฐโโฏ zsteg -E b1,g,lsb,xy sunset.png > raw_bits_g.bin
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ INT ๎ kali ๏ 06:12:56
โฐโโฏ zsteg -E b1,b,lsb,xy sunset.png > raw_bits_b.bin
Namun hasilnya tidak langsung membentuk file valid. Akhirnya saya coba untuk melakukannya satu satu.
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:14:18
โฐโโฏ file raw_bits_r.bin
raw_bits_r.bin: Zip archive data, at least v2.0 to extract, compression method=deflate
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:14:34
โฐโโฏ mv raw_bits_r.bin raw_bits_r.zip
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:14:46
โฐโโฏ zipinfo raw_bits_r.zip
Archive: raw_bits_r.zip
Zip file size: 228125 bytes, number of entries: 1
-rw-a-- 6.3 fat 141366 bx defN 22-Jul-03 21:20 r.txt
1 file, 141366 bytes uncompressed, 81587 bytes compressed: 42.3%
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:14:53
โฐโโฏ unzip raw_bits_r.zip
Archive: raw_bits_r.zip
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
unzip: cannot find zipfile directory in one of raw_bits_r.zip or
raw_bits_r.zip.zip, and cannot find raw_bits_r.zip.ZIP, period.
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:15:38
โฐโโฏ 7z x raw_bits_r.zip
7-Zip 25.01 (x64) : Copyright (c) 1999-2025 Igor Pavlov : 2025-08-03
64-bit locale=en_US.UTF-8 Threads:12 OPEN_MAX:1024, ASM
Scanning the drive for archives:
1 file, 228125 bytes (223 KiB)
Extracting archive: raw_bits_r.zip
WARNINGS:
There are data after the end of archive
--
Path = raw_bits_r.zip
Type = zip
WARNINGS:
There are data after the end of archive
Physical Size = 81731
Tail Size = 146394
Characteristics = Local Central
Everything is Ok
Archives with Warnings: 1
Warnings: 1
Size: 141366
Compressed: 228125
Setelah saya pisahkan masing masing, saya coba ke bagian 'r' dulu. Ternyata 'r' adalah .zip. Saya coba ke yang lain akhirnya.
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ INT ๎ kali ๏ 06:22:50
โฐโโฏ file raw_bits_g.bin
raw_bits_g.bin: Zip archive data, at least v2.0 to extract, compression method=deflate
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:22:59
โฐโโฏ file raw_bits_b.bin
raw_bits_b.bin: Zip archive data, at least v2.0 to extract, compression method=deflate
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:23:02
โฐโโฏ mv raw_bits_g.bin raw_bits_g.zip
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:23:19
โฐโโฏ mv raw_bits_b.bin raw_bits_b.zip
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:23:26
โฐโโฏ 7z x raw_bits_g.zip
7-Zip 25.01 (x64) : Copyright (c) 1999-2025 Igor Pavlov : 2025-08-03
64-bit locale=en_US.UTF-8 Threads:12 OPEN_MAX:1024, ASM
Scanning the drive for archives:
1 file, 228125 bytes (223 KiB)
Extracting archive: raw_bits_g.zip
WARNINGS:
There are data after the end of archive
--
Path = raw_bits_g.zip
Type = zip
WARNINGS:
There are data after the end of archive
Physical Size = 81862
Tail Size = 146263
Characteristics = Local Central
Everything is Ok
Archives with Warnings: 1
Warnings: 1
Size: 141366
Compressed: 228125
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:23:39
โฐโโฏ 7z x raw_bits_b.zip
7-Zip 25.01 (x64) : Copyright (c) 1999-2025 Igor Pavlov : 2025-08-03
64-bit locale=en_US.UTF-8 Threads:12 OPEN_MAX:1024, ASM
Scanning the drive for archives:
1 file, 228125 bytes (223 KiB)
Extracting archive: raw_bits_b.zip
WARNINGS:
There are data after the end of archive
--
Path = raw_bits_b.zip
Type = zip
WARNINGS:
There are data after the end of archive
Physical Size = 81826
Tail Size = 146299
Characteristics = Local Central
Everything is Ok
Archives with Warnings: 1
Warnings: 1
Size: 141366
Compressed: 228125
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:23:44
โฐโโฏ ls
b.txt raw_bits.bin raw_bits_g.zip r.txt
g.txt raw_bits_b.zip raw_bits_r.zip sunset.png
๐ง Step 3 โ Analisis Channel RGB
Dilakukan pemisahan channel menjadi tiga file:
r.txt
g.txt
b.txt
Ketiganya memiliki ukuran sama:
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:23:51
โฐโโฏ wc -c r.txt g.txt b.txt
141366 r.txt
141366 g.txt
141366 b.txt
424098 total
Menunjukkan bahwa kemungkinan besar ketiga channel harus digabung kembali.
โ ๏ธ Step 4 โ Dead End Awal
Beberapa percobaan awal:
XOR antar channel โ tidak menghasilkan hasil
Interleave byte RGB โ tidak menghasilkan file valid
Cek compression (zlib/gzip) โ gagal
Ini menunjukkan bahwa encoding bukan metode standar.
๐ Step 5 โ Insight Penting
Dengan melihat isi file:
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:25:49
โฐโโฏ xxd r.txt | head
00000000: 3563 3038 3030 3036 6232 6330 6563 3038 5c080006b2c0ec08
00000010: 2030 3130 3034 3233 3332 6333 3532 3830 010042332c35280
00000020: 3020 205c 2e2e 2e2e 2e2e 2e20 2e2e 4233 0 \....... ..B3
00000030: 2c35 282e 0d0a 3163 3130 3035 3030 3639 ,5(...1c10050069
00000040: 3030 6531 3830 2030 6531 6530 3036 3032 00e180 0e1e00602
00000050: 3430 3934 3033 6520 202e 2e2e 2e69 2e2e 409403e ....i..
00000060: 2e20 2e2e 2e60 242e 403e 0d0a 3334 3562 . ...`$.@>..345b
00000070: 3565 3165 3163 3232 3766 3162 2030 3265 5e1e1c227f1b 02e
00000080: 6337 3865 3366 3733 3064 3266 3820 2034 c78e3f730d2f8 4
00000090: 5b5e 2e2e 227f 2e20 2e2e 782e 2e30 2e2e [^..".. ..x..0..
didapatkan pola seperti:
5c080006b2c0ec08
Artinya:
๐ Data bukan raw byte, melainkan hex-encoded
โ๏ธ Step 6 โ Reconstruct dengan Bit Interleave
Setiap channel berisi hex nibble (4-bit).
Pendekatan yang digunakan:
Convert hex โ binary (4-bit)
Ambil bit dari R, G, B
Interleave menjadi:
Rbit Gbit BbitGabungkan menjadi stream bit
Convert kembali ke byte
๐งช Solver
Ini merupakan dasar code yang saya bisa simpulkan.
def combine_channels_to_bytes(r_data, g_data, b_data):
binary_data = ''
for r, g, b in zip(r_data, g_data, b_data):
r_binary = bin(int(r, 16))[2:].zfill(4)
g_binary = bin(int(g, 16))[2:].zfill(4)
b_binary = bin(int(b, 16))[2:].zfill(4)
binary_data += ''.join(a + b + c for a, b, c in zip(r_binary, g_binary, b_binary))
output = bytearray()
for i in range(0, len(binary_data), 8):
chunk = binary_data[i:i+8]
if len(chunk) == 8:
output.append(int(chunk, 2))
return output
def hex_to_bytes(filename):
out = bytearray()
with open(filename) as f:
for line in f:
parts = line.strip().split()
for p in parts:
# hanya ambil string yang benar-benar hex
if all(c in "0123456789abcdefABCDEF" for c in p):
if len(p) % 2 == 0:
out.extend(bytes.fromhex(p))
return out
Dengan memakai dasar seperti ini, saya bisa mengembangkan menjadi seperti ini:
def combine_channels(r_data, g_data, b_data):
binary = ""
for r, g, b in zip(r_data, g_data, b_data):
r_bin = bin(r)[2:].zfill(8)
g_bin = bin(g)[2:].zfill(8)
b_bin = bin(b)[2:].zfill(8)
binary += ''.join(a+b+c for a,b,c in zip(r_bin,g_bin,b_bin))
out = bytearray()
for i in range(0, len(binary), 8):
byte = binary[i:i+8]
if len(byte) == 8:
out.append(int(byte, 2))
return out
r = hex_to_bytes("r.txt")
g = hex_to_bytes("g.txt")
b = hex_to_bytes("b.txt")
combined = combine_channels(r, g, b)
open("combined_solver.bin", "wb").write(combined)
print("output size:", len(combined))
Saya namai sebagai solver.py.
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ INT ๎ kali ๏ 06:28:48
โฐโโฏ python3 solver.py
output size: 125658
๐ฆ Step 7 โ Hasil
Langsung cek hasil without hesitation:
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:32:01
โฐโโฏ file combined_solver.bin
combined_solver.bin: Zip archive data, at least v1.0 to extract, compression method=store
Output:
Zip archive data
Kemudian:
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:32:14
โฐโโฏ mv combined_solver.bin combined_solver.zip
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:32:57
โฐโโฏ 7z x combined_solver.zip
7-Zip 25.01 (x64) : Copyright (c) 1999-2025 Igor Pavlov : 2025-08-03
64-bit locale=en_US.UTF-8 Threads:12 OPEN_MAX:1024, ASM
Scanning the drive for archives:
1 file, 125658 bytes (123 KiB)
Extracting archive: combined_solver.zip
WARNINGS:
There are data after the end of archive
--
Path = combined_solver.zip
Type = zip
WARNINGS:
There are data after the end of archive
Physical Size = 68430
Tail Size = 57228
Comment = ๏ฟฝ
Everything is Ok
Archives with Warnings: 1
Warnings: 1
Size: 68026
Compressed: 125658
โญโ ๏ง ๏ผ ~/FGTE/foren/sunset/forWU โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๎ kali ๏ 06:33:01
โฐโโฏ ls
123.png combined_solver.zip raw_bits.bin raw_bits_g.zip r.txt sunset.png
b.txt g.txt raw_bits_b.zip raw_bits_r.zip solver.py
menghasilkan:
123.png
๐ผ๏ธ Step 8 โ Final
Membuka gambar:
open 123.png
Didapatkan gambar:
๐ก Insight
Tidak semua stego menggunakan byte-level encoding
Bit-level interleave sering digunakan untuk menghindari deteksi tool otomatis
Analisis format data (hex vs raw) sangat krusial
Signature file (
PK,PNG) adalah indikator penting keberhasilan
๐ฅ Antisipasi
Karena ini merupakan chall yang susah, saya insert data yang penting ke ChatGPT, lalu buatkan code agar saya bisa menghadapi ketika stuck seperti ini. Hasil code:
import itertools
def hex_to_bytes(filename):
out = bytearray()
with open(filename) as f:
for line in f:
parts = line.strip().split()
for p in parts:
if all(c in "0123456789abcdefABCDEF" for c in p):
if len(p) % 2 == 0:
out.extend(bytes.fromhex(p))
return out
def interleave_bits(a, b, c):
binary = ""
for x, y, z in zip(a, b, c):
xb = bin(x)[2:].zfill(8)
yb = bin(y)[2:].zfill(8)
zb = bin(z)[2:].zfill(8)
binary += ''.join(i+j+k for i,j,k in zip(xb,yb,zb))
out = bytearray()
for i in range(0,len(binary),8):
chunk = binary[i:i+8]
if len(chunk)==8:
out.append(int(chunk,2))
return out
def check_signature(data):
if data.startswith(b'PK'):
return "ZIP"
if data.startswith(b'\x89PNG'):
return "PNG"
if data.startswith(b'\xff\xd8'):
return "JPEG"
if data.startswith(b'GIF'):
return "GIF"
if data.startswith(b'%PDF'):
return "PDF"
return None
print("loading channels...")
r = hex_to_bytes("r.txt")
g = hex_to_bytes("g.txt")
b = hex_to_bytes("b.txt")
channels = {
"R": r,
"G": g,
"B": b
}
print("trying permutations...")
for perm in itertools.permutations(["R","G","B"]):
a = channels[perm[0]]
b = channels[perm[1]]
c = channels[perm[2]]
data = interleave_bits(a,b,c)
sig = check_signature(data)
if sig:
print("FOUND:", perm, "->", sig)
filename = f"output_{perm[0]}{perm[1]}{perm[2]}.bin"
open(filename,"wb").write(data)
print("written:", filename)
Flag
flag{9e068194-a2a5-4e4b-bf95-b85a9ca7d7fe}