【验证码逆向专栏】某安登录流程详解与验证码逆向分析与识别

783JYG.png

声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!

前言

最近知识星球有粉丝表示自己在逆向某安的过程中有一些疑惑,过来咨询,K 哥一向会尽力满足粉丝需求。本文就对某安进行深入研究,包括登录接口逆向、验证码识别、风控等方面进行全方位的分析。

逆向目标

  • 目标:某安登录界面
  • 网址:aHR0cHM6Ly9hY2NvdW50cy5iaW5hbmNlLmNvbS96aC1DTi9sb2dpbg==

抓包分析

进入登录页,随便输入账号和密码,打开开发者工具,点击下一步,会弹出九宫格点选验证码,抓包如下:

78k6Pm.jpg

通过返回值我们可以看见,该接口给我们返回的验证码的类型以及 sessionId 还有 validateId 参数,接下来是获取图片的接口,将我们上个接口获得的 validateId 传入:

78k2K5.jpg

然后该接口给我们返回图片地址,盐值 salt,还有 sig 以及点选问题 tag:

78ks9j.jpg

接着是验证接口,需要提交 validateId、sig、data 参数,验证成功则会返回 token 值:

78B0Pa.jpg
然后携带 token 值在接口 check/result 传入进行校验:

78BQML.jpg

若通过则返回如下参数:

78B7NI.jpg

该参数可以在后续登录接口进行使用,如通过 valid 参数判断账号是否注册等:

78BEaV.jpg

该网站主要验证码类型为九宫格,本文将主要对九宫格进行详细的剖析:
78Bq0J.jpg

验证码逆向分析

data 参数

九宫格验证接口中,data 参数为唯一加密参数,定位方式有很多种,这里我们直接采用跟栈的方式进行定位:

78BKbb.jpg
从第一个堆栈进入,在 t.apply 这一行打上断点,点击验证按钮,成功断了下来,如下:

78BbPe.jpg

继续向前跟栈,找到 T 函数跟进去:

78BgFP.jpg

然后继续向前跟,找到参数 D 生成的地方,即为 data 参数加密的位置:

78BGa6.jpg

发现这个 JS 被混淆了,我们可以用 v_jstools 进行简单的变量还原,替换进去即可,最终我们分析可得,data 参数是由 ek 和轨迹明文加密得到的,这里我们跟进加密函数 h 中,看看 data 是如何生成的:

78BA3Q.jpg

很明显这是平坦流,经过分析可知将传入的参数 ek 进行处理后,同 w 参入传入 m 函数进行处理:

78BxMO.jpg

最终通过 return f[n("0x916", "h1Kz")](m, w, t) 将处理结果进行返回,即生成最终的 data 参数,所以我们需要将 e 函数与 m 函数成功拿下,即可复现 data 参数的生成流程,接下来我们将用俩种扣代码的方法实现 data 参数复现。

第一种方法,我们可以首先将大数组、移位函数、解密函数这三个模块拿下来:

78BV5f.jpg

然后我们将大函数 h 整体拿下来,然后我们仿照源代码
var D = i[n("0x1f2", "3Izv")](h, JSON[n("0x564", "W73O")](K), w[n("0x962", "tz(W")].ek)
自己封装一个加密函数,对这个 h 函数进行调用,如下:

function encode(am, ek) {word = JSON.stringify(am);ms = h(word, ek)return ms
}

然后会提示,v 或者 f 不存在:

78BWCc.jpg

我们在网页相同的地方下断点,将 v 与 f 扣下来补到我们刚刚的 js 文件中。
接着继续调试,同样还会提示各种函数不存在:

78BvB3.jpg

我们同上的方法将缺失模块找到放到 js 文件种进行调试,最终 data 参数即可生成:

78Babj.jpg

这种方法最后全部必要的 js 代码拿下来的话,代码 800 行左右。

第二种方法,我们可以跟进主要的加密函数进行代码分析,将主要代码扣下来,在大函数 h 中,首先对 ek 进行了翻转,如下:

78BDR5.jpg

复现如下:

 var i = ek["split"]("")["reverse"]()["join"]("")

紧接着将翻转后的 ek 传入var t = f[n("0xc1", "8s2n")](i, f[n("0x930", "8Sjv")](e, i, 4)); 进行处理,我们可以看见翻转后的 ek 为 i ,同 4 被传入 e 中进行处理,跟进 e 中,看看他进行了哪些操作:

