一. 观察verify请求
首先,我们需要观察verify请求的Initiator,可以看到所有请求都来自于gcaptcha4.js这个文件,所以该文件是我们此次的目标所在。
打开gcaptcha4.js文件,格式化后,我们在13339行发现,代码经过混淆处理,这时候我们有两种选择:硬刚或者使用AST还原。我选择了AST还原JS文件,然后使用Chrome上的reres插件将混淆的JS替换掉,再一步步调试。AST还原代码已放在GitHub上,reres插件的安装和使用请自行搜索。
替换成功后,我们得到以下结果:
二. 定位w参数加密位置
搜索w参数,我们可以通过以下关键词定位:
w
.w
'w'
"w"
搜索"w"后,我们找到了目标,在2527行打上断点,可以看到w的值r在2525行定义,我们也在此打上断点,刷新页面,成功断上。至此,我们已完成w参数的加密位置定位。
三. 分析w参数加密算法
简化w的值r的定义:
javascript
var r = (0, d["default"])(l["default"]["stringify"](e), a)
等价于:
javascript
var r = d.default(l.default.stringify(e), a)
分析l.default.stringify(e)的含义:
可以看出此处是对e进行JSON序列化操作。
分析d.default(l.default.stringify(e), a)的含义:
跟进d函数,在几个条件判断处打上断点,调试后得出结论:
javascript
function a(e, t) {
var n = c["guid"](),
a = new _["default"]()["encrypt"](n);
o = i["default"]["encrypt"](e, n);
return c["arrayToHex"](o) + a;
}
我们确定参数t并未使用,参数e即w的明文。继续分析JSON序列化前e的组成:
r
library(jsonlite)
e <- list(
device_id = "A8A0",
em = list(
cp = 0,
ek = "11",
nt = 0,
ph = 0,
sc = 0,
si = 0,
wd = 1
),
ep = "123",
geetest = "captcha",
fq6a = "1925502591",
lang = "zh",
lot_number = "7e22264d4f3e4dd8a6ffbf6e82e1122d",
passtime = 166,
pow_msg = "",
pow_sign = "",
setLeft = 88,
track = list(c(38, 18, 0), c(1, 0, 33)),
userresponse = 87.47978686742837
)
四. 分析pow_msg和pow_sign
搜索pow_msg,打上断点,刷新,保留成功断上的断点:
r
u <- paste(n, a, s, o, t, e, r, sep = "|")
p <- generate_guid()
g <- paste(u, p, sep = "")
pow_msg <- g
pow_sign <- digest::digest(g, algo = "md5")
我们需要分析generate_guid算法:
r
generate_guid <- function() {
guid <- paste0(sample(c(0:9, letters), 4, replace = TRUE), collapse = "")
return(paste0(guid, guid, guid, guid))
}
五. 分析set_left、track、passtime、userresponse
set_left为滑块移动距离取整。
track为移动轨迹,从第二步开始,是上一步的相对移动距离(x, y, t)。
passtime为总移动时间。
userresponse为set_left / (0.8876 * 340 / 300)。
至此,我们已将w的明文分析完毕。以下是R实现代码:
六. 代码实现
r
library(jsonlite)
library(digest)
generate_guid <- function() {
guid <- paste0(sample(c(0:9, letters), 4, replace = TRUE), collapse = "")
return(paste0(guid, guid, guid, guid))
}
generate_w_params <- function() {
device_id <- "A8A0"
em <- list(cp = 0, ek = "11", nt = 0, ph = 0, sc = 0, si = 0, wd = 1)
ep <- "123"
geetest <- "captcha"
fq6a <- "1925502591"
lang <- "zh"
lot_number <- "7e22264d4f3e4dd8a6ffbf6e82e1122d"
passtime <- 166
set_left <- 88
track <- list(c(38, 18, 0), c(1, 0, 33))
userresponse <- set_left / (0.8876 * 340 / 300)
guid <- generate_guid()
u <- paste(lot_number, guid, sep = "|")
p <- generate_guid()
g <- paste(u, p, sep = "")
pow_msg <- g
pow_sign <- digest(g, algo = "md5")
e <- list(
device_id = device_id,
em = em,
ep = ep,
geetest = geetest,
fq6a = fq6a,
lang = lang,
lot_number = lot_number,
passtime = passtime,
pow_msg = pow_msg,
pow_sign = pow_sign,
setLeft = set_left,
track = track,
userresponse = userresponse
)
return(toJSON(e, auto_unbox = TRUE))
}
w_params <- generate_w_params()
print(w_params)