验证码识别&暴力破解

前言

对于平常Web渗透中,验证码的问题难倒一群英雄汉,前端加密+验证码更是直接放弃,所以下面就分享一下自己在渗透中对验证码识别和存在前端加密情况的暴力破解。

所有工具都是开源的,并且都是学习需求,切勿用于不法用途,觉得可以的话去给作者点个star吧。

验证码识别

burp插件-captcha-killer

captcha-killer是只专注做好对各种验证码识别技术接口的调用工具,具体点就是burp通过同一个插件,就可以适配各种验证码识别接口,无需重复编写调用代码。

原GitHub项目地址:https://github.com/c0ny1/captcha-killer

修改版GitHub项目地址:https://github.com/f0ng/captcha-killer-modified

使用说明:https://gv7.me/articles/2019/burp-captcha-killer-usage/

  • 将获取验证码的数据包发送到插件

使用burp抓取获取验证码数据包,然后右键captcha-killer -> send to captcha panel发送数据包到插件的验证码请求面板。

image-20220419094604872

然后到切换到插件面板,点击获取即可拿到要识别的验证码图片内容。

image-20220419094717568

注意:获取验证码的cookie一定要和intruder发送的cookie相同!

  • 配置识别接口的地址和请求包

拿到验证码之后,就要设置接口来进行识别了。我们可以使用网上寻找免费的接口,也可以本地起一个验证码识别的服务

ddddocr识别接口数据包实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /ocr/b64/json HTTP/1.1
Host: 192.168.50.71:9898
Connection: close
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: none
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Content-Length: 113

<@BASE64><@IMG_RAW></@IMG_RAW></@BASE64>

然后我们把图片内容的位置用标签来代替。比如该例子使用的接口是post提交image参数,参数的值为图片二进制数据的base64编码后的url编码。那么Request template(请求模版)面板应该填写如下:

image-20220419095551063

ID 标签 描述
1 <@IMG_RAW></@IMG_RAW> 代表验证码图片原二进制内容
2 <@URLENCODE></@URLENCODE> 对标签内的内容进行url编码
3 <@BASE64></@BASE64> 对标签内的内容进行base64编码

后点击“识别”即可获取到接口返回的数据包,同时在request raw可以看到调用接口最终发送的请求包。

image-20220419095734777

  • 设置用于匹配识别结果的规则

通过上一步我们获取到了识别接口的返回结果,但是插件并不知道返回结果中,哪里是真正的识别结果。插件提供了4中方式进行匹配,可以根据具体情况选择合适的。

ID 规则类型 描述
1 Repose data 这种规则用于匹配接口返回包内容直接是识别结果
2 Regular expression 正则表达式,适合比较复杂的匹配。比如接口返回包{"coede":1,"result":"abcd"}说明abcd是识别结果,我们可以编写规则为result":"(.*?)"\}
3 Define the start and end positions 定义开始和结束位置,使用上面的例子,可以编写规则{"start":21,"end":25}
4 Defines the start and end strings 定义开始和结束字符,使用上面的例子,可以编写规则为{"start":"result\":\","end":"\"\}"}

通过分析我们知道,接口返回的json数据中,字段result的值为识别结果。我们这里使用Regular expression(正则表达式)来匹配,然后选择78cc右键标记为识别结果,系统会自动生成正则表达式规则" (.*?)"\}\]

image-20220419095847618

注意:若右键标记自动生成的规则匹配不精确,可以人工进行微调。比如该例子中可以微调规则为"result"\: "(.*?)"\}将更加准确!

点击识别可从右边侧栏查看准确率

image-20220419100343450

到达这步建议将配置好常用接口的url,数据包已经匹配规则保存为模版,方便下次直接通过右键模板库中快速设置。

image-20220419100103753

  • 在Intruder模块调用

配置好各项后,可以点击锁定对当前配置进行锁定,防止被修改导致爆破失败!接着按着以下步骤进行配置

image-20220419102125943

image-20220419101936267

即可进行爆破

