欢迎光临
我们一直在努力

DVWA sqli浅析

0x00首先简单介绍一下DVWA。

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is damn vulnerable.

GitHub – RandomStorm/DVWA: Damn Vulnerable Web Application (DVWA)

简单来说就是一个web漏洞实验环境,可以用来练习web向各种漏洞的利用。

 

0x01

环境怎么安装就不啰嗦了,可以去官网或者github上查找教程。

Sqli的实验有三种难度,low,medium和high。

实验的目的是要我们通过sqli漏洞,从数据库中拿到各个账号的密码。

 

0x02

从low的看起。

一般我们测试sql注入的注入点,通常是在参数值后面加一个单引号,如果这时候数据库报错,就可以确认此处有注入。

正常情况下,参数为id,然后后台将id的值放入sql语句中查询,然后返回查询的结果

1-3 DVWA sqli浅析

我们在id字段的值后面添加一个单引号测试,发现sql语法错误,于是我们可以确定,此处存在注入点。

于是开始琢磨怎么拿数据,方法有很多种,常见的有利用union select,报错注入,时间盲注,布尔盲注,思路和步骤上大体差不多,只是具体的payload和适用环境有所区别。

以下以用union select为例,简单说明一下注入思路。

1.确定查询字段数。

2.确定数据库名。

3.确定表名。

4.确定列名。

5.导出数据。

因为此处使用union select来注数据,所以需要确定字段的个数,因为union select需要跟原本的sql语句保持相同的字段数目和字段类型。此处既可以用ordey by从句,也可以直接使用union select 尝试。

在提交payload的时候,我们需要用注释符注释掉源代码中payload之后的sql语句,从而避免语法错误。mysql的注释符有#和–,用#注释的时候需要用url编码,用–的时候可以不编码,但是要在之后加一个空格,或者加号(本质上都是空格)。

order by 3时报错,order by 2时正确回显。可以得出应该是两列。

1-3 DVWA sqli浅析

确立字段数之后我们需要确立回显点。用union select 1,2 来确定查询的数据会回显在页面的什么位置上。

看下图,第二条查询记录中first name和last name之后的1,2就代表回显位置,这里的1,2的意思是select的第一列和第二列。并且这个环境这里是简单的模式,通常遇到的情况是每次回显只能回显一条select的结果,那这种情况下,就要使原本的查询无结果,比如此处另id=0,从而使union select的查询结果存放在第一位显示。

1-3 DVWA sqli浅析

接下来都是固定格式的payload,注数据库名。如果环境是每次只能显示一条查询结果的话,通过后面添加limit子句逐条将名称爆出。

1-3 DVWA sqli浅析

表名同理。

1-3 DVWA sqli浅析

字段名。

1-3 DVWA sqli浅析

然后就可以注数据了,利用payload:union select 字段名 1,字段名2 from 数据库名.表名 limit …的格式逐个注出用户名,密码。

1-3 DVWA sqli浅析

这里发现密码都是MD5存储的,感兴趣的可以爆一爆.

比如admin的MD5值是5f4dcc3b5aa765d61d8327deb882cf99

解密一下,结果是password

1-3 DVWA sqli浅析

在存在回显的情况下,还有一种常见的注入方式是报错注入(double query)。利用sql错误发生时的回显将数据注出来。剩下的两种盲注我们暂时不说。DVWA中有另外一个单独的sql盲注专题。盲注通常使用在不管sql语句对错与否都不发生回显的状况下。

这里报错信息会回显,所以我们讲一下报错注入,这种注入的payload格式也比较固定。payload如下:

