###4.1.1 挖掘过程

Sql注入漏洞

SQL注入漏洞估计是我们平时听到漏洞最多的一个词,即使是对安全方面没有接触太多的程序员来说对于这个词应该也很不陌生,他也是目前被利用得最多的漏洞。
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行指定的SQL语句。具体来说,它是利用现有应用程序,将SQL语句注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入SQL语句得到一个存在安全漏洞的网站上的数据,而不是按照设计者意图去执行SQL语句。
所以它的危害不言而喻,通常利用 SQL注入的攻击方式有下面几种:
一:是在权限较大的情况下,通过SQL注入可以直接 写入wcbshcll。
二:是在权限较小的情况下,也可以通过注入来获得管理员的密码等信息,或者修改数据库内容进行一些钓鱼或者其他间接利用针对SQL注入漏洞的利用工具也是越来越智能.sqlmap是目前被使用最多的注入工具,这是一款国外开源的跨平台SQL注入工具•用Python开发,支持多种方式以及 几乎所有类型的数据库注入,对SQL注入漏洞的兼容性也非常强。 既然SQL注入是被利用最多的漏洞,因此它也是被研究最深的漏洞,针对不同的 漏洞代码情况和运行环境,有多种的利用方式,如普通注入、肓注、报错注入、宽字节注入、二次注入等,但是它们的原理都是大同小异的.卜面会介绍怎么挖掘到 这些注入漏洞。
下面简单给大家演示一下普通注入漏洞,首先创建一个数据表,如图1所示。

(图1)

普通注入

测试代码如下: > <?php > $id = $_GET[‘id’]; > //数据库服务器 > $mysql_server_name = ‘localhost’; > //数据库用户名 > $mysql_username = ‘root’; > //数据库密码 > $mysql_password = ‘root’; > //数据库名 > $mysql_database = ‘oacs’; > //连接数据库 > $conn = mysqli_connect($mysql_server_name,$mysql_username,$mysql_password,$mysql_database); > //连接数据库错误提示 > if (mysqli_connect_errno($conn)) { >     die(“连接 MySQL 失败: ” . mysqli_connect_error()); > } > //查询代码 > $sql = “SELECT * FROM oa_admin where id= “.$id; > $res = $conn->query($sql); > $data = $res->fetch_all(); > print_r(‘当前的SQL语句:’.$sql.’
执行结果:’); > print_r($data); > exit; > ?>

我们可以看出此代码段中 GET id参数存在SQL注入漏洞,测试方法如图2所示。

(图2)
从图2可以看出原本的sql语句已经被注入更改 ,使用了union查询到当前的用户。

从上面的测试代码中可以发现,数据库操作存在一些关键字,比如 select from,mysql_connect,mysql_query,mysql_fetch_row 等,数据库的查询方式还有 update,insert,delete 只需要查找这些关键字,就可以定向挖掘SQL注入漏洞。

宽字节注入

当php连接mysql时如果set character_set_client =gbk时会导致该注入的发生。提交`/1.php?id= -1' and 1=1%231时,单引号会被\转义.这时如果提交?id=-1%df’ and 1=1#的话,过滤用的\ (%5c)会与%df%5c组合,mysql语句就成了<br />select * from user where id=‘-1運’ and 1=1#1
在web中通常使用addslashes()、mysql_real_escape_string()、mysql_escape_string函数或者开启GPC的方式来防止注入,原理就是给预定义字符也就是单引号、双引号、反斜杠和NULL进行转义,但是如果某处使用了urldecode或者rawurldecode函数,如果开启了GPC来过滤,那么提交?id=1%25%27,%25经过url解码为%,%27解码为单引号,那么成功引发注入,在代码审计的过程中要注意这两个函数。

二次注入

测试代码如下: > <?php > $name = $_GET[‘name’]; > //数据库服务器 > $mysql_server_name = ‘localhost’; > //数据库用户名 > $mysql_username = ‘root’; > //数据库密码 > $mysql_password = ‘root’; > //数据库名 > $mysql_database = ‘oacs’; > //连接数据库 > $conn = mysqli_connect($mysql_server_name,$mysql_username,$mysql_password,$mysql_database); > //连接数据库错误提示 > if (mysqli_connect_errno($conn)) { > die(“连接 MySQL 失败: ” . mysqli_connect_error()); > } > //查询代码 > $sql = “SELECT * FROM oa_admin where username= ‘$name’”; > print_r(‘当前的SQL语句:’.$sql.’
执行结果:’); > > $res = $conn->query($sql); > $date = $res->fetch_all(); > //print_r($data); > ?> > <!DOCTYPE html> > > > > <?php echo $date[0][1] ?> > > >

<?php echo $date[0][1] ?>


> 姓名:<?php echo $date[0][1] ?>
> 密码:<?php echo $date[0][2]?>
> 性别: <?php echo $date[0][3]; ?>
> >

第二段测试代码 > <?PHP > //配置连接数据库 > //addslashes 将预定义字符串转义 > $username = addslashes($_POST[‘username’]); > $password = $_POST[‘password’]; > $sex = $_POST[‘sex’]; > $insert = “INSERT INTO oa_admin (username,password,sex) VALUES(‘$username’,‘$password’,‘$sex’)”; > echo $insert; > mysql_query(“set names utf8”); //设置编码 > if($result = mysql_query($insert)){ > $num=mysql_affected_rows($con); > echo $num; > } > ?>

首先我们简单看一下这两段代码。第一段代码是一个用户信息显示页面,通过传入的username在数据库进行查询,然后在页面输出展示,我们可以看到传递的参数username并没有经过过滤,可以成为一个典型的字符串GET注入,我们在上面已经提到了,但是我们今天要讨论的是二次注入。
第二段代码是一个添加页面,通过表单POST的数据执行INSERT语句插入数据,成功后返回数据库影响行数,而且这里的username参数用addslashes函数进行了转义。两段代码结合,我们可以发现一个典型的二次注入点,虽然文章添加页面中过滤的非常严格,但是addslashes有一个特点就是虽然参数在过滤后会添加 “\” 进行转义,但是“\”并不会插入到数据库中,再配合内容显示页面中的查询是通过title查询的,所以我们就可以利用这个构造一个二次注入。
首先我们插入一条SQL语句,可以看到 转义用的“\”并没有插入数据库,但是我们的单引号还是成功插入了。

我们来看下我们的主页面。

发现成功返回了 user() database()。
修复的方法:最基本的就是在执行INSERT前判断转义后的字符是否存在“\‘”如果存在就不执行INSERT。其次在$id=GET[‘id’]获取参数时,进行过滤例如$id=addslashes($_GET[‘id’]),这样在获取到的参数中也会被转义无法执行。


作者:skad  创建时间:2022-05-19 09:36
 更新时间:2023-04-12 16:17