暴力破解,简称”爆破“。不要以为没人会对一些小站爆破。实现上我以前用 wordpress 搭建一个博客开始就有人对我的站点进行爆破。这是装了 WordfenceWAF 插件后的统计的情况。



装了 WordfenceWAF 看到报告就深刻感受到国际友人对我这破站的安全性的深刻关怀了。你不封他们的 ip ,他们的程序就会像中了 “奇淫合欢散” 那些对你的网站锲而不舍地爆破。而下面会从 dvma 中学习如何爆破和如何防爆破。

初级

页面是这样的。

很简单的登录,代码可以点击 view source 可以看到

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

这提交太简单,简直引人犯罪,来看看人类满满的恶意吧。下面介绍在 Kali Linux 中比较常用的两个工具 burp suite 和 hydra

Burp Suite

Burp Suite 是 Kali Linux 中预装的非常强大的渗透工具。在这个部分主要用来抓包和进行吧爆破。(可以在这里下载,win,mac都可以用的

将安全等级设置为 low 后,打开 burp suite,设置火狐浏览器的网络走 burp suite 的代理(即localost:8080,如图所示),让 burp suite 拦截火狐的请求

如果你要修改 burp suite 端口的话,你可以在 proxy-> options 中修改

之后你可以在 DVWA 的 Brute Force 的页面上输入帐号 admin 和 密码,密码随便都可以,提交后,发现页面动不了了,因为 burp suite 拦截了请求了。 点击右键,将求的信息发送到入侵器(intruder)(你点击 Forward 会将请求跑完,如果错过了,可以在 Proxy->Http History 和 target 那里都能找到之前的记录 )

然后在 intruder->position 那里点击 clear ,清理掉所有的变量,然后再添加 password 部分。也就是爆破点只有 password 部分。

然后点击 payloads,添加一份常用密码(Kali Linux 在 /usr/share/john/password.lst 或者从 github 上搜一份),并移除注释。

然后再设置爆破的标准,因为密码错误的时候会提示 Username and/or password incorrect

所以报文如果不能匹配到 incorrect,就说明密码爆破成功。所以在 Options 那里设置成这样就行了

然后再点击上面,右上角的 start attack 就可以了

结果如下

明显 password 就是密码了

Hydra

爆破的原理是一样的,不过 hydra 用的是命令行。而根据上面抓包得出的信息。(文档可以看这里) 可以马上用这条命令进行爆破。

hydra 192.168.0.110 -s 5678 -l admin -IVv -P /usr/share/john/password.lst http-get-form "/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:incorrect.:H=Cookie: security=low;PHPSESSID=isk2inn2psu1sh56slicq6oim7"

常用参数

  • s :端口
  • l:用户名
  • L:用户列表文件
  • p:密码
  • P:密码文件
  • I:忽略现有的恢复文件,强制退出就有恢复文件了(不需要等10秒)
  • v:输出详细信息
  • V:输出每次尝试的用户和密码

而 http-get-form 的东西和上面说的都差不多只是一个是图形化界面一个是命令行参数罢了。应该很容易理解。得到的结果如下。

SQL 注入

如果你看上面的源代码的话,你会发现会有 SQL 注入的问题的。密码因为有 md5 一下所有不存在注入的问题,但是 $user 没有。。。所以往 $user 参数的方向去想。 比如 user 是 admin'# 时

    $query  = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
//结果会是这样
$query = "SELECT * FROM `users` WHERE user = 'admin'#' AND password = '$pass';"
//mysql 语句中 # 后面都是注释,就变成
$query = "SELECT * FROM `users` WHERE user = 'admin'

从而登录到了 admin 帐号。。。

中级

中级的界面是这样的



而代码与前面相比只是多了要用mysqli_real_escape_string函数进行验证,以及登录失败会 sleep(2)

将 用户名和密码转义,比如说 \n 被转义成 \\n,' 转义成 \',这可以抵御一些 SQL 注入攻击,但是不能抵御爆破。代码如下

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

用 hydra 试试 hydra 192.168.0.110 -s 5678 -l admin -IVv -P /usr/share/john/password.lst http-get-form "/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:incorrect.:H=Cookie: PHPSESSID=pfoju9qirkvqmcnpgb49a2bop4; security=medium" 毫无疑问可以爆破的

高级

高级的页面代码

<form action="#" method="GET">
Username:<br>
<input type="text" name="username"><br>
Password:<br>
<input type="password" autocomplete="off" name="password"><br>
<br>
<input type="submit" value="Login" name="Login">
<input type="hidden" name="user_token" value="b258081b421c1ee77b3b1d5a53be58ca">
</form>

服务端的代码

<?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

意思是,用户访问 login.php 的时候就生成一个 token 保存在 session,并让它登录的时候发送给服务器,如果服务器有这个 token 就证明这个请求是确实打开了 login.php 才再提交了。

登录失败或者根本就没 token 就将这个 token 从 session 中移除,生成新的 token 再执行之前的操作。

就如注释所言但这是用来防止 CSRF 攻击的,所谓的 CSRF 就是比如打开恶意网站,里面有张图片,或者伪造一个输入框利用网站 cookies 就可以直接“帮你”做删除数据之类的操作的。

这段代码防不了爆破,每次爆破之前获取页面的 token 不就可以了吗。 而 stripslashes 是用来还原 html 词汇,比如 a\tsay\t\'world\' 之类,就会还原成 a say 'world' 对防御爆破没什么帮助的。

一些文章会用 python 去写,我觉得要写代码去做功能考虑去做,如果能工具去做的事绝不写代码。

(有点奉太郎的味道

所以下面主要是用 brup 实现,而基本操作 在 Kali Linux 中要用 brup v1.3.6 才行。v1.3.5 有录制宏的bug 。 burp suite 也不复杂。

爆破可以配置成这样,在作用域(scope)中设置匹配的 Url 及相关的宏,爆破前就能就获取页面的 token,并将之放到 url 参数中

下面是设置过程

录制请求

之后你可以在 DVWA 的 Brute Force 的页面上输入帐号 admin 和 密码,密码随便都可以,提交后,发现页面动不了了,因为 burp suite 拦截了请求了。

此时,如果你点击 Forward 会将请求会继续跑

配置作用域

在 target-> sitemap 那里配置作用域

设置匹配条件

在 project options -> session 的 Session Handle Rules 上,配置匹配的项目以及匹配后要做的事。 点击 Add 按钮创建匹配 Url 后要做的东西。

这里配置意思是说,这是只有爆破的时候才会启动(intruder),其他功能不会用到这个规则。

录制获取 token 的行为的宏

行为是,在爆破前获取 token ,并将之放到 url 中。



然后点击 Add 按钮,添加宏

选择需要那个需要获取 token 的页面,点击最下面的 ok 按钮

配置选项

创建要添加到 url 的参数

填写要放到参数名,双击 b59619b0e13a9016a524e686f47720e2 后帮你自动填好的。然后点击 ok

配置后如下



然后一直点击 Ok 就行了。

爆破设置

步骤和之前的一样。在 target->site map 中找到要爆破的请求

到 Intruder 页,设置要爆破的参数

配置常用密码字典

匹配出错情况

开始爆破

爆破结果如下

不可能级别

到这个级别,利用工具基本无法爆破。来看看代码吧

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

这代码就多了很多锁定用户的逻辑了。而且 sql 查询也不用stripslashes( $pass )mysql_real_escape_string($pass )了,更加简洁和安全了。觉得最好还是加个验证码,比如是错了三次之后就要填写验证码之类的逻辑。

最后

  1. 任何手段都无法保护弱密码,如果密码就是 123456,password之类的弱密码就不需要爆破也能解决,当你的密码是有大小写的英文,有数字,有特殊符号(@#.)之类的8位数以上就非常难被爆破获得了
  2. 锁定的用户的逻辑其实是有漏洞的,假如我讨厌一个人,那么我写个程序每隔一段登录失败,他就永远登录不了了。。。
  3. 登录简单吗?一个简单的功能可以很简单,但也可以很不靠谱,老鸟与菜鸟实现同一种功能可能会考虑很多种情况,为何他会知道这种情况,可能是看书的,可能是看别人写的代码,但更有可能是坑过或者曾被坑过。。。这就是老鸟的价值了。

DVWA 黑客攻防演练(二)暴力破解 Brute Froce的更多相关文章

  1. DVWA 黑客攻防演练(一) 介绍及安装

    原本是像写一篇 SELinux 的文章的.而我写总结文章的时候,总会去想原因是什么,为什么会有这种需求.而我发觉 SELinux 的需求是编程人员的神奇代码或者维护者的脑袋短路而造成系统容易被攻击.就 ...

  2. DVWA 黑客攻防演练(十二) DOM型 XSS 攻击 DOM Based Cross Site Scripting

    反射型攻击那篇提及到,如何是"数据是否保存在服务器端"来区分,DOM 型 XSS 攻击应该算是 反射型XSS 攻击. DOM 型攻击的特殊之处在于它是利用 JS 的 documen ...

  3. DVWA 黑客攻防演练(六)不安全的验证码 Insecure CAPTCHA

    之前在 CSRF 攻击 的那篇文章的最后,我觉得可以用验证码提高攻击的难度. 若有验证码的话,就比较难被攻击者利用 XSS 漏洞进行的 CSRF 攻击了,因为要识别验证码起码要调用api,跨域会被浏览 ...

  4. DVWA 黑客攻防演练(十四)CSRF 攻击 Cross Site Request Forgery

    这么多攻击中,CSRF 攻击,全称是 Cross Site Request Forgery,翻译过来是跨站请求伪造可谓是最防不胜防之一.比如删除一篇文章,添加一笔钱之类,如果开发者是没有考虑到会被 C ...

  5. DVWA 黑客攻防演练(十三)JS 攻击 JavaScript Attacks

    新版本的 DVWA 有新东西,其中一个就是这个 JavaScript 模块了. 玩法也挺特别的,如果你能提交 success 这个词,成功是算你赢了.也看得我有点懵逼. 初级 如果你改成 " ...

  6. DVWA 黑客攻防演练(十一) 存储型 XSS 攻击 Stored Cross Site Scripting

    上一篇文章会介绍了反射型 XSS 攻击.本文主要是通过 dvwa 介绍存储型 XSS 攻击.存储型 XSS 攻击影响范围极大.比如是微博.贴吧之类的,若有注入漏洞,再假如攻击者能用上一篇文章类似的代码 ...

  7. DVWA 黑客攻防演练(九) SQL 盲注 SQL Injection (Blind)

    上一篇文章谈及了 dvwa 中的SQL注入攻击,而这篇和上一篇内容很像,都是关于SQL注入攻击.和上一篇相比,上一篇的注入成功就马上得到所有用户的信息,这部分页面上不会返回一些很明显的信息供你调试,就 ...

  8. DVWA 黑客攻防演练(八)SQL 注入 SQL Injection

    web 程序中离不开数据库,但到今天 SQL注入是一种常见的攻击手段.如今现在一些 orm 框架(Hibernate)或者一些 mapper 框架( iBatis)会对 SQL 有一个更友好的封装,使 ...

  9. DVWA 黑客攻防演练(五)文件上传漏洞 File Upload

    说起文件上传漏洞 ,可谓是印象深刻.有次公司的网站突然访问不到了,同事去服务器看了一下.所有 webroot 文件夹下的所有文件都被重命名成其他文件,比如 jsp 文件变成 jsp.s ,以致于路径映 ...

随机推荐

  1. [Swift]LeetCode459. 重复的子字符串 | Repeated Substring Pattern

    Given a non-empty string check if it can be constructed by taking a substring of it and appending mu ...

  2. [Swift]LeetCode860. 柠檬水找零 | Lemonade Change

    At a lemonade stand, each lemonade costs $5. Customers are standing in a queue to buy from you, and ...

  3. [Swift]LeetCode923.三数之和的多种可能 | 3Sum With Multiplicity

    Given an integer array A, and an integer target, return the number of tuples i, j, k  such that i &l ...

  4. Spotlight监控Oracle--Spotlight On Oracle安装和使用

    网上找了很久,发现单独Spotlight On Oracle的安装包很少,要么要积分C币的,要么官网要授权的. 应用过程中也没有一个集安装与运用与一体的文档,故汇总相关信息,供参考. Spotligh ...

  5. 面向对象-Java MOOC翁恺老师第一次作业

    由于看这个慕课的时候已经结课了,没有办法提交查看代码是否正确...先保存一下,以后再提交改错 欢迎批评指正! 题目链接:https://www.icourse163.org/learn/ZJU-100 ...

  6. 【Kafka专栏】-Kafka从初始到搭建到应用

    一.前述 Kafka是一个分布式的消息队列系统(Message Queue). kafka集群有多个Broker服务器组成,每个类型的消息被定义为topic. 同一topic内部的消息按照一定的key ...

  7. 【java提高】---queue集合

    queue集合 什么是Queue集合? 答:Queue用于模拟队列这种数据结构.队列通常是指“先进先出(FIFO)”的容器.队列的头部保存在队列中存放时间最长的元素,尾部保存存放时间最短的元素. 新元 ...

  8. mockjs,json-server一起搭建前端通用的数据模拟框架

    无论是在工作,还是在业余时间做前端开发的时候,难免出现后端团队还没完成接口的开发,而前端团队却需要实现对应的功能,不要问为什么,这是肯定存在的.本篇文章就是基于此原因而产出的.希望对有这方面的需求的同 ...

  9. EF下lambda与linq查询&&扩展方法

    1. linq查询数据 WebTestDBEntities db = new WebTestDBEntities(); 1.1 linq查询所有列数据 var userInfoList = from ...

  10. 转:OAuth 2.0 介绍

    OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版. 本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为R ...