Exploiting a Race Condition in the Upload Feature
Pada kesempatan kali ini, saya ingin berbagi sedikit tentang eksploitasi race condition pada fitur file upload. Jujur, saya sendiri belum pernah menemukan kerentanan ini dalam skenario nyata atau berhasil mengeksploitasinya di aplikasi real-world. Namun, setelah memahami konsep ini lebih dalam, saya merasa ini penting untuk dimasukkan ke dalam checklist saat melakukan pentest terhadap fitur upload.
Untuk referensinya sendiri, saya mengambil dari Lab Portswigger berikut:
Namun agar lebih memahami root cause, saya mencoba membuat ulang skenario lab ini secara lokal dengan bantuan ChatGPT.
Lab Setup
Cara setup labnya sangat mudah.
git clone https://github.com/yuyudhn/race_file_uploadcd race_file_upload/docker compose up -d --force-recreate
Akses labnya di http://localhost:8089.
Skema Fitur Upload
Fitur upload pada lab ini memiliki mekanisme pengecekan MIME type dan juga ekstensi file. Untuk uji coba, kita akan coba mengunggah file PHP berisi web shell dengan ekstensi .jpg.
Namun, bagaimana jika kita mengunggah file dengan MIME type yang valid, tetapi menggunakan ekstensi .php?
File gagal diupload karena gagal pada pengecekan ekstensi. Sampai di sini, terlihat bahwa sistem telah melakukan validasi dengan baik. Namun mari kita lihat lebih dalam pada potongan kode berikut:
if (!move_uploaded_file($_FILES["image"]["tmp_name"], $target_file)) {
echo "🚫 Gagal menyimpan file.";
exit;
}
if (checkMime($target_file) && checkFileType($target_file)) {
echo "✅ File berhasil diupload: <a href='$target_file'>" . htmlspecialchars($target_file) . "</a>";
} else {
unlink($target_file);
echo "🚫 File tidak valid dan telah dihapus.";
}
echo '<br><br><a href="' . htmlspecialchars($_SERVER["PHP_SELF"]) . '">Kembali</a>';
exit;
}
Kerentanan
Masalah terletak pada urutan prosesnya. Alur upload berjalan seperti ini:
- File diterima dan disimpan ke temporary location.
- File dipindahkan ke direktori tujuan (uploads/) menggunakan move_uploaded_file.
- Setelah itu baru dilakukan pengecekan MIME dan ekstensi.
- Jika validasi gagal, file akan dihapus menggunakan unlink().
Artinya, ada window of time (race condition) di mana file sudah berada di server dan bisa diakses, sebelum validasi selesai dan file dihapus jika tidak lolos.
Eksploitasi
Menggunakan Burp, kirim request upload file berbahaya (misalnya web shell PHP). Secara bersamaan, lakukan request GET ke lokasi file upload (/uploads/nama_file.php).
Lalu pada tab Repeater, klik kanan > Add tab to Group > Create Group. Lalu masukan tab upload dan tab get shell.
Selanjutnya, pada tab untuk akses lokasi shell, duplicate tab nya menjadi 6. Untuk jumlah ini bisa disesuaikan sendiri ya.
Selanjutnya pada tombol send, ubah menjadi Send group in parallel.
Lalu klik button Send group. Lalu cek pada Burp Logger. Ada satu request ke shell yang berhasil di hit sebelum file dihapus oleh fungsi unlink().
Eksploitasi ini juga bisa diotomatisasi menggunakan Python script dengan bantuan modul threading. Ini mempermudah untuk mencoba timing eksploitasi berulang kali secara cepat.
Race condition seperti ini cukup tricky dan jarang ditemui, namun sangat penting untuk dikenali. Validasi seharusnya dilakukan sebelum file disimpan ke direktori akhir, bukan setelahnya. Ini menjadi salah satu checklist tambahan saya ke depannya saat melakukan pengujian terhadap fitur file upload.
Semoga sharing kali ini bermanfaat!
Posting Komentar untuk "Exploiting a Race Condition in the Upload Feature"
Posting Komentar
Silahkan tinggalkan komentar jika ada masukan, pertanyaan, kritik ataupun dukungan. Namun pastikan untuk berkomentar secara sopan.