一、实例研究
本研究以春秋航空的注册场景验证码为研究对象。
实例研究地址: 春秋航空注册页面
实例研究场景: 春秋航空注册验证码
二、请求分析
本研究通过网络抓包分析了极验验证码与极验服务器之间的交互过程,共有8次交互。破解极验验证码的关键在于弄清每次请求携带的参数及其生成方式,从而伪造参数以达到破解目的。
1. 数据说明
在分析极验请求前,先解释两个重要参数:
gt: 极验为每个使用方提供的唯一身份标识,用于区分服务。
challenge: 用于请求串联,确保各个请求能被关联起来。注意该参数会发生变化,需要及时更新。
2. 请求分析
请求1:gt.js
请求介绍:
gt.js文件用于加载验证所需的JS库,详细介绍见极验官方文档。
关键代码:
javascript
Config.prototype = {
api_server: 'api.geetest.com',
protocol: 'http://',
typePath: '/gettype.php',
fallback_config: {
slide: {
static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
type: 'slide',
slide: '/static/js/geetest.0.0.0.js'
},
fullpage: {
static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
type: 'fullpage',
fullpage: '/static/js/fullpage.0.0.0.js'
}
},
_get_fallback_config: function () {
var self = this;
if (isString(self.type)) {
return self.fallback_config[self.type];
} else if (self.new_captcha) {
return self.fallback_config.fullpage;
} else {
return self.fallback_config.slide;
}
},
_extend: function (obj) {
var self = this;
new _Object(obj)._each(function (key, value) {
self[key] = value;
})
}
};
正常请求:
plaintext
# Request URL
https://api.geetest.com/gettype.php?gt=25ba81caec944f8d74c98befd841a667&callback=geetest_1605974702024
# Query String Parameters
gt: 25ba81caec944f8d74c98befd841a667
callback: geetest_1605974702024
兜底策略:
当极验服务器无法响应时,发送请求到http://static.geetest.com/static/js/geetest.0.0.0.js获取本地验证的JS文件,确保应用服务正常运行。
请求2:gettype.js
请求介绍:
该请求目的是获取极验安全核心JS文件/static/js/fullpage.9.0.2.js以及各类型验证码对应的JS文件。
请求详情:
plaintext
# Request URL
https://api.geetest.com/gettype.php?gt=25ba81caec944f8d74c98befd841a667&callback=geetest_1605974702024
# Query String Parameters
gt: 25ba81caec944f8d74c98befd841a667
callback: geetest_1605974702024
# Response
geetest_1605974702024({status: "success",…})
data: {
type: "fullpage",
voice: "/static/js/voice.1.2.0.js",
maze: "/static/js/maze.1.0.1.js",
…
}
请求3:fullpage.js
请求介绍:
该请求获取极验验证码核心JS文件,用于收集指纹数据和环境检测数据。
获取方式:
https://static.geetest.com/static/js/fullpage.9.0.2.js
请求4:get.php
请求介绍:
该请求发送通过fullpage.js收集的浏览器数据,用于设备指纹计算和初步风险检测。
关键步骤:
数据收集:
浏览器数据:包括JS文件元素、浏览器大小、浏览器插件、canvas、字体、时区等数据。
json
{
"textLength": ...,
"HTMLLength": ...,
"documentMode": ...,
...
}
格式处理:
用“!”对数据进行切割。
请求参数构造:
json
{
"gt": gt,
"challenge": challenge,
"new_captcha": true,
"protocol": "https://",
"beeline": scriptInfo.beeline,
"fullpage": scriptInfo.fullpage,
"static_servers": scriptInfo.static_servers,
"pencil": scriptInfo.pencil,
"click": scriptInfo.click,
"voice": scriptInfo.voice,
"slide": "/static/js/slide.7.7.5.js",
"geetest": "/static/js/geetest.6.0.9.js",
"https": true,
"i": "...(收集的浏览器数据)"
}
加密请求参数:
使用对称加密算法(如AES)对明文参数加密。
构造密文请求参数:
json
{
"gt": "25ba81caec944f8d74c98befd841a667",
"challenge": "61f4492c9e8ea1e136e98b38107d561e",
"lang": "zh-cn",
"pt": 0,
"client_type": "web",
"w": "Wt(lNJWNy9DeW5Z6nJck3NZCQaoyQdi3TTcxtdnFpU65OTMLZvjnrK9bgDx94DdhAlV0bvg61eh)…"
}
返回数据:
json
{
"status": "success",
"data": {
"logo": false,
"s": "73304840",
"i18n_labels": {
"read_reversed": false,
"copyright": "\u7531\u6781\u9a8c\u63d0\u4f9b\u6280\u672f\u652f\u6301",
"goto_confirm": "\u524d\u5f80",
...
},
"static_servers": ["static.geetest.com", "dn-staticdown.qbox.me"],
"theme": "wind",
"feedback": "",
"c": [12, 58, 98, 36, 43, 95, 62, 15, 12],
"api_server": "api.geetest.com",
"theme_version": "1.5.8"
}
}
无感验证:
若浏览器信息伪造得足够好,将触发无感验证。
json
{
"status": "success",
"data": {
"s": "6b402d61",
"theme": "wind",
"api_server": "api.geetest.com",
...
}
}
请求5:ajax.php
请求介绍:
该请求再次收集浏览器数据和鼠标行为数据,用于进一步验证。
关键步骤:
数据收集:
再次收集浏览器数据。
格式处理:
用“!”和“magic”对数据进行切割。
鼠标数据收集:
json
复制代码
[
["move", 900, 400, 1552388419164, "pointermove"],
["move", 904, 397, 1552388419180, "pointermove"],
...
]
构造密文请求参数:
json
{
"gt": "25ba81caec944f8d74c98befd841a667",
"challenge": "f91e9b5f7cb34fc2fef98a1281c4f9a5",
"lang": "zh-cn",
"pt": 0,
"client_type": "web",
"w": "PN3AyfkANbA5SEGeV3zj3wrdYwzvdZZw0hxaGHTXJUKFj7oeqLehkFa0c2Wma0D)DkvqU4xfIcbZGjnFyBK0NQ7VFApE3JDQoV0lYP4yCdiT7iPMbk6E..."
}
返回数据:
json
{
"status": "success",
"data": {
"cap_id": "5dbb5c20d1b0c9a01d247ec7",
"mobile": "61f4492c9e8ea1e136e98b38107d561e",
...
}
}
请求6:status.php
请求介绍:
该请求通过Spring Session和用户标识验证用户登录状态。
请求详情:
plaintext
# Request URL
https://passport.springairlines.com/ajax.php
状态收集:
Spring Session和用户标识。
请求参数构造:
json
{
"gt": "25ba81caec944f8d74c98befd841a667",
"challenge": "3c3298bd84f94e8d8e988a5f2be63c0b",
"lang": "zh-cn",
"pt": 0,
"client_type": "web",
"w": "ax9Ay(0kO39kyj28oTx3mr7BLFXL2XW1WJRR5tduMevUMgufUsvjc64I5DG(ujAIY)FEMjCvn"
}
返回数据:
json
{
"status": "success",
"data": {
"mobile": "13800138000",
"cap_id": "5dbb5c20d1b0c9a01d247ec7",
...
}
}
请求7:register.php
请求介绍:
该请求发送极验验证码生成的注册表单数据,用于进行最终的注册请求。
请求详情:
plaintext
# Request URL
https://passport.springairlines.com/register.php
请求参数:
json
{
"phone": "13800138000",
"password": "123456",
"cap_id": "5dbb5c20d1b0c9a01d247ec7",
"smscode": "123456",
...
}
返回数据:
json
{
"status": "success",
"message": "注册成功",
"data": {
...
}
}
请求8:login.php
请求介绍:
该请求模拟用户登录,验证注册是否成功。
请求详情:
plaintext
# Request URL
https://passport.springairlines.com/login.php
请求参数:
json
{
"username": "13800138000",
"password": "123456",
...
}
返回数据:
json
{
"status": "success",
"message": "登录成功",
"data": {
...
}
}
更多内容联系1436423940