[网络安全]DVWA之Brute Force攻击姿势及解题详析合集
DVWA之Brute Force攻击之low level
思路:先爆用户名,再爆密码。
- 抓包后给username添加payload位置
- 添加Burp自带用户名字典,启动爆破
由下图回显可知,单独的用户名/密码爆破是不行的
- 假定用户名为admin,接着进行单个payload爆破—给password添加payload位置
由下图回显可知,密码为password
DVWA之Brute Force攻击之medium level
步骤为:抓包、假定用户名为admin,给password添加payload位置、爆破
,操作同上,不再赘述。medium级别与low级别最大的区别在于爆破的时间较长。
源代码
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>";
}
其中包含了一段 sleep(2) 的代码,这会导致每次登录失败后停留 2 秒钟再进行下一次尝试。
在字典数量过多时,若真实密码位于字典后端,爆破时间自然增加。
DVWA之Brute Force攻击之high level
checkToken函数
主要用于防范 CSRF 攻击
,其原理是通过比较用户提交的 token 值和后端存储的 token 值是否一致来判断请求是否合法。其具体步骤如下:
1.从用户请求中获取 token 值,通常是通过表单或 URL 参数提交,例如 $_REQUEST['user_token']。
2.从后端存储中获取当前用户的 session_token 值,通常是通过 $_SESSION['session_token'] 来获取。
3.检查两个 token 值是否相等,如果相等,则说明该请求是合法的。否则记录日志。
4.在每次成功的请求处理后,更新后端存储中的 session_token 值,避免重复使用相同的 token 值造成安全问题。
- 抓包,为
password和user_token
添加payload位置,并修改攻击类型为Pitchfork
- 为第一个payload集添加字典
- 选择payload集2的payload类型为递归提取
- 选择
重定向跟随类型
为总是
- 在设置中找到
检索-提取
,点击添加
, 点击获取响应
,搜索栏输入token
,选择value部分
,点击确认
。
6.粘贴token
- 在资源池中
新建资源池,设置线程为1
- 开始爆破
DVWA之Brute Force攻击之Impossible level
源代码
<?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();
?>
代码审计
- 防御CSRF攻击
该代码防御了 CSRF 攻击,使用了 Anti-CSRF token 进行检查。在用户提交表单时,通过 checkToken 函数检查请求中的 $_REQUEST[‘user_token’] 值是否等于 $_SESSION[‘session_token’] ,如果这两者不相等,就表示该请求很可能是恶意提交,将被拒绝。这样可以有效地防御 CSRF 攻击。
- 防御SQL注入
该代码对 $_POST[‘username’] 和 $_POST[‘password’] 变量进行了处理,使用了 mysqli_real_escape_string 函数来转义输入中的特殊字符,进而防止 SQL 注入攻击。此外,使用了 PDO prepare 函数来执行预处理语句,从而增强了安全性。
- 密码加密
该代码对用户输入的密码进行了 md5 加密处理,从而保护了用户密码,同时增加了数据安全性。
- 多次登录失败锁定账户
该代码使用了 total_failed_login 和 lockout_time 变量来控制账户的锁定策略。当用户登录失败达到 3次时,将会被锁定15分钟。此外,代码还记录了用户上一次登录时间(last_login)和登录失败次数(failed_login),在用户登录成功后输出到页面供用户查看。
- 随机延迟增加安全性
代码使用了 sleep 函数来产生一个随机的延迟时间,从而增加了系统的安全性。此举可在一定程度上防止暴力破解密码,在某些情况下还可以减轻恶意攻击的压力。