Tulisan ini merupakan bagian awal dari rangkaian dokumentasi taktis saya dalam menyelesaikan seluruh tantangan lab di PortSwigger Web Security Academy. Saya memulainya dengan seri SQL Injection.

Selain sebagai bentuk latihan write-up dan reporting, dokumentasi ini saya tulis untuk membedah kerangka berpikir saya saat menghadapi ketidaktahuan di dalam sistem.

Karena saya rasa, tidak ada (atau saya tidak tahu) yang membuat dokumentasi terstruktur dan lengkap yang ada di PortSwigger dalam BAHASA INDONESIA. PortSwigger memiliki sekitar 263 lab. Di antaranya adalah lab Cross-site scripting, Cross-site request forgery (CSRF), Clickjacking, Cross-origin resource sharing (CORS), dan banyak… lagi.

Wow, berarti saya akan menulis 262 tulisan lagi. Entah butuh waktu berapa bulan untuk menyelesaikannya. Yaa.. barangkali seperti catatan pembelajaran pribadi yang siapa tahu bisa bermanfaat suatu hari nanti.

Di sini saya memulai dengan lab: SQL injection attack, querying the database type and version on Oracle.

Memeriksa Jenis Database (Di luar konteks lab, hanya opini pribadi saat di lapangan)

Opini saya, mengetahui versi database itu ibarat mengetahui merk kunci rumah sasaran. Setiap versi database punya kerentanan (CVE) yang berbeda. Kalau kita tahu itu Oracle 11g, kita bisa cari eksploit yang spesifik untuk versi tersebut. Jadi, ini adalah tahap Reconnaissance yang sangat vital.

Dalam konteks lab ini, kita sudah diberikan hint bahwa database yang digunakan adalah Oracle. Maka, fokus utama saya adalah mempraktikkan cara mengekstraksi tipe dan versinya secara presisi.

Mengetuk Pintu

Saya mulai dengan hal paling simpel: memasukkan petik tunggal (') di akhir parameter kategori (setelah kata Accessories).

https://0a7200880469d0f68023080b00b6004e.web-security-academy.net/filter?category=Accessories'

None

Ketika halaman memunculkan Internal Server Error, ada rasa senang sekaligus tegang. Bagi saya error adalah "pintu". Error ini berarti server merespon input secara mentah.

Menghitung Kolom

Langkah selanjutnya adalah mencari tahu jumlah kolom. Saya menggunakan teknik ORDER BY. Teknik ini adalah "kunci T" yang universal, bisa dipakai di hampir semua database.

Saya mencoba:

https://0a7200880469d0f68023080b00b6004e.web-security-academy.net/filter?category=Accessories' ORDER BY 1--

  1. ' ORDER BY 1-- (Halaman normal)
None
https://0a7200880469d0f68023080b00b6004e.web-security-academy.net/filter?category=Accessories%27%20ORDER%20BY%201--
  1. ' ORDER BY 2-- (Halaman normal)
None
https://0a7200880469d0f68023080b00b6004e.web-security-academy.net/filter?category=Accessories%27%20ORDER%20BY%202--
  1. ' ORDER BY 3-- (Error)
None
https://0a7200880469d0f68023080b00b6004e.web-security-academy.net/filter?category=Accessories%27%20ORDER%20BY%203--

Dari sini saya belajar bahwa tabel ini cuma punya 2 kolom. Jangan pernah coba UNION kalau jumlah kolomnya belum pas, karena pasti akan ditolak mentah-mentah oleh database.

Menyapa Oracle

Di sinilah saya sempat garuk-garuk kepala. Saya terbiasa dengan sintaks MySQL yang simpel seperti SELECT @@version. Tapi Oracle dia tidak mau menjalankan SELECT tanpa ada klausa FROM.

Saya harus menggunakan tabel khusus bernama v$version. Payload final saya:

' UNION SELECT BANNER, NULL FROM v$version--

Operator UNION digunakan untuk menggabungkan hasil dari dua perintah SELECT menjadi satu hasil (satu tampilan di layar). Query asli dari aplikasi menampilkan daftar produk. Dengan UNION, kita "menempelkan" hasil query kita sendiri (yaitu versi database) di bawah atau di samping daftar produk tersebut.

Syarat mutlak agar UNION bekerja, jumlah kolom dan tipe data antara query asli dan query kita "harus identik". Itulah kenapa Fase 2 (mencari jumlah kolom) sangat krusial.

Dalam database Oracle, informasi mengenai versi dan detail sistem tidak disimpan dalam fungsi sederhana seperti version(), melainkan di dalam sebuah kolom bernama BANNER.

Inilah data "rahasia" yang ingin kita bocorkan ke permukaan web.

Lantas, kenapa saya tidak menulis ' UNION SELECT BANNER FROM v$version-- saja? Karena query asli memiliki 2 kolom. Jika saya hanya memanggil BANNER (1 kolom), database akan protes karena jumlahnya tidak sama.

Kenapa pilih NULL bukan angka 1 atau teks 'a'? Karena kita belum tahu kolom kedua itu tipenya apa (apakah angka atau teks).

NULL adalah nilai universal yang diterima oleh semua tipe data di database manapun. Jadi, NULL adalah "pengganjal" paling aman agar query tidak error akibat ketidakcocokan tipe data.

v$versionIni adalah "ciri khas" Oracle. Berbeda dengan MySQL yang bisa melakukan SELECT melayang, Oracle mewajibkan setiap perintah SELECT merujuk ke sebuah tabel.

v$version adalah built-in view (tabel sistem) di Oracle yang menyimpan informasi versi perangkat lunak yang sedang berjalan. Tanpa menyebutkan tabel ini (FROM v$version), Oracle akan menolak perintah kita dengan pesan error "FROM keyword not found".

--Dua tanda strip ini adalah karakter komentar di Oracle. Tugasnya sederhana tapi vital: menghancurkan sisa kode SQL asli milik aplikasi yang ada di belakang payload kita. Tanpa ini, sisa kode asli akan dianggap sebagai bagian dari perintah kita dan menyebabkan syntax error.

Hasil Akhir:

Begitu saya tekan Enter, di halaman web muncullah berikut:

None
https://0a3d00850424acc6800f1c51003c00b9.web-security-academy.net/filter?category=Clothing%2c+shoes+and+accessories%27%20UNION%20SELECT%20BANNER,%20NULL%20FROM%20v$version--

Rasanya sangat memuaskan melihat data internal server muncul di halaman yang seharusnya cuma buat jualan barang. Ini bukti bahwa celah sekecil petik tunggal bisa membocorkan identitas rahasia sebuah server besar.

Personal Note:

Di sinilah pentingnya Parameterized Queries (Prepared Statements). Solusi ini menutup total celah bagi user untuk menyisipkan perintah SQL ke dalam logika aplikasi. Cara kerjanya didasarkan pada dua prinsip sederhana:

1. Pemisahan Logika & Data Struktur. Query SQL dikirimkan lebih dulu ke database dengan placeholder (seperti tanda ?). Input user baru dikirimkan belakangan secara terpisah.

2. Input Sebagai Data Murni. Apapun yang diketik user — meskipun itu mengandung karakter ' UNION SELECT — akan dianggap sebagai "teks biasa/string literal", bukan perintah kode yang akan dijalankan oleh mesin database.

Ibaratnya, kita memberi barista formulir isian pesanan yang kaku. Pelanggan boleh menulis apa saja di kolom "Pesanan", tapi barista tidak akan pernah menganggap tulisan itu sebagai instruksi untuk membakar kafe.