image-20220419102240400

ddddocr

https://github.com/sml2h3/ddddocr

简介

ddddocr是由sml2h3开发的专为验证码厂商进行对自家新版本验证码难易强度进行验证的一个python库,其由作者与kerlomz共同合作完成,通过大批量生成随机数据后进行深度网络训练,本身并非针对任何一家验证码厂商而制作,本库使用效果完全靠玄学,可能可以识别,可能不能识别。

使用ocr_api_server一键启动识别服务

https://github.com/sml2h3/ocr_api_server

  • 最简单运行方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 安装依赖
pip install -r requirements.txt -i https://pypi.douban.com/simple

# 运行 可选参数如下
# --port 9898 指定端口,默认为9898
# --ocr 开启ocr模块 默认开启
# --old 只有ocr模块开启的情况下生效 默认不开启
# --det 开启目标检测模式

# 最简单运行方式,只开启ocr模块并以新模型计算
python ocr_server.py --port 9898 --ocr

# 开启ocr模块并使用旧模型计算
python ocr_server.py --port 9898 --ocr --old

# 只开启目标检测模块
python ocr_server.py --port 9898 --det

# 同时开启ocr模块以及目标检测模块
python ocr_server.py --port 9898 --ocr --det

# 同时开启ocr模块并使用旧模型计算以及目标检测模块
python ocr_server.py --port 9898 --ocr --old --det

  • docker运行方式(目测只能在Linux下部署)
1
2
3
4
5
6
7
8
9
10
11
12
13
git clone https://github.com/sml2h3/ocr_api_server.git
# docker怎么安装?百度吧

cd ocr_api_server

# 修改entrypoint.sh中的参数,具体参数往上翻,默认9898端口,同时开启ocr模块以及目标检测模块

# 编译镜像
docker build -t ocr_server:v1 .

# 运行镜像
docker run -p 9898:9898 -d ocr_server:v1

  • 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1、测试是否启动成功,可以通过直接GET访问http://{host}:{port}/ping来测试,如果返回pong则启动成功

# 2、OCR/目标检测请求接口格式:

# http://{host}:{port}/{opt}/{img_type}/{ret_type}
# opt:操作类型 ocr=OCR det=目标检测 slide=滑块(match和compare两种算法,默认为compare)
# img_type: 数据类型 file=文件上传方式 b64=base64(imgbyte)方式 默认为file方式
# ret_type: 返回类型 json=返回json(识别出错会在msg里返回错误信息) text=返回文本格式(识别出错时回直接返回空文本)

# 例子:

# OCR请求
# resp = requests.post("http://{host}:{port}/ocr/file", files={'image': image_bytes})
# resp = requests.post("http://{host}:{port}/ocr/b64/text", data=base64.b64encode(file).decode())

# 目标检测请求
# resp = requests.post("http://{host}:{port}/det/file", files={'image': image_bytes})
# resp = requests.post("http://{host}:{port}/ocr/b64/json", data=base64.b64encode(file).decode())

# 滑块识别请求
# resp = requests.post("http://{host}:{port}/slide/match/file", files={'target_img': target_bytes, 'bg_img': bg_bytes})
# jsonstr = json.dumps({'target_img': target_b64str, 'bg_img': bg_b64str})
# resp = requests.post("http://{host}:{port}/slide/compare/b64", files=base64.b64encode(jsonstr.encode()).decode())

详细实操步骤:

  • step1:安装下载项目依赖
1
git clone https://github.com/sml2h3/ocr_api_server.git
1
python3 -m pip install -r requirements.txt -i https://pypi.douban.com/simple
  • step2:运行开启
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 最简单运行方式,只开启ocr模块并以新模型计算
python3 ocr_server.py --port 9898 --ocr

# 开启ocr模块并使用旧模型计算
python3 ocr_server.py --port 9898 --ocr --old

# 只开启目标检测模块
python3 ocr_server.py --port 9898 --det

# 同时开启ocr模块以及目标检测模块
python3 ocr_server.py --port 9898 --ocr --det

