目录
1、low级别
step1 判断注入点和注入类型
step2 判断字段数
step3 获取数据库信息
2、medium级别
3、high级别
4、impossible级别
之前使用的是旧的版本,这次去官网换成了1.9版本。
SQL注入的步骤大概包括以下几个步骤:1、判断网站能不能注入;2、判断注入的字段数;3、获取数据库。
low级别的代码如下:
' . mysql_error() . '
' );
// Get results
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {
// Get values
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result, $i, "last_name" );
// Feedback for end user
echo "ID: {$id}"; // Increase loop count $i++; } mysql_close(); } ?>
First name: {$first}
Surname: {$last}
low级别下使用的是$_REQUEST方式对信息进行提交,和其他级别的主要区别也在这里,medium级别下使用的是$_POST,high级别下使用的是$_SESSION。
可以参考https://blog.csdn.net/god_xiangyu/article/details/95389549对网站的是否存在注入点进行判断以及注入的类型。
首先输入 ' 等特殊符号,如1' ,如果报错就说明可能存在注入点,下图是输入 ' 后显示的结果。也可以使用一些工具对注入点进行判断,比如sqlmap。
如果存在注入点,再去判断此注入点是字符型还是数字型。
字符型即 user_id = '$id' ,如果是字符型,则1 and ‘1’=’1 不报错,1 and ‘1’=’1'会报错('没有闭合)。
数字型即 user_id = $id ,如果是数字型,则1 and ‘1’=’1 会报错,1 and ‘1’=’1'不报错。
low级别下符合字符型的注入。
因为不能修改本来的代码,所以查找的字段数要与本来的字段数保持一致。
使用1' union select 1 -- ,会报列数不对的错误,如下图所示。然后逐次增加后面的列数,在输入1' union select 1,2 -- 时不会报错,所以low级别的字段为2.
每一个MySQL数据库中都有一个information_schema库来存储这个数据库的元信息,所以可以通过查询此数据库来获取想要的数据。获取用户的账号密码的过程如下。
第一步,在information_schema库的tables表中获得库名,使用
1' union select table_schema,1 from information_schema.tables # 。
第二步,其中有一个库是dvwa,猜测会存放相关信息,获取它所拥有的表,使用 ' union select 1,table_name from information_schema.tables where table_schema='dvwa' -- 。注意--后一定要带空格,否则会报错。
第三步,查看users表中的字段,使用 ' union select table_name,column_name from information_schema.columns where table_name='users' --
第四步,获取user字段和password字段的内容,使用 ' union select user,password from dvwa.users --
第五步,经过尝试,密码经过md5加密,使用md5进行解码就可以获得密码。
验证阶段,使用获得的账户密码可以登录login界面,说明注入成功。
此级别的代码的主要区别如下。
// Get input
$id = $_POST[ 'id' ];
$id = mysql_real_escape_string( $id );
此级别下有这两行不一样,第一行使用的是$_POST方式,在提交内容时不会在网址栏中显示其他的内容;第二行用来转义 ' 等的字符,此时就不能使用字符型注入而要进行数字型注入。
因为此级别是一个下拉框,没有进行输入的地方,所以要使用burpsuite进行抓包。
对这里进行修改即可,类似下图所示。可以参考low级别的步骤。
此级别下代码与low级别就一点区别,就是数据提交的方式使用$_SESSION进行。
// Get input
$id = $_SESSION[ 'id' ];
操作步骤与low级别完全相同。
代码的变化主要如下。
// 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();
$row = $data->fetch();
// Make sure only 1 result is returned
if( $data->rowCount() == 1 ) {
// Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ];
// Feedback for end user
echo "ID: {$id}
First name: {$first}
Surname: {$last}
";
}
}
之前的级别都是在接收到id后直接或进行处理后进行SQL语句的查询,此级别下线进行判断是否是数字,在进行SQL查询时,使用$data->execute()函数保证输入的参数只有一个。