About

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

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

创建针对目标的字典通常会获得最高的成功率。有一些公共工具可以根据公司网站、个人社交网络和其他常见信息(如生日或毕业年份)创建字典。

最后一种手段是尝试所有可能的密码,称为暴力攻击。理论上,如果尝试次数没有限制,暴力攻击总是会成功的,因为可接受密码的规则必须公开;但随着密码长度的增加,可能的密码数量也会增加,从而延长攻击时间。

Object

您的目标是通过暴力穷举获得管理员的密码。获得其他四个用户密码是一个加分项!

001 Low

本次的任务是入侵一个登陆页面:

001-1.png

我们先随便输入,比如admin:12345678,然后得到一个错误提示:

001-2.png

我们打开 Burpsuite 的 Proxy,拦截页面请求,可以发现登陆请求用的是 GET 方法,参数通过 URL 传递,分别为usernamepassword

001-3.png

我们点击 Action → Send to Intruder 把数据包发送给攻击器。点击右侧的Clear §,然后高亮password=12345678,点击Add §,攻击模式选择 Sniper:

001-4.png

四种暴力破解方式的区别:

  • 一个字典,两个参数,先匹配第一项,再匹配第二项【sniper】
  • 一个字典,两个参数,同用户名同密码【battering ram】
  • 两个字典,两个参数,同行匹配,短的截止【pitch fork】
  • 两个字典,两个参数,交叉匹配,所有可能【cluster bomb】

来到 Payload 页面,选择从文件加载,去 github 下载字典,然后载入字典:

001-5.png

现在我们点“开始攻击”,等待攻击器扫描完,把结果按长度排序,选择最长的那个:

001-6.png


第二种登陆的方法是使用 SQL 注入。我们观察源码:

001-7.png

页面从 GET 请求拿到参数后,直接使用 SQL 语句:

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

查询,没有任何防护措施。所以,我们可以用简单的 SQL 注入登陆后台:

  • Username:admin' or '1'='1
  • Password:随意

001-8.png

002 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
        // ...
    }
    else {
        // Login failed
        // ...
    }
    // ...
}

?>

该等级下代码增加了mysql_real_escape_string()函数,它转义 SQL 语句中使用的字符串中的特殊字符,这抵挡大部分的 SQL 注入,但代码没有增加暴力破解的防护,所以可以和 Low 等级一样用 Brupsuite 穷举出弱口令。

003 High

观察源代码:

003-1.png

该级别的代码对用户输入增加了两个校验:

  • stripslashes()函数:返回一个去除转义反斜线后的字符串(\' 转换为 ' 等等)。双反斜线(\\)被转换为单个反斜线(\)。
  • mysql_real_escape_string()函数:转义 SQL 语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集。

抓包后我们发现这里多了一个参数user_token

003-2.png

把它转发给 Repeater(重放器),发送第一次请求会返回状态码为 200 的页面:

003-3.png

第二次发送请求则会返回状态码为 302 的页面:

003-4.png

这是由于每次user_token的值会随着请求包的变化而变化,我们根据重定向,发现是 CSRF 错误:

003-5.png


对于这种情况,我们需要同时爆破passworduser_token,攻击模式选用 Pitchfork:

003-6.png

Payload 1 和之前一样,使用 Simple List,载入密码字典。Payload 2 使用 Recursive Grep。选择 Option,把 Grep - Match 项清空,添加incorrect

003-7.png

然后到 Grep - Extract 里添加一个项,如页面没出来就 Fetch response:

003-8.png

由于我们会遇到 302 的页面,所以我们往下拉,把 Redirections 改为 Always:

003-9.png

开始攻击,注意 Brupsuite 会提示 Recursive Grep 无法用多线程,我们创建一个新的资源池,并发请求数为 1 就行了。

看图可知,上一个 Response 的user_toekn会作为下一个 Request 的user_token

003-10.png

我们观察 incorrect 标志位可以区分出那个请求是成功了的。

References