# 同时开启ocr模块并使用旧模型计算以及目标检测模块
python3 ocr_server.py --port 9898 --ocr --old --det

可根据需求运行相应的命令

image-20220419145429200

  • step3:接口格式类型

常用请求模版:

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /ocr/b64/json HTTP/1.1
Host: 192.168.50.71:9898
Connection: close
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: none
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Content-Length: 113

<@BASE64><@IMG_RAW></@IMG_RAW></@BASE64>

配合burp的captcha-killer插件使用,识别准确率还是杠杠的

image-20220419150904585

同时作者还公开其训练的脚本,感兴趣的可以自己搞张显卡训练,训练项目如下:

https://github.com/sml2h3/dddd_trainer

dist-cpu

dist-cpu是已经训练好的ocr识别项目(现github地址已删除)

双击exe即可运行,监听地址为http://0.0.0.0:19952/,监听地址和端口可在config.yaml中更改

image-20220419165903261

1
2
3
4
5
6
7
8
9
10
11
POST /captcha/v1 HTTP/1.1
Host: 192.200.254.79:19952
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
Content-Length: 3854

{"image":"<@BASE64><@IMG_RAW></@IMG_RAW></@BASE64>"}

配合burp插件captcha-kiler使用,使用方法和ddddocr类似,效果比ddddocr差些

image-20220419172209252

PKAV HTTP Fuzzer

需要安装.net framework 4.0或以上版本。

image-20220419164748908

image-20220419165214811

暴力破解

blaster+ddddocr

https://github.com/PoJun-Lab/blaster

blaster 是一款弱密码隐患检测工具,用于网站登录弱密码检测。

无论是在漏洞响应平台,还是日常工作中,大家或许在为图片验证码、登录加密等无法直接登录测试而烦恼,所以blaster应运而生。它支持导入用户名密码字典,多并发图片验证码识别,自动填充表单元素,无视任何登录加密。

  • 支持复选框勾选:主要场景为阅读平台使用须知、 隐私政策单选表单等。
  • 支持复杂场景的事件操作:可根据不同场景,在登录前后自定义事件操作。
  • 支持正则匹配反向过滤:应对不同响应类型、长度,提取关键信息进行反向过滤。
  • 图片验证码识别:采用python第三方库进行ocr识别。
  • 无视任何加密方式:它将用户名及密码字典填充至对应表单进行提交,无需逆向加密方式。
  • 支持多次输入账号密码错误才出现验证码情况
  • 支持多并发

配置

服务端搭建,该服务对应客户端配置中的 captchabreak_serverurl,它用于图片验证码识别。

1
python3 cbhs.py -a user:pass -p port	# 自定义服务端basic认证用户名密码、开放端口

客户端配置 config.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 示例目标网址:http://www.example.com/login
# 示例登录目标最终发送的请求数据包地址:http://www.example.com/api/user/login
# 示例图片验证码识别服务:python3 cbhs.py -a admin:123 -p 8999

