BWAPP之SQL注入通关



1、SQL injection(GET/search)

low

输入单引号直接报错,说明有注入点

直接order by二分法得出主查询字段数为7

直接union注入,测出回显点为2,3,4,5

image-20210411191254273

查数据库信息:

image-20210411191455987

测出数据库名为bwapp,用户为root,版本为5.5.53

查询表名:

image-20210411191918327

查询字段名:

image-20210411193238583

查字段值:

image-20210411193613249

没有难度。

medium

尝试多种方法都不行,看了一眼源码:

image-20210411201445656

发现是用addslashes()进行转义的,尝试了下宽字节绕过,也不行。

看了下原来数据库采用的是urf8编码,本来想改成gbk复现一下,结果改不成。

image-20210411201421085

character_set_system:数据库系统使用的编码格式,这个值一直是utf8,不需要设置,它是为存储系统元数据的编码格式。

所以暂时想不到什么绕过方法。

high

使用了mysql_real_escape_string()函数将特殊字符转义

受影响的字符:

  • \x00
  • \n
  • \r
  • \
  • "
  • \x1a

暂时无法注入。


2、SQL Injection(GET/Select)

是一个选择表单的格式,但这也不妨碍注入。直接在url中注入

image-20210411203039359

low

输入单引号报错,说明存在注入点。

判断是数字型

image-20210411204738873

order by测出主查询字段数为7

直接union注入

image-20210411205150179

找到了回显点。

查询数据库名 bwapp

查询表名

可以用limit来限制回显个数,也可以用group_concat()一次性查出效率更高

image-20210411205605947

查询字段名

image-20210411205827571

查询数据

image-20210411210039402
medium

虽然用了addslashes()函数进行了转义,但因为是数字型的不需要单引号闭合,所以没什么用,方法和上面一样。

high

采用了PDO技术,做了参数化和预处理,将sql语句和用户输入分离,有效预防了sql注入。

image-20210411213504350


3、SQL Injection (POST/Search)

low

由于是post型注入,所以直接burp抓包:

输入单引号直接报错

image-20210411213930830image-20210411213945366

order by 测到8报错,所以确定主查询为7个字段

image-20210411214136517image-20210411214146269

测出回显点位2,3,4,5。剩下的就和上面一样了,暴数据库名、表名、字段名、字段值

image-20210411214320864

medium

用了addslashes()函数进行了转义’ " \ null,所以绕过比较困难。

但并不是说,只要加了这个函数就可以防御所有情况,这篇文章给了三种情况:

1、参数没有加引号的,直接绕过

2、宽字节注入(两种情况1.数据库字符集为gbk,2.代码中用了转换字符编码的函数)

3、addslashes()过滤后进行了url解码,直接url双重编码绕过。

总之比较灵活,还是要具体情况具体对待。

但是对这一关而言,绕过还是比较难的。

high

用了mysql_real_escape_string()函数进行了转义,绕过比较困难。

image-20210411222546698


4、SQL Injection (POST/Select)

这一关与SQL Injection(GET/Select)只是请求方式上的差异。


5、SQL Injection (AJAX/JSON/jQuery)

image-20210416194856755

可以看到通过AjAX异步请求发送到sqli_10-2.php,然后其他的和前面一样。


5、SQL Injection(CAPTCHA)

这一关和前面的区别就是多了一道验证码,正确输入验证码进入后,直接注入,手法和之前一样。


6、SQL Injection (Login Form/Hero)

使用万能密码直接登入(需要提前知道用户名)

image-20210416221804644

在用户名的位置进行注入测试:

用order by测出主查询字段数为4

image-20210416222118304image-20210416222140974

进行union注入:

image-20210416222340148image-20210416222354753

如图所示,获得回显点为2和4

获取数据库名和用户名:

image-20210416222517842image-20210416222533159

获取表名:

image-20210416222745351image-20210416222756873

获取字段名:

image-20210416222926422image-20210416222950809

获取字段值:

image-20210416223152774image-20210416223210014

最后将密码利用md5在线解密网站进行解密。

打完收工。

medium级别使用addslashes()进行转义

high级别使用mysql_real_escape_string()函数将特殊字符转义