and(select 1 from(select count(*),concat((select (select (语句)) from information_schema.tables limit 0,1),0x7e,floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1

我们在本实验环境下用这种方法来试一试结果。

以注数据库名为例。

1-3 DVWA sqli浅析

表名字段名及数据后不赘述,大家感兴趣的可以自己实验,payload结合上面这条和之前用union注入所用的格式即可。

当存在注入点的时候,我们还可以通过一些sql自带的函数干一些其他羞羞的事情。

1.user() 获取数据库用户名

2.database() 获取当前数据库名

3.version() 获取MYSQL数据库版本

4.load_file() MYSQL读取本地文件的函数

5.@@datadir 读取数据库路径

6.@@basedir MYSQL 安装路径

7.@@version_compile_os 操作系统

8.into_outfile() 写一句话木马

以读取本地文件及数据库为例。

1-3 DVWA sqli浅析

sqli最基础的思路和步骤就介绍完了。以上是在应用上未做任何防御的前提下实施的注入攻击。当应用侧做了防御之后,我们需要对这些基础的payload作出一些微小的调整,来获取数据。

sqli的本质,是数据和代码的混淆不清。传入的数据,构成了代码的一部分,从而达到攻击者的目的。所有有输入的程序,都可能发生这种原理的漏洞。

 

0x03

然后我们来看medium难度下的实验环境。我们还是试探性用单引号测试。结果报错了。报错信息中我们发现单引号前面存在/,于是猜测单引号被转义了,主机侧代码可能做了addslashes().

1-3 DVWA sqli浅析

为了更好的解释问题,此处我们直接查看源代码。

$id = $_GET['id'];
$id = mysql_real_escape_string($id);
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id";

这里对传入的参数进行了叫做mysql_real_escape_string()的预处理操作,这个函数可以转义 SQL 语句中使用的字符串中的特殊字符。所以我们看到,单引号被转义了,没有办法构成代码。

那么怎么办呢?

我们仔细看发现,这里的id参数是直接引用的,并没有加任何的引号,所以get请求中id后面的所有内容,可以直接参与sql语句的构建。比如如果id的内容是id = 0 union select database(),user().那拼接到php代码中就是

select first_name,last_name from users where user_id=0 union select database(),user().

这完全是一条合法的sql语句,它甚至都不用在payload的结尾加上注释符。所以实质上这里的mysql_real_escape_string()并没有构成任何的防御作用,这个函数只有当参数被引号包围起来的时候,才起作用(当然也能突破,这个我们后面再说)。

所以我们还是顺着上一章提到的思路,确定字段数,确定回显位置,爆数据库名,爆表名,爆字段名,爆数据内容。

在这些步骤中,可能会遇到一丢丢小的麻烦,那就是当我们爆表名的时候,payload中where子句需要明确表所在的数据库的名字,这个参数是用单引号引起来的,那么引号既然被转义了,我们怎么才能把这个参数弄进去呢?

1-3 DVWA sqli浅析

这里我们可以将数据库的名称用十六进制表示,来绕过引号,数据库同样是可以解析的。

1-3 DVWA sqli浅析

成功绕过,后面列名同理。用引号引起来的数据都可以用16进制表示来绕过这个限制。

在平常的学习实验还有ctf中,大多注入题都会存在一些防御手段,基本都是针对payload的关键字进行过滤。

过滤select等关键字

绕过方法:大小写混合,用selselectect等方式

过滤空格

绕过方法:注释符/**/,利用(),%0a,%0b,%0c,%0d,%09,%a0等等

转义单引号

绕过方法:当应用的字符集为GBK时,可以采用宽字节方法绕过,%BF‘

以下是一些绕waf的思路和总结:

waf 绕过的技巧

深入了解SQL注入绕过waf和过滤机制

Bypass WAF Cookbook

 

0x04

终于到了搞基的部分,啊不,是高级的部分。

直接看代码。这段代码我看了很久很久很久,都没想出来怎么破,实在没有办法谷歌了一下。

然后查到的结果说,这段代码就是没有办法注入的,它代表着平台作者所认为的sql注入的正确防御姿势。

作者:天谕
链接:https://zhuanlan.zhihu.com/p/20710250
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

<?php    

if (isset($_GET['Submit'])) {

    // Retrieve data

    $id = $_GET['id'];
    $id = stripslashes($id);
    $id = mysql_real_escape_string($id);

    if (is_numeric($id)){

        $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
        $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );

        $num = mysql_numrows($result);

        $i=0;

        while ($i < $num) {

            $first = mysql_result($result,$i,"first_name");
            $last = mysql_result($result,$i,"last_name");
            
            echo '<pre>';
            echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
            echo '</pre>';

            $i++;
        }
    }
}
?>

我们来简单分析一下,防御步骤一共有三步。

1.用stripslashes()去掉参数中的斜杠

2.用mysql_real_escape_string()将参数中的特殊字符转义

3.用is_numeric()判断参数是否为数字型,是则进行查询,否则drop.

并且id在sql语句中还处在单引号中。在这种情况下,即使存在GBK字符集条件下的宽字节绕过mysql_real_escape_string()函数,下面的is_numeric()函数,也会直接将恶意的payload丢弃。所以该处无法注入。

谷歌下有人提到sqlmap在此处可以注出数据,但是sqlmap是有缓存的,当url在它的记录中,它会直接返回缓存中的结果,也就是low,medium难度下得到的结果,并不是在high level下获取的数据。

 

0x05

DVWA上关于sql注入的还有一个盲注的篇章,下次有机会再分享。

在实际中,sql还有很多其他的形式

1.insert,update,delete语句的注入

2.存储型的二次注入

3.stacked注入

另外一个专门的sqli练习平台上有很好的归类,大家有兴趣的可以自己安装来练习。

GitHub – Audi-1/sqli-labs: SQLI labs to test error based, Blind boolean based, Time based.

 

 

 

【原文:DVWA sqli浅析? MottoIN小编整理发布】

原创文章,作者:Moto,如若转载,请注明出处:http://www.mottoin.com/579.html

未经允许不得转载:杂术馆 » DVWA sqli浅析
分享到: 更多 (0)