target_url: 'http://www.example.com/login' # 登录目标网址
browser_path: 'C:\Program Files\Google\Chrome\Application\chrome.exe' # 浏览器的路径
headless: false # 设置false显式运行浏览器 true则反之
captchabreak_serverurl: 'http://admin:123@127.0.0.1:8999/cb' # 图片验证码识别服务,使用captchabreak_serverurl文件夹中的脚本进行搭建
before_all_js_expr: '' # 在开始填写账号密码之前执行的js表达式
userinput_jspath: 'document.querySelector("#loginid")' # 用户名输入框js path
passinput_jspath: 'document.querySelector("#security_in")' # 密码输入框js path
captchainput_jspath: 'document.querySelector("#jcaptcha")' # 验证码输入框js path
captchaimg_jspath: 'document.querySelector("#vcode")' # 验证码图片js path
before_login_js_expr: '' # 在点击登录之前执行的js表达式
loginbutton_jspath: 'document.querySelector("#vcode")'
loginreq_pattern: '*user/login*' # 登录请求的url特征码,实际登录数据包url path 里面的通配符*必不可少
body_exclude_regex: # 排除请求的正则,即只要命中其中任意一个正则的请求响应将被抛弃
- 'regex1'
- 'regex2'
maxbody_bytes_display: 512 # 登录请求响应包最大限制,超过限制则不会显示
concurrency: 1 # 并发数
timeout_ms: 50000 # 浏览器中操作的超时时间(毫秒)
timeinterval_ms: 300 # 浏览器中操作登录过程中每个操作之间的时间间隔(毫秒)
proxy: '' # 代理
  • captchabreak_serverurl

    before_all_js_expr

    • 在开始填写账号密码之前执行的js表达式,如页面打开后有弹出层,可以将通过该参数关闭弹窗,不局限于弹出层一个场景。

    • 示例场景:打开页面出现弹出层,需要关闭弹窗后输入账号密码。

    • 示例解决弹出层:判断某按钮(弹出层关闭按钮X)是否存在,如果存在则点击;找出关闭按钮的js path按照格式编写代码即可。

    • 1
      null != jspath && jspath.click()	// js代码格式
    • 表达式不限于一个,如有其他场景或多个弹出层,可通过 && 或 || 进行叠加

    before_login_js_expr

    • 在点击登录之前执行的js表达式,如登录需要勾选阅读平台使用须知、 隐私政策单选表单等

    • 示例场景:输入账号密码后需要选择阅读平台使用须知、 隐私政策等表单才可登录

    • 示例解决表单勾选:判断某勾选框是否已经勾选如果未勾选则点击;找出表单勾选的js path按照格式编写代码即可。

    • 1
      !jspath.checked && jspath.click() // js代码格式
    • 表达式不限于一个,如有其他场景或多个勾选,可通过 && 或 || 进行叠加

    body_exclude_regex

    • 排除请求的正则,即只要命中其中任意一个正则的请求响应将被抛弃,即反向grep。

    • 示例场景:登录后的响应页面长度较大,返回格式为HTML,其中有(账号不存在、密码错误、验证码错误、登录成功)等不同情况,由于响应长度较大我们无法轻易区分测试数据的真实响应情况。

    • 示例解决响应长度较大问题:经过手工登录测试发现响应的HTML中出现这些关键信息(如账号不存在、密码错误、验证码错误),根据自己的需求,编写正则表达式,在发现响应中存在这些匹配内容时不输出到终端及结果文件中。

    • 这里需要具备一些正则表达式的技能,如果使用者技能有些欠缺,可以直接使用关键信息进行排除,或是在交流群内寻求帮助。

    • 1
      2
      3
      body_exclude_regex:
      - '账号不存在'
      - '验证码错误'
    • 该参数不限于一个表达式,使用者根据自己的需求来增删表达式即可。

    客户端配置中的jspath可在浏览器页面对应表单右键选择检查(Inspect),并在检查中右键选中的表单标签,选择Copy>Copy JS path即可复制jspath。

使用

