文章总结: 这篇文章详细分析了funcaptcha验证系统的逆向过程,包括请求流程和加密参数bda的生成逻辑。作者通过分析三个目标网站的请求,总结了funcaptcha的五个请求步骤,并重点解析了bda参数的AES-CBC加密实现,提供了重构代码。文章指出还需逆向其他参数如X-Requested-ID、guess、tguess等,并完成验证图片识别。
综合评分: 86
文章分类: 逆向分析,漏洞分析,WEB安全,安全工具,二进制安全
funcaptcha逆向
原创
逆向狗都不学
逆向狗都不学
2025年8月19日 12:48
广东
声明
本文仅供学习交流使用, 如侵立删!
目标网址
第一个目标网址
aHR0cHM6Ly93d3cuYXJrb3NlbGFicy5jb20vYXJrb3NlLW1hdGNoa2V5Lw==
第二个目标网址
aHR0cHM6Ly9vY3RvY2FwdGNoYS5jb20v
第三个目标网址
aHR0cHM6Ly93d3cuYW1hem9uLmNvbS9hYXV0L3ZlcmlmeS9mbGV4LW9mZmVycy9jaGFsbGVuZ2U/Y2hhbGxlbmdlVHlwZT1BUktPU0VfTEVWRUxfMiZyZXR1cm5Ubz1odHRwczovL3d3dy5hbWF6b24uY29tJmhlYWRlckZvb3Rlcj1mYWxzZQ==
对这三个目标网址发起多次请求
并进行交叉验证
分析funcaptcha在不同网址、不同版本之间的差异与相似性
请求流程
对这三个目标网址的请求进行观察
总结出funcaptcha的请求流程
funcaptcha请求流程:
1.funcaptcha标识ID获取请求
2.验证码初始化请求
3.验证码生成请求
4.验证码事件上报请求
5.验证码验证请求
funcaptcha标识ID获取请求
以Github注册验证页面为例
请求html页面
获取该页面中api.js的地址
api.js是funcaptcha加密JS之一
在api.js地址中
有funcaptcha下发给当前网站的标识ID
不同网站搭载的funcaptcha
标识ID各不相同
标识ID不仅仅用于拼接api.js的地址
还是后续验证码注册请求参数public_key的值
验证码初始化请求
在这个请求中
通过请求参数
标识了网站站点(public_key)
上传了初始化验证码参数(capi_mode、style_theme等)
还有当前验证码初始化环境指纹(bda)
当请求成功后
与验证码服务器建立了连接
返回了验证码后续访问的唯一标识(token)和验证码加载的样式
验证码生成请求
在这个请求中
通过请求参数
确定验证码的唯一会话标识(token)
并上传更加精确的验证码生成配置(render_type、isAudioGame等)
当请求成功后
返回了验证码生成资源(game_data)
验证码事件上报请求
连续请求三次的验证码事件上报请求
通过不同次数请求的请求参数(category、action)
监控验证码的生命周期
第一次验证码事件上报请求
第二次验证码事件上报请求
第三次验证码事件上报请求
当每次上报请求成功后
返回了服务器监控确认响应
验证码验证请求
在这个请求中
通过请求参数
提交验证码验证结果(guess、tguess)
还有在验证过程中的行为指纹(bio)
当请求成功后
返回服务器对验证通过响应
当确定请求流程后
就需要针对请求流程中的请求参数进行解析
做好相应的笔记
最后根据请求参数的逻辑进行构造
加密参数bda
在验证码初始化请求中
请求参数bda是一个Base64编码字符串
对其进行解码
得到一个对象转换得到的JSON字符串
在加密JS中
查找这个对象的生成代码
使用关键字bda进行全局搜索
找到bda赋值位置
这是一个异步嵌套代码
对其进行调试跟栈
成功找到bda生成位置
对这段代码进行分析
bda解码对象键名ct值
指纹对象字符串加密结果
标准AES-CBC加密(Base64编码表示)
bda解码对象键名s值
随机8字节数据的Hex编码表示
也是标准AES-CBC加密时
使用的keys生成参数之一
bda解码对象键名iv值
随机16字节数据的Hex编码表示
也是标准AES-CBC加密时
使用的iv
根据其逻辑
本地进行重构
重构代码:
const crypto = require('crypto');
function get_bda(Fingerprint_obj_str, ua) {
// 指定大小随机字节数组生成
function random_byte_array(t, size) {
const array = new t(size);
crypto.randomFillSync(array);
return array;
}
// 字节数组转hex编码字符串
function byte_array_to_hex(t) {
returnArray.from(t, byte =>
byte.toString(16).padStart(2, '0')
).join('');
}
// MD5
// binaryOutput = false
// 输出hex编码字符串
// binaryOutput = true
// 输出原始字节字符串
function md5(input, binaryOutput = false) {
const hash = crypto.createHash('md5');
hash.update(input, 'binary');
return binaryOutput ? hash.digest('binary') : hash.digest('hex');
}
// 将一个字符串和一个hex编码字符串拼接
// 对拼接结果连续进行三次MD5摘要
// 每次将得到的摘要结果依次拼接
// 最后返回拼接结果的前32字节(以Uint8Array数组形式)
function md5_keys(t, e) {
// hex编码字符串转换成对应的原始字节字符串
const hexToBin = (hex) => {
let bin = '';
for (let i = 0; i < hex.length; i += 2) {
bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
}
return bin;
};
const c = t + hexToBin(e);
let f = '';
let prev = md5(c, true);
f += prev;
for (let i = 1; i < 3; i++) {
prev = md5(prev + c, true);
f += prev;
}
returnnewUint8Array(
Array.from(f.substring(0, 32))
.map(c => c.charCodeAt(0))
);
}
// 标准AES-CBC加密
function AES_CBC(plaintext_str, keys, iv) {
const plaintext = Buffer.from(plaintext_str, 'utf8');
const cipher = crypto.createCipheriv('aes-256-cbc', keys, iv);
const encrypted = Buffer.concat([
cipher.update(plaintext),
cipher.final()
]);
return encrypted.toString('base64')
}
// 时间戳获取(单位:秒)
const gt = newDate()["getTime"]() / 1000;
const mt = ua;
// 取当前时间的前6个小时的整点时间戳(单位:秒)
const yt = Math["round"](gt - gt % 21600);
const Ot = mt + yt;
const Et = random_byte_array(Uint8Array, 16);
const _t = random_byte_array(Uint8Array, 8);
const It = byte_array_to_hex(Et);
const xt = byte_array_to_hex(_t);
const At = md5_keys(Ot, xt);
const encrypt_str_result = AES_CBC(Fingerprint_obj_str, At, Et);
const bda_obj_str = JSON["stringify"]({
ct: encrypt_str_result,
s: xt,
iv: It
})
return btoa(bda_obj_str)
}
传入指纹对象转换的字符串与ua
即可生成bda
总结
本地还原加密参数bda逻辑后
还需要还原
请求头加密参数X-Requested-ID、加密参数guess、加密参数tguess等参数的生成逻辑
还要对验证图片进行识别
星球
相关笔记与代码已放置星球
欢迎加入知识星球
学习更多的逆向技巧与思路
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:逆向狗都不学 逆向狗都不学《funcaptcha逆向》