78BOZm.jpg

同样这部分操作也进行了平坦流的混淆,经过分析可知, 这个算法将输入字符串 w 按照参数 c 分块,对每个块的字符进行 Unicode 编码累加,乘以参数 e(默认 31),然后取模字符串 i 的长度,从中选出对应字符,最终生成一个新的字符串返回。 最终算法如下:

function eee(w, c, e) {var i = "abcdhijkxy";var t = 1;var x = [];for (var r = 0; r < c; r++) {var D = 0;var s = r * t;var K = r == (c - 1) ? (t + w.length % c) : t;for (var C = 0; C < K; C++) {var O = s + C;if (O < w.length) {D += w.charCodeAt(O);}}D = D * (e || 31);x.push(i.charAt(D % i.length));}return x.join("");
}

同网站测试结果相同,说明我们算法正确:

78BIDI.gif

最终我们再来分析 m 函数,进入 m 函数中,发现同样也是吃相极其难看的代码:

78BUq4.jpg

经过分析可知,m 函数初步流程为使用密钥 c 进行简单的编码,复现如下:

if (!w) {return "";}var e = w;var t = "";for (var x = 0; x < e["length"]; x++) {t += String.fromCharCode(e["charCodeAt"](x)^ c["charCodeAt"](x%c["length"]));}

最终传入 d 函数进行最后的加密,最后我们进入 d 函数进行分析:

78B1Dh.jpg

发现有我们很熟悉关键字 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",最终证实 d 函数确实是一个 base64 加密,只是通过平坦流将代码拆分,变成我们不熟悉的样子,至此所以加密流程分析完毕,将全部代码进行整合,即可复现 data 参数的生成:

78BPf9.jpg

发现代码加密流程仅 40 行,相比之前的 800 多行,发现算法跟踪下来,我们生成的加密算法更加简洁,不同方法适应不同的人,总会找到一个适合你的方法。

九宫格模型训练

针对模型的训练,相信之前的文章大家也都了解的很多了,九宫格可以采用纯分类实现,也可以使用检测+分类去实现,具体实现方法参考往期文章:

import os
import shutil
import random
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications.resnet50 import ResNet50
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras.optimizers import SGD# 参数配置
config = {'train_data': './data','val_data': './data','input_shape': (60, 60, 3),'batch_size': 32,'nb_epoch': 100,'workers': 1,'learning_rate': 0.001,'momentum': 0.9,'reduce_lr_patience': 4,'early_stopping_patience': 10,'model_name': 'tuili','base_model_path': '', # 预训练模型  为空就用 ResNet50
}def split_dataset(dataset_dir, train_dir, val_dir, val_ratio=0.2):"""划分数据集为训练集和验证集:param dataset_dir: str, 数据集文件夹路径:param train_dir: str, 训练集文件夹路径:param val_dir: str, 验证集文件夹路径:param val_ratio: float, 验证集比例:return:"""if not os.path.isdir(train_dir):os.makedirs(train_dir)if not os.path.isdir(val_dir):os.makedirs(val_dir)for class_name in os.listdir(dataset_dir):class_dir = os.path.join(dataset_dir, class_name)if not os.path.isdir(class_dir):continuetrain_class_dir = os.path.join(train_dir, class_name)val_class_dir = os.path.join(val_dir, class_name)if not os.path.isdir(train_class_dir):os.makedirs(train_class_dir)if not os.path.isdir(val_class_dir):os.makedirs(val_class_dir)img_list = os.listdir(class_dir)img_num = len(img_list)val_num = int(val_ratio * img_num)random.shuffle(img_list)val_list = img_list[:val_num]train_list = img_list[val_num:]for img_name in val_list:src_path = os.path.join(class_dir, img_name)dst_path = os.path.join(val_class_dir, img_name)shutil.copyfile(src_path, dst_path)for img_name in train_list:src_path = os.path.join(class_dir, img_name)dst_path = os.path.join(train_class_dir, img_name)shutil.copyfile(src_path, dst_path)print('Split dataset into train and val successfully!')def prepare_data(data_dir, val_data_dir, input_shape, batch_size):"""数据预处理和加载"""train_datagen = ImageDataGenerator(rescale=1.0 / 255)val_datagen = ImageDataGenerator(rescale=1.0 / 255)train_ds = train_datagen.flow_from_directory(data_dir,target_size=input_shape[:2],batch_size=batch_size,class_mode='categorical',seed=123)val_ds = val_datagen.flow_from_directory(val_data_dir,target_size=input_shape[:2],batch_size=batch_size,class_mode='categorical',seed=123)return train_ds, val_dsdef build_model(input_shape, num_classes, base_model_path=None):"""构建模型"""if base_model_path:model = tf.keras.models.load_model(base_model_path)else:base_model = ResNet50(weights='imagenet', include_top=False, input_shape=input_shape)x = base_model.outputx = Flatten()(x)predictions = Dense(num_classes, activation='softmax')(x)model = Model(inputs=base_model.input, outputs=predictions)model.compile(optimizer=SGD(learning_rate=config['learning_rate'], momentum=config['momentum']),loss='categorical_crossentropy',metrics=['accuracy'])return modeldef main():# 数据集划分(如果需要)# split_dataset(config['dataset_dir'], config['train_dir'], config['val_dir'])train_ds, val_ds = prepare_data(config['train_data'], config['val_data'], config['input_shape'],config['batch_size'])# 获取类别数num_classes = len(train_ds.class_indices)# 构建模型model = build_model(config['input_shape'], num_classes, config['base_model_path'])# 模型摘要打印model.summary()# 设置回调callbacks = [tf.keras.callbacks.ModelCheckpoint(filepath=config['model_name'], monitor='val_accuracy', save_best_only=True,mode='max'),tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', patience=config['reduce_lr_patience']),tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=config['early_stopping_patience']),]# 训练模型model.fit(train_ds,epochs=config['nb_epoch'],validation_data=val_ds,callbacks=callbacks,workers=config['workers'])if __name__ == '__main__':main()