1
2
3
4
5
6
7
8
9
10
C:\Users\balster>blaster_win.exe
Usage of blaster_win.exe:
-c string
config file # 指定config.yaml
-o string
output file path (optional) # 暴力破解测试数据输出文件位置
-p string
pass dict file path # 指定密码字典
-u string
user dict file path # 指定用户名字典
1
2
3
4
5
6
7
8
9
10
11
12
13
C:\Users\blaster>blaster_win.exe -c conf.yaml -u user.txt -p pwds.txt -o res.csv
2022/01/28 19:09:08 200 OPTIONS admin admin 0
2022/01/28 19:09:08 200 POST admin admin 86 {"result":-1,"errorCode":"10005","title":"fail","description":"10005","retValue":null}
2022/01/28 19:09:10 200 POST admin admin123 135 {"result":-1,"errorCode":"10011","title":"fail","description":"密码过于简单,请使用手机号验证码登录","retValue":null}
2022/01/28 19:09:13 200 POST admin 123456 135 {"result":-1,"errorCode":"10011","title":"fail","description":"密码过于简单,请使用手机号验证码登录","retValue":null}
2022/01/28 19:09:16 200 POST admin 1234567 135 {"result":-1,"errorCode":"10011","title":"fail","description":"密码过于简单,请使用手机号验证码登录","retValue":null}
2022/01/28 19:09:18 200 POST admin 12345678 135 {"result":-1,"errorCode":"10011","title":"fail","description":"密码过于简单,请使用手机号验证码登录","retValue":null}
2022/01/28 19:09:21 200 POST admin password 86 {"result":-1,"errorCode":"10005","title":"fail","description":"10005","retValue":null}
2022/01/28 19:09:24 200 POST admin Aa123456. 86 {"result":-1,"errorCode":"10001","title":"fail","description":"10001","retValue":null}
2022/01/28 19:09:26 200 POST admin p@$$w0rd 86 {"result":-1,"errorCode":"10005","title":"fail","description":"10005","retValue":null}
2022/01/28 19:09:29 200 POST admin 1q2W#e4r 86 {"result":-1,"errorCode":"10001","title":"fail","description":"10001","retValue":null}
2022/01/28 19:09:32 200 POST admin P@$$w0rd 126 {"result":-1,"errorCode":"10008","title":"fail","description":"密码错误次数已满,请明天再登录","retValue":null}
2022/01/28 19:09:34 200 POST admin password123 126

使用操作实例

1、验证码服务启动(没验证码就不用,且注释配置文件关于验证码选项)

image-20220420101316059

2、配置config.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 示例目标网址:http://www.example.com/login
# 示例登录目标最终发送的请求数据包地址:http://www.example.com/api/user/login
# 示例图片验证码识别服务:python3 cbhs.py -a admin:123 -p 8999

target_url: 'http://xx:9090/login/index.jsp' # 登录目标网址
browser_path: 'C:\Program Files\Google\Chrome\Application\chrome.exe' # 浏览器的路径
headless: false # 设置false显式运行浏览器 true则反之
captchabreak_serverurl: 'http://admin:123@127.0.0.1:8999/cb' # 图片验证码识别服务,使用captchabreak_serverurl文件夹中的脚本进行搭建
before_all_js_expr: 'document.getElementById("userN").value=""' # 在开始填写账号密码之前执行的js表达式
userinput_jspath: 'document.querySelector("#userN")' # 用户名输入框js path
passinput_jspath: 'document.querySelector("#passWs")' # 密码输入框js path
captchainput_jspath: 'document.querySelector("#validCode")' # 验证码输入框js path
captchaimg_jspath: 'document.querySelector("#kaptchaImage")' # 验证码图片js path
before_login_js_expr: '' # 在点击登录之前执行的js表达式
loginbutton_jspath: 'document.querySelector("#a_login")'
loginreq_pattern: '*/login/login_valid.jsp*' # 登录请求的url特征码,实际登录数据包url path
body_exclude_regex: # 排除请求的正则,即只要命中其中任意一个正则的请求响应将被抛弃
- 'regex1'
- 'regex2'
maxbody_bytes_display: 512 # 登录请求响应包最大限制,超过限制则不会显示
concurrency: 2 # 并发数
timeout_ms: 50000 # 浏览器中操作的超时时间(毫秒)
timeinterval_ms: 600 # 浏览器中操作登录过程中每个操作之间的时间间隔(毫秒)
proxy: '' # 代理

注:里面的loginreq_pattern通配符*必不可少

3、运行

1
blaster_win.exe -c conf.yaml -u user.txt -p pass.txt -o re.csv

image-20220420101547279

参考链接

https://github.com/c0ny1/captcha-killer

https://github.com/f0ng/captcha-killer-modified

https://gv7.me/articles/2019/burp-captcha-killer-usage/

https://github.com/sml2h3/ddddocr

https://github.com/sml2h3/ocr_api_server

https://github.com/PoJun-Lab/blaster