DVWA V1.9:Brute Force(暴力破解)

Brute Force 介绍

密码破解是从计算机系统中存储或传输的数据中恢复密码的过程。
一种常见的方法是反复尝试对密码进行猜测。

用户经常选择弱密码。
不安全选择的例子包括字典中发现的单个单词、姓氏、任何太短的密码(通常被认为小于6或7个字符)或可预测的模式(例如交替元音和辅音,这被称为LeTalk,因此“密码”变成“p@ 55 W0RD”)。

创建针对目标生成的有针对性的词表,通常给出最高的成功率。
这里有一些公共工具,将基于公司网站、个人社交网络和其他常见信息(如生日或毕业年)的组合来创建词典。

最后一个办法是尝试所有可能的密码,称为蛮力攻击。
理论上,如果没有尝试次数的限制,暴力攻击总是成功的,因为可接受密码的规则必须是公开的;但是随着密码长度的增加,可能的密码的数量也会增加攻击时间。
在这里插入图片描述

Low 级别

核心代码

<?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 = mysql_real_escape_string( $user );

    // Sanitise password input
    $pass = $_GET[ 'password' ];
    $pass = stripslashes( $pass );
    $pass = mysql_real_escape_string( $pass );
    $pass = md5( $pass );

    // Check database
    $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 ) {
        // Get users details
        $avatar = mysql_result( $result, 0, "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>";
    }

    mysql_close();
}

// Generate Anti-CSRF token
generateSessionToken();

?>

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

官方提示

开发商完全错过了任何保护方法允许任何人尝试他们希望的次数,登录到任何用户没有任何影响。

漏洞利用

方法一:
使用burp抓包,发到intruder模块,加载字典进行爆破。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
根据返回长度可以判断password为密码,使用admin和password登录,是ok的。
在这里插入图片描述
在这里插入图片描述
方法二:
我们发现它存在sql注入漏洞,进行利用。

admin' #

当然也是可以的。
在这里插入图片描述
在这里插入图片描述

Medium 级别

核心代码

<?php

if( isset( $_GET[ 'Login' ] ) ) {
    // Sanitise username input
    $user = $_GET[ 'username' ];
    $user = mysql_real_escape_string( $user );

    // Sanitise password input
    $pass = $_GET[ 'password' ];
    $pass = mysql_real_escape_string( $pass );
    $pass = md5( $pass );

    // Check the database
    $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 ) {
        // Get users details
        $avatar = mysql_result( $result, 0, "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>";
    }

    mysql_close();
}

?>

相比Low级别的代码,Medium级别的代码主要增加了mysql_real_escape_string函数
这个函数会对字符串中的特殊符号(x00,n,r,,’,”,x1a)进行转义,基本上能够抵御sql注入攻击
说基本上是因为查到说 MySQL5.5.37以下版本如果设置编码为GBK,能够构造编码绕过mysql_real_escape_string 对单引号的转义(因实验环境的MySQL版本较新,所以并未做相应验证);同时,$pass做了MD5校验,杜绝了通过参数password进行sql注入的可能性。
但是,依然没有加入有效的防爆破机制(sleep(2)实在算不上)。

官方提示

这个阶段在失败的登录屏幕上添加了一个睡眠。
这意味着当登录不正确时,在页面可见之前会有额外的两秒钟等待。

这只会减慢一分钟可以处理的请求的数量,使它变得蛮力。

漏洞利用

sql注入是没戏了,但是还是可以利用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 = mysql_real_escape_string( $user );

    // Sanitise password input
    $pass = $_GET[ 'password' ];
    $pass = stripslashes( $pass );
    $pass = mysql_real_escape_string( $pass );
    $pass = md5( $pass );

    // Check database
    $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 ) {
        // Get users details
        $avatar = mysql_result( $result, 0, "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>";
    }

    mysql_close();
}

// Generate Anti-CSRF token
generateSessionToken();

?>

High级别的代码加入了Token,可以抵御CSRF攻击,同时也增加了爆破的难度,通过抓包,可以看到,登录验证时提交了四个参数:username、password、Login以及user_token。
在这里插入图片描述
每次服务器返回的登陆页面中都会包含一个随机的user_token的值,用户每次登录时都要将user_token一起提交。
服务器收到请求后,会优先做token的检查,再进行sql查询。

同时,High级别的代码中,使用了stripslashes(去除字符串中的反斜线字符,如果有两个连续的反斜线,则只去掉一个)、 mysql_real_escape_string对参数username、password进行过滤、转义,进一步抵御sql注入

官方提示

已经使用了“反交叉站点请求伪造(CSRF)令牌”。
这个级别也在中等水平上扩展,通过等待失败的登录,但是这次是在两到四秒之间的一个随机的时间量。

使用ACAPTCHA form could have a similar effect as a CSRF token.

漏洞利用

由于加入了Anti-CSRFtoken预防无脑爆破,这里就不推荐用Burpsuite了,还是简单用python写个脚本。
具体实现查看底部参考链接。

Impossible 级别

核心代码

<?php

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

    // Sanitise username input
    $user = $_POST[ 'username' ];
    $user = stripslashes( $user );
    $user = mysql_real_escape_string( $user );

    // Sanitise password input
    $pass = $_POST[ 'password' ];
    $pass = stripslashes( $pass );
    $pass = mysql_real_escape_string( $pass );
    $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 = $row[ 'last_login' ];
        $last_login = strtotime( $last_login );
        $timeout    = strtotime( "{$last_login} +{$lockout_time} minutes" );
        $timenow    = strtotime( "now" );

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

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

?>

可以看到Impossible级别的代码加入了可靠的防爆破机制,当检测到频繁的错误登录后,系统会将账户锁定,爆破也就无法继续。

同时采用了更为安全的PDO(PHP Data Object)机制防御sql注入,这是因为不能使用PDO扩展本身执行任何数据库操作,而sql注入的关键就是通过破坏sql语句结构执行恶意的sql命令。

官方提示

蛮力(和用户枚举)不可能在不可能的水平上。
开发人员添加了一个“锁定”功能,如果在过去15分钟内有五个错误登录,则锁定用户无法登录。

如果被锁定的用户试图登录,即使使用有效的密码,也会说他们的用户名或密码不正确。
这将不可能知道系统上是否存在有效的帐户、密码和帐户是否被锁定。

这可能导致“拒绝服务”(DoS),因为有人不断尝试登录到某人的帐户。
这个级别需要通过黑名单攻击(例如IP地址、国家、用户代理)来扩展。

靶场地址:
用户名admin,密码password。
DVWA V1.9 在线靶场
参考链接:
新手指南:DVWA-1.9全级别教程之Brute Force

发布了139 篇原创文章 · 获赞 19 · 访问量 3241

猜你喜欢

转载自blog.csdn.net/qq_43233085/article/details/104072049