DVWA 之 Brute Force-暴力破解
一、Brute Force-暴力破解
原理
攻击者使用用户名和密码字典,一个一个去枚举,尝试是否能够登录,其关键是字典的构建。
1. Low
随便输入一个用户名和密码,查看效果,发现登录失败
尝试使用万能密码 admin' or '1'='1
或 admin' #
,发现登录成功
查看后台源代码,
// 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';";
发现其对用户名和密码没有任何的检查,因此当用户名为 admin' #
时,语句为
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';";
// 变为
$query = "SELECT * FROM `users` WHERE user = 'admin' #' AND password = '$pass';";
其中,#为单行注释符,# 号后面的语句不会执行,因此只要加入单引号闭合字符串并注释掉后面的内容,只要存在admin
账号,就可以登录成功。
2. Medium
尝试使用万能密码 admin' or '1'='1
或 admin' #
,登录失败。查看后台源代码
$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)) ? "" : ""));
发现使用了 mysqli_real_escape_string()
函数对用户名以及密码中的特殊字符进行字符串转义,防止了 sql 注入,因此万能密码登录失败。且其登录失败后会等待 2 s。
尝试使用Burp Suite工具中的intruder模块对用户名密码进行爆破,利用Burp Suite抓包并发送到Intruder,在用户名以及密码处添加爆破位置,并选用字典进行爆破。
爆破成功,长度不同的那一项表明爆破成功。即得到用户名和密码分别是 admin
和 password
。
尝试登录,登录成功。
虽然登录失败后会等待 2 s 才能进行下一次登录,但并不能防止暴力破解。
3. High
抓包,发现多了一个user_token参数
查看源代码
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
发现增加了Token机制,Token是服务端生成的一串字符串,作为客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token并将其返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需带上用户名和密码。
每次服务器返回的登录界面中都会包含一个随机的 user_token 的值,用户每次登录时都要将 user_token 一起提交。服务器收到请求后,会优先做token的检查,再进行sql查询,因此在中等难度中使用的方法行不通。
因此我们要做的就是在暴力破解的每次请求时都要带上 user_token 参数,同样可以使用Burp Suite实现。
- 抓包,发送到Intruder模块
- 选择Pitchfork模式,添加爆破的参数
- 在Options中找到Request Engine模块,把线程数设为1
- 在Options中找到Rediections模块,选择always,允许重定向
- 在Options中找到Grep-Extract模块,点击Add,先点击Refetch response,然后选中user_token的值,会自动设置筛选条件,最后点击OK(将此处这个token值保存下来)
- 在Payloads中为选择的参数设置字典
将保存下来的token值填写在 initial payload for first request 处
- 开始爆破,发现爆破失败,原来在Pitchfork模式下,按照固定顺序匹配,只有用户名和密码在两个字典的同一行才能正确爆破,感觉这是很小概率的事件。因此假设已知用户名,只对密码进行爆破,最终爆破成功。
防护方法
- 登录页面采取有效的验证码机制
- 对用户密码错误的次数做限制