Preface
不管用什么语言编写的Web应用,它们都用一个共同点,具有交互性并且多数是数据库驱动。在网络中,数据库驱动的Web应用随处可见,由此而存在的SQL注入是影响企业运营且最具破坏性的漏洞之一,这里我想问,我们真的了解SQL注入吗?看完本篇文章希望能让你更加深刻的认识SQL注入。
目录
第一节 注入攻击原理及自己编写注入点
1.1、什么是SQL?
1.2、什么是SQL注入?
1.3、SQL注入是怎么样产生的?
1.4、编写注入点
第二节 寻找及确认SQL注入
2.1、推理测试法
2.2、and大法和or大法
2.3、加法和减法
正文
第一节 注入攻击原理及自己编写注入点
1.1 什么是SQL?
SQL 是一门 ANSI 的标准计算机语言,用来访问和操作数据库系统。SQL 语句用于取回和更新数据库中的数据。SQL 可与数据库程序协同工作,比如 MS Access、DB2、Informix、MS SQL Server、Oracle、Sybase 以及其他数据库系统。
1.2 什么是SQL注入?
看起来很复杂,其实很简单就能解释,SQL注入就是一种通过操作输入来修改后台SQL语句达到代码执行进行攻击目的的技术。
1.3 SQL注入是怎么样产生的?
构造动态字符串是一种编程技术,它允许开发人员在运行过程中动态构造SQL语句。开发人员可以使用动态SQL来创建通用、灵活的应用。动态SQL语句是在执行过程中构造的,它根据不同的条件产生不同的SQL语句。当开发人员在运行过程中需要根据不同的查询标准来决定提取什么字段(如SELECT语句),或者根据不同的条件来选择不同的查询表时,动态构造SQL语句会非常有用。
在PHP中动态构造SQL语句字符串:
query="SELECT∗FROMusersWHEREusername=". _GET[‘id’];
看上面代码我们可以控制输入参数id,修改所要执行SQL语句,达到攻击的目的。
1.4 编写注入点
这里先介绍一下涉及到的基础知识:
SELECT 列名称 FROM 表名称
符号 * 取代列的名称是选取所有列 WHERE 子句
下面的运算符可在 WHERE 子句中使用:
操作符 | 描述 |
---|---|
= | 等于 |
<> | 不等于 |
> | 大于 |
< | 小于 |
/>= | 大于等于 |
<= | 小于等于 |
BETWEE | 在某个范围内 |
LIKE | 搜索某种模式 |
注:不等于有<>和!=,都可以在mysql中使用,不过,因为!=在sql2000中会使用到,为了兼容,所以一般会用<>
了解了以上基础知识就让我们来自己编写注入点把。
第一步:使用if语句来判断变量是否已初始化
<?php
if(isset($_GET['id'])){
$conn = mysql_connect("localhost", "root", "password");
if(!$conn){
die('Could not connect: '. mysql_error());
}
mysql_select_db("SQLInjection", $conn);
$querry = "select * from users where id=". $_GET['id'];
$sql = mysql_query($querry, $conn);
$result = mysql_fetch_array($sql);
echo "<table class='itable' border='1' cellpadding='0' width='300px' height='150'>";
echo "<tr>";
echo "<td>id</td>";
echo "<td>username</td>";
echo "</tr>";
echo "<tr>";
echo "<td>".$result['id']."</td>";
echo "<td>".$result['username']."</td>";
echo "</tr>";
echo "</table>";
mysql_close($conn);
echo "\n";
echo "查询语句为:". $querry;
}
?>
MySQL数据库环境配置:
第一步:创建数据库
create database SQLInjection;
第二步:创建表users和列id, username, password
use SQLInjection;
create table users(id int primary key, username varchar(255), password varchar(255));
第三步:查看表信息
desc users;
如图所示:
第四步:插入数据
use SQLInjection;
insert into users(id, username, password) values(1, 'Jim', 'whatever');
insert into users(id, username, password) values(2, 'Tom', 'Idonknow');
insert into users(id, username, password) values(3, 'Jim', 'kiddyou');
最终查询的结果如下:
第二节 寻找及确认SQL注入
2.1 推理测试法
寻找SQL注入漏洞有一种很简单的方法,就是通过发送特殊的数据来触发异常。
首先我们需要了解数据是通过什么方式进行输入,这里我总结了三个:
- GET请求:该请求在URL中发送参数。
- POST请求:数据被包含在请求体中。
- 其他注入型数据:HTTP请求的其他内容也可能会触发SQL注入漏洞。
了解完数据的输入方式,我们接下来再学习数据库错误。这里我们以MySQL为例,其它的请大家自行学习咯。
我们现在参数后面加个单引号,如下图:
注1:因为不同的浏览器处理方式不同,所以,你的URL可能跟我不一样,但是,没有关系,不影响。
注2:有人可能会出现Warning: mysql_fetch_array() expects…….之类的错误,有的人不会,也都不要紧。我的可能是因为php版本过于新的原因。因此不影响结果。
不过,从表格可以看出来,我们的处理结果是不正确的,所以也没有结果。原因在这里:
mysql_query()函数会返回一个布尔值,在下行代码中mysql_fetch_array($sql)将执行失败,并且PHP会显示一条警告信息,告诉我们mysql_fetch_array()的第一个参数必须是个资源,而代码在实际运行中,给出的参数值却是一个布尔值。
为了显示出错误,我们修改以下代码:
$sql = mysql_query($querry,$con);
var_dump($sql);
2.select
为了更好地了解MySQL错误,我们在
$sql = mysql_query($querry,$con);
加上:
if(!$sql){
die('<p>error:'.mysql_error().'</p>');
}
这样当应用捕获到数据库错误且SQL查询失败时,就会返回错误信息:(我们在参数中添加单引号返回的错误信息)
error:You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''' at line 1
这就是我们平时渗透测试时候经常喜欢看到的内容了。有注入点存在。
2.2 and和or
页面不返回任何错误信息,我们就可以借助本方法来推断了,首先我们在参数后面加上 and 1=1和and 1=2看看有什么不同,如图:
可以发现and 1=1 返回了数据,而and 1=2没有,这是由于1=1是一个为真的条件,前面的结果是true,true and true所以没有任何问题,第二个1=2是个假条件, true and false还是false,所以并没有数据返回。
好,讲完and,我们自来看看 or ,or就是或者,两个都为假,才会为假。我们先把id改为5
可以发现id=5是没有数据的。
但是可以发现我们加上or 1=1就成功返回了数据。
这是因为1=1为真,不管前面是不是假,数据都会返回,这样就把表里面数据全部返回,我们没看见,是因为代码中并没有迭代输出。这样,我们来修改一下代码。
echo "<table class='itable' border='1' cellspacing='0' width='300px' height='150'>";
echo "<tr>";
echo "<td>id</td>";
echo "<td>username</td>";
echo "</tr>";
//遍历查询结果
while ($result = mysql_fetch_array($sql)) {
echo "<tr>";
echo "<td>" . $result[0] . "</td>";
echo "<td>" . $result[1] . "</td>";
echo "</tr>";
}
然后你就可以发现:
57de436484bbf.gif
2.3 加法和减法
这里我们需要区分一下数字型和字符串型:
数字型:不需要使用单引号来表示
其他类型:使用单引号来表示
综合上述,我们可以发现我们的例子是数字型的,这样我们就可以使用加法和减法来判断了。
加法,我们在参数输入1+1,看看返回的数据是不是id等于2的结果,这里注意一下+号在SQL语句是有特效含义的,所以我们要对其进行url编码,最后也就是%2b。
减法是同样的道理,不过我们不需要对-号进行url编码了。
到此结束。其他的之后更新。
最终的代码
文件名志己随便取
<?php
if(isset($_GET['id'])){
$conn = mysql_connect("localhost", "root", "zhangzhiis");
if(!$conn){
die('Could not connect: '. mysql_error());
}
mysql_select_db("SQLInjection", $conn);
$querry = "select * from users where id=". $_GET['id'];
$sql = mysql_query($querry, $conn);
if(!$sql){
die('<p>error:'. mysql_error().'</p>');
}
var_dump($sql);
echo "<table class='itable' border='1' cellpadding='0' width='300px' height='150'>";
echo "<tr>";
echo "<td>id</td>";
echo "<td>username</td>";
echo "</tr>";