最终在推理的时候,将模型转为 onnx (相关转换在上述付费文章中均有讲到),然后我们只需要将九宫格图片按照指定的大小切割出来去识别然后和标题对应就好了,关于打标的话,星球也有相关配套工具给大家使用:

78BMfV.gif

推理如下:

import onnxruntime
import numpy as np
import cv2
from PIL import Imageclass OCR():def __init__(self, model_path):self.ort_session = onnxruntime.InferenceSession(model_path)def inference(self, img_tensor):inputs = {self.ort_session.get_inputs()[0].name: img_tensor}outInfo = self.ort_session.run(None, inputs)[0]result_index = int(np.argmax(outInfo))class_names = ['大象', '熊猫', '狗', '猫', '自行车', '船', '车', '飞机', '鱼', '鸟']result = class_names[result_index]return resultdef preprocess_image(self, img):img = cv2.resize(img, (110, 110))img = np.asarray(img).astype(np.float32)img = np.expand_dims(img, axis=0)return imgdef split_image(img):content_box_list = []height, width = img.shape[:2]block_height = height // 3block_width = width // 3for i in range(3):for j in range(3):block = img[i * block_height:(i + 1) * block_height, j * block_width:(j + 1) * block_width]content_box_list.append(block)return content_box_listdef identify_grid_content(image_path, model_path):ocr = OCR(model_path)image = cv2.imread(image_path)content_box_list = split_image(image)result_list = []for idx, image in enumerate(content_box_list):img_tensor = ocr.preprocess_image(image)identified_item = ocr.inference(img_tensor)result_list.append((idx, identified_item))return result_list# Example usage
if __name__ == '__main__':image_path = '1.jpg'model_path = './mouan.onnx'results = identify_grid_content(image_path, model_path)print(results)

另外一种办法就是用 v8 去检测实现分类识别,关于相关文章在之前也有提过,训练完毕以后我们可以采用星球成员提出的方法进行推理部署:

基于 fastdeploy 的多方法图标推理:https://t.zsxq.com/Xndh3

不管哪种方法,只要能实现就是最好的办法,关于分类的数据集会整理上传到星球,星球成员可以自主下载数据集进行训练。

风控检测

风控会更新,以下是之前研究的时间段的测试结果,仅供参考。

环境正常,会弹九宫格,验证码类型随环境风险等级的提升而改变:

九宫格(bCaptcha2)、Cloudflare(turnstile)、reCaptcha(reCAPTCHA)、滑块(bCaptcha)

出现滑块,就是环境完全黑了,过了滑块也无法请求成功(网页端手动操作也一样)。

主要是三级风控:1. device-info;2. Cookies(BNC_FV_KEY_T、se_gsd 等等);3. 指纹,三级都黑了,就会风控区号(mobileCode),浏览器登录同样被限制(找朋友测试,区号黑了,地理位置、设备不同,登录都是一样的效果):

783XdB.png

风控限制和请求速度无关,与请求量有关,区号被风控后会逐步恢复,1 小时左右会解除限制。对爱尔兰的 ip 风控相对较松。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/393202.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DedeCMS-V5.7.82-UTF8织梦管理系统漏洞

将靶场环境放到www目录下——访问/dedecms/uploads 安装程序 - 织梦内容管理系统 V5.7 UTF8SP2 同意协议——继续 继续 配置后——点击继续 进入后台 登录后台——填写用户名密码。 方法一&#xff1a;上传shell文件 后台——核心——附件管理——上传新文件。 访问/dedecms…

接口测试之python+rquest+unittest分层自动化框架

接口测试之接口po框架 一、新建一个项目 接口自动化框架设计实战&#xff1a; 第一包&#xff1a;config 案例&#xff1a; #登录接口 dl_url http://cms.duoceshi.cn/cms/manage/loginJump.do dl_d {userAccount: admin, loginPwd: 123456} dl_h "Content-Type:app…

若依分离版本部署流程—开启HTTPS访问。

目录 前言 一、申请证书 二、后端打包 三、前端打包 四、服务器部署 ① Redis启动 ② 运行Jar包 ③ 上传ssl证书到服务器 ④ Nginx配置前端部分 五、访问 前言 在若依分离版本的项目部署过程中&#xff0c;跟大多数前后端分离项目差不多&#xff0c;都是前后端分别打包到服…

鸿蒙(API 12 Beta2版)媒体开发【使用AudioRenderer开发音频播放功能】

音频播放开发概述 如何选择音频播放开发方式 系统提供了多样化的API&#xff0c;来帮助开发者完成音频播放的开发&#xff0c;不同的API适用于不同音频数据格式、音频资源来源、音频使用场景&#xff0c;甚至是不同开发语言。因此&#xff0c;选择合适的音频播放API&#xff…

Linux学习笔记:iptables命令管理

1、iptables简介 其实iptables只是Linux防火墙的管理工具而已&#xff0c;位于/sbin/iptables。真正实现防火墙功能的是netfilter&#xff0c;它是Linux内核中实现包过滤的内部结构。 语法格式&#xff1a;iptables [-t table] COMMAND [chain] CRETIRIA -j ACTION -t&#…

xss漏洞(五,xss-labs靶场搭建及简单讲解)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 前言&#xff1a; 本文基于github上的xss-labs靶场以及PHP study进行操作。 一&#xff0c;靶场环境搭建。 1, 下载并解压到phpstudy的www目录下。 同前文一致&#xff0c;将文件…

精准防控,高效管理:AI智能分析网关V4区域未停留检测算法的介绍及应用

一、区域未停留AI检测算法概述 随着人工智能和计算机视觉技术的飞速发展&#xff0c;区域未停留AI检测算法作为一种重要的视频分析技术&#xff0c;逐渐在各个领域得到广泛应用。该算法通过高效处理视频流数据&#xff0c;能够实时分析并判断目标对象是否在预设区域内有足够的…

PSTNET阅读

ICLR2021 点云序列在空间维度上具有不规则性和无序性&#xff0c;但在时间维度上具有规律性和有序性。 现有的基于网格的卷积不能直接应用于原始点云序列的时空建模。 在时空序列下&#xff0c;基于网格和基于点的卷积对比。 创新点 1.首次尝试在原始点云序列建模中分解空间…

【Java 第九篇章】多线程实际工作中的头大的模块

多线程是一种编程概念&#xff0c;它允许多个执行路径&#xff08;线程&#xff09;在同一进程内并发运行。 一、多线程的概念和作用 1、概念 线程是程序执行的最小单元&#xff0c;一个进程可以包含多个线程。每个线程都有自己的程序计数器、栈和局部变量&#xff0c;但它们…

Python获取Excel内容

