目录
- 暴力破解
- low
- 方法1
- 方法2
- medium
- high
- impossible
暴力破解
暴力破解是一种尝试通过穷尽所有可能的选项来获取密码、密钥或其他安全凭证的攻击方法。它是一种简单但通常无效率的破解技术,适用于密码强度较弱的环境或当攻击者没有其他信息可供利用时。暴力破解的基本原理是依次尝试所有可能的组合,直到找到正确的答案。
low
方法1
sql注入万能密码,输入admin’ or ‘1’=1
方法2
随意输入,然后抓包
发送到爆破模块,添加变量并选择集束炸弹模式
在pyload设置里设置字典攻击,然后开始攻击即可
筛选长度查看,攻击成功
代码审计
<?php
if( isset( $_GET[ 'Login' ] ) ) {
// Get username
$user = $_GET[ 'username' ];
// Get password
$pass = $_GET[ 'password' ];
$pass = md5( $pass ); //明文md5算法不安全
// Check the database
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';"; //此处直接将用户输入的用户名和密码嵌入到 SQL 查询中,容易受到 SQL 注入攻击。攻击者可以通过输入特定的恶意字符串来操作数据库
$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
$html .= "<p>Welcome to the password protected area {$user}</p>";
$html .= "<img src=\"{$avatar}\" />";
}
else {
// Login failed
$html .= "<pre><br />Username and/or password incorrect.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
medium
随意输入抓包并发送到爆破模块
添加变量选择集束炸弹模式攻击
在pyload模块设置字典并攻击
攻击速度会比较慢,因为源码设置了每次登录后需要2秒才能再次登录,爆破成功
代码审计
<?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 ); //md5算法不安全
// Check the database
$query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';"; //代码使用 mysqli_real_escape_string 函数对用户输入进行清理,但仍然存在 SQL 注入的风险,因为 SQL 查询是通过字符串拼接的。
$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
$html .= "<p>Welcome to the password protected area {$user}</p>";
$html .= "<img src=\"{$avatar}\" />";
}
else {
// Login failed
sleep( 2 );
$html .= "<pre><br />Username and/or password incorrect.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
high
随意输入然后抓包,可以看到这里设置了token,token相当于一个房门的钥匙,没有它即使有账号密码也无法登录
选择交叉攻击,并且token也要设置变量
在设置里添加token,选中并添加
重定向选中总是
资源池设置最大并发请求为1,防止还没使用token就被刷掉
在设置里,攻击结果这取消勾选此选项
回到浏览器,找到token,复制下来
选中递归提取,并把刚复制的token复制进去
设置好字典后就可以攻击了
攻击成功
代码审计
<?php
if( isset( $_GET[ 'Login' ] ) ) {
// 检查 Anti-CSRF 令牌
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // 增加了一个 token 检测
// 清理用户名输入
$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] 修复 mysql_escape_string() 调用!此代码无法工作。", E_USER_ERROR)) ? "" : ""));
// 对字符串中的特殊字符(\x00,\n,\r,\',\",\x1a)进行转义
// 清理密码输入
$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] 修复 mysql_escape_string() 调用!此代码无法工作。", E_USER_ERROR)) ? "" : ""));
$pass = md5( $pass ); // 将密码进行 MD5 哈希处理
// 检查数据库
$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 ) {
// 获取用户详情
$row = mysqli_fetch_assoc( $result );
$avatar = $row["avatar"];
// 登录成功
$html .= "<p>欢迎来到受密码保护的区域 {$user}</p>";
$html .= "<img src=\"{$avatar}\" />";
}
else {
// 登录失败
sleep( rand( 0, 3 ) ); // 随机暂停 0 到 3 秒
$html .= "<pre><br />用户名和/或密码不正确。</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); // 关闭数据库连接
}
// 生成 Anti-CSRF 令牌
generateSessionToken();
?>
impossible
这是最高的难度,其中每次登录都由GET提交方式改为POST提交方式,同样加了token校验机制,还有就是他限制的登录的次数,如果登录失败3次,账户就会被锁定,需要等待15,然后才能重新尝试。
代码审计
<?php
if( isset( $_POST[ 'Login' ] ) && isset ($_POST['username']) && isset ($_POST['password']) ) {
// 检查 Anti-CSRF 令牌
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// 清理用户名输入
$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] 修复 mysql_escape_string() 调用!此代码无法工作。", E_USER_ERROR)) ? "" : ""));
// 清理密码输入
$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] 修复 mysql_escape_string() 调用!此代码无法工作。", E_USER_ERROR)) ? "" : ""));
$pass = md5( $pass ); // 将密码进行 MD5 哈希处理
// 默认值
$total_failed_login = 3; // 允许失败登录的最大次数
$lockout_time = 15; // 锁定时间(分钟)
$account_locked = false; // 账户是否被锁定
// 检查数据库(检查用户信息)
$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();
// 检查用户是否被锁定
if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) ) {
// 用户被锁定
//$html .= "<pre><br />此账户因登录错误过多而被锁定。</pre>";
// 计算用户何时可以再次登录
$last_login = strtotime( $row[ 'last_login' ] );
$timeout = $last_login + ($lockout_time * 60);
$timenow = time();
/*
print "最后一次登录时间是: " . date ("h:i:s", $last_login) . "<br />";
print "当前时间是: " . date ("h:i:s", $timenow) . "<br />";
print "超时时间是: " . date ("h:i:s", $timeout) . "<br />";
*/
// 检查是否经过足够的时间,如果没有,则锁定账户
if( $timenow < $timeout ) {
$account_locked = true;
// print "账户已锁定<br />";
}
}
// 检查数据库(如果用户名与密码匹配)
$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( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) {
// 获取用户详情
$avatar = $row[ 'avatar' ];
$failed_login = $row[ 'failed_login' ];
$last_login = $row[ 'last_login' ];
// 登录成功
$html .= "<p>欢迎来到受密码保护的区域 <em>{$user}</em></p>";
$html .= "<img src=\"{$avatar}\" />";
// 自上次登录以来,账户是否被锁定?
if( $failed_login >= $total_failed_login ) {
$html .= "<p><em>警告</em>: 可能有人正在暴力破解您的账户。</p>";
$html .= "<p>登录尝试次数: <em>{$failed_login}</em>。<br />上一次登录尝试是在: <em>{$last_login}</em>.</p>";
}
// 重置错误登录计数
$data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' );
$data->bindParam( ':user', $user, PDO::PARAM_STR );
$data->execute();
} else {
// 登录失败
sleep( rand( 2, 4 ) ); // 随机暂停2到4秒
// 给用户一些反馈
$html .= "<pre><br />用户名和/或密码不正确.<br /><br/>或者,账户因登录失败次数过多而被锁定.<br />如果是这种情况,<em>请在 {$lockout_time} 分钟后再试</em>.</pre>";
// 更新错误登录计数
$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();
}
// 设置最后登录时间
$data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' );
$data->bindParam( ':user', $user, PDO::PARAM_STR );
$data->execute();
}
// 生成 Anti-CSRF 令牌
generateSessionToken();
?>
设置了防爆破模式,同时采用了更为安全的PDO(PHP Data Object)机制防御sql注入,这是因为不能使用PDO扩展本身执行任何数据库操作,而sql注入的关键就是通过破坏sql语句结构执行恶意的sql命令。