声明
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!
前言
最近有小伙伴私信,询问关于某时捷官网亚马逊 cookie 反爬以及验证码的相关问题,该站有 cookie 无感和九宫格验证码,本篇就对该站进行逆向分析,以及如何不训练就秒掉这类型的验证码。
逆向目标
- 目标:AWS (Amazon) aws-waf-token 参数
- 地址:
aHR0cHM6Ly9uZnQucG9yc2NoZS5jb20vb25ib2FyZGluZ0A2
抓包分析
提前打开控制台,再进入网站,会发现先访问了首页,返回了 405 状态码以及一些相关参数:
紧接着走了一个 /verify 包,载体里包括 checksum、Present 等参数:
该接口返回了 token 值,并且将 token 直接赋值给 cookie 中的 aws-waf-token
,即本文要研究的参数:
获取到 cookie 后,再通过验证码,返回 captcha_voucher,后续操作将会用到:
逆向分析
checksum 分析
通过 hook cookie 中的 aws-waf-token
参数对其进行定位,hook 的方式有很多种,可以阅读 K 哥往期文章,对其有详细介绍,这里使用 v 神插件进行 hook:
(function () {
'use strict';
var cookieTemp = '';
Object.defineProperty(document, 'cookie', {
set: function (val) {
if (val.indexOf('aws-waf-token') != -1) {
debugger;
}
console.log('Hook捕获到cookie位置->', val);
cookieTemp = val;
return val;
},
get: function () {
return cookieTemp;
},
});
})();
清除缓存后刷新网页,能成功断住,向上跟栈发现其在这个地方进行了 cookie 的赋值:
全局搜索 checksum 发现其在如下位置赋值:
继续跟栈发现在当前作用域下,该值已经生成:
我们继续全局搜索 _0x2b7beb
,看看该值在哪个作用域下,经过搜索可知,这个值在这个 _0x33b1b6
函数下被定义:
那么 this 指向的函数中均有可能有该值的生成逻辑,经过调试可知,sum 的生成逻辑在 this[_0x2ef99b(0x171)]
中。在平坦流 switch case 处进行断点,我们慢慢跟进。
首先,在开头进行了环境的收集,将其都包裹在一个大的 Object 中:
紧着着通过 _0x253a08[_0x49cba2(0x190)](_0x88c227)
方法后,我们发现 checksum 好像已经生成,并且与环境值进行了拼接:
最终加密位置如下,采用了 CRC 计算,结果如下:
我们找一个在线网站验证一下,发现结果一致:
KramerAndRio 分析
继续在平坦流下面分析,发现有一处异步调用,最终赋值给了 KramerAndRio:
我们进入前面的 _0xf1297f[_0x49cba2(0x18b)
函数中,发现是一个 GCM 加密,其 key 生成逻辑如下,是一个 hexToBytes 定值:
其 iv 生成逻辑如下,是一个随机值:
let _0x1708cb = function (_0x3ab307) {
// var _0x518645 = _0x4c2419;
// if (!(null == _0x27f1a0 ? void 0x0 : _0x27f1a0["getRandomValues"]))
// throw new Error(_0x518645(0x8b));
var _0x58daaf = new Uint8Array(_0x3ab307);
return getRandomValues(_0x58daaf),
String["fromCharCode"]["apply"](null, _0x58daaf);
}(0xc);
最终进行 GCM 加密生成 ciphertext 与 tag(hex):
let {ciphertext, tag} = encryptAesGcm(_0x3cd8cd, key, _0x1708cb);
将 iv 进行 base64 加密与环境明文、ciphertext、tag 拼接生成 Present:
let present = identifier + "::" + encode64(_0x1708cb) + "::" + tag.toString('hex') + "::" + ciphertext
验证码识别
在通过 cookie 验证后,还有最后一道门那就是九宫格验证码,验证码的提交并没有加密,答案正确即可通过,关于 6、9 宫格验证码的识别可以参考往期文章:
人均通杀 AIGC 六、九宫格验证码:https://mp.weixin.qq.com/s/6a6N_TOKs1FZnzwMGOwzwQ
识别思路大致是批次处理,取相似度前五作为最终答案:
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = load_from_name("RN50", device=device, download_root='./')
model.eval()
def find_similar_images(base64_list=None, text_prompt=None, top_k=5, threshold=None, big_base64=None):
# 如果是单张九宫格图,切成9张
if big_base64:
full_img = decode_base64_image(big_base64)
sub_images = split_3x3_image(full_img)
else:
sub_images = [decode_base64_image(b64) for b64 in base64_list]
images_tensor = torch.stack([
preprocess(img).to(device)
for img in sub_images
])
text_tokens = clip.tokenize(["11111111111", text_prompt, "22222222222"]).to(device)
with torch.no_grad():
logits_per_image, _ = model.get_similarity(images_tensor, text_tokens)
probs = logits_per_image.softmax(dim=-1).cpu().numpy()
flat_probs = [float(x[1]) for x in probs] # 取 text_prompt 对应相似度
if threshold is not None:
filtered = [(i, p) for i, p in enumerate(flat_probs) if p >= threshold]
else:
filtered = list(enumerate(flat_probs))
# topK按相似度排序
topk = sorted(filtered, key=lambda x: x[1], reverse=True)[:top_k]
# 最终按索引排序
sorted_topk = sorted(topk, key=lambda x: x[0])
indices = [i for i, _ in sorted_topk]
scores = [s for _, s in sorted_topk]
return indices, scores
indices, scores = find_similar_images(base64_list, text_prompt, top_k=5, threshold=None)
结果
毫秒级识别速度,准确率基本在 98% 以上: