zoukankan      html  css  js  c++  java
  • DVWA靶场(一、暴力破解)

    Brute Force(low)

    Brute Force即为暴力破解,通过枚举获取管理员的账号和密码,一般用于破解后台管理系统的登录。
    需要准备以下工具

    • 密码字典
    • Burp Suite

    Burp环境设置好后,浏览器开启代理就可以进行抓包了
    首先打开搭建好的DVWA,选择low级别,选择暴力破解模块,输入用户名,密码这里随便输入,点击login

    这时抓到相应的http包,可以看到为GET请求,username为admin,password为123456,点击右键发送到intruder模块

    选择攻击类型Attack type为Sniper,攻击类型有以下

    • Sniper:狙击手,可以指定多个变量同时进行破解,但只设置一个字典文件,将指定的变量挨个用字典内容进行替换
    • Batteringram:攻城锤,可以指定多个变量,但仍只设置一个字典文件,将所有的变量一起用字典文件内容进行替换
    • Ptichfork:草叉子,可以指定多个变量,但需要每个变量分别设置一个字典文件,然后用对应的字典内容对变量同时进行替换
    • Cluster bomb:集束炸弹,可以指定多个变量,并为每个变量分别设置一个字典文件,然后用字典内容组合对变量进行替换

    在positions中清除变量并双击密码变量后选择添加,在payloads中选择payload type为Runtime fiel,常用载荷类型有以下

    • Simple list:可以手动添加字典列表,也可以导入Brup自带的字典,或者导入自定义字典
    • Runtime file:只能加载自定义的字典
    • Numbers:设定一个数值范围,从范围内依次或随机取值进行测试
    • Brute forcer:自己定义字符范围来生成字典文件


    这里特别注意密码字典命名和路径不能包含汉字或者汉字符号,否则加载不出字典

    在Options里可以设置请求引擎,加快破解速度,进程数设置为10,网络失败重试次数为0,重试前暂停(毫秒)为0

    设置Grep匹配为登录错误时的提示

    点击Start attack后开始暴力破解,得到以下结果

    通过长度以及Grep匹配可以看出密码为password,暴力破解结束。

    Brute Force(medium)

    中等等级的暴力破解和低等级的相同,只是低等级的暴力破解可以进行sql注入,而中等级的把其中的字符串过滤了,操作还是一样的,在此我就不再演示。
    中级的暴力破解相对来说比较慢,因为有个sleep函数,在破解失败后会使程序停止运行两秒。附上低级和中级的代码对比:
    可以看到低等级的代码,服务器只是验证了参数Login是否被设置(isset函数在php中用来检测变量是否设置,该函数返回的是布尔类型的值,即true/false),没有任何的防爆破机制,且对参数username、password没有做任何过滤,存在明显的sql注入漏洞。

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

    相比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)实在算不上)。

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

    Brute Force(higt)

    按照之前的方法进行破解,对higt级别不管用,因为代码中增加了user_token参数

    可以看到破解出来的密码长度都是一样的

    首先我们正常抓包,得到完整数据包之后,我们把需要猜解的参数范围选中user_token和password,选择Pitchfork测试类型。

    找到Redirections选中always允许重定向,最后在Options中找到Grep-Extract模块,点击Add,并设置筛选条件,得到user_token。
    然后设置密码本,点击payload,选择第一项的密码本与低等级的相同,第二项的时候选择Recursive grep 并且把之前得到的token值粘贴到方框中。
    分析higt级别代码:

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

    High级别的代码加入了Token,可以抵御CSRF攻击,同时也增加了爆破的难度,通过抓包,可以看到,登录验证时提交了四个参数:username、password、Login以及user_token。每次服务器返回的登陆页面中都会包含一个随机的user_token的值,用户每次登录时都要将user_token一起提交。服务器收到请求后,会优先做token的检查,再进行sql查询。
    同时,High级别的代码中,使用了stripslashes(去除字符串中的反斜线字符,如果有两个连续的反斜线,则只去掉一个)、 mysql_real_escape_string对参数username、password进行过滤、转义,进一步抵御sql注入。
    由于加入了Anti-CSRFtoken预防无脑爆破,还有一种办法是用python写个脚本:

    import  requests
    from bs4 import BeautifulSoup
    
    header={
         'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0'
         'Cookie': 'PHPSESSID=o8fani7hijfi1g42oo0opnhbl7; security=high'
    }
    
    url="http://192.168.115.130:89/vulnerabilities/brute/index.php"
    
    def get_token(url,heders):
        r=requests.get(url,heders=header)
        #print(r.status code,end=' ')
        html = r.content.decode()
        #print(len(html),end=' ')
        soup = BeautifulSoup(html,"html.parser")
        user_token = soup.find_all('input')[3]['value']
        return user_token
    
    user_token = get_token(url,headers)
    i=0
    for line in open("test.txt"):
    	url = "http://192.168.115.130:89/vulnerabilities/brute/index.php"+"?username=admin&password="+line.strip()+"&Login=Login&user_token="+user_token
    	i = i+1
    	print i,'admin',line.strip(),user_token,
    	user_token = get_token(url,headers)
    	if (i == 30):
    		break
    

    Brute Force(impossible)

    Impossible级别的代码加入了可靠的防爆破机制,当检测错误登录3次后,账户将锁定15分钟,爆破也就无法继续。
    同时采用了更为安全的PDO(PHP Data Object)机制防御sql注入。

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

    防止暴力破解措施

    1、增加密码复杂度
    2、设置Anti-CSRF token,设置验证码
    3、设置登录失败次数和锁定时间
    4、使用双因素认证,如密码+证书
    5、过滤用户输入,防止SQL注入

  • 相关阅读:
    C# Winform下一个热插拔的MIS/MRP/ERP框架(通用控件)
    Xamarin如何使用终端设备的NFC功能传递卡号等信息给Web页面(Android)
    C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)
    C# Winform中自定义筛选及自带统计行的Datagridview控件
    C#下Excel的普通处理和报表设计
    JVM 垃圾回收算法
    谈数据库的性能优化
    RedisService
    bean 与 map 互转.
    RedisService
  • 原文地址:https://www.cnblogs.com/tonywell/p/14008758.html
Copyright © 2011-2022 走看看