暴力破解,简称”爆破“。不要以为没人会对一些小站爆破。实现上我以前用 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 )
了,更加简洁和安全了。觉得最好还是加个验证码,比如是错了三次之后就要填写验证码之类的逻辑。
最后
- 任何手段都无法保护弱密码,如果密码就是 123456,password之类的弱密码就不需要爆破也能解决,当你的密码是有大小写的英文,有数字,有特殊符号(@#.)之类的8位数以上就非常难被爆破获得了
- 锁定的用户的逻辑其实是有漏洞的,假如我讨厌一个人,那么我写个程序每隔一段登录失败,他就永远登录不了了。。。
- 登录简单吗?一个简单的功能可以很简单,但也可以很不靠谱,老鸟与菜鸟实现同一种功能可能会考虑很多种情况,为何他会知道这种情况,可能是看书的,可能是看别人写的代码,但更有可能是坑过或者曾被坑过。。。这就是老鸟的价值了。
DVWA 黑客攻防演练(二)暴力破解 Brute Froce的更多相关文章
-
DVWA 黑客攻防演练(一) 介绍及安装
原本是像写一篇 SELinux 的文章的.而我写总结文章的时候,总会去想原因是什么,为什么会有这种需求.而我发觉 SELinux 的需求是编程人员的神奇代码或者维护者的脑袋短路而造成系统容易被攻击.就 ...
-
DVWA 黑客攻防演练(十二) DOM型 XSS 攻击 DOM Based Cross Site Scripting
反射型攻击那篇提及到,如何是"数据是否保存在服务器端"来区分,DOM 型 XSS 攻击应该算是 反射型XSS 攻击. DOM 型攻击的特殊之处在于它是利用 JS 的 documen ...
-
DVWA 黑客攻防演练(六)不安全的验证码 Insecure CAPTCHA
之前在 CSRF 攻击 的那篇文章的最后,我觉得可以用验证码提高攻击的难度. 若有验证码的话,就比较难被攻击者利用 XSS 漏洞进行的 CSRF 攻击了,因为要识别验证码起码要调用api,跨域会被浏览 ...
-
DVWA 黑客攻防演练(十四)CSRF 攻击 Cross Site Request Forgery
这么多攻击中,CSRF 攻击,全称是 Cross Site Request Forgery,翻译过来是跨站请求伪造可谓是最防不胜防之一.比如删除一篇文章,添加一笔钱之类,如果开发者是没有考虑到会被 C ...
-
DVWA 黑客攻防演练(十三)JS 攻击 JavaScript Attacks
新版本的 DVWA 有新东西,其中一个就是这个 JavaScript 模块了. 玩法也挺特别的,如果你能提交 success 这个词,成功是算你赢了.也看得我有点懵逼. 初级 如果你改成 " ...
-
DVWA 黑客攻防演练(十一) 存储型 XSS 攻击 Stored Cross Site Scripting
上一篇文章会介绍了反射型 XSS 攻击.本文主要是通过 dvwa 介绍存储型 XSS 攻击.存储型 XSS 攻击影响范围极大.比如是微博.贴吧之类的,若有注入漏洞,再假如攻击者能用上一篇文章类似的代码 ...
-
DVWA 黑客攻防演练(九) SQL 盲注 SQL Injection (Blind)
上一篇文章谈及了 dvwa 中的SQL注入攻击,而这篇和上一篇内容很像,都是关于SQL注入攻击.和上一篇相比,上一篇的注入成功就马上得到所有用户的信息,这部分页面上不会返回一些很明显的信息供你调试,就 ...
-
DVWA 黑客攻防演练(八)SQL 注入 SQL Injection
web 程序中离不开数据库,但到今天 SQL注入是一种常见的攻击手段.如今现在一些 orm 框架(Hibernate)或者一些 mapper 框架( iBatis)会对 SQL 有一个更友好的封装,使 ...
-
DVWA 黑客攻防演练(五)文件上传漏洞 File Upload
说起文件上传漏洞 ,可谓是印象深刻.有次公司的网站突然访问不到了,同事去服务器看了一下.所有 webroot 文件夹下的所有文件都被重命名成其他文件,比如 jsp 文件变成 jsp.s ,以致于路径映 ...
随机推荐
-
navicat 结合快捷键
ctrl+q 打开查询窗口ctrl+/ 注释sql语句ctrl+shift +/ 解除注释ctrl+r 运行查询窗口的sql语句ctrl+shift+r 只运行选中的sql语句F6 打开一个mysql ...
-
bzoj 2809: [Apio2012]dispatching
#include<cstdio> #include<algorithm> #define M 1000005 using namespace std; long long an ...
-
poj1611 带权并查集
题意:病毒蔓延,现在有 n 个人,其中 0 号被认为可能感染,然后给出多个社交圈,如果某个社交圈里有人被认为可能被感染,那么所有这个社交圈里的人都被认为可能被感染,现在问有多少人可能被感染. 带权并查 ...
-
POJ 3723 Conscription 最小生成树
题目链接: 题目 Conscription Time Limit: 1000MS Memory Limit: 65536K 问题描述 Windy has a country, and he wants ...
-
Mysql个人语句笔记
--一些简单语句记录: /*mysql*/SHOW DATABASES CREATE DATABASE guoDROP DATABASE guo /*查看创建的数据库*/SHOW CREATE DAT ...
-
Tomcat证书安装(pfx和jks)
tomcat安装证书需要修改tomcat/conf下的server.xml,需要修改Connector port=”8443”开头的标签,一般情况下是注释掉的. 1.pfx 增加keystoreFil ...
-
紧急整理了 20 道 Spring Boot 面试题,我经常拿来面试别人!
面试了一些人,简历上都说自己熟悉 Spring Boot, 或者说正在学习 Spring Boot,一问他们时,都只停留在简单的使用阶段,很多东西都不清楚,也让我对面试者大失所望. 下面,我给大家总结 ...
-
关于node.js的进程管理
如果是单纯的运行一个node进程,那会比较简单,例如: node ./example.js 但是一般来说,当我们运行一个node进程之后,我们可能希望对这个进程进行更多的管理,例如,当node程序是一 ...
-
windows 环境下安装elasticsearch ,ik,head,marvel
elasticsearch 自带的中分分词器将会使中文分成一个一个的单词,需要安装ik分词等,ik分词分为 ik_smart(粗粒度分词),ik_max_word(细粒度分词)两种模式. 1:首先安 ...
-
【TypeScript】TypeScript 学习 3——类
在 EcmaScript 6 中,我们将会拥有原生的类,而不是像现在通过原型链来实现.使用 TypeScript 我们能提前体验这一特性. 首先来看看一个简单的例子: class Greeter { ...