← Back to list

CTF Write-up: The Mosaic

Category: Misc

Rahmat Hadinata · 2025-12-03 08:17 · 0 claps · 3.3 min read
#misc #ctf #wrieup #hard #decompiler
Open on Medium ↗

CTF Write-up: The Mosaic

Category: Misc

Difficulty: Medium

**m0leCon Beginner CTF**

Chall

Chall

Deskripsi Tantangan

Diberikan 100 file gambar (potongan puzzle) dengan nama acak. Deskripsi soal menyebutkan tentang “labels on the back of the canvas” dan tugas untuk memperbaiki “masterpiece” yang pecah sebelum pameran dibuka. Salah satu file gambar memiliki comment: “Reconstruct the timeline to find the truth.”

Analisis & Percobaan Gagal (Trial & Error)

Sebelum menemukan solusi yang tepat, kami menghadapi beberapa jalan buntu dan jebakan yang disiapkan oleh pembuat soal:

  1. Jebakan “Timeline” (Waktu Modifikasi):
  • Ide: Berdasarkan petunjuk “Reconstruct the timeline”, kami mencoba menyusun gambar dengan mengurutkan file berdasarkan waktu modifikasi (timestamp).
  • Masalah: Setelah dijalankan, hasilnya adalah gambar static noise yang acak. Setelah diperiksa, ternyata ke-100 file tersebut memiliki timestamp yang identik, sehingga pengurutan berdasarkan waktu mustahil dilakukan. Petunjuk ini kemungkinan besar adalah red herring atau merujuk pada urutan data internal, bukan waktu file.
  1. Kesalahan Parsing Metadata:
  • Ide: Kami menyadari adanya metadata posisi pada gambar.
  • Masalah: Script awal kami mencoba membaca tag bernama FragID. Script gagal dan menghasilkan peta kosong.
  • Solusi: Setelah menggunakan perintah exiftool -s, kami menemukan bahwa nama tag yang benar adalah Frag_ID (menggunakan underscore).
  1. Jebakan “Time Waste” pada Binary:
  • Masalah: Setelah berhasil mengekstrak file biner (data.bin) dari gambar dan menjalankannya, program tersebut berjalan sangat lambat (print satu karakter per detik). Ini adalah teknik anti-debugging sederhana (menggunakan sleep) untuk membuang waktu peserta. Kami memutuskan untuk membedah binary tersebut daripada menunggunya.

Langkah Penyelesaian (Solusi Valid)

1. Ekstraksi Metadata yang Benar

Setelah mengetahui nama tag yang valid, kami membuat peta koordinat menggunakan exiftool untuk mengekstrak Frag_ID dari semua file:

exiftool -p '$Frag_ID|$FileName' -q -ext png . > map_final.txt

Format output map adalah X|Y|NamaFile (contoh: 5|6|zbcb9rjm.png).

2. Rekonstruksi Gambar (Puzzle Reassembly)

Kami menggunakan script Python untuk menyusun potongan-potongan tersebut menjadi satu gambar utuh berdasarkan koordinat dari map_final.txt.

Script Penyusun (solve_puzzle.py):

import os
from PIL import Image
TILE_SIZE = 50
CANVAS_SIZE = 550 # Ukuran otomatis berdasarkan koordinat max
canvas = Image.new('RGB', (CANVAS_SIZE, CANVAS_SIZE))
with open('map_final.txt', 'r') as f:
    for line in f:
        parts = line.strip().split('|')
        if len(parts) >= 3:
            x, y, filename = int(parts[0]), int(parts[1]), parts[2]
            if os.path.exists(filename):
                img = Image.open(filename)
                canvas.paste(img, (x * TILE_SIZE, y * TILE_SIZE))
canvas.save("flag_reconstructed.png")

Hasil: Gambar yang dihasilkan (flag_reconstructed.png) terlihat seperti static noise (semut TV) yang sangat padat dan berwarna-warni. Dalam konteks CTF, pola noise yang padat seperti ini biasanya mengindikasikan Visual Cryptography atau Raw Data (Pixel-to-Bytes), bukan gambar rusak.

