【Day49】SQL注入攻击

来源:互联网 发布:appium ios python 编辑:程序博客网 时间:2024/06/04 00:50
首先我们了解一下,什么是sql?SQL 是一门 ANSI 的标准计算机语言,用来访问和操作数据库系统。SQL 语句用于取回和更新数据库中的数据。SQL 可与数据库程序协同工作,比如 MS Access、DB2、Informix、MS SQL Server、Oracle、Sybase 以及其他数据库系统。那么什么是sql注入呢?看起来很复杂,其实很简单就能解释,SQL注入就是一种通过操作输入来修改后台SQL语句达到代码执行进行攻击目的的技术。sql注入的产生知道了sql和sql注入,那么sql注入是如何产生的呢?在PHP中动态构造SQL语句字符串:
$query = "SELECT * FROM users WHERE username = ".$_GET["ichunqiu"];
看上面代码我们可以控制输入参数ichunqiu,修改所要执行SQL语句,达到攻击的目的。    那么我们开始编写一个注入点:第一步,我们使用if语句来先判断一下变量是否初始化
<?php   if(isset($_GET["leslie"])){   }   ?>
第二步,在if语句里面,我们连接数据库。在PHP中,这个任务通过 mysql_connect() 函数完成。
mysql_connect(servername,username,password);   servername        可选。规定要连接的服务器。默认是 "localhost:3306"username        可选。规定登录所使用的用户名。默认值是拥有服务器进程的用户的名称。   password        可选。规定登录所用的密码。默认是 ""
第三步:连接成功后,我们需要选择一个数据库。
mysql_select_db(database,connection)   database        必需。规定要选择的数据库。   connection        可选。规定 MySQL 连接。如果未指定,则使用上一个连接。
第四步:选择完数据库,我们需要执行一条 MySQL 查询。
mysql_query(query,connection)   query        必需。规定要发送的 SQL 查询。注释:查询字符串不应以分号结束。   connection        可选。规定 SQL 连接标识符。如果未规定,则使用上一个打开的连接。

第五步:执行完查询,我们再对结果进行处理

