Insecure CAPTCHA 不安全验证码:全等级绕过与 Burp 逻辑重放实操

📅 2026/7/18 16:53:14 👁️ 阅读次数 📝 编程学习
Insecure CAPTCHA 不安全验证码:全等级绕过与 Burp 逻辑重放实操

Insecure CAPTCHA 不安全验证码:全等级绕过与 Burp 逻辑重放实操

    • 前言
    • 1. 不安全验证码漏洞核心理论基础
      • 1.1 什么是 CAPTCHA 验证码
      • 1.2 不安全验证码漏洞本质
      • 1.3 验证码漏洞的常见类型
      • 1.4 漏洞危害
      • 1.5 DVWA Insecure CAPTCHA 模块说明
    • 2. DVWA Insecure CAPTCHA 模块(Low)
      • 2.1 首先抓请求包
      • 2.2 将数据包发送到Repeater
      • 2.3 源码分析
        • 2.3.1 整体逻辑拆分
        • 2.3.2 step=1 分支完整流程
        • 2.3.3 step=2 分支完整流程
    • 3. DVWA Insecure CAPTCHA 模块(Medium)
      • 3.1 使用Low级别的攻击方案尝试
      • 3.2 源码分析
      • 3.3 攻击实现
      • 3.4 攻击总结
    • 4. DVWA Insecure CAPTCHA 模块(High)
      • 4.1 纯黑盒测试的巨大难点
      • 4.2 High 级别源码完整分析
        • 4.2.1 整体逻辑改动
        • 4.2.2 验证码校验核心判断(漏洞关键)
      • 4.3 完整攻击利用步骤
      • 4.4 攻击总结
    • 5. DVWA Insecure CAPTCHA 模块(Impossible)
      • 5.1 安全等级说明
      • 5.2 多层安全防护源码分析
        • 5.2.1 CSRF 令牌校验(前置拦截)
        • 5.2.2 输入数据多层过滤与转义
        • 5.2.3 验证码校验逻辑(无后门、无绕过通道)
        • 5.2.4 原始密码校验(身份二次鉴权)
        • 5.2.5 数据库更新逻辑
      • 5.3 完整防护逻辑流程
      • 5.4 四级安全层级完整对比
    • 免责声明

前言

在上一篇文章中,我们完整完成了 DVWA Brute Force 暴力破解模块全难度实操,熟练掌握了 Burp Suite 抓包、请求重放、Intruder 爆破模块的基础与进阶用法,理解了无防护登录接口存在的账号爆破风险。

正常场景下,网站会引入验证码机制抵御暴力猜解,阻挡批量重复请求。但很多开发者仅简单实现验证码,校验逻辑存在严重缺陷:只做前端校验、后端未核验验证码有效性、会话未销毁旧验证码等,导致验证码防护形同虚设。

本文承接前文 Burp 操作基础,针对 DVWA Insecure CAPTCHA 不安全验证码模块,逐层审计 Low/Medium/High 三级源码,演示不同层级验证码绕过思路,区分前端校验漏洞与会话复用逻辑漏洞,对比 Impossible 安全防护方案,帮你吃透验证码类 Web 逻辑漏洞的挖掘与修复思路。

📌 免责声明:本文仅用于网络安全学习与教学演示,所有实验均在本地搭建的授权靶场中进行。请勿将文中技术用于任何未授权的系统测试,违者自行承担相应法律责任。


1. 不安全验证码漏洞核心理论基础

1.1 什么是 CAPTCHA 验证码

CAPTCHA(全自动区分计算机和人类的图灵测试)的设计初衷是区分操作发起者是真人还是自动化脚本,防止机器人批量注册、暴力破解、刷票、爬虫等恶意行为。

常见形式:图形字符验证码、滑动拼图验证码、短信/邮箱验证码、Google reCAPTCHA、极验行为验证码等。


1.2 不安全验证码漏洞本质

验证码的安全核心在于:校验逻辑必须和业务操作强绑定,且校验结果不可被客户端篡改

如果开发者把验证码校验拆成多步、把校验结果放在客户端可控的参数里、或者校验通过后没有和后续业务操作强绑定,就会出现不安全验证码漏洞——攻击者可以绕过验证码校验,直接执行敏感操作。

一句话总结:验证码形同虚设,自动化脚本可以直接绕过,防护完全失效。


1.3 验证码漏洞的常见类型

漏洞类型原理说明
客户端校验绕过验证码只在前端JS校验,后端不校验,直接抓包跳过前端即可绕过
校验结果可控验证码是否通过由客户端参数控制(如step参数、passed_captcha标志位),篡改参数直接绕过
验证码复用同一个验证码可以反复使用,不失效、不刷新,抓一次包用无限次
验证码可预测验证码生成算法有规律,可被预测或枚举爆破
多步校验逻辑缺陷验证码校验和业务操作拆成两步,第一步过验证码,第二步直接改参数跳业务逻辑
验证码可识别图形验证码过于简单,可被OCR工具/机器学习模型自动识别

1.4 漏洞危害

  • 暴力破解账号密码:不受验证码限制,无限次尝试登录密码
  • 批量注册垃圾账号:机器人批量注册,用于刷量、发广告、薅羊毛
  • 短信/邮件轰炸:无限次发送验证码,消耗服务商资源,骚扰用户
  • 刷票刷量:自动化脚本批量投票、刷评论、刷积分、刷关注
  • 直接执行敏感操作:绕过验证码直接改密、转账、删除数据等高危操作

1.5 DVWA Insecure CAPTCHA 模块说明

DVWA 的 Insecure CAPTCHA 模块以「修改密码」业务场景为载体,模拟了 Google reCAPTCHA 验证码的多步校验逻辑。

四个安全等级分别演示了不同程度的验证码设计缺陷:

  • Low:客户端参数完全可控,直接修改 step 参数绕过
  • Medium:校验逻辑存在缺陷,可被伪造绕过
  • High:校验和业务绑定不严谨,存在可利用的绕过通道
  • Impossible:完整正确的验证码校验逻辑,无绕过空间

接下来从 Low 级别开始,逐级抓包复现、源码审计,完整拆解验证码漏洞的利用与防御。


2. DVWA Insecure CAPTCHA 模块(Low)

2.1 首先抓请求包

开启 Burp Suite 拦截功能,页面输入新密码与确认密码(示例:123),点击Change提交表单,捕获 POST 原始请求。
观察请求参数可发现隐藏控制参数step=1,该参数用于区分业务流程阶段。

渗透测试通用测试思路:页面出现stepstage这类分段流程参数时,直接修改参数数值遍历测试:

  1. step=0:无对应业务逻辑,页面重置;
  2. step=1:进入验证码校验流程,强制校验人机验证;
  3. step=2:直接执行密码修改逻辑,不存在验证码校验环节。

2.2 将数据包发送到Repeater

将捕获的原始请求发送至 Repeater 模块,修改请求参数:把step=1替换为step=2,其余密码参数保持不变。

可以看到这里已经成功了,回到Proxy将step改成2,然后点击Forward,将数据包发送过去

此时可以看见密码修改成功

2.3 源码分析

此处我们贴出源码

Unknown Vulnerability Source vulnerabilities/captcha/source/low.php<?phpif(isset($_POST['Change'])&&($_POST['step']=='1')){// Hide the CAPTCHA form$hide_form=true;// Get input$pass_new=$_POST['password_new'];$pass_conf=$_POST['password_conf'];// Check CAPTCHA from 3rd party$resp=recaptcha_check_answer($_DVWA['recaptcha_private_key'],$_POST['g-recaptcha-response']);// Did the CAPTCHA fail?if(!$resp){// What happens when the CAPTCHA was entered incorrectly$html.="<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";$hide_form=false;return;}else{// CAPTCHA was correct. Do both new passwords match?if($pass_new==$pass_conf){// Show next stage for the userecho" <pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre> <form action=\"#\" method=\"POST\"> <input type=\"hidden\" name=\"step\" value=\"2\" /> <input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" /> <input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" /> <input type=\"submit\" name=\"Change\" value=\"Change\" /> </form>";}else{// Both new passwords do not match.$html.="<pre>Both passwords must match.</pre>";$hide_form=false;}}}if(isset($_POST['Change'])&&($_POST['step']=='2')){// Hide the CAPTCHA form$hide_form=true;// Get input$pass_new=$_POST['password_new'];$pass_conf=$_POST['password_conf'];// Check to see if both password matchif($pass_new==$pass_conf){// They do!$pass_new=((isset($GLOBALS["___mysqli_ston"])&&is_object($GLOBALS["___mysqli_ston"]))?mysqli_real_escape_string($GLOBALS["___mysqli_ston"],$pass_new):((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.",E_USER_ERROR))?"":""));$pass_new=md5($pass_new);// Update database$insert="UPDATE `users` SET password = '$pass_new' WHERE user = '".dvwaCurrentUser()."';";$result=mysqli_query($GLOBALS["___mysqli_ston"],$insert)ordie('<pre>'.((is_object($GLOBALS["___mysqli_ston"]))?mysqli_error($GLOBALS["___mysqli_ston"]):(($___mysqli_res=mysqli_connect_error())?$___mysqli_res:false)).'</pre>');// Feedback for the end userecho"<pre>Password Changed.</pre>";}else{// Issue with the passwords matchingecho"<pre>Passwords did not match.</pre>";$hide_form=false;}((is_null($___mysqli_res=mysqli_close($GLOBALS["___mysqli_ston"])))?false:$___mysqli_res);}?>
2.3.1 整体逻辑拆分

代码分为两个独立互不依赖的if判断分支,依靠客户端传入的step参数区分业务流程:

  1. step == 1:验证码校验阶段
  2. step == 2:密码修改阶段

两段代码是并列关系,不存在先后锁死、会话标记校验,服务端完全不记录用户是否完成验证码验证,仅靠前端传参决定走哪段逻辑,这是漏洞根源。


2.3.2 step=1 分支完整流程
  1. 接收password_newpassword_conf、谷歌验证码返回值g-recaptcha-response
  2. 调用第三方谷歌接口校验验证码合法性;
  3. 验证码校验失败:直接输出验证码错误提示,返回页面,终止流程;
  4. 验证码校验成功,且两次新密码一致:
    页面输出一段隐藏表单,表单内置step=2、新旧密码,提供按钮提交,进入下一阶段;
  5. 验证码正确但两次密码不一致:返回密码不匹配提示,停留在验证码页面。

关键点:
只有正常通过验证码校验,页面才会生成携带step=2的表单,正常访问谷歌的环境下能抓到step=2请求;国内网络无法连通谷歌验证接口,验证码校验直接失败,永远不会渲染该表单。


2.3.3 step=2 分支完整流程

该分支无任何验证码相关校验代码,执行逻辑:

  1. 接收前端传入的password_newpassword_conf
  2. 仅判断两次输入的新密码是否相同;
  3. 密码一致:对密码做转义 + MD5 加密,执行 SQL 更新语句,修改当前登录用户数据库密码,输出Password Changed.
  4. 密码不一致:返回密码不匹配提示。

致命缺陷:
程序没有设置 Session 标记记录 “用户已完成验证码校验”,攻击者可直接构造step=2的 POST 请求,跳过整个验证码校验流程,直接执行改密操作。


3. DVWA Insecure CAPTCHA 模块(Medium)

3.1 使用Low级别的攻击方案尝试

开启 Burp 拦截捕获原始提交数据包,依旧尝试将step=1修改为step=2直接发包,发现无法成功绕过。
Low 级别的单纯修改流程参数的攻击手段失效,必须结合源码审计寻找新增校验逻辑。

3.2 源码分析

对比 Low 源码,Medium 在step=2分支新增了客户端参数校验逻辑:
服务端会读取 POST 参数passed_captcha,仅当该参数值为true时,才允许执行密码更新操作。
正常流程中,验证码校验通过后页面才会自动生成携带passed_captcha=true的隐藏表单;若手动构造step=2请求却缺少该参数,后端会直接拦截改密操作。

3.3 攻击实现

  1. 将原始请求发送至 Burp Repeater,修改核心参数:step=1step=2
  2. 在请求末尾追加校验标识参数:passed_captcha=true


3. 完整 Payload:

step=2&password_new=1111&password_conf=1111&Change=Change&passed_captcha=true


  1. 发送构造完成的请求,页面返回Password Changed.,漏洞利用成功

3.4 攻击总结

漏洞成因

  1. 服务端仅校验前端传入的passed_captcha参数,未使用 Session 在服务端存储验证码校验状态
  2. 校验标记完全由客户端可控,攻击者可手动添加该参数伪造 “已完成验证码验证” 的状态;
  3. 分段流程参数step依旧无服务端状态锁,仅增加一层前端参数校验,防护存在缺陷。

4. DVWA Insecure CAPTCHA 模块(High)

4.1 纯黑盒测试的巨大难点

  1. Low、Medium 两种经典绕过手段全部失效
    • 仅修改step=2发包:本层级代码已完全移除 step 分段逻辑,不存在两段独立业务分支,该方法彻底无效;
    • 追加passed_captcha=true参数:代码中无任何该参数的校验逻辑,添加后无任何作用;
    • 随意篡改、删除验证码参数:后端直接判定验证码错误,拦截改密操作。
  2. 隐藏后门校验条件无任何前端线索
    漏洞核心是后端内置了一组特殊的绕过判定,该逻辑完全写在服务端代码内,页面、请求、响应均无任何提示,纯黑盒依靠抓包试错几乎不可能猜到。

4.2 High 级别源码完整分析

4.2.1 整体逻辑改动

与 Low/Medium 最大区别:取消 step 分段流程,所有操作合并为单段代码,不再分两次提交表单,统一在一次请求内完成验证码校验 + 密码修改。

4.2.2 验证码校验核心判断(漏洞关键)
if($resp||($_POST['g-recaptcha-response']=='hidd3n_valu3'&&$_SERVER['HTTP_USER_AGENT']=='reCAPTCHA')){// 校验通过,执行改密码逻辑}

校验逻辑为「或」关系,满足任意一个条件即可放行:

  1. 正常条件$resp:谷歌验证码接口返回验证成功;
  2. 隐藏后门条件:
    • POST 参数g-recaptcha-response值固定为hidd3n_valu3
    • 请求头User-Agent固定为reCAPTCHA

只要同时满足以上两个头部 + 参数条件,后端直接判定验证码合法,无需真实人机验证。


4.3 完整攻击利用步骤

  1. 抓取原始提交数据包,原始请求携带正常表单参数;
  2. 修改两处关键内容:
    • POST 参数新增 / 修改:g-recaptcha-response=hidd3n_valu3
    • 请求头User-Agent修改为:reCAPTCHA
  3. 完整请求参数示例:
    step=2&password_new=1111&password_conf=1111&user_token=65189ca59a58a9b887f22fd50ce84a0b&Change=Change&g-recaptcha-response=hidd3n_valu3

  1. 发送构造后的请求,页面返回Password Changed.,绕过验证码成功。


4.4 攻击总结

漏洞成因

  1. 开发者在后端内置硬编码后门,预留固定参数 + 请求头组合绕过验证码校验;
  2. 后门判断使用逻辑或||,与正常验证码校验并列,无需真实人机验证即可放行;
  3. 后门条件无任何前端提示,黑盒测试极难发现,仅源码审计可快速定位。

5. DVWA Insecure CAPTCHA 模块(Impossible)

此处我们贴出源码

<?phpif(isset($_POST['Change'])){// Check Anti-CSRF tokencheckToken($_REQUEST['user_token'],$_SESSION['session_token'],'index.php');// Hide the CAPTCHA form$hide_form=true;// Get input$pass_new=$_POST['password_new'];$pass_new=stripslashes($pass_new);$pass_new=((isset($GLOBALS["___mysqli_ston"])&&is_object($GLOBALS["___mysqli_ston"]))?mysqli_real_escape_string($GLOBALS["___mysqli_ston"],$pass_new):((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.",E_USER_ERROR))?"":""));$pass_new=md5($pass_new);$pass_conf=$_POST['password_conf'];$pass_conf=stripslashes($pass_conf);$pass_conf=((isset($GLOBALS["___mysqli_ston"])&&is_object($GLOBALS["___mysqli_ston"]))?mysqli_real_escape_string($GLOBALS["___mysqli_ston"],$pass_conf):((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.",E_USER_ERROR))?"":""));$pass_conf=md5($pass_conf);$pass_curr=$_POST['password_current'];$pass_curr=stripslashes($pass_curr);$pass_curr=((isset($GLOBALS["___mysqli_ston"])&&is_object($GLOBALS["___mysqli_ston"]))?mysqli_real_escape_string($GLOBALS["___mysqli_ston"],$pass_curr):((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.",E_USER_ERROR))?"":""));$pass_curr=md5($pass_curr);// Check CAPTCHA from 3rd party$resp=recaptcha_check_answer($_DVWA['recaptcha_private_key'],$_POST['g-recaptcha-response']);// Did the CAPTCHA fail?if(!$resp){// What happens when the CAPTCHA was entered incorrectlyecho"<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";$hide_form=false;}else{// Check that the current password is correct$data=$db->prepare('SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;');$data->bindParam(':user',dvwaCurrentUser(),PDO::PARAM_STR);$data->bindParam(':password',$pass_curr,PDO::PARAM_STR);$data->execute();// Do both new password match and was the current password correct?if(($pass_new==$pass_conf)&&($data->rowCount()==1)){// Update the database$data=$db->prepare('UPDATE users SET password = (:password) WHERE user = (:user);');$data->bindParam(':password',$pass_new,PDO::PARAM_STR);$data->bindParam(':user',dvwaCurrentUser(),PDO::PARAM_STR);$data->execute();// Feedback for the end user - success!echo"<pre>Password Changed.</pre>";}else{// Feedback for the end user - failed!echo"<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>";$hide_form=false;}}}// Generate Anti-CSRF tokengenerateSessionToken();?>

5.1 安全等级说明

Impossible 为最高安全防护层级,整合多层防护机制,不存在可绕过验证码的漏洞,无法通过篡改参数、修改请求头、复用会话等方式绕过校验。纯黑盒测试无任何可利用入口,直接结合源码分层拆解安全防护逻辑。


5.2 多层安全防护源码分析

5.2.1 CSRF 令牌校验(前置拦截)
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
  1. 每次提交表单必须携带服务端会话生成的一次性user_token
  2. Token 存储在服务端 Session,每次页面刷新会重新生成;
  3. 无 Token、Token 篡改、Token 过期均会直接拦截请求,杜绝批量重放、跨站伪造请求攻击。

5.2.2 输入数据多层过滤与转义

对当前密码、新密码、确认密码统一做安全处理:

  1. stripslashes():清除输入中的转义反斜杠;
  2. mysqli_real_escape_string():特殊字符数据库转义,防SQL注入;
  3. md5():密码统一哈希加密,不存储明文;
    所有用户可控输入均做净化,避免注入类漏洞。

5.2.3 验证码校验逻辑(无后门、无绕过通道)
$resp=recaptcha_check_answer($_DVWA['recaptcha_private_key'],$_POST['g-recaptcha-response']);if(!$resp){echo"<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";$hide_form=false;}

仅保留唯一合法校验通道:必须调用谷歌 reCAPTCHA 第三方接口验证人机结果,移除了High级别的硬编码后门,不存在自定义参数、UA伪造绕过的逻辑分支。验证码校验失败直接终止业务流程。


5.2.4 原始密码校验(身份二次鉴权)
$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
  1. 采用PDO预编译SQL语句,参数绑定,彻底杜绝SQL注入;
  2. 修改密码前强制校验当前登录账号的旧密码,仅当旧密码哈希匹配数据库记录时,才允许执行改密操作;
  3. 双重条件放行:新密码一致 + 旧密码正确,任意一项不满足直接返回失败提示。

5.2.5 数据库更新逻辑

同样使用PDO预编译语句执行UPDATE更新,全程参数绑定,无字符串拼接漏洞,数据库操作安全可控。


5.3 完整防护逻辑流程

  1. 接收POST请求 → 校验一次性CSRF Token,非法Token直接拦截;
  2. 清洗、加密全部密码输入参数;
  3. 调用谷歌接口校验验证码,验证码错误直接返回页面;
  4. 验证码合法后,查询数据库校验用户输入的旧密码是否匹配;
  5. 同时满足「新旧两次密码一致」「旧密码校验通过」两个条件,才执行密码更新;
  6. 页面刷新生成全新Session Token,销毁旧令牌。

5.4 四级安全层级完整对比

等级核心漏洞绕过方式防护短板
Low分段step完全可控,无验证码校验抓包修改step=2无任何服务端校验逻辑
Mediumstep分段+前端参数标记校验step=2 & passed_captcha=true校验凭证存于客户端,可伪造
High内置硬编码后门绕过验证码UA:reCAPTCHA + g-recaptcha-response=hidd3n_valu3后端预留明文后门判断
Impossible无可用漏洞不存在有效绕过手段多层安全机制闭环防护

免责声明

  1. 本文所有内容仅用于网络安全技术研究与教学演示,所有测试均在本地授权搭建的 DVWA 靶场环境中进行,旨在帮助读者理解漏洞原理与防御机制。
  2. 请勿将本文涉及的技术与方法用于任何未经授权的真实系统测试。任何利用本文内容进行的非法攻击行为,均与作者无关,由使用者自行承担相应法律责任。
  3. 网络安全学习请严格遵守《中华人民共和国网络安全法》及相关法律法规,仅在获得明确书面授权的前提下开展安全测试。