- 目标链接
'aHR0cDovL3d3dy5qc2dzai5nb3YuY246NTg4ODgvbWluaS9uZXR3ZWIvU01MaWJyYXJ5LmpzcA=='
- 接口分析
-
点击搜索就会跳出验证码,netWebServlet.json 的请求,会返回 challenge 和 gt
-
接着可以看响应请求图片信息的接口,可以看到请求参数包含challenge、gt、type(验证码类型)
响应数据新的challenge、验证码图片地址乱、序图片地址、c、s这些都是接下来用到的值
- 然后通过ajax.php 验证是否通过,通过之后返回一个 validate,请求里同样是需要我们逆向的 w 参数:
响应数据validate,拿着去请求就可获得参数
- 接口参数分析
好像也就是一个w参数需要逆向,全局搜w是不太可能的了;可以从这里跟栈。
- 也可以w 的 Unicode 值 \x77 即可定位。所以直接全局搜\x77
相当于要解决r7z 、H7z两个值
var H7z = V7zM9r.C8z(92)()
, q7z = n0B[M9r.R8z(699)](h7BM9r.C8z(105), V7zM9r.R8z(818))
, r7z = p7B
-
获取H7z值,跟栈可以发现这里就是生成H7z值的地方,查看原型可以发现包含setPublic所以属于RSA加密
直接导入库加密生成H7z值 -
获取 r7z值
q7z = n0B[M9r.R8z(699)](h7B[M9r.C8z(105)](Y7z), V7z[M9r.R8z(818)]())
r7z = p7B[M9r.R8z(260)](q7z)
可以看到其中有个变量 Y7z 参与了计算,先来看看他是怎么来的,直接搜索即可定位,可以发现同样是16进制的编码,由五个值组成:userresponse、passtime、imgload、aa、ep;需要往上找到Y7z生成的地方。
-
先分析userresponse值
将滑动距离和 challenge 的值传入一个方法,得到一个 9 位字符串
-
获取 passtime 值
passtime 不用考虑是怎么通过函数获取的,含义就是滑动完成所花费的时间,直接取轨迹的最后一个值即可,这个也和三四代是一样的,获取语句为:var passtime = track[track.length - 1][2],如下图所示,轨迹的最后一个值时间为 871,passtime 的值同样也为 871。
-
获取 imgload 值即使可以写死的。
-
获取 aa 值
是通过轨迹进行加密的,加密进行了两次这里直接跟栈将代码扣下即可 -
获取 ep 值,从开始传入进来的
ep 的值就是一个版本号,此处是 {‘v’: ‘6.0.9’},写死即可。 -
获取 rp 值
自此 Y7z 的第一步生成就分析完毕了,注意接下来还有一步,向 Y7z 里新增了一个 rp 参数:
这个值的组成看起来很长,实际上是将 gt、challenge 前 32 位以及 passtime 相加经过 MD5 加密后得到的。
Y7z["rp"] = md5(gt + challenge.slice(0, 32) + passtime)
- 自此 Y7z 的值就搞定了,然后接着前面的看,也就是 q7z 的值,同样和三四代一样的,encrypt 是 AES 加密,Y7z 经过 JSON.stringify() 处理为字符串作为待加密对象,后面是 16 为随机字符串作为 AES 的 Key,注意这里的随机字符串应该和获取 H7z 值时的随机字符串一致,不然是验证不成功的。
跟栈下一步就是获取 r7z 的值,将上一步得到的 q7z 经过一个方法进行处理。
function $_GJF(e) {
var t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()";
return e < 0 || e >= t["length"] ? "." : t["charAt"](e);
}
function $_HBO(e, t) {
return e >> t & 1;
}
function $_HCX(e, o) {
var i = this;
o || (o = i);
for (var t = function(e, t) {
for (var n = 0, r = 24 - 1; 0 <= r; r -= 1)
1 === $_HBO(t, r) && (n = (n << 1) + $_HBO(e, r));
return n;
}, n = "", r = "", s = e.length, a = 0; a < s; a += 3) {
var c;
if (a + 2 < s)
c = (e[a] << 16) + (e[a + 1] << 8) + e[a + 2],
n += $_GJF(t(c, 7274496)) + $_GJF(t(c, 9483264)) + $_GJF(t(c, 19220)) + $_GJF(t(c, 235));
else {
var _ = s % 3;
2 == _ ? (c = (e[a] << 16) + (e[a + 1] << 8),
n += $_GJF(t(c, 7274496)) + $_GJF(t(c, 9483264)) + $_GJF(t(c, 19220)),
r = ".") : 1 == _ && (c = e[a] << 16,
n += $_GJF(t(c, 7274496)) + $_GJF(t(c, 9483264)),
r = "." + ".");
}
}
return {
"res": n,
"end": r
};
}
最好就是整个r7z还原成功了。
总结:
- RSA加密时候的随机值要和AES的相同
- 滑行时间需要跟你轨迹的最后一个参数相同
- 因为它的滑块图前面存在一定空白距离,需要减去否者一直失败
报错总结
- 里面的rsa和aes的随机值时需要一样的,否者报错
geetest_xxxxxxxxxxxxx({"status": "error", "error": "param decrypt error", "user_error": "\u7f51\u7edc\u4e0d\u7ed9\u529b", "error_code": "error_03"})
- challenge不对
geetest_xxxxxxxxxxxxx({"status": "error", "error": "illegal challenge", "user_error": "\u7f51\u7edc\u4e0d\u7ed9\u529b", "error_code": "error_23"})
- 水平位移不对
geetest_1617617004437({"success": 0, "message": "fail"})
- 如果水平位移正确,轨迹被检测,需要更换轨迹代码
geetest_1617268400314({"success": 0, "message": "forbidden"})
- 存在时间问题passtime 滑行时间需要跟你轨迹的最后一个参数相同,否则w错误