验证码不寻常对抗系列1: 双重验证的破解之法

admin 2024年3月11日07:48:50评论22 views字数 4040阅读13分28秒阅读模式

验证码不寻常对抗系列1: 双重验证的破解之法

前言

若阁下问我此文意欲何为?答曰: 记录下日常渗透中遇到一些特殊验证码绕过Cases并集成一个系列发布到公众号作分享,同时,非常欢迎师傅找我进行与验证码绕过相关的技术交流。

验证码场景分析

某天偶遇一套比较小众的业务网关系统,看到验证码那么简单,反手一波逻辑小漏洞无果(后端判断验证码参数不能为空且会对已使用验证码注销,即无法重用)

验证码不寻常对抗系列1:   双重验证的破解之法

验证码请求和验证逻辑是非常明确的。

第一步/xxx/captcha接口生成验证码,返回两个参数idcaptcha, 其中id是验证码的标识,captcha是验证码的图片二进制Base64

验证码不寻常对抗系列1:   双重验证的破解之法

第二步/xxx/login验证登录逻辑,captchaIdcaptcha需要同时验证两个参数,并且captchaId来源于上一个请求包。

验证码不寻常对抗系列1:   双重验证的破解之法

绕过思路

利用: captcha-killer-modified 项目进行绕过

https://github.com/f0ng/captcha-killer-modified/releases/tag/0.24.4

1.将请求包发送到 captcha panel

验证码不寻常对抗系列1:   双重验证的破解之法

点击获取程序会自动识别出验证码说明提取成功

验证码不寻常对抗系列1:   双重验证的破解之法

接下来我们利用响应提取功能: "id":"(.*?)" 正则匹配id即可获取到标识:@captcha-killer-modified@

验证码不寻常对抗系列1:   双重验证的破解之法

2.配置验证码结果

由于这个验证码比较简单,利用ddocr库就可以实现99%的识别率, 作者提供的codereg脚本在PY3存在问题,自己改了下。

requirements.txt

 1aiohttp==3.8.3
 2aiosignal==1.3.1
 3async-timeout==4.0.3
 4attrs==23.2.0
 5certifi==2024.2.2
 6charset-normalizer==2.1.1
 7coloredlogs==15.0.1
 8ddddocr==1.4.11
 9flatbuffers==23.5.26
10frozenlist==1.4.1
11humanfriendly==10.0
12idna==3.6
13mpmath==1.3.0
14multidict==6.0.5
15numpy==1.26.4
16onnxruntime==1.17.1
17opencv-python-headless==4.9.0.80
18packaging==23.2
19Pillow==9.5.0
20protobuf==4.25.3
21requests==2.31.0
22sympy==1.12
23urllib3==2.2.1
24yarl==1.9.4