mysql_fetch_array(data,array_type)   data        可选。规定要使用的数据指针。该数据指针是 mysql_query() 函数产生的结果。   array_type           可选。规定返回哪种结果。可能的值:   MYSQL_ASSOC - 关联数组   MYSQL_NUM - 数字数组   MYSQL_BOTH - 默认。同时产生关联和数字数组
我们使用echo将执行的SQL语句输出,方便我们查看后台执行了什么语句。
echo $querry
最终代码如下:if(isset($_GET["id"])){       $con = mysql_connect("127.0.0.1:3306","root","root");       if (!$con)       {           die('Could not connect: ' . mysql_error());       }       mysql_select_db("ichunqiu",$con);       $querry = "select * from users where id = " . $_GET['id'];       $sql = mysql_query($querry,$con);       $result = mysql_fetch_array($sql);       echo "<table class='itable' border='1' cellspacing='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($con);       echo $querry;   }   ?>

MySQL数据库实验环境配置:

代码层工作已经做好,但是在数据库里面,我们还没有leslie这个数据库啊,接下来我就带大家一步步创建数据库,创建表,创建列,插入数据。第一步:创建数据库第二步:创建表users和列id,username,password

第二节 寻找及确认SQL注入

2.1、推理测试法

寻找SQL注入漏洞有一种很简单的方法,就是通过发送特殊的数据来触发异常。首先我们需要了解数据是通过什么方式进行输入,这里我总结了三个:GET请求:该请求在URL中发送参数。POST请求:数据被包含在请求体中。其他注入型数据:HTTP请求的其他内容也可能会触发SQL注入漏洞。sql语句最终变为
    select * from users where id = 1'
执行失败,所以mysql_query()函数会返回一个布尔值,在下行代码中mysql_fetch_array($sql)将执行失败,并且PHP会显示一条警告信息,告诉我们mysql_fetch_array()的第一个参数必须是个资源,而代码在实际运行中,给出的参数值却是一个布尔值。我们修改代码在
$sql = mysql_query($querry,$con);下一行加上   var_dump($sql);

可以发现显示bool(false)

为了更好的了解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 MySQL server version for the right syntax to use near ''' at line 1然后借助这些错误,我们这可以推断应该存在SQL注入。还有其他数据库错误信息,以及MySQL其他错误信息,由于篇幅问题就不一一讲解了。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>";       }
然后你就可以发现:

这里写图片描述

2.3、加法和减法这里我们需要区分一下数字型和字符串型:数字型:不需要使用单引号来表示其他类型:使用单引号来表示综合上述,我们可以发现我们的例子是数字型的,这样我们就可以使用加法和减法来判断了。加法,我们在参数输入1+1,看看返回的数据是不是id等于2的结果,这里注意一下+号在SQL语句是有特效含义的,所以我们要对其进行url编码,最后也就是%2b。减法是同样的道理,不过我们不需要对-号进行url编码了。

这里写图片描述

第三节 利用SQL注入

3.1、识别数据库

要想发动SQL注入攻击,就要知道正在使用的系统数据库,不然就没法提取重要的数据。首先从Web应用技术上就给我们提供了判断的线索:ASP和.NET:Microsoft SQL ServerPHP:MySQL、PostgreSQLJava:Oracle、MySQL底层操作系统也给我们提供了线索,比如安装IIS作为服务器平台,后台数据及很有可能是Microsoft SQL Server,而允许Apache和PHP的Linux服务器就很有可能使用开源的数据库,比如MySQL和PostgreSQL。基于错误识别数据库大多数情况下,要了解后台是什么数据库,只需要看一条详细的错误信息即可。比如判断我们事例中使用的数据库,我们加个单引号。
error: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 ''' at line 1
从错误信息中,我们就可以发现是MySQL。
Microsoft OLE DB Provider for ODBC Drivers 错误 '80040e14'   [Microsoft][ODBC SQL Server Driver][SQL Server]Line 1:
上面错误信息可以发现是Microsoft SQL Server,如果错误信息开头是ORA,就可以判断数据库是Oracle,很简单,道理都是一样的,就不一一列举了。基于数字函数推断

这里写图片描述

这里以我们搭建的环境为例来做推断:connection_id()不管它值多少,基本上都是正的,也就是为真,last_insert_id()用法大家自行百度,这里不存在insert语句,默认情况就是返回零,也就是假。那么如果and connection_id()数据返回正常,and connection_id()不返回数据,我们就可以推断这是一个MySQL数据库了。

这里写图片描述

3.2、UINON语句提取数据UNION操作符可以合并两条或多条SELECT语句的查询结果,基本语法如下:
select column-1 column-2 from table-1   UNION   select column-1 column-2 from table-2
如果应用程序返回了第一条查询得到的数据,我们就可以在第一条查询后面注入一个UNION运算符来添加一个任意查询,来提取数据,是不是很容易啊,当然在使用UNION之前我们必须要满足两个条件:两个查询返回的列数必须相同两个查询语句对于列返回的数据类型必须相同首先我来看第一个条件,如何知道第一条查询的列数呢?我们可以使用NULL来尝试,由于NULL值会被转换成任何数据类型,所以我们不用管第二个条件。

这里写图片描述

就是这样的一个个加上去进行尝试,直到不返回错误。神奇的ORDER BY子句除了上述方法,我们还可以是用order by子句得到准确列数

这里写图片描述

我们先尝试了12,返回错误,说明列数是小于12的,我们继续尝试了6,返回错误,同理,列数小于6的,我们尝试3,返回正常,说明列数是大于等于3的,继续尝试4,返回错误。说明列数是小于4,列数大于等于3,小于4,可以得到列数是3。使用order by子句可以帮助我们快速得到列数。得到列数后我们还需要满足第二个条件

这里写图片描述

很简单,只要一次一列使用我们的测试字符串替换NULL即可,可以发现第一列和第二列都可以存放字符串,第三列数据没有输出。接下来就让我们提取数据库用户名和版本号:

这里写图片描述

3.3、枚举数据库

这里由于篇幅问题,我们只以MySQL数据库为例了,枚举数据库并提取数据遵循一种层次化的方法,首先我们提取数据库名称,然后提取表,再到列,最后才是数据本身。要想获取远程数据库的表、列,就要访问专门保存描述各种数据库结构的表。通常将这些结构描述信息成为元数据。在MySQL中,这些表都保存在information_schema数据库中第一步:提取数据库在MySQL中,数据库名存放在information_schema数据库下schemata表schema_name字段中
id=1 union select null,schema_name,null from information_schema.schemata
第二步:提取表名在MySQL中,表名存放在information_schema数据库下tables表table_name字段中
?id=1 union select null,table_name,null from information_schema.tables where table_schema='leslie'
这里我使用where子句来筛选了,只返回数据库ichunqiu下的表名,想返回所有表名,去掉where子句就行了。第三步:提取字段名在MySQL中,字段名存放在information_schema数据库下columns表column_name字段中同样加上where子句限制,不让你都不知道字段名是哪个数据库哪个表下。第四步:提取数据这一步就简单了,不再介绍了,看图。3.4、窃取哈希可令哈希口令是通过使用PASSWORD()函数计算的:3.5、获取WebShell利用SQL注入攻击获取WebShell其实就是在向服务器写文件。(注意:这里我们需要得到网站的绝对路径)所有常用的关系数据库管理系统(RDBMS)均包含内置的向服务器文件系统写文件的功能。
select into outfile(dumpfile)  //MySQL写文件命令
例如:
select "<?php echo 'test'; ?>" into outfile "F:\\www\\test.php";

这里写图片描述

1 0
原创粉丝点击