Write-Up: RTR II — Cyber Competition 2026 (CTF Mode)

Writeup tim (Matlee Arya Sadewa, Achmad Kamal, Huga Hazimulfikri Nawawi) — 10 challenge berhasil diselesaikan dari 5 kategori: reverse engineering, cryptography, binary exploitation, digital forensics, dan web exploitation.
RTR II — Cyber Competition 2026 · Writeup
Rise The Ranger II — Cyber Competition 2026
Platform: ctf-risetheranger.satsiber-tni.mil.id · Format flag: RTRTNI26{...}
Anggota Tim
| Nama |
|---|
| Matlee Arya Sadewa |
| Achmad Kamal |
| Huga Hazimulfikri Nawawi |
Ringkasan
10 challenge berhasil diselesaikan dari 6 kategori. Poin di platform bersifat dinamis (menurun seiring bertambahnya solver); nilai di bawah adalah nilai saat challenge dikerjakan.
| # | Challenge | Kategori | Poin | Kerentanan Inti |
|---|---|---|---|---|
| 1 | RE EASYYYYY | Reverse Engineering | 50 | Overlapping stack write |
| 2 | The Leaky Archive | Cryptography | 50 | ZipCrypto known-plaintext |
| 3 | NoteVault v1.4 | Binary Exploitation | 50 | Format string → arbitrary read |
| 4 | License Beacon | Reverse Engineering | 100 | Custom VM + FNV-1a/xorshift64 |
| 5 | Forensik Memory GUYS | Digital Forensics | 200 | Process masquerading |
| 6 | Ghost in the Handset | Digital Forensics | 171 | ADB + Redis clipboard leak |
| 7 | Backup Never Dies | Web Exploitation | 50 | Exposed editor backup |
| 8 | Cookie Monster | Web Exploitation | 50 | Client-side authorization |
| 9 | Confidential Notes | Web Exploitation | 50 | IDOR |
| 10 | Saya Anggota | Web Exploitation | 50 | Hidden non-contiguous IDs |
Daftar Flag
RTRTNI26{p3rb4nd1ng4N_E5_0nl1}
RTRTNI26{kn0wn_pl41nt3xt_1s_4ll_y0u_n33d}
RTRTNI26{f0rm4t_str1ng_4rbitrary_r34d}
RTRTNI26{Lic3nse_VM_runT1me_traC3}
RTRTNI26{m3m0ry_f0r3ns1c_x0r_b4se64_gh1dr4_r3v_2026}
RTRTNI26{Ag3nt_L_n0nfreSh_w@rm_t34}
RTRTNI26{robots_are_not_security}
RTRTNI26{never_trust_client_side}
RTRTNI26{always_check_authorization}
RTRTNI26{66ead40b24f877734f07a9ef4a84b3b7}
1. RE EASYYYYY
Kategori: Reverse Engineering · Poin: 50 · Attachment: vault.zip

Langkah 1 — Identifikasi binary

strings memberi empat fragmen yang tampak seperti potongan flag, tetapi urutannya tidak masuk akal. Yang menonjol: fragmen 2INTRTR adalah RTRTNI2 terbalik — petunjuk kuat bahwa string tersimpan dalam urutan terbalik.
Langkah 2 — Menemukan trik sebenarnya