codereg.py

 1# -*- coding:utf-8 -*-
 2# author:f0ngf0ng
 3# @Date: 2022/3/11 下午1:44
 4import argparse
 5import ddddocr  # 导入 ddddocr
 6from aiohttp import web
 7import base64
 8
 9print(
10    "欢迎使用captcha-killer-modified服务端脚本,项目地址:https://github.com/f0ng/captcha-killer-modifiedn谷歌reCaptcha验证码 / hCaptcha验证码 / funCaptcha验证码商业级识别接口:https://yescaptcha.com/i/bmHz3Cnn")
11parser = argparse.ArgumentParser()
12
13parser.add_argument("-p", help="http port", default="8888")
14args = parser.parse_args()
15ocr = ddddocr.DdddOcr()
16port = int(args.p)
17
18auth_base64 = "f0ngauth"  # 可自定义auth认证
19
20
21# 识别常规验证码
22async def handle_cb2(request):
23    if request.headers.get('Authorization') != 'Basic ' + auth_base64:
24        return web.Response(text='Forbidden', status='403')
25    # print(await request.text())
26    img_base64 = await request.text()
27    img_bytes = base64.b64decode(img_base64)
28    # return web.Response(text=ocr.classification(img_bytes)[0:4]) 验证码取前四位
29    # return web.Response(text=ocr.classification(img_bytes)[0:4].replace("0","o")) 验证码取前四位、验证码中的0替换为o
30    res = ocr.classification(img_bytes)
31    print(res)
32
33    return web.Response(text=ocr.classification(img_bytes)[0:10])
34
35
36# 识别算术验证码
37async def handle_cb(request):
38    zhi = ""
39    if request.headers.get('Authorization') != 'Basic ' + auth_base64:
40        return web.Response(text='Forbidden', status='403')
41    # print(await request.text())
42    img_base64 = await request.text()
43    img_bytes = base64.b64decode(img_base64)
44    res = ocr.classification(img_bytes).replace("=", "").replace("?", "")
45    print(res)
46    if '+' in res:
47        zhi = int(res.split('+')[0]) + int(res.split('+')[1][:-1])
48        print(zhi)
49        return web.Response(text=str(zhi))
50    elif '-' in res:
51        zhi = int(res.split('-')[0]) - int(res.split('-')[1][:-1])
52        print(zhi)
53        return web.Response(text=str(zhi))
54    elif '*' in res:
55        zhi = int(res.split('*')[0]) * int(res.split('*')[1][:-1])
56        print(zhi)
57        return web.Response(text=str(zhi))
58    elif 'x' in res:
59        zhi = int(res.split('x')[0]) * int(res.split('x')[1][:-1])
60        print(zhi)
61        return web.Response(text=str(zhi))
62    elif '/' in res:
63        zhi = int(res.split('/')[0]) / int(res.split('/')[1][:-1])
64        return web.Response(text=str(zhi))
65    else:
66        return web.Response(text=res)
67
68
69app = web.Application()
70app.add_routes([
71    web.post('/reg2', handle_cb),  # 识别算数验证码
72    web.post('/reg', handle_cb2),  # 识别常规验证码
73])
74
75if __name__ == '__main__':
76    web.run_app(app, port=port)

安装执行

1# 安装项目依赖
2pip3 install -r requirement.txt
3# 直接执行
4python3 codereg.py -p 10010
验证码不寻常对抗系列1:   双重验证的破解之法

3.配置验证码识别接口

导入模版库

验证码不寻常对抗系列1:   双重验证的破解之法

修改模版为你正在运行的接口,可以配置Basic认证,但本地用不用考虑这些。

验证码不寻常对抗系列1:   双重验证的破解之法

点击识别,如果出现正确识别结果,说明成功。

验证码不寻常对抗系列1:   双重验证的破解之法

可以看到成功率很高。

灵活运用识别结果

1.在重放器Reapeater使用

@captcha-killer-modified@ -> 对应验证码的标识即正则从相应包提取的结果

@captcha@ -> 对应验证码识别的结果

1username=admin&password=admin&captchaId=@captcha-killer-modified@&captcha=@captcha@

你可以多重放几次,看看有没有提示验证码错误,完全没有问题。

验证码不寻常对抗系列1:   双重验证的破解之法

当然你也可以在Logger++看到请求最终发送的值。

验证码不寻常对抗系列1:   双重验证的破解之法

2.在Intruder中进行爆破

无论在哪里使用如果需要用到识别和提取结果,都需要勾选是使用该插件,否则没办法hook关键字替换。

验证码不寻常对抗系列1:   双重验证的破解之法

配置集束模式同时爆破用户名和密码

验证码不寻常对抗系列1:   双重验证的破解之法

调整速率为1并发,防止过快,导致请求出错。

验证码不寻常对抗系列1:   双重验证的破解之法

配置用户名字典

1admin
2test

配置密码字典

1admin
2test
3123456
4111111
5admin@123
6admin@111
7admin888

这样设置尝试14个请求,只有一个验证码出错,效果还算可以。

验证码不寻常对抗系列1:   双重验证的破解之法

一些问题

1.不支持较高并发,比如5并发就会出现全部错误的情况,可以改进的!

2.面对一些更加复杂的场景可能还是不够。

3.识别出错的情况,没有进行hook重试等比较准确的保底策略。

除了一些小问题,剩下都是数不尽的对项目作者和其他相关人员的赞美,正因为淋过雨所以想为别人撑伞。

验证码不寻常对抗系列1:   双重验证的破解之法

原文始发于微信公众号(一个不正经的黑客):验证码不寻常对抗系列1: 双重验证的破解之法

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年3月11日07:48:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   验证码不寻常对抗系列1: 双重验证的破解之法https://cn-sec.com/archives/2564834.html

发表评论

匿名网友 填写信息