37_某东三种验证码分析流程

Date
Mar 17, 2024
Created
Mar 16, 2024 11:39 PM
Tags
JS逆向实战

声明

本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

目标

解决JD常用的验证码

前言

这里常用的就三种接口
  1. 登录接口的滑块
  1. cfe链接接口中的滑块
  1. cfe链接接口中的点选
还有两个验证码
  • 旋转验证码
    • 这个验证码我一直没有触发。听说触发了这个验证码 就离毁号不远了。且爬且珍惜吧。
  • 手势验证码
    • 固定接口才有。

三种验证

登录的滑块接口

接口链接
aHR0cHM6Ly9wYXNzcG9ydC5qZC5jb20vdWMvbG9naW4/bHR5cGU9bG9nb3V0
notion image
如上图所示。
这里就不多说废话了。直接刷新看接口
notion image
这里可以看到 有两个接口请求发出。分别为
  • s: 负责验证请求
  • g:负责获取图片和参数

g请求

这里看g请求。直接进第二个栈。
notion image
这里看到 很多值已经给了我们值了。这里我们重点观察两个值。分别是ej
notion image
这里打断点进栈
notion image
好了 然后再进去。然后发现到一个虚拟机里了 这里包含了 e的生成。
notion image
然后就是j
notion image
j的生成不必多说。看下图就知道了。
notion image
其他的值。
  • appId:写死就行
  • scene: 同上
  • product: 同上
  • lang: 同上
  • callback: 一个callback随机数算法 写死就行
然后看返回值
notion image
上述请求有几个值需要提出来。方便后续s调用

S请求

这里继续看s请求。
notion image
这里和上图结果图作为比较。可以发现。
c好像就是challenge。
这里话不多说了。其他的值都不重要 。
最主要是这个d参数。
我们重点来看这个d
notion image
如下图所示。很多值的生成都能直接看到。
这里d 值的生成 则是由一个方法传参加密了一堆数组。
notion image
那这个数组是啥东西。其实我们不难发现这就是个轨迹。通过getCoordinate这个方法 才变成了请求接口中的d这个样子。
d方法如下:
'getCoordinate': function(a) { var b = this; var c = new Array(); for (var d = 0x0; d < a['length']; d++) { if (d == 0x0) { c['push'](b['pretreatment'](a[d][0x0] < 0x3ffff ? a[d][0x0] : 0x3ffff, 0x3, !![])); c['push'](b['pretreatment'](a[d][0x1] < 0xffffff ? a[d][0x1] : 0xffffff, 0x4, !![])); c['push'](b['pretreatment'](a[d][0x2] < 0x3ffffffffff ? a[d][0x2] : 0x3ffffffffff, 0x7, !![])); } else { var e = a[d][0x0] - a[d - 0x1][0x0]; var f = a[d][0x1] - a[d - 0x1][0x1]; var g = a[d][0x2] - a[d - 0x1][0x2]; c['push'](b['pretreatment'](e < 0xfff ? e : 0xfff, 0x2, ![])); c['push'](b['pretreatment'](f < 0xfff ? f : 0xfff, 0x2, ![])); c['push'](b['pretreatment'](g < 0xffffff ? g : 0xffffff, 0x4, !![])); } } return c['join'](''); }
这个方法很简单。缺什么扣什么。
然后传值轨迹。
至于轨迹的生成。可以通过某些算法去实现这个列表数组的生成。
这里是通过举例然后偏移出数组变量
这里贴个方法用于生成数组。
def offer(distance): index = 0 slide = [] indexTime = str(int(time.time()))[:9] for item in self.base_slide: index += 1 item[2] = int(indexTime + str(item[2])[-4:]) if int(item[0]) >= (distance + int(self.base_slide[0][0])): slide = self.base_slide[:index] slide.append( [str(distance + int(self.base_slide[0][0])), item[1], item[2] + 700 + int(random.random() * 1000)]) break last = int(slide[-1][0].split('.')[0]) pIndex = 0 for item in self.push_slide: if pIndex == 0 or pIndex == len(self.push_slide) - 1: times = slide[-1][2] else: times = slide[-1][2] + (self.push_slide[pIndex + 1][2] - self.push_slide[pIndex][2]) slide.append([str(item[0] + last), '369', times]) pIndex += 1 # print(json.dumps(slide)) return slide
最后通过getCoordinate 生成加密值。
最后伪装成功参数 然后请求就行了 返回下图代表成功。
notion image

cfe接口滑块

