【Day49】SQL注入攻击

首先我们了解一下,什么是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语句来先判断一下变量是否初始化
   
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 "";   
    echo"";   
    echo"";   
    echo"";   
    echo"";   

    echo"";   
    echo"";   
    echo"";   
    echo"";   
    echo"
id username
".$result['id']." ".$result['username']."
"
; 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('

error:'.mysql_error().'

'
); }
这样当应用捕获到数据库错误且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看看有什么不同

【Day49】SQL注入攻击_第1张图片

可以发现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是没有数据的。

【Day49】SQL注入攻击_第2张图片

可以发现我们加上or 1=1就成功返回了数据,这是因为1=1为真,不管前面是不是假,数据都会返回,这样就把表里面数据全部返回,我们没看见,是因为代码中并没有迭代输出。这样,我们来修改一下代码。
echo "";   
        echo"";   
        echo"";   
        echo"";   
        echo"";   
        //遍历查询结果   while ($result = mysql_fetch_array($sql)) {   
        echo"";   
        echo"";   
        echo"";   
        echo"";   
    }
然后你就可以发现:

【Day49】SQL注入攻击_第3张图片

2.3、加法和减法

这里我们需要区分一下数字型和字符串型:

数字型:不需要使用单引号来表示
其他类型:使用单引号来表示

综合上述,我们可以发现我们的例子是数字型的,这样我们就可以使用加法和减法来判断了。

加法,我们在参数输入1+1,看看返回的数据是不是id等于2的结果,这里注意一下+号在SQL语句是有特效含义的,所以我们要对其进行url编码,最后也就是%2b。

减法是同样的道理,不过我们不需要对-号进行url编码了。

【Day49】SQL注入攻击_第4张图片

第三节 利用SQL注入

3.1、识别数据库

要想发动SQL注入攻击,就要知道正在使用的系统数据库,不然就没法提取重要的数据。

首先从Web应用技术上就给我们提供了判断的线索:

ASP和.NET:Microsoft SQL Server
PHP:MySQL、PostgreSQL
Java: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,很简单,道理都是一样的,就不一一列举了。

基于数字函数推断

【Day49】SQL注入攻击_第5张图片

这里以我们搭建的环境为例来做推断:

connection_id()不管它值多少,基本上都是正的,也就是为真,last_insert_id()用法大家自行百度,这里不存在insert语句,默认情况就是返回零,也就是假。

那么如果and connection_id()数据返回正常,and connection_id()不返回数据,我们就可以推断这是一个MySQL数据库了。

【Day49】SQL注入攻击_第6张图片

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值会被转换成任何数据类型,所以我们不用管第二个条件。

【Day49】SQL注入攻击_第7张图片

就是这样的一个个加上去进行尝试,直到不返回错误。

神奇的ORDER BY子句

除了上述方法,我们还可以是用order by子句得到准确列数

【Day49】SQL注入攻击_第8张图片

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

得到列数后我们还需要满足第二个条件

【Day49】SQL注入攻击_第9张图片

很简单,只要一次一列使用我们的测试字符串替换NULL即可,可以发现第一列和第二列都可以存放字符串,第三列数据没有输出。

接下来就让我们提取数据库用户名和版本号:

【Day49】SQL注入攻击_第10张图片

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 " echo 'test'; ?>" into outfile "F:\\www\\test.php";

这里写图片描述

你可能感兴趣的:(php,中级篇)

id username
" . $result[0] . " " . $result[1] . "