Tidak ada enkripsi sama sekali — main hanya melakukan satu strcmp. Triknya ada pada cara buffer dibangun: dua penulisan terakhir memakai offset -0x21 dan -0x19 yang bukan kelipatan 8.
Akibatnya chunk ketiga menimpa byte ke-15 milik chunk kedua (kebetulan sama-sama n, jadi tidak merusak data), sehingga panjang string menjadi 30 byte, bukan 32. Inilah sebabnya pembacaan strings biasa menghasilkan urutan yang salah.
offset: 0 8 15 23 30
|________|_______|_______|______|
}1ln0_5E _N4gn1d n4br3p{6 2INTRTR\0
^
byte ke-15 ditimpa (n -> n)
Langkah 3 — Rekonstruksi dan verifikasi

buf = bytearray(48)
def w(off, val): buf[off:off+8] = val.to_bytes(8, 'little')
w(0x00, 0x45355f306e6c317d) # }1ln0_5E
w(0x08, 0x6e64316e67344e5f) # _N4gn1dn
w(0x0f, 0x367b70337262346e) # n4br3p{6 <- overlap di offset 15
w(0x17, 0x525452544e4932) # 2INTRTR\0
pw = buf.split(b'\x00')[0].decode()
print(pw[::-1])
Red herring: teks
Password pertama— tidak ada tahap kedua di binary.
Flag: RTRTNI26{p3rb4nd1ng4N_E5_0nl1}
2. The Leaky Archive
Kategori: Cryptography · Poin: 50 · Attachment: soundofshire.zip

"Pencuri yang bijak takkan membuang waktu mendobrak pintu besi raksasa milik sang naga. Ia hanya perlu mencari guratan kuno yang terpahat di sudut ambang pintu — sebuah tanda yang selalu sama sejak Zaman Pertama."
Langkah 1 — Membaca struktur arsip

Tiga fakta yang menentukan seluruh strategi:
| Fakta | Implikasi |
|---|---|
csz = usz + 12 | ZipCrypto legacy, bukan AES-256 |
method = 0 (stored) | plaintext = byte mentah file, tak perlu menebak hasil deflate |
test_image.png ikut di arsip | header PNG-nya publik dan konstan |
ZipCrypto punya kelemahan fatal: seluruh file dalam satu arsip memakai internal key (X, Y, Z) yang sama, hanya berbeda 12-byte header acak. Begitu kunci dipulihkan dari satu file, semua file lain ikut terbuka — persis seperti hint: "seluruh gembok di Erebor pun akan terbuka tanpa bersuara."
Langkah 2 — Menyiapkan known-plaintext

"Tanda yang selalu sama sejak Zaman Pertama" = magic bytes PNG. 16 byte kontigu di offset 0 sudah melewati minimum bkcrack (12 byte); sisanya ditambahkan sebagai sparse plaintext untuk mempersempit ruang cari.
Langkah 3 — Serangan dan dekripsi

Flag: RTRTNI26{kn0wn_pl41nt3xt_1s_4ll_y0u_n33d}
3. NoteVault v1.4
Kategori: Binary Exploitation · Poin: 50 · Target: 45.92.158.64:20001

Langkah 1 — Proteksi dan permukaan serangan

Binary non-PIE berarti seluruh alamat global bersifat tetap — tidak perlu leak alamat. Kombinasi getenv + dprintf langsung mengarahkan dugaan ke format string.
Langkah 2 — Menemukan lokasi flag

Flag dibaca dari environment variable FLAG ke g_flag @ 0x406880 — inilah "flag yang tersimpan di memori proses" yang diminta soal. Menariknya, fungsi Admin Debug pada binary justru membocorkan seluruh layout memorinya sendiri.
Struktur data catatan:
struct note { // total 0x170, array 16 slot @ 0x405140
char title[0x60]; // 0x000 <- memcpy(title_len), TIDAK null-terminated
uint64_t title_len; // 0x060
char content[0x100]; // 0x068 <- strncpy(0xff)
int id; // 0x168
int used; // 0x16c
};
Langkah 3 — Kerentanan format string

view_note menyalin 96 byte judul catatan ke stack lalu memanggil dprintf(fd, tmp) dengan eax = 0 (tanpa vararg). Judul catatan dipakai langsung sebagai format string — dan judul dikendalikan penuh oleh penyerang.
Langkah 4 — Eksploitasi

Offset buffer dikalibrasi otomatis dengan probe AAAABBBB%1$p.%2$p..., mencari nilai 0x4242424241414141. Hasilnya buffer berada di %7$, sehingga payload:
title = "%8$sAAAA" + p64(0x406880)
└────────┘ └────────────┘
8 byte qword ke-1 buffer = %8$ = alamat g_flag
Red herring: fitur
BULK:dan string umpanFLAG{th1s_1s_n0t_th3_r34l_fl4g}.
Flag: RTRTNI26{f0rm4t_str1ng_4rbitrary_r34d}
4. License Beacon
Kategori: Reverse Engineering · Poin: 100 · Attachment: License Beacon.zip
![]()
"Vendor menyatakan bahwa license VM mereka tidak dapat dianalisis tanpa activation service. Buktikan sebaliknya."
Langkah 1 — Isi paket dan perilaku awal

Dua kode error yang berbeda memberi informasi penting: partner.lic lolos verifikasi signature dan hanya gagal di activation, sedangkan enterprise.lic gagal lebih awal.
Langkah 2 — Membongkar license VM

Fungsi di 0x17d0 benar-benar sebuah interpreter bytecode: ia mengeksekusi 24 byte program di .rodata:0x2190 terhadap akumulator 64-bit, dengan opcode ditentukan oleh byte & 3.
| op | operasi |
|---|---|
| 0 | s = (c<<33) ^ s ^ 0x9E3779B97F4A7C15 |
| 1 | s = rol64(s, c%31+1) + 0x6A09E667F3BCC909 |
| 2 | s = (c | 0xBF58476D1CE4E5B9) * (s ^ (s>>29)) |
| 3 | s ^= rol64(s + 0x94D049BB133111EB, c%23+1) |
Ketiga konstanta itu adalah konstanta splitmix64 — sidik jari yang membantu mengenali struktur algoritmanya.
Langkah 3 — Oracle gratis untuk validasi

Inilah kunci penyelesaiannya. partner.lic sudah membawa signature valid (EEA9ABAA), sehingga bisa dipakai untuk membuktikan reimplementasi VM bit-exact sebelum menghitung activation. Kalau sig cocok, jalur activation dipastikan ikut benar — tidak perlu menebak.
Ini penting karena modulo 31 dan 23 di dalam VM muncul sebagai idiom magic-division di assembly, bagian yang paling rawan salah dibaca.
sig = hi32 ^ lo32 of VM( rol64(fnv(nonce),17) ^ fnv(serial) )
act = VM( rol64(VM(rol64(fnv(region),29) ^ fnv(nonce)), 19)
^ VM(rol64(fnv(node),11) ^ fnv(serial))
^ 0xA5C31D7E29F0486B )
Langkah 4 — Verifikasi dengan binary asli

sealed.dat di-XOR dengan keystream xorshift64 yang di-seed dari VM(activation ^ fnv1a("reconciliation")), di-refresh setiap 8 byte.
Red herring:
enterprise.licmustahil dipakai — binary melakukanstrcasecmp(tier,"trial")dan wajib bernilai 0, sehingga tierenterpriseselalu jatuh ke E23 berapa pun signature-nya.beacon.cachejuga tidak dipakai sama sekali.
Flag: RTRTNI26{Lic3nse_VM_runT1me_traC3}
5. Forensik Memory GUYS
Kategori: Digital Forensics · Poin: 200 · Attachment: memory.raw.zst (1,3 GB → 13 GB)

⚠️ Dekompresi jangan ke
/tmpbila itu tmpfs — 13 GB akan memakan RAM.
Langkah 1 — Identifikasi memory image

banners.Banners mengeluarkan ntkrnlmp.pdb, langsung memastikan ini image Windows, bukan Linux.
Langkah 2 — Menemukan proses yang menyamar

pslist sama sekali tidak membantu di sini — seluruh 46 svchost.exe ber-parent services.exe dengan nama yang tampak wajar. Yang membongkarnya adalah windows.cmdline.
Penyamarannya dua lapis:
- Homoglyph — angka nol menggantikan huruf
o:svch0stbukansvchost - Path — dijalankan dari
C:\ctf\, bukanC:\Windows\System32\
Ditambah parent PID 6124 yang bukan services.exe — svchost asli tidak pernah demikian.
Langkah 3 — Dump binary implan

PE32+ 68 KB hasil kompilasi MinGW-w64. String-nya langsung membuka jalan: dua blob base64 dan literal RTRTNI.
Langkah 4 — Memulihkan konfigurasi rahasia

Obfuskasinya base64 → XOR kunci berulang, dengan kunci tertinggal sebagai literal di dalam binary.
Yang membuatnya bisa dipecahkan tanpa menebak sama sekali: blob kedua diawali enam byte nol. Pada XOR kunci-berulang, byte nol berarti plaintext identik dengan kunci di posisi tersebut — jadi enam karakter pertama flag adalah kuncinya, dan panjang kunci dipastikan 6.
Flag: RTRTNI26{m3m0ry_f0r3ns1c_x0r_b4se64_gh1dr4_r3v_2026}
6. Ghost in the Handset
Kategori: Digital Forensics · Poin: 171 · Attachment: challenge.pcapng + nc 45.92.158.64 32392

"Agen lapangan berkode 'L' menghilang. Apa yang sebenarnya terjadi pada Agent L? Dan siapa yang membaca pesannya lebih dulu?"
Langkah 1 — Memetakan trafik

Seluruh trafik adalah loopback — capture diambil dari host yang menjalankan emulator Android (Genymotion).
Port 6555 ditentukan dari protokolnya, bukan tebakan: hanya stream 0 yang memuat magic ADB (OPEN/WRTE/CLSE), sedangkan 5037 murni jalur adb-server lokal.
Langkah 2 — Kebocoran lewat Redis clipboard sync

Genymotion menyinkronkan clipboard melalui Redis, dan itu merekam perintah attacker apa adanya. Dari sini juga terkonfirmasi shell yang diperoleh adalah root.
Langkah 3 — Merekonstruksi database

Bagian yang paling menuntut ketelitian: byte mentah TCP bukan file yang valid. adb pull membungkus payload dalam chunk DATA + panjang 32-bit little-endian, diakhiri DONE. Tanpa de-chunking, file SQLite akan korup.
Langkah 4 — Isi bukti dan penyelesaian kuis

Service nc mengajukan 10 pertanyaan investigasi berurutan:
| # | Pertanyaan | Jawaban |
|---|---|---|
| 1 | Remote debugging protocol | adb |
| 2 | Port adbd sisi device | 6555 |
| 3 | User shell attacker | root |
| 4 | Pub/sub yang membocorkan perintah | redis |
| 5 | Database pertama di-pull | /data/data/com.android.providers.telephony/databases/mmssms.db |
| 6 | Database kedua di-pull | /data/data/com.android.providers.contacts/databases/contacts2.db |
| 7 | Nomor pengirim SMS | (237) 230-7212 |
| 8 | Clue phrase | nonfresh_warm_tea |
| 9 | Display name kontak | Agent_L |
| 10 | Email kontak | agent_l@ex4mpl3.com |
Jawaban naratifnya: attacker-lah yang membaca pesan itu lebih dulu. Ia sudah memegang shell root dan menarik mmssms.db, sehingga SMS berisi clue sudah dibacanya sebelum sempat berarti bagi siapa pun.
Red herring: SMS keluar terenkripsi di Redis (
baseband sms outbound 122 RlFLZi7OozpldM6UIw==) sama sekali tidak dibutuhkan.
Flag: RTRTNI26{Ag3nt_L_n0nfreSh_w@rm_t34}
7. Backup Never Dies
Kategori: Web Exploitation · Poin: 50 · Target: http://45.92.158.64:28491/

Langkah 1 — robots.txt justru membocorkan lokasinya

Ironinya sesuai dengan flag-nya sendiri: robots.txt bukan kontrol keamanan — ia justru mempublikasikan daftar path sensitif kepada siapa pun.
Langkah 2 — Directory listing dan file backup editor

Dua kesalahan konfigurasi bertumpuk:
- Directory listing aktif pada
/backup/ - File backup editor (
.bak,.old,.save,.tmp) tidak diproses PHP, sehingga source code tersaji mentah
Flag: RTRTNI26{robots_are_not_security}
8. Cookie Monster
Kategori: Web Exploitation · Poin: 50 · Target: http://45.92.158.64:37204/

Langkah 1 — Menganalisis mekanisme autentikasi

Login mengembalikan dua cookie. PHPSESSID sudah tersedia sebagai sesi server-side — namun role justru disimpan terpisah di cookie yang sepenuhnya dikendalikan klien.
Langkah 2 — Memalsukan role

Root cause: state otorisasi disimpan di data milik klien dan tidak diverifikasi ulang di server. Seharusnya role berada di $_SESSION.
Flag: RTRTNI26{never_trust_client_side}
9. Confidential Notes
Kategori: Web Exploitation · Poin: 50 · Target: http://45.92.158.64:19482/

"Agen K merilis sistem penyimpanan catatan rahasia yang ia klaim sepenuhnya privat. Namun rumor mengindikasikan adanya celah tipis pada arsitektur isolasi datanya."
Langkah 1 — Kredensial demo tercetak di halaman login

Langkah 2 — Daftar difilter, detail tidak

Aplikasi memfilter daftar di notes.php, tetapi note.php sama sekali tidak memeriksa kepemilikan.
| id | owner | isi |
|---|---|---|
| 1 | guest | Project Meeting |
| 2 | admin | Salary Review — dinyatakan sendiri sebagai decoy |
| 3 | guest | Welcome Note |
| 4 | admin | Administrator Secret → flag |
Langkah 3 — Membaca catatan milik admin

Root cause: otorisasi diterapkan di lapisan presentasi, bukan di lapisan akses data — persis "celah tipis pada arsitektur isolasi data" yang disebut soal.
Flag: RTRTNI26{always_check_authorization}
10. Saya Anggota
Kategori: Web Exploitation · Poin: 50 · Target: http://45.92.158.64:26391/

Langkah 1 — Ketidakcocokan jumlah anggota

Dashboard menyatakan 110 Total Anggota, tetapi enumerasi ID 1–130 hanya mengembalikan 100 record. Selisih 10 itulah "anggota yang terlibat" yang diminta soal.
Ini bukan SQL injection — input divalidasi ketat sebagai integer; 1', 1 OR 1=1, 01, 1e2, +1, 0x65 semuanya ditolak.
Langkah 2 — Enumerasi ID non-kontigu

Record tersembunyi diberi ID non-kontigu agar tidak terlihat lewat penelusuran normal. Sapuan ID 1–9000 menemukan sembilan, tiga di antaranya berisi fragmen base64.
Langkah 3 — Menyusun ulang fragmen terbalik

Fragmen ketiga diawali } — tanda seluruh rangkaian tersimpan terbalik. Dua jalur rekonstruksi yang independen memberi hasil identik, dan itulah yang meyakinkan:
- C) gabung urut ID naik, lalu balik tiap fragmen
- D) gabung urut ID turun, lalu balik keseluruhan string
Hasilnya tepat 32 karakter heksadesimal (persis panjang MD5) diikuti kurung tutup. Prefiks RTRTNI26{ sudah diberikan di deskripsi soal.
Flag: RTRTNI26{66ead40b24f877734f07a9ef4a84b3b7}
Struktur Repository
.
├── WRITEUP.md <- dokumen ini
├── images/
│ ├── challenges/ <- screenshot halaman soal
│ └── steps/ <- gambar langkah pengerjaan
├── re-easyyyyy/ <- binary vault + disassembly
├── leaky-archive/ <- arsip, plain.bin, flag hasil dekripsi
├── notevault/ <- binary + exploit.py
├── license-beacon/ <- solve.py (mandiri, tanpa binary)
├── memforensics/ <- vol3 wrapper + dump proses 1348
└── ghost-handset/ <- extract_db.py, ask.py, database rekonstruksi
Tooling
volatility3 · bkcrack · tshark / capinfos · objdump / readelf / pefile · sqlite3 · Pillow · curl · Python 3
Matlee Arya Sadewa · Achmad Kamal · Huga Hazimulfikri Nawawi