3. Ekstraksi Data (Pixel to Binary)

Karena curiga gambar tersebut adalah data mentah, kami mengekstrak setiap pixel RGB kembali menjadi urutan bytes.

Script Ekstraksi:

from PIL import Image
img = Image.open("flag_reconstructed.png").convert("RGB")
data = img.tobytes()
# Menyimpan hasil ekstraksi sebagai data.bin
with open("data.bin", "wb") as f:
    f.write(data)

Kami memeriksa jenis file yang dihasilkan:

$ file data.bin
data.bin: ELF 64-bit LSB executable, x86-64, ...

Ternyata benar, gambar tersebut menyembunyikan sebuah program Linux (ELF Binary).

4. Reverse Engineering Binary

Seperti disebutkan di bagian “Analisis”, program data.bin ini memiliki jebakan waktu (sleep). Kami melakukan static analysis menggunakan objdump untuk melihat logika aslinya tanpa menjalankan program.

objdump -d -M intel data.bin | grep -A 500 "<main>:"

Temuan Penting dari Assembly:

  1. XOR Key: Terdapat instruksi mov DWORD PTR [rbp-0x38], 0x42. Ini menunjukkan kunci XOR adalah 0x42.
  2. Data Terenkripsi: Terdapat beberapa instruksi movabs yang memindahkan nilai heksadesimal panjang (8 byte) ke register rax dan rdx. Ini adalah potongan-potongan flag yang terenkripsi.

5. Final Solver (Bypass Program)

Daripada melakukan patching binary untuk menghilangkan sleep, kami membuat script Python untuk membaca data terenkripsi langsung dari file data.bin dan mendekripsinya secara manual menggunakan kunci 0x42.

Script Solver Final (solve_final.py):

import struct
filename = "data.bin"
def extract_real_flag():
    print(f"[*] Membuka file {filename}...")
    with open(filename, "rb") as f:
        content = f.read()
    # 1. Cari Pola Data Enkripsi (Signature Based)
    # Hex dari instruksi movabs pertama: 0x1d313673392f3632
    # Karena Little Endian, urutan byte di file dibalik:
    target_pattern = b'\x32\x36\x2f\x39\x73\x36\x31\x1d'

    data_offset = content.find(target_pattern)
    if data_offset == -1:
        print("Pola tidak ditemukan!")
        return
    # 2. Ambil Data Berdasarkan Offset Relatif (Dihitung dari objdump)
    # Jarak antar blok data sesuai struktur instruksi assembly
    block1 = content[data_offset : data_offset + 8]
    block2 = content[data_offset + 10 : data_offset + 18]
    block3 = content[data_offset + 28 : data_offset + 36]
    block4 = content[data_offset + 38 : data_offset + 46]
    block5 = content[data_offset + 57 : data_offset + 61] # Sisa 3 byte terakhir

    # Ambil Key (0x42) yang berada 64 byte dari awal data
    xor_key = content[data_offset + 64]
    # 3. Gabungkan & Decrypt
    full_encrypted_data = block1 + block2 + block3 + block4 + block5[:3]

    # Lakukan XOR
    flag = "".join([chr(b ^ xor_key) for b in full_encrypted_data])
    print(f"FLAG: {flag}")
if __name__ == "__main__":
    extract_real_flag()

Hasil Akhir

Setelah menjalankan script solver, flag berhasil didapatkan secara instan.

Flag:

ptm{1ts_ju5t_pngs_4ll_th3_w4y_d0wn}

메타데이터
post_id
de88cc040ffd
slug
ctf-write-up-the-mosaic-de88cc040ffd
url
https://medium.com/@rsafei731/ctf-write-up-the-mosaic-de88cc040ffd
canonical_url
https://medium.com/@rsafei731/ctf-write-up-the-mosaic-de88cc040ffd
author_url
https://medium.com/@rsafei731
status
ok
fetched_at
2026-06-20 20:29:01