46

菜鸡的渗透学习之路:DVWA暴力破解

 4 years ago
source link: https://www.tuicool.com/articles/fAzIvuV
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

直接就提示成功了,这是为什么呢?

查看一下代码来理解。

<?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); 
} 
?> 

可以通过注释看到在获取输入的数据后,直接连接数据库进行查询和判断,数据没有进行任何过滤,和防范。

而我们输入的“admin’ or ‘1’=’1”在数据库中,大概是select * from *where username=’admin’ or ‘1’=’1’。首先我们要知道or语法是一真则真,因为’1’=’1’是恒成立的,where语句后面也就都为真,所以我们能够直接绕过验证,成功登录。

2.用爆破的方法搞

使用burpsuit抓包,并将数据包发送至intruder。

aMbMvy6.jpg!web

在intruder中可以选择不同的模式和要进行爆破的点。

ER3i2aQ.jpg!web

Sniper:对变量依次进行破解。多个标记依次进行。
battering ram:对变量同时进行破解。多个标记同时进行。
pitchfork:每一个变量标记对应一个字典,取每个字典的对应项。
cluster bomb:每个变量对应一个字典,并且进行交集破解,尝试各种组合。适用于用户名+密码的破解。
add:插入一个新的标记。
clear:清除所有的标记。
auto:自动设置标记,一个请求发到该模块后burpsuite会自动标记cookie URL等参数。
refresh:如果必要的话,这可以要求模板编辑器的语法高亮。

在这里。我选择的是cluster bomb模式,并且只是对密码和用户名出进行标记。

YBzInuy.jpg!web

然后开始构造Payload,对于第一个变量,直接添加一些常见的默认用户名。

EJzuUvB.jpg!web

对于密码处,我导入了一个字典。

FJfqE3Y.jpg!web

然后点击start attack 开始爆破。

Ej2aEn7.jpg!web

通过这些数据我们会发现当username为admin,password为password的时候,length值与其他的不同。这就是我们想要得到的密码了。

Medium

1. 尝试sql注入

与low级别的相同,对网站的sql注入问题进行尝试。

7vYzEvn.jpg!web

好像是不行。

2. 进行爆破。

既然不能注入,那我们就进行爆破。方法呢,依然与low相同。

QZjIfmR.jpg!web

我们点击length那一栏,通过排序的方式查看。发现直接就爆破出来了。

然后我们通过代码来看看到底为什么。

<?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); 
} 
?> 

通过代码查看发现,这里对我们输入的username与password做了一些处理。然后才连接数据库进行了判断,所以导致了sql注入没成功。

High

1.既然medium里sql注入都没成功,high里应该也没可能了。

2.直接进行爆破。

JJFn2yn.jpg!web

通过抓包发现,这里对直接进行爆破进行了限制,加入了token值。

这可咋整,先看看代码吧。

<?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(); 
?> 

这里是有个token值的问题,每次登录验证的时候除了用户名密码,还会对token值进行验证的。百度找找答案,发现burpsuit的爆破功能,可以获取token值。

yIFf2an.jpg!web

设置一下获取token值的位置。

FnE73ui.jpg!web

改一下模式,还有第一个的token值。

IBfMv2U.jpg!web

没效果,崩了,我们发现我们构造的第三个Payload一直没有变,也就是token没能够成功获取。

百度去解决问题,没能成功解决,等待一个大佬帮忙分析下。

Impossible

这个高级的都没成功,这个我应该也没有办法,但是还是看看代码。

<?php 
if( isset( $_POST[ 'Login' ] ) && isset ($_POST['username']) && isset ($_POST['password']) ) { 
    // Check Anti-CSRF token 
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); 

    // Sanitise username input 
    $user = $_POST[ '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 = $_POST[ '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 ); 

    // Default values 
    $total_failed_login = 3; 
    $lockout_time       = 15; 
    $account_locked     = false; 

    // Check the database (Check user information) 
    $data = $db->prepare( 'SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;' ); 
    $data->bindParam( ':user', $user, PDO::PARAM_STR ); 
    $data->execute(); 
    $row = $data->fetch(); 

    // Check to see if the user has been locked out. 
    if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) )  { 
        // User locked out.  Note, using this method would allow for user enumeration! 
        //echo "<pre><br />This account has been locked due to too many incorrect logins.</pre>"; 

        // Calculate when the user would be allowed to login again 
        $last_login = strtotime( $row[ 'last_login' ] ); 
        $timeout    = $last_login + ($lockout_time * 60); 
        $timenow    = time(); 

        /* 
        print "The last login was: " . date ("h:i:s", $last_login) . "<br />"; 
        print "The timenow is: " . date ("h:i:s", $timenow) . "<br />"; 
        print "The timeout is: " . date ("h:i:s", $timeout) . "<br />"; 
        */ 

        // Check to see if enough time has passed, if it hasn't locked the account 
        if( $timenow < $timeout ) { 
            $account_locked = true; 
            // print "The account is locked<br />"; 
        } 
    } 

    // Check the database (if username matches the password) 
    $data = $db->prepare( 'SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' ); 
    $data->bindParam( ':user', $user, PDO::PARAM_STR); 
    $data->bindParam( ':password', $pass, PDO::PARAM_STR ); 
    $data->execute(); 
    $row = $data->fetch(); 

    // If its a valid login... 
    if( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) { 
        // Get users details 
        $avatar       = $row[ 'avatar' ]; 
        $failed_login = $row[ 'failed_login' ]; 
        $last_login   = $row[ 'last_login' ]; 

        // Login successful 
        echo "<p>Welcome to the password protected area <em>{$user}</em></p>"; 
        echo "<img src=\"{$avatar}\" />"; 

        // Had the account been locked out since last login? 
        if( $failed_login >= $total_failed_login ) { 
            echo "<p><em>Warning</em>: Someone might of been brute forcing your account.</p>"; 
            echo "<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>${last_login}</em>.</p>"; 
        } 

        // Reset bad login count 
        $data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' ); 
        $data->bindParam( ':user', $user, PDO::PARAM_STR ); 
        $data->execute(); 
    } else { 
        // Login failed 
        sleep( rand( 2, 4 ) ); 

        // Give the user some feedback 
        echo "<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>"; 

        // Update bad login count 
        $data = $db->prepare( 'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' ); 
        $data->bindParam( ':user', $user, PDO::PARAM_STR ); 
        $data->execute(); 
    } 

    // Set the last login time 
    $data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' ); 
    $data->bindParam( ':user', $user, PDO::PARAM_STR ); 
    $data->execute(); 
} 
// Generate Anti-CSRF token generateSessionToken(); 
?> 

emmm。能看出来, 当输入错误3次,锁定15分钟的可靠方式防止了爆破,然后还有一些其他的限制。

    $total_failed_login = 3; 
    $lockout_time       = 15; 
    $account_locked     = false; 

*本文作者:Mario丶ml,转载请注明来自FreeBuf.COM


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK