BurpSuite插件集成ddddocr实现自动化验证码识别与爆破测试

📅 2026/8/4 5:07:55 👁️ 阅读次数 📝 编程学习
BurpSuite插件集成ddddocr实现自动化验证码识别与爆破测试

1. 项目概述:当自动化渗透测试遇上图片验证码

在渗透测试或者安全研究的过程中,登录框、注册接口、找回密码这些地方常常是安全测试的重点。传统的暴力破解(Brute Force)或字典攻击,其核心逻辑就是自动化地、高速地尝试大量用户名和密码的组合。然而,现代Web应用为了抵御这种自动化攻击,普遍引入了验证码(CAPTCHA)机制,其中图片验证码(如扭曲的数字字母、简单的算术题、滑块拼图等)是最常见的一种。它要求用户识别并输入图片中的内容,这对于人类来说很简单,但对于自动化脚本来说,在很长一段时间内都是一个不小的障碍。

手动输入验证码?那意味着你的“自动化”攻击链条在这里断掉了,你得守在电脑前,每发起几次请求就手动敲几个字符,效率低下且毫无技术美感。这就像你开着一辆跑车上了高速公路,却每隔100米就得下车手动推开一个路障。我们的目标,就是拆掉这个路障,让自动化流程畅通无阻。

这就是“BurpSuite插件 + ddddocr”组合的价值所在。BurpSuite是安全测试人员必备的瑞士军刀,其强大的可扩展性允许我们通过插件(Extender)来增强功能。而ddddocr是一个基于深度学习的开源OCR(光学字符识别)库,以其对各类验证码,尤其是中文验证码的高识别率而闻名。将两者结合,我们就能在BurpSuite发起爆破(Intruder)攻击时,实时识别请求响应中的验证码图片,并将识别结果自动填入下一次攻击的请求中,从而实现全自动的、针对带图片验证码接口的爆破测试。

这套方案特别适合那些验证码复杂度不高、但确实构成了自动化测试瓶颈的场景。它不是什么“银弹”,无法破解所有验证码(特别是那些加入了强干扰、行为验证的),但对于很多实战中的“中低强度”验证码,它能显著提升测试效率。接下来,我将以一个完整的、保姆级的配置流程,带你从零开始搭建这个自动化攻击环境,并分享我在实际使用中踩过的坑和积累的技巧。

2. 环境准备与核心工具解析

工欲善其事,必先利其器。在开始动手之前,我们需要明确每个组件的角色和安装要点。这个方案的核心是三个部分:BurpSuite、Jython环境、以及我们的自定义插件。

2.1 BurpSuite与Jython环境搭建

BurpSuite本身是用Java编写的,它支持通过Jython(Java实现的Python)或JRuby来运行Python/Ruby编写的插件。ddddocr是一个Python库,因此我们必须为BurpSuite配置Jython环境,让它能调用Python解释器来执行我们的识别代码。

BurpSuite版本选择:社区版(Community)和专业版(Professional)都支持扩展。社区版对于学习和小规模测试完全足够。如果你需要进行高速、并发的Intruder攻击,专业版的Turbo Intruder等功能会更强大,但本教程的核心逻辑在社区版上同样可以运行。

Jython安装与配置

  1. 下载Jython独立Jar包:访问Jython官网,下载最新的jython-standalone-2.7.x.jar文件。不建议使用系统已安装的CPython,必须使用这个Jar包,因为它包含了完整的Python运行时,并能被Java程序直接调用。
  2. 在BurpSuite中配置:打开BurpSuite,进入Extender->Options标签页。在Python Environment部分,点击Select file...,选择你下载的jython-standalone-2.7.3.jar(版本号可能不同)文件。加载成功后,下方会显示Jython的版本信息。

注意:确保你下载的Jython版本是2.7.x。虽然Python 3是主流,但很多BurpSuite的Python插件生态仍基于2.7,且ddddocr的某些早期版本或安装方式在Jython 2.7下兼容性更好。这是第一个容易踩坑的点。

2.2 ddddocr库的识别原理与优势

为什么选择ddddocr而不是Tesseract或其他OCR引擎?这需要从验证码识别的特殊性说起。

传统的通用OCR(如Tesseract)是为扫描文档、印刷体文字设计的,它依赖于复杂的图像预处理(二值化、去噪、分割)和语言模型。而验证码的核心目的就是抵御机器识别,因此充满了噪声点、干扰线、字符粘连、扭曲、变色等对抗性设计。通用OCR面对这些“刻意破坏”的图像,效果往往很差。

ddddocr则走了另一条路:端到端的深度学习识别。它本质上是一个训练好的卷积神经网络(CNN)模型。你不需要关心图像的前期处理应该用哪种滤波算法,字符该如何分割。你只需要把原始的验证码图片(通常是RGB或灰度图)输入给这个模型,它就会直接输出它认为最可能的字符序列。

它的优势在于:

  • 高准确率:针对常见的数字、字母(尤其是中文)验证码,在测试中识别率常常能达到90%以上,对于清晰的验证码甚至接近100%。
  • 使用简单:几乎无需配置,几行代码即可调用。
  • 轻量级:模型文件相对不大,加载和识别速度很快,适合集成到需要快速响应的爆破流程中。

它的局限性在于:模型是固定的。如果遇到它训练数据中未充分覆盖的、特别复杂的字体或干扰方式(如极度扭曲、背景复杂、动态干扰线),识别率会下降。但对于大多数企业站、后台系统的验证码,它已经足够强大。

2.3 自定义BurpSuite插件的作用与设计思路

BurpSuite的Intruder模块在爆破时,可以处理Payload(攻击载荷),比如从字典中读取用户名密码。但它原生无法处理“根据上一个请求的响应,动态生成下一个请求的Payload”这种场景。验证码恰恰就是这种场景:你需要先请求一次,拿到一个包含新验证码图片的响应,识别出里面的文字,再将这个文字作为下一个登录请求的参数。

因此,我们需要一个插件来充当“中间人”和“大脑”。这个插件需要实现以下核心功能:

  1. 监听与拦截:监听BurpSuite的代理流量或特定的Intruder请求。
  2. 图像提取:从指定的HTTP响应中,提取出验证码图片的二进制数据。验证码可能以Base64编码形式嵌入在JSON/HTML中,也可能是一个直接的图片URL(如/captcha/image?t=123456789)。
  3. 调用识别引擎:将图片数据传递给ddddocr库进行识别。
  4. 动态修改请求:将识别出的验证码文本,填充到即将发出的HTTP请求的对应参数中(通常是captchacodeverify等字段)。

这个插件将作为一个IBurpExtenderIIntruderPayloadProcessor(入侵者载荷处理器)来开发。IIntruderPayloadProcessor接口允许我们在Intruder发送每个Payload(即每次爆破尝试)之前,动态修改请求数据,这正是我们实现自动化验证码填充的关键。

3. 保姆级插件开发与配置流程

理论清晰后,我们进入实战环节。我将一步步展示如何编写、加载和配置这个插件。请确保你已经完成了2.1节中的Jython环境配置。

3.1 插件代码编写与详解

创建一个新的Python文件,例如captcha_buster.py。以下是完整的代码,我将逐段进行解释。

# captcha_buster.py from burp import IBurpExtender, IIntruderPayloadProcessor import base64 import json import re import sys # 将ddddocr库的路径加入系统路径,确保可以导入 # 假设你的ddddocr库安装在 /path/to/your/ddddocr 或通过Jython的pip安装在了site-packages # 这里是一个通用示例,实际路径需要你根据情况修改 sys.path.append(‘/path/to/jython2.7.3/Lib/site-packages’) try: import ddddocr OCR_AVAILABLE = True except ImportError: print(“[!] 无法导入 ddddocr 库,请检查路径或安装。”) OCR_AVAILABLE = False class BurpExtender(IBurpExtender, IIntruderPayloadProcessor): def registerExtenderCallbacks(self, callbacks): self._callbacks = callbacks self._helpers = callbacks.getHelpers() callbacks.setExtensionName(“Auto Captcha Buster”) # 注册为 Intruder 的 Payload Processor callbacks.registerIntruderPayloadProcessor(self) print(“[+] Auto Captcha Buster 插件加载成功!”) if not OCR_AVAILABLE: print(“[!] 警告: ddddocr 库未加载,验证码识别功能将不可用。”) def getProcessorName(self): return “Auto Captcha Payload Processor” def processPayload(self, currentPayload, originalPayload, baseValue): """ 核心方法:在Intruder发送每个Payload前调用。 currentPayload: 当前将要被处理的Payload(字节数组) originalPayload: 原始的Payload模板(字节数组) baseValue: 基础值(通常用不到) 返回值:处理后的新Payload(字节数组) """ if not OCR_AVAILABLE: return currentPayload # 如果OCR不可用,直接返回原Payload # 1. 将字节数组的Payload转换为字符串,方便操作 payloadStr = self._helpers.bytesToString(currentPayload) # 2. 检查请求中是否包含获取验证码的请求标记(需要先手动发送一次获取验证码的请求,并为其添加标记) # 这里假设我们通过Burp的“Send to Intruder”功能,并且已经配置好。 # 更智能的做法是:插件自己记录上一次“获取验证码”请求的响应。 # 为了简化,我们采用一种“标记位”方法。 # 在实际请求中,我们寻找一个特殊的标记,例如 “@@CAPTCHA_IMAGE@@”, # 这个标记意味着“此处需要替换为最新识别出的验证码”。 # 但更常见的流程是:在Intruder的“Payload Processing”规则中调用本处理器。 # 我们这里实现一个简单逻辑:假设当前请求就是登录请求,我们需要从某个固定的“上一响应”中取验证码。 # **这需要你在使用前,先手动发送一次获取验证码的请求,并将其响应体(图片)保存到一个变量中。** # 以下是一个示例逻辑: # 假设我们有一个全局变量存储最新的验证码图片数据(Base64字符串) # 注意:这个变量需要在某个地方被更新,例如通过一个单独的“获取验证码”的Intruder攻击线程,或者手动触发。 # 这是一个简化示例,实际插件可能需要更复杂的状态管理。 if not hasattr(self, ‘latest_captcha_image_b64’): # 如果没有存储过验证码,直接返回 print(“[-] 未找到缓存的验证码图片。”) return currentPayload try: # 3. 调用OCR识别 ocr = ddddocr.DdddOcr(show_ad=False) # show_ad=False 关闭广告 image_bytes = base64.b64decode(self.latest_captcha_image_b64) captcha_text = ocr.classification(image_bytes) print(“[+] 识别验证码为: {}”.format(captcha_text)) # 4. 替换请求中的验证码参数 # 假设登录请求中,验证码参数名为 “captcha_code” # 使用正则表达式找到参数值并替换 # 例如,原始请求部分:...&captcha_code=old_value&... pattern = r’(captcha_code=)([^&]*)’ # 将匹配到的参数值替换为识别结果 new_payload_str = re.sub(pattern, r’\1’ + captcha_text, payloadStr) # 5. 返回处理后的Payload return self._helpers.stringToBytes(new_payload_str) except Exception as e: print(“[!] 验证码处理失败: {}”.format(str(e))) import traceback traceback.print_exc() return currentPayload # 出错时返回原Payload,避免中断攻击 # 需要一个方法来更新 latest_captcha_image_b64 # 这可以通过实现 IHttpListener 接口,监听流量,当发现获取验证码的响应时,自动更新。 # 由于代码复杂度,以下给出一个概念性方法: # def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo): # if not messageIsRequest: # # 是响应 # response = messageInfo.getResponse() # analyzedResponse = self._helpers.analyzeResponse(response) # headers = analyzedResponse.getHeaders() # # 判断是否是验证码图片响应 (通过URL或Content-Type) # for header in headers: # if ‘Content-Type’ in header and ‘image’ in header: # # 提取图片数据,转换为base64存储 # body = response[analyzedResponse.getBodyOffset():] # self.latest_captcha_image_b64 = base64.b64encode(body).decode(‘utf-8’) # print(“[+] 已更新验证码图片缓存。”) # break

代码关键点解析

  1. 路径问题(sys.path.append:这是最大的一个坑。Jython有自己独立的site-packages目录。你需要找到ddddocr实际被安装在哪里。一个可靠的方法是,在命令行使用Jython的pip进行安装:java -jar jython-standalone-2.7.3.jar -m pip install ddddocr。安装后,库文件通常位于jython-standalone-2.7.3.jar同目录下的Lib/site-packages中。你必须将这个绝对路径添加到sys.path
  2. 插件接口:类BurpExtender必须实现IBurpExtender(入口)和IIntruderPayloadProcessor(核心功能)。registerExtenderCallbacks是入口函数,用于注册扩展。
  3. processPayload方法:这是魔法发生的地方。Intruder在发送每个请求前,都会调用这个方法。我们在这里完成“识别验证码 -> 替换参数”的操作。
  4. 状态管理:示例代码中的latest_captcha_image_b64是一个简化状态。在真实场景中,验证码往往是一次性的,且需要与对应的会话(Session)绑定。更健壮的实现需要:
    • 实现IHttpListener接口,自动监听并捕获所有验证码图片响应。
    • 使用字典结构,以会话Cookie或用户ID为键,存储对应的最新验证码。
    • processPayload中,根据当前请求的会话信息,查找对应的验证码进行替换。
  5. 参数匹配:示例中使用正则表达式替换captcha_code参数。在实际应用中,验证码参数名可能是codeverifyCodevcode等,你需要根据目标网站的具体情况修改正则表达式,或者设计更灵活的配置方式。

3.2 插件的加载与初始化

  1. 将编写好的captcha_buster.py和安装好的 ddddocr 库(确保在sys.path指向的目录内)准备好。
  2. 打开BurpSuite,进入Extender->Extensions标签页。
  3. 点击Add按钮。
  4. Extension Type下拉菜单中选择Python
  5. Extension file中,选择你编写的captcha_buster.py文件。
  6. 点击Next,如果环境配置正确且代码无语法错误,下方输出框会显示[+] Auto Captcha Buster 插件加载成功!。如果看到导入ddddocr失败的错误,请反复检查sys.path的设置。

3.3 Intruder模块配置与联动

插件加载成功后,它只是一个“处理器”,还需要在Intruder攻击中正确配置才能生效。

标准操作流程如下

  1. 手动获取一次验证码:在浏览器或Burp的Repeater中,访问获取验证码的接口(例如GET /api/captcha)。在Burp的Proxy history中找到这个请求和响应。
  2. 分析验证码响应:查看该响应,确认其内容类型(Content-Type: image/pngimage/jpeg),并记住这个请求的特征(如URL路径)。
  3. 发送登录请求到Intruder:在Proxy history中找到你的登录请求(POST到/api/login),右键选择Send to Intruder
  4. 配置Intruder Positions:在Positions标签页,清除所有自动标记,手动标记出需要爆破的参数。通常你需要标记两个位置:username(或password)和captcha_code
    • username:设置为Payload set 1,类型为Simple list,加载你的用户名字典。
    • captcha_code这是关键。将其设置为Payload set 2,但类型选择Runtime file或者Extension-generated?不,这里我们换一种思路。
  5. 配置Payloads
    • 对于username(Payload 1):正常配置你的字典。
    • 对于captcha_code(Payload 2):这里不直接设置字典。因为验证码是动态的,我们需要让插件来填充。你可以将Payload set 2的类型设置为Null payloads(生成空值),或者设置一个无意义的初始值。真正的替换工作将由插件完成
  6. 配置Payload Processing:转到Options标签页,找到Payload Processing部分。点击Add->Invoke a Burp extension。在弹出的扩展列表中,你应该能看到我们刚加载的Auto Captcha Payload Processor。选中它并添加规则。
    • 重要:你需要确保插件能获取到最新的验证码。根据插件实现的不同,你可能需要:
      • 方案A(简单但半自动):在发起Intruder攻击前,手动在Repeater中获取一次验证码,并触发插件更新缓存(例如通过插件提供的自定义按钮或控制台命令)。然后快速启动Intruder。
      • 方案B(全自动,需要更复杂插件):插件实现了IHttpListener,能自动捕获Intruder攻击线程中发出的“获取验证码”请求(如果攻击配置里包含了这个请求)。这通常需要你将“获取验证码”和“提交登录”两个请求在Intruder中配置成PitchforkCluster bomb攻击模式,并确保两个请求在同一个会话中。这涉及到更复杂的Intruder配置和插件逻辑。

实操心得:对于初学者,我强烈建议从方案A开始。先让插件跑通“识别-替换”这个核心链路。你可以先手动获取一个验证码图片,将其Base64编码后硬编码到插件的latest_captcha_image_b64变量中,然后运行Intruder攻击单次请求,看登录请求中的验证码参数是否被成功替换为识别结果。这能帮你快速排除OCR识别和参数替换环节的问题。

4. 实战演练:针对一个示例登录接口的爆破

为了让你更清楚整个流程,我们假设一个目标:http://test.local/login,采用POST方式,参数为userpasscaptcha。验证码接口是http://test.local/captcha.jpg,每次访问返回一个新的JPEG图片。

我们的作战计划

  1. 编写增强版插件:我们需要一个能自动抓取验证码的插件。

    # captcha_buster_advanced.py from burp import IBurpExtender, IIntruderPayloadProcessor, IHttpListener import base64 import re import sys sys.path.append(‘你的Jython site-packages路径’) try: import ddddocr OCR_AVAILABLE = True except ImportError: OCR_AVAILABLE = False class BurpExtender(IBurpExtender, IIntruderPayloadProcessor, IHttpListener): def registerExtenderCallbacks(self, callbacks): self._callbacks = callbacks self._helpers = callbacks.getHelpers() self._callbacks.setExtensionName(“Advanced Captcha Buster”) self._callbacks.registerIntruderPayloadProcessor(self) self._callbacks.registerHttpListener(self) # 注册HTTP监听器 # 用于存储会话和验证码的映射,使用请求主机和会话ID作为键 self.captcha_store = {} print(“[+] Advanced Captcha Buster 加载成功!”) def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo): # 只处理来自Intruder工具的响应消息 if toolFlag == self._callbacks.TOOL_INTRUDER and not messageIsRequest: response = messageInfo.getResponse() if response is None: return analyzed = self._helpers.analyzeResponse(response) headers = analyzed.getHeaders() # 检查是否是图片响应,并且URL包含‘captcha’关键词(根据实际情况调整) url = self._helpers.analyzeRequest(messageInfo).getUrl() if ‘captcha’ in url.toString().lower(): # 检查Content-Type for h in headers: if h.lower().startswith(‘content-type:’) and ‘image’ in h.lower(): body = response[analyzed.getBodyOffset():] img_b64 = base64.b64encode(body).decode(‘utf-8’) # 生成一个简单的会话键,这里用请求主机+端口。更佳做法是提取Cookie。 host = url.getHost() port = url.getPort() session_key = “{}:{}”.format(host, port) self.captcha_store[session_key] = img_b64 print(“[+] 捕获并存储验证码图片,会话键: {}”.format(session_key)) break def getProcessorName(self): return “Advanced Captcha Processor” def processPayload(self, currentPayload, originalPayload, baseValue): if not OCR_AVAILABLE: return currentPayload # 获取当前请求的URL,用于查找对应的验证码 # 注意:processPayload中无法直接获取messageInfo,我们需要从原始Payload解析主机信息。 # 这是一个简化版,假设我们只处理一个目标。 payloadStr = self._helpers.bytesToString(currentPayload) # 从Payload中解析出Host头(这是一个粗略的方法) host_key = None for line in payloadStr.split(‘\r\n’): if line.lower().startswith(‘host:’): host = line.split(‘:’, 1)[1].strip() host_key = host # 简单用host做键 break if not host_key or host_key not in self.captcha_store: print(“[-] 未找到对应会话的验证码缓存。”) return currentPayload try: ocr = ddddocr.DdddOcr(show_ad=False) img_data = base64.b64decode(self.captcha_store[host_key]) captcha_text = ocr.classification(img_data) print(“[+] 识别验证码: {} -> {}”.format(host_key, captcha_text)) # 替换验证码参数,这里假设参数名是‘captcha’ # 使用更稳健的替换,考虑参数可能在URL中或Body中 # 这里简单处理Body中的POST参数 if ‘captcha=’ in payloadStr: # 使用正则替换body中的captcha参数值 # 注意:这个正则可能不适用于所有情况,需要根据实际请求格式调整 pattern = r’(captcha=)([^&]*)’ new_body = re.sub(pattern, r’\1’ + captcha_text, payloadStr) return self._helpers.stringToBytes(new_body) else: print(“[-] 请求中未找到captcha参数。”) return currentPayload except Exception as e: print(“[!] OCR处理异常: {}”.format(e)) return currentPayload

    这个增强版插件会监听所有来自Intruder的响应,如果发现URL包含captcha且内容是图片,就自动将其Base64编码存储起来,键值为目标主机。

  2. Intruder配置(Pitchfork模式)

    • 攻击类型:选择Pitchfork。它允许我们为每个位置设置独立的Payload集,并且会同步遍历这些集。这适合我们“一次获取验证码,紧接着使用该验证码登录”的场景。
    • Positions
      • 第一个Payload位置:标记captcha.jpg这个GET请求的URL?不,我们需要两个不同的请求。Pitchfork模式可以在一个攻击中处理多个请求模板。
      • 实际上,更常见的做法是:在Intruder的“Resource Pool”设置中,将线程数设为1,然后通过配置Payloads来顺序执行“获取验证码”和“提交登录”两个动作。但这超出了基础插件的范畴,通常需要配合宏(Macros)或者更复杂的插件逻辑。
    • 简化实战流程:对于这个增强版插件,我们可以采用一个“笨”但有效的方法:
      1. 在Intruder中,只配置登录请求(POST/login)。
      2. 在攻击开始前,先手动或通过Repeater连续访问几次captcha.jpg,让插件捕获并存储几个验证码图片(注意会话一致性,需保持相同Cookie)。
      3. 启动Intruder攻击(单线程)。插件会为每次登录请求,使用它最近一次捕获的对应会话的验证码图片进行识别和替换。
      4. 由于验证码通常一次有效,这种方式成功率取决于验证码的过期时间和你攻击的速度。如果验证码立即失效,则需要实现“每次登录前先获取一次验证码”的原子操作,这需要借助Burp的Session Handling RulesMacros功能,在每次Intruder请求前自动执行一个获取验证码的请求。
  3. 运行与观察:启动攻击后,观察Intruder的结果和插件的输出台(Extender ->Output)。你应该能看到[+] 捕获并存储验证码图片[+] 识别验证码: ...这样的信息。在Intruder的结果表中,查看请求和响应,确认验证码参数已被正确替换。

5. 常见问题、排查技巧与进阶优化

在实际操作中,你一定会遇到各种问题。下面是我总结的常见故障排查清单和进阶优化思路。

5.1 插件加载与依赖问题

问题现象可能原因解决方案
加载插件时报ImportError: No module named ddddocr1.sys.path指向错误。
2. ddddocr未安装在Jython环境中。
3. ddddocr依赖的某些原生库(如OpenCV)在Jython中不兼容。
1. 使用绝对路径,并通过在插件开头打印sys.pathsite.getsitepackages()来调试。
2. 使用java -jar jython-standalone-2.7.3.jar -m pip install ddddocr重新安装。
3. 尝试安装纯Python版本的OCR库,如pytesseract(需要系统安装Tesseract),但识别率可能不如ddddocr。
加载插件时无错误,但Intruder中看不到处理器插件未正确实现IIntruderPayloadProcessor接口或getProcessorName方法。检查类定义是否继承了IIntruderPayloadProcessor,并确保registerIntruderPayloadProcessor(self)被调用。getProcessorName方法必须返回一个字符串。
控制台打印了加载成功,但处理请求时无任何输出processPayload方法未被调用。检查Intruder的Payload Processing规则是否已添加并启用了该扩展处理器。确保该处理器被正确勾选。

5.2 验证码识别失败问题

问题现象可能原因解决方案
识别结果为空或完全错误1. 图片格式问题。ddddocr期望RGB或灰度图。
2. 验证码复杂度超出模型能力。
3. 图片数据在提取或解码过程中损坏。
1. 在调用classification前,可以尝试用PIL库(需安装Pillow for Jython)将图片统一转换为RGB模式:Image.open(io.BytesIO(image_bytes)).convert(‘RGB’)
2. 考虑对图片进行简单的预处理,如二值化、去噪(需安装numpy等库)。ddddocr内置了一定预处理能力,对于强干扰可能需额外处理。
3. 打印或保存接收到的Base64字符串的前100字符和图片字节长度,与原始响应对比,确保数据完整。
识别率忽高忽低验证码有多种变体(如数字、字母混合,加减法运算)。ddddocr有专门的DdddOcrSlide类。对于算术题,可能需要先识别字符,再解析算式计算结果。这需要定制代码逻辑。
特定字符识别差字体特殊或训练数据不足。考虑使用目标网站的大量验证码样本对ddddocr进行微调(fine-tuning),但这需要一定的机器学习知识和数据准备。

5.3 请求替换与流程问题

问题现象可能原因解决方案
验证码参数未被替换1. 正则表达式不匹配参数名。
2. 参数在请求中的位置(URL查询参数 vs. POST Body)与代码处理逻辑不符。
3. 插件中的latest_captcha_image_b64未更新。
1. 在插件中打印payloadStr,确认参数名和请求格式。使用更通用的正则,如r’(captcha[^=]*=)([^&]*)’
2. 分别处理请求行(URL)和请求体。使用self._helpers.analyzeRequest来解析请求会更可靠。
3. 实现IHttpListener并添加调试输出,确保捕获验证码响应的逻辑被触发。
“验证码已过期”或“验证码错误”1. 验证码一次有效,被重复使用。
2. 会话不匹配。获取验证码的请求和登录请求使用的Cookie或Session ID不同。
1. 实现“一次一码”机制:确保每次登录请求前,都先执行一次获取验证码的请求。这需要结合Burp的Session Handling RulesMacros
2. 在插件中,以更精确的会话标识(如Cookie中的JSESSIONID值)作为captcha_store的键,而不是简单的host。
Intruder攻击速度慢每个Payload都要进行OCR识别,OCR是计算密集型操作。1. 在插件中初始化OCR对象 (self.ocr = ddddocr.DdddOcr()) 放在registerExtenderCallbacks中,避免每次识别都重新加载模型。
2. 考虑对同一验证码进行缓存,避免同一张图识别多次(如果攻击重试)。
3. 降低Intruder的线程数,避免资源竞争。

5.4 进阶优化与安全测试考量

  1. 集成Session Handling:这是实现全自动化的关键。在Burp的Project options->Sessions中,可以创建规则。你可以创建一个宏(Macro),包含两个动作:第一个是“获取验证码”请求,第二个是“登录”请求(其中验证码参数用一个自定义参数如§captcha§标记)。然后配置规则,在每次Intruder请求前运行这个宏,并将宏响应中验证码图片的内容提取出来,赋值给§captcha§参数。这样,Intruder只需要负责迭代用户名密码字典,验证码的获取和填充完全由Session规则自动完成。我们的插件则可以集成到这个流程中,作为处理验证码图片、返回识别文本的一个“自定义参数处理器”。

  2. 错误重试与熔断:在插件代码中加入重试逻辑。如果一次识别失败(返回空或明显无效字符),可以尝试重新获取验证码并识别,连续失败N次后暂停攻击,避免因识别失败导致账号被锁。

  3. 验证码类型判断:不是所有图片响应都是验证码。可以通过URL模式、响应头Content-Type、响应大小(验证码图片通常较小)等多重条件来精确过滤,避免误处理。

  4. 伦理与法律边界:这套技术仅用于授权测试。在未获得明确书面授权的情况下,对任何系统进行暴力破解或自动化攻击都是非法的。即使在授权范围内,也应谨慎控制攻击速率,避免对目标系统造成拒绝服务(DoS)影响。

这套“BurpSuite插件+ddddocr”的方案,将看似棘手的图片验证码问题,转化为了一个可工程化解决的自动化环节。它可能不是百分百完美,但能为你打开一扇门,让你在安全测试的效率和深度上迈进一大步。真正的挑战往往不在于工具本身,而在于如何根据目标系统的具体行为(会话管理、验证码失效策略、风控机制)来灵活调整和组合你的工具链。多思考,多调试,你总能找到那条通往目标的自动化路径。