Brute Force(暴力破解)——在DVWA中的练习

DVWA  BruteForce

Security Level: low

        Brute Force,即暴力(破解),是指黑客利用密码字典,使用穷举法猜解出用户口令,是现在最为广泛使用的攻击手法之一,穷举法的基本思想是根据已知信息或者范围,并在此范围内对所有可能的情况逐一验证,直到全部情况验证完毕。若某个情况验证符合全部条件,则为一个有效结果;若全部情况验证后都不符合要求的全部条件,则本次操作没有有效结果。穷举法也称为枚举法。

先看一下源代码:

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

?>

       服务器只是验证了参数Login是否被设置(isset函数在php中用来检测变量是否设置,该函数返回的是布尔类型的值,即true/false),没有任何的防爆破机制,且对参数username、password没有做任何过滤,存在明显的sql注入漏洞。

使用burpsuit进行用户名密码爆破

  1. 设置好代理以后用burpsuit进行抓包

2.将抓包数据发送到intruder模块。打开intruder标签。

点击Clear清除参数,需要枚举哪一项就去Add哪一项。此处只演示操作步骤,就只进行密码的爆破,admin账户是已知存在的。当然在实际操作中,密码爆破还是看人品和字典。并不是不能同时爆破用户名和密码,只是步骤一致为了简单不做演示。

  1. 设置需要爆破的参数

像这样,就表示已经成功的设定了爆破密码这个参数

  1. 进入payloads页面进行参数的设定

设置好读取字典的路径就可以开始爆破了,有关工具的使用在爆破大体介绍一下。图片来源

https://blog.csdn.net/u011781521/article/details/54772795 感谢lfendo老哥整理。

具体爆破使用lfendo老哥做出了详细的整理,这里就不暴露人类复读机的本质了。

出于演示的目的字典是我随便敲得,里面包含着正确的密码password,还是那句话在实际操作中,爆破还是看人品和字典,使用弱口令字典的同时结合社会工程学进行专用字典的构造是一个极好的方法。

  1. 实施攻击(点击Start attack)

  1. 结果反馈

将结果进行按照长度返回,不一样的哪一个就是正确密码。

登录成功

方法二Sql注入:

在前面看源代码的时候,发现没有对username和password进行过滤,存在sql注入漏洞:

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

比如在username中输入admin’#或者admin’or’1’=’1都可以成功登录。

 

DVWA  BruteForce

Security Level: 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注入。但是它也有漏洞,在MySQL5.5.37以下版本有绕过方法。sleep(2)降低了暴力破解速度,但是没有从根源上防住爆破!因此,破解方法同Low级别。

DVWA  BruteForce

Security Level: 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,可抵御CSRF攻击,每次提交需要将username、password、Login和user_token四个参数一起提交到后台,因此要想解决每次变化的user_token需要每次重新获取,破解难度提升,需要编码解决。

原理:每次服务器返回的登陆页面中都会包含一个随机的user_token的值,用户每次登录时都要将user_token一起提交。服务器收到请求后,会优先做token的检查,再进行sql查询。

牵扯到编码的问题,等在学习一下Python的时候再回来解决。

DVWA  BruteForce

Security Level: 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(); 

?>

        当输入错误3次,锁定15分钟的可靠方式防止了爆破,同时采用PDO(PHP Data Object,PHP数据对象)机制更为安全,不会在本地对SQL进行拼接。当调用prepare()时,将SQL模板传给MySQL Server,传过去的是占位符“?”,不包含用户数据,当调用execute()时,用户的变量值才传递到MySQL Server,分开传递,阻止了SQL语句被破坏而执行恶意代码。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值