7、SQL Injection (Login Form/User)

进行注入测试,发现存在sql注入:

image-20210417113727287image-20210417113737019

order by测出主查询字段数为9,但是无法进一步union注入。

image-20210417115702840image-20210417115710471

看一眼源码:

image-20210417115546667

发现只有密码通过后面的验证之后才能回显。

image-20210417115838168

而这一段payload回显password值为3,显然无法通过判断。

所以要想进一步注入,就要知道bee账号对应的密码的散列值,这要在实战中直接就拉闸了,顶多能进账户,想脱库很难。

为了演示,假设我们已经知道bee账号对应的散列值,重新更改payload:

image-20210417120303184

如图所示,这样的回显应该可以通过检测了。

试一下:

image-20210417120436025image-20210417120447031

果然如此,和猜想一致,不过要注意的是password字段的值要加引号,不然会报错。

然后进一步暴数据库名:

image-20210417120649472image-20210417120655581

接着暴表名、字段名、字段值。

与上一关不同之处在于,上一关在回显之前并没有验证密码,如图所示:

image-20210417141033334


8、SQL Injection - Stored (Blog)

先随便输一个:333

image-20210417144756056

发现直接将输入的语句回显到了页面上,于是判断后台应该是先将用户输入的内容存入数据库,然后查询回显。

语句大概是这样: insert into blog values(username, now(), ‘$content’)

思路一:

所以可以尝试使用报错注入:

insert into blog values(username, now(), ''or updatexml(1,concat(0x7e,database()),2) or ‘’)

image-20210417145445869image-20210417145431115

如图所示,成功爆出数据库名。

接着暴表名:

image-20210417145739868image-20210417145800030

暴字段名:

image-20210417145944671image-20210417145957365

暴字段值:

image-20210417150307715image-20210417150317964

如图所示,成功爆出用户名和字段的md5值,但是回显的字符串长度有限制,已经被截断了。

于是可以使用substr()函数来截取后一段:

image-20210417151044412image-20210417151057427

以此类推,将所有的密码截取完拼接起来。

小结:

注意报错注入一定要用concat()函数,否则无法正常回显。

思路二:

还有一种思路是构造闭合,在注入字段的后面字段中做文章。

条件:注入的那个字段,不是insert语句中的最后一个字段。

例如原句为:

insert into blog (login, content, date) values(username, ‘$content’, now())

理想效果:

insert into blog (login,content, date) values(username, ‘hello baby’, database())#’)

这是我们先验证注入字段的位置:

image-20210417143610693image-20210417143629004

如图所示报错:Column count doesn’t match value count at row 1

说明注入的字段并不是insert语句中的最后一个,满足条件。

于是加一个字段,继续测试:

image-20210417153841882image-20210417153851271

这一次没有报错,成功插入!

于是可以在后面的那个字段上做文章:

查询数据库名:

image-20210417154033235image-20210417154044248

暴表名:

image-20210417154227347image-20210417154237724

暴字段名:

image-20210417154353890image-20210417154402113

暴字段值:

image-20210417154519163image-20210417154526843

打完收工!


9、SQL Injection - Stored (User-Agent)

image-20210417170015897

从页面回显的内容来看,猜测网站会将数据包中的host和user-agent字段存入数据库中,然后回显到页面。

所以注入点可能在user-agent字段,然后后端的语句应该是insert

所以报错注入来一波:

image-20210417170348992

如图所示,成功回显数据库名,然后再依次暴表名、字段名、字段值,姿势与上面类似这里不再赘述。


10、SQL Injection - Stored (XML)

image-20210417170746266

点击any bugs然后抓包:

image-20210417170822108

发现请求包的数据是一个xml格式。

于是尝试更改bee为单引号:

image-20210417170950797

结果报错。

分析页面的功能,发现是重置秘密的,所以可能是update语句

于是报错注入来一波:

image-20210417171209740

如图所示,成功爆出数据库名。后续脱库步骤与上面相仿。

源码分析:
//sqli_8-1.php
<script type="text/javascript">

        function ResetSecret()
        {
            var xmlHttp;
            // Code for IE7+, Firefox, Chrome, Opera, Safari
            if(window.XMLHttpRequest)
            {
                xmlHttp = new XMLHttpRequest();
            }
            // Code for IE6, IE5
            else
            {
                xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
            xmlHttp.open("POST","sqli_8-2.php",true);
            xmlHttp.setRequestHeader("Content-type","text/xml; charset=UTF-8");
            xmlHttp.send("<reset><login><?php if(isset($_SESSION["login"])){echo $_SESSION["login"];}?></login><secret>Any bugs?</secret></reset>");  //利用Ajax技术将xml文件发送到sqli_8-2.php
        }

    </script>
//sqli_8-2.php

$body = file_get_contents("php://input");  //访问请求的原始数据的只读流

// If the security level is not MEDIUM or HIGH
if($_COOKIE["security_level"] != "1" && $_COOKIE["security_level"] != "2")
{

    ini_set("display_errors",1);

    $xml = simplexml_load_string($body);  // 函数转换形式良好的 XML 字符串为 SimpleXMLElement 对象

    // Debugging
    // print_r($xml);

    $login = $xml->login;
    $secret = $xml->secret;

    if($login && $login != "" && $secret)
    {

        $sql = "UPDATE users SET secret = '" . $secret . "' WHERE login = '" . $login . "'";

        // Debugging
        // echo $sql;      

        $recordset = $link->query($sql);

        if(!$recordset)
        {

            die("Connect Error: " . $link->error);

        }

        $message = $login . "'s secret has been reset!";
    }

从上面的代码可以看出,sqli_8-1.php利用Ajax技术将xml数据发送到sqli_8-2.php后,进行xml解析,然后没有进行任何过滤直接将解析的数据拼接到sql语句中执行了,所以造成sql注入漏洞。修复方法:在拼接sql语句之前,将参数进行过滤或转义,或者使用PDO技术进行预处理和参数化。

相关函数:

file_get_contents(“php://input”) //访问请求的原始数据的只读流 详细

simplexml_load_string() //函数转换形式良好的 XML 字符串为 SimpleXMLElement 对象


11、SQL Injection - Blind - Boolean-Based

输入单引号直接报错:

image-20210417180426349image-20210417180437633

经过多次尝试,无论输入什么都只会回显The movie exists in our database!和The movie does not exist in our database!两种情况。如下图:

image-20210417180227921image-20210417180240431
image-20210417180304352image-20210417180318182

于是判断是布尔盲注。


//猜解数据库名

先猜解数据库名长度

image-20210417182503227image-20210417182647890

测出数据库名的第一个字母ascii为96(b)

image-20210417181450961image-20210417181504262

以此类推一共猜解5次测出数据库名为bwapp;


//猜解表名

先猜解数据库中表的数量

二分法测出表的数量为5

image-20210417182822493image-20210417182829752

猜解第一个表的长度:

二分法猜解出表的长度为4

image-20210417183637184image-20210417183646071

猜解第一个表的第一个字母

二分法测出为98(b)

image-20210417183230562image-20210417183242726

然后通过更改substr的参数更换字母,逐个猜解出表名的每个字母;然后再更改limit的参数更换表名,重复上述过程猜解出每张表的表名。最后猜解出表名依次为blog,heroes,movies,users,visitors。


//猜解字段名,字段值与上述过程相仿。

总结猜解三步走:

1、猜解数量

例:and (select count(table_name) from information_schema.tables where table_schema=database())>6

2、猜解长度

例:and length(select table_name from information_schema.tables where table_schema=database() limit 0,1)>5

3、猜解值

例:and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>110

以上三步不断迭代方可制胜


12、SQL Injection - Blind - Time-Based

image-20210417205805924image-20210417205817979
image-20210417210244431image-20210417210233764

如图所示,根据回显延迟的大小就可判断。只需将布尔注入的语句与if函数和sleep函数相结合便可完成注入。

扔进sqlmap中一会就完事。


收获

关于addslashes()函数绕过的三种方式

报错注入时一定要与concat()函数相结合,不然无法正常回显

报错注入的两种思路

盲注时三步走:猜解数量、猜解长度、猜解值

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值