下面接口网站如下
aHR0cHM6Ly9jZmUubS5qZC5jb20vcHJpdmF0ZWRvbWFpbi9yaXNrX2hhbmRsZXIvMDMxMDE5MDAvP3JldHVybnVybD1odHRwcyUzQSUyRiUyRml0ZW0uamQuY29tJTJGMTAwMDQ4MjcyNzYyLmh0bWwmcnFob3N0PWh0dHBzJTNBJTJGJTJGYXBpLm0uamQuY29tJnJwaWQ9cnAtMTg2NTQ5NDkwLTEwMDU2LTE3MDk3MTMyMDgzNzEmZXZ0eXBlPTImZXZhcGk9Y29sb3JfcGNfZGV0YWlscGFnZV93YXJlQnVzaW5lc3Mmc291cmNlPTEmZm9yY2VDdXJyZW50Vmlldz0x
如下图页面。这就到了另一个滑块的接口。
notion image
这里我们点击快速验证。然后完整的走一遍流程看看。具体的走向是如何的
如下图所示。
notion image
这里首先筛选xhr请求。请求太多
如下图所示。图中经过了这么多的请求。
notion image
我们一个一个看。
第一个m?std 请求 返回值是0 目测只是判断状态的请求。
第二个api请求。如下图 返回了一个值。请求参数中enbody加密了
notion image
notion image
第三个api请求也是加密了 enbody。返回值没东西。应该也是个请求判定。
第四个fp请求。请求需要伪装si 和 ct。 而这个si 刚好和第二个api请求的si相同。 返回了 fp 和 st。
notion image
notion image
第五个请求: web_jcap_report 返回了 code为0 无用请求。
第六个请求:请求传参中带有上图fp参数的加密 还多了个tk加密。返回值 返回了 缺口图和背景图。
notion image
notion image
第七个请求:无用请求
第八个请求:即是第二个check请求。同第六个请求相似。但是返回值不一样。
那这样我们大概就能明白个具体流程了。
  1. api请求得到si
  1. 通过fp请求 请求出fp和st
  1. 通过上述这些返回值 以及其他参数获得check的请求参数加密。
  1. 通过第一次check请求得到图片。进行识别
  1. 然后通过识别到的信息再次请求check。完成滑块加密。

api请求

这里我们首先去看一下api请求。
notion image
如上图。所示 只有这个enbody值是通过加密获得的。那我们去搜索一下 或者走栈。
notion image
如下图所示 直接获取到了 enbody加密的地方。
notion image
这里简化一下代码
result = encrypt(JSON.stringify(param), 'rhiasnkdhandrisk', 'r-s-h-n_r_isnkdk')
然后过一下断点。这里可以看到 加密的值分别为
eid: 可以为空
evType: 应该是验证码类型 2
requestId: 由另一个接口605返回的requestID
shshshfpx: 是一个随机值的算法。包含随机生成以及时间戳的拼接。
notion image
第二次api请求。这里第二次请求加密的值是 第一次的返回值 已经第一次的那个请求参数。其实可以不需要。这里也展示一下
notion image

fp请求

这里fp请求。不太好搜索。我们直接进栈
notion image
进栈然后搜索 .si 这里可以发现。ct的算法 已经出来了。
notion image
notion image
这里可以看到 。这个值应该就是加密的值。
然后把几个函数互相扣一下就行。
这个x函数的算法如下
notion image
function s(t, e, n) { var r = t , a = o; e && (i = e); return c(r, a) }
这里层层扣即可。
然后把第一次api返回的那个data 和这个新生成的ct
去请求 得到fp st

两次check

第一次
断点继续走 走到下图所在位置
notion image
如上图所示。
  • si即是 第一次请求的返回的data
  • lang: 写死。
  • tk:上述乱七八糟的值拼接加密的值
  • ct: 字符串拼接 包含环境代码。
  • version: 写死
  • client: 写死
这里需要注意的是 这里的t 暂时是不传值的。这里t是什么先留个悬念。
notion image
然后进行加密就得到了tk和ct。
然后请求。得到两张以base64为编码的图片。
第二次check请求
这里其他值加密都是一样的。
唯一不同就是这个 JSON.stringify(t) 如下图所示
notion image
这里传值是轨迹。通过两张图片识别出来的距离 最终通过算法生成轨迹。
这里轨迹简单看看 第一个是移动的距离值。
notion image
第二个和第三个 如下图js所示的位置
notion image
这里可以通过算法去实现 也可以通过自建库来实现。
最后通过这些值加密 得到请求参数即可完成滑块。整体流程如下
notion image

cfe 点选验证

下面接口网站如下
aHR0cHM6Ly9jZmUubS5qZC5jb20vcHJpdmF0ZWRvbWFpbi9yaXNrX2hhbmRsZXIvMDMxMDE5MDAvP3JldHVybnVybD1odHRwcyUzQSUyRiUyRml0ZW0uamQuY29tJTJGMTAwMDQ4MjcyNzYyLmh0bWwmcnFob3N0PWh0dHBzJTNBJTJGJTJGYXBpLm0uamQuY29tJnJwaWQ9cnAtMTg2NTQ5NDkwLTEwMDU2LTE3MDk3MTMyMDgzNzEmZXZ0eXBlPTImZXZhcGk9Y29sb3JfcGNfZGV0YWlscGFnZV93YXJlQnVzaW5lc3Mmc291cmNlPTEmZm9yY2VDdXJyZW50Vmlldz0x
和滑块一个连接 不同的是 验证码不一样。
触发方式应该是与爬取的等级而定。
notion image
如上图所示。
其实上图大体流程都是一样的。这里唯一有一点区别。
如下图所示。这里JSON.stringify(t) 里面传值的不是轨迹。而是 点选的坐标。
notion image
这里可以通过两种方式去解决
  1. 通过打码平台识别——亲测识别率很低
  1. 通过训练。这里可以导出几百张数据集。然后通过yolov5识别
这里还有一点需要注意。
这里点选的 验证码
第一次check返回的tp值是22 。
而滑块是30
notion image
可以通过这个去区分验证码。

结语

另外本文某些算法 在本人星球里。有需要的小伙伴可以加一下
https://t.zsxq.com/17OvVkJha