DVWA从入门到精通(二):Brute Force(暴力破解) 摘要本文是《DVWA从入门到精通》系列的第二篇带你全面掌握Brute Force暴力破解模块的攻防全流程。从暴力破解的核心原理出发逐步讲解Low、Medium、High三个级别的攻击手法与源码分析并深入探讨Impossible级别的终极防御方案。文章包含Burp Suite的详细操作教程、字典制作方法、Token绕过技术以及账户锁定机制的实现原理让你真正做到“知其然更知其所以然”。一、什么是暴力破解1.1 暴力破解的核心原理暴力破解Brute Force在Web攻击中是指攻击者使用大量的认证信息在认证接口进行尝试登录直到得到正确的结果。它的核心原理是通过自动化工具以极高的速度尝试各种可能的用户名和密码组合直到找到能成功登录的那一组。暴力破解不依赖特定的系统缺陷而是用最直接的方式与系统“正面硬刚”。它的成功与否取决于以下几个因素因素说明密码复杂度密码越简单、越常见被猜中的概率越高字典质量字典越全面覆盖的密码组合越多防护机制是否有验证码、登录限制、账户锁定等攻击速度自动化工具每秒可尝试数百上千次1.2 为什么暴力破解依然有效你可能会想“都什么年代了还有人用暴力破解”但现实是暴力破解在实战中依然成功率极高。原因很简单——它利用了人们设置密码时的“通病”为了方便记忆很多人会使用123456、password、admin这类简单的弱口令很多人会在多个平台使用相同的密码企业员工常常使用公司名称、部门名称、生日等可猜测的信息作为密码攻击者正是将这些高频词汇制成字典进行有针对性的字典攻击而不是真的一个一个字符去试。1.3 暴力破解 vs 字典攻击在正式开始之前有必要澄清两个概念概念含义特点暴力破解Brute Force尝试所有可能的字符组合理论上一定能破解但耗时极长字典攻击Dictionary Attack仅尝试字典中预定义的词汇速度快但依赖字典质量在实际的Web安全测试中我们通常说的“暴力破解”其实指的是字典攻击——使用精心编制的用户名和密码字典进行快速尝试。二、准备工作环境与工具在开始攻击之前需要做好以下准备2.1 靶场环境确保你的DVWA已经成功部署并正常运行访问地址http://你的服务器IP/dvwa/login.php默认账号admin/password2.2 必备工具Burp SuiteBurp Suite是本次实验的核心工具我们将使用其Intruder模块完成攻击演示。Burp Suite的四种攻击模式模式说明适用场景Sniper狙击手单字典依次替换标记的参数只有一个爆破点如仅爆破密码Battering ram攻城锤单字典同时替换所有标记的参数所有参数值相同时使用Pitchfork草叉多字典并行替换多个爆破点且需一一对应如High级别的Token爆破Cluster bomb集束炸弹多字典笛卡尔积交叉匹配用户名和密码均未知时使用2.3 字典文件准备用户名和密码字典。常用的字典来源SecListsGitHub上最全的安全字典集合rockyou.txt经典的密码字典包含1400万个密码也可以自行制作针对性的小型字典进行测试三、Low级别毫无防护的“裸奔”状态3.1 安全级别设置首先将DVWA Security设置为Low级别然后进入Brute Force模块。3.2 观察与初步测试随意输入一个用户名和密码观察页面的行为输入错误时页面会显示“Username and/or password incorrect.”没有任何次数限制——你可以无限次尝试通过浏览器地址栏可以看到用户名和密码是通过GET请求明文传输的3.3 源码分析点击DVWA页面底部的“View Source”按钮查看Low级别的核心代码?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 pWelcome to the password protected area {$user}/p; echo img src\{$avatar}\ /; } else { // Login failed echo prebr /Username and/or password incorrect./pre; } ((is_null($___mysqli_res mysqli_close($GLOBALS[___mysqli_ston]))) ? false : $___mysqli_res); } ?这段代码存在以下致命缺陷无登录次数限制无论尝试多少次都不会触发任何保护机制存在SQL注入漏洞直接将用户输入拼接到SQL语句中明文传输用户名和密码通过GET请求明文传递无验证码没有任何人机验证机制3.4 攻击方法一SQL注入绕过登录由于Low级别的代码直接将用户输入拼接到SQL语句中我们可以使用SQL注入直接绕过登录。在Username输入框中输入admin or 11在Password输入框中随便输入任何内容如123。原理分析当输入admin or 11时拼接后的SQL语句变成了SELECT * FROM users WHERE user admin or 11 AND password 123由于11恒为真整个WHERE条件恒为真因此会返回users表中的记录从而成功登录。3.5 攻击方法二使用Burp Suite进行暴力破解第一步配置Burp Suite代理打开Burp Suite进入Proxy→Options确认代理监听地址为127.0.0.1:8080在浏览器中设置代理为127.0.0.1:8080第二步抓取登录请求在Burp Suite中点击Proxy→Intercept确保Intercept is on在DVWA的Brute Force页面输入任意用户名和密码如admin/123点击LoginBurp Suite会拦截到登录请求抓取到的数据包类似这样第三步发送到Intruder模块右键点击拦截到的请求选择“Send to Intruder”或按CtrlI。第四步配置爆破位置进入Intruder→Positions标签点击“Clear”清除所有默认标记选中password123中的123点击“Add”将其设为爆破变量也可以将usernameadmin中的admin也设为变量如果用户名未知攻击模式选择如果仅爆破密码已知用户名为admin选择Sniper狙击手如果用户名和密码均未知选择Cluster bomb集束炸弹第五步配置字典进入Intruder→Payloads标签在Payload Options中加载字典文件点击Load导入.txt字典也可以手动添加几个测试密码123456、password、admin、123等第六步开始爆破点击右上角的“Start Attack”按钮开始爆破。第七步分析结果爆破完成后通过Length响应长度来筛选结果登录成功的页面长度通常与失败的不同找到长度异常的条目查看响应内容在DVWA中默认账号密码为admin / password爆破成功后页面会显示“Welcome to the password protected area admin”。3.6 Low级别总结缺陷说明无登录次数限制可无限次尝试SQL注入漏洞可直接绕过登录明文传输GET请求暴露密码无验证码无任何人机验证四、Medium级别增加了延迟的“缓兵之计”4.1 安全级别设置将DVWA Security切换为Medium级别。4.2 观察变化在Medium级别下你会发现登录失败后页面响应明显变慢了。4.3 源码分析查看Medium级别的核心代码?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 pWelcome to the password protected area {$user}/p; echo img src\{$avatar}\ /; } else { // Login failed sleep( 2 ); echo prebr /Username and/or password incorrect./pre; } ((is_null($___mysqli_res mysqli_close($GLOBALS[___mysqli_ston]))) ? false : $___mysqli_res); } ?Medium级别的变化增加了输入过滤使用mysqli_real_escape_string()对用户输入进行转义处理有效防御了SQL注入增加了延迟机制登录失败后执行sleep(2)程序休眠2秒4.4 攻击方法Medium级别的防护本质上是“缓兵之计”SQL注入被修复了输入被转义但暴力破解依然可行——只是变慢了攻击步骤与Low级别完全一致使用Burp Suite抓取登录请求发送到Intruder模块配置爆破位置和字典开始爆破唯一的区别是由于每次失败都有2秒延迟爆破速度会显著降低。但只要有足够的时间和耐心依然可以成功爆破出密码。4.5 Medium级别总结改进局限性输入转义防SQL注入对暴力破解无效sleep(2)延迟仅降低速度不阻断攻击五、High级别Token机制的“动态防线”5.1 安全级别设置将DVWA Security切换为High级别。5.2 观察变化在High级别下再次抓取登录请求你会发现数据包中多了一个参数——user_token5.3 源码分析查看High级别的核心代码?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 pWelcome to the password protected area {$user}/p; echo img src\{$avatar}\ /; } else { // Login failed sleep( rand( 0, 3 ) ); echo prebr /Username and/or password incorrect./pre; } ((is_null($___mysqli_res mysqli_close($GLOBALS[___mysqli_ston]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?High级别的核心变化增加了Token验证服务器要求每一个登录请求都必须携带一个名为user_token的参数且这个值必须和服务器Session中存的session_token完全一致Token是动态的每次请求后服务器都会生成一个新的Token保留了延迟机制依然存在登录失败的延迟5.4 Token机制的原理Token机制是如何防御暴力破解的服务器生成Token用户打开登录页面时服务器生成一个随机的Token存储在Session中同时输出到页面的隐藏字段中客户端提交Token用户提交登录请求时必须同时提交这个Token服务器验证Token服务器比对提交的Token与Session中的Token是否一致Token更新每次验证后服务器都会生成新的Token这样一来攻击者每尝试一个密码都必须先访问登录页面获取一个新的随机Token然后把这个Token塞进下一个请求中。传统的字典爆破工具无法直接处理这种动态Token。5.5 攻击方法使用Burp Suite绕过Token虽然Token机制增加了难度但Burp Suite的Intruder模块提供了绕过Token的能力。核心思路从服务器的响应包中提取最新的user_token将提取到的Token自动填入下一个请求包中如此循环实现自动化爆破详细步骤第一步抓取登录请求在DVWA的Brute Force页面输入任意用户名和密码用Burp Suite抓包。第二步发送到Intruder右键 →“Send to Intruder”。第三步配置爆破位置进入Intruder→Positions点击“Clear”清除所有标记为password参数添加变量标记为user_token参数添加变量标记攻击模式选择Pitchfork草叉因为需要将密码字典与动态Token一一对应第四步配置Payload进入Intruder→PayloadsPayload set 1密码加载密码字典Payload set 2Token选择“Recursive grep”类型第五步配置Token提取规则进入Intruder→Options→Grep - Extract点击“Add”在响应包中找到user_token的值配置正则表达式提取规则这样Burp Suite就会自动从每个响应中提取新的Token第六步配置资源池由于Token机制要求串行处理必须等上一个请求完成、获取新Token后才能发下一个请求需要进入Intruder→Resource pool创建新的资源池将最大并发数设为1第七步设置初始Token值在Payloads→Payload Options中将初始Token值填入“Initial payload for first request”。第八步开始爆破点击“Start Attack”等待爆破完成。第九步分析结果通过响应长度筛选出成功登录的请求。5.6 High级别总结防御机制作用绕过方法动态Token阻断传统字典爆破使用Burp Suite的Recursive grep自动提取Token输入过滤防御SQL注入对暴力破解影响不大延迟机制降低爆破速度通过串行处理并发数1应对六、Impossible级别终极防御方案6.1 安全级别设置将DVWA Security切换为Impossible级别。6.2 源码分析查看Impossible级别的核心代码?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 prebr /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 hasnt locked the account if( $timenow $timeout ) { $account_locked true; // print The account is lockedbr /; } } // 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 pWelcome 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 pemWarning/em: Someone might of been brute forcing your account./p; echo pNumber 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 prebr /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, emplease 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(); ?6.3 Impossible级别的防御体系Impossible级别构建了多层防御体系第一层账户锁定策略参数值说明$total_failed_login3连续输错3次密码账号即被冻结$lockout_time15锁定后必须等待15分钟才能再次尝试锁定逻辑服务器在每次登录前先查询failed_login计数如果失败次数 ≥ 3$account_locked设为true即使后来猜对了密码只要在锁定时间内登录依然失败第二层PDO预处理防SQL注入使用PDO预处理语句Prepared Statements$data $db-prepare( SELECT * FROM users WHERE user (:user) AND password (:password) LIMIT 1; );SQL指令模板和数据用户输入的用户名/密码是分开发送给数据库的。无论用户输入什么特殊字符如 OR 11 #都会被数据库严格当作普通字符串处理绝不会被执行。第三层Token验证保留了High级别的Token机制确保每个请求都必须携带有效的动态Token。6.4 Impossible级别能否被绕过理论上Impossible级别的防护已经非常完善账户锁定阻止了暴力破解的核心——大量尝试PDO预处理彻底杜绝了SQL注入Token机制防止了请求重放除非存在逻辑漏洞或其他漏洞配合如XSS配合CSRF否则单纯依靠暴力破解无法突破Impossible级别。七、防御暴力破解的最佳实践通过DVWA四个级别的对比我们可以总结出防御暴力破解的最佳实践7.1 必须实施的防御措施措施说明优先级账户锁定连续失败N次后锁定账户如3次/15分钟⭐⭐⭐⭐⭐验证码登录失败后或一定次数后要求输入验证码⭐⭐⭐⭐⭐强密码策略要求密码包含大小写字母、数字、特殊字符⭐⭐⭐⭐双因素认证2FA增加第二层验证短信、OTP等⭐⭐⭐⭐7.2 推荐的辅助措施措施说明优先级请求延迟登录失败后增加延迟如sleep⭐⭐⭐日志监控记录所有登录尝试异常时告警⭐⭐⭐IP黑名单对异常IP进行临时封禁⭐⭐⭐Token机制使用动态Token防止重放攻击⭐⭐⭐7.3 常见误区在实际开发中以下做法不能有效防御暴力破解❌仅使用sleep延迟只能降低速度不能阻断攻击❌仅使用输入过滤对暴力破解无效❌仅使用前端验证攻击者可以绕过前端直接发请求❌使用简单的验证码容易被OCR识别或打码平台破解八、总结本文围绕暴力破解漏洞展开完整学习我们先理清其依靠工具批量遍历账号密码组合猜解凭证的核心原理对比 Low 无防护、Medium 延时限制、High 增加 Token 校验、Impossible 融合账号锁定、PDO 预处理与 Token 三重防护四个等级的代码与防护迭代差异实操掌握 Burp Suite 针对不同安全等级的各类爆破绕过手段同时分清 Intruder 模块 Sniper、Battering ram、Pitchfork、Cluster bomb 四种攻击模式的适用场景并梳理出账号锁定、验证码、强密码、双因素认证等多层防御方案暴力破解属于入门级 Web 攻击却极易被忽略借助 DVWA 暴力破解模块我们兼顾攻击思路与防护逻辑生产环境中搭配账号锁定、验证码、强密码的多重防护策略可有效抵御大部分暴力破解行为。重要声明本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。如果这篇文章帮你解决了实操上的困惑别忘记点击点赞、分享也可以留言告诉我你遇到的其它问题我会尽快回复。你的关注是我坚持原创和细节共享的力量来源谢谢大家。