Python获取Excel内容 目录 Python获取Excel内容1.读取Excel并登陆2.下载Excel中图片 数据存储到列表3.上传到接口 需求&#xff1a;获取xlsx files目录下的所有Excel信息&#xff0c;并将数据打包成字典格式上传到接口 示例数据&#xff1a; 1.读取Excel并登陆 import os impo…

【算法】贪心算法

应用场景——集合覆盖问题 假设存在下面需要付费的广播台&#xff0c;以及广播台信号可以覆盖的地区。如何选择最少的广播台&#xff0c;让所有的地区都可以接收到信号 贪心算法介绍 1.贪心算法是指在对问题进行求解时&#xff0c;在每一步选择中都采取最好或者最优的选择 2…

智观察 | 行业赛道里的AI大模型

‍ “AI改变世界”被炒得热火朝天&#xff0c;结果就换来AI聊天&#xff1f; 实际上&#xff0c;在日常娱乐之下&#xff0c;AI正在暗暗“憋大招”&#xff0c;深入各行各业&#xff0c;发挥更专业的作用。 自动驾驶 最近“萝卜快跑”霸榜热搜长达一周&#xff0c;让无人驾…

手机在网状态接口如何对接?(二)

一、什么是手机在网状态&#xff1f; 传入手机号码&#xff0c;查询该手机号的在网状态&#xff0c;返回内容有正常使用、停机、在网但不可用、不在网&#xff08;销号/未启用/异常&#xff09;、预销户等多种状态。 二、手机在网状态使用场景&#xff1f; 1.用户验证与联系…

【问题解决方案】npm install报错问题:npm ERR! - 多种解决方案,总有一种可以解决

文章目录 1.问题重述2.解决方案方案1.确认根目录正确方案2.确认文件名正确方案3. 确认node.js安装完成&#xff08;注意这个环境变量配置没有写完&#xff09;方案4 改用yarn安装&#xff08;亲测可用&#xff09; 3.延申问题解决方案问题1&#xff1a;需要低版本的node.js 写在…

企业图纸防泄密怎么做?最好的八款图纸加密软件推荐

保护企业图纸不被泄露是现代企业信息安全管理中的重要任务。随着信息技术的发展&#xff0c;企业需要采取多种措施来确保图纸的安全性。以下是一些常用的图纸防泄密方法和八款推荐的图纸加密软件&#xff1a; 图纸防泄密方法 1. 数据备份&#xff1a;定期备份图纸数据&#xf…

Jboss 漏洞

一.CVE-2015-7501 访问/invoker/JMXInvokerServlet 开启下载存在漏洞 二.CVE-2017-7504 三CVE-2017-12149 启动vulhub环境&#xff0c;访问/invoker/readonly出现如下界面&#xff0c;说明存在漏洞 使用工具连接 四.Administration Console弱⼝令 访问/admin-console/login…

数据库的管理

1、官网下载或者wget tar -xvf mysql-8.0.33-1.el7.x86_64.rpm-bundle.tar 2、确定mysql-community-server正常安装之后就可以开始配置 3、初始化mysqld 服务 mysqld initeialize 4、启动服务 systemctl start mysqld 5、添加开机启动列表 systecmctrl enable mysqld在/var…

git——Git提交本地项目代码到远程Github仓库步骤图解

目录 一、Git提交本地项目代码到远程Github仓库步骤 一、Git提交本地项目代码到远程Github仓库步骤 1、在Github创建一个空仓库&#xff0c;例如名称为jetcache-demo 2、打开【Git Bash Here】 3、进入本地项目文件夹 cd d:/ cd D:/project1/本地服务/jetcache-demo4、初始…

Golang面试题三(map)

1.map底层实现 由图看出&#xff0c;其实map的底层结构体是hmap&#xff0c;同时hmap里面维护着若干个bucket数组&#xff08;即桶数组&#xff09;。bucket数组中每个元素都是bmap结构的&#xff0c;bmap中存储着8个key-value的键值对&#xff0c;如果是满了的话&#xff0c;当…

用OpenCV与MFC写一个简单易用的图像处理程序

工厂里做SOP及测试报告以及员工资格鉴定等常需用到简单的图像处理&#xff0c;PS等软件正版费用不菲&#xff0c;学习起来成本也高。Windows自带的图像处理软件&#xff0c;用起来也不是那么得心应手。因此我用OpenCV与MFC写了一个简单易用的图像处理程序。 程序界面 基于简单…