【JS逆向学习】快乐学堂登陆接口(自定义DES加密、ddddocr验证码识别)

逆向目标
  • 网址:https://www.91118.com/Passport/Account/Login
  • 接口:https://www.91118.com/passport/Account/LoginPost
  • 参数:
    • pass
    • r
逆向过程

输入手机号、密码、验证码 点击登陆,多试几次,然后观察并比较不通请求参数有哪些变化,其中 ckcode 是验证码
在这里插入图片描述

逆向分析

先使用关键词 pass 搜索,匹配项太多,直接从启动器入口进去跟栈分析
在这里插入图片描述
调试如下
在这里插入图片描述
可以发现参数 r就是一个随机值 Math.random()pass 跟栈进去如下
在这里插入图片描述
加解密的方法都有了

var _key = 'k1fsa01v';
var _iv = 'k1fsa01v';
function encryptByDES(message) {var keyHex = CryptoJS.enc.Utf8.parse(_key);var encrypted = CryptoJS.DES.encrypt(message, keyHex, {iv: CryptoJS.enc.Utf8.parse(_iv),mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();
}
function decryptByDES(ciphertext) {var keyHex = CryptoJS.enc.Utf8.parse(_key);var decrypted = CryptoJS.DES.decrypt({ciphertext: CryptoJS.enc.Base64.parse(ciphertext)}, keyHex, {iv: CryptoJS.enc.Utf8.parse(_iv),mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return decrypted.toString(CryptoJS.enc.Utf8);
}

看着像是 DES 对称加密,使用标准库 crypto-js 来加密看看结果是否一致


var CryptoJS = require("crypto-js");
// 定义加密密钥,使用Utf8编码解析密钥字符串
const SECRET_KEY = CryptoJS.enc.Utf8.parse("k1fsa01v");
// 定义加密向量IV,使用Utf8编码解析IV字符串
const SECRET_IV = CryptoJS.enc.Utf8.parse("k1fsa01v");/*** 加密函数,接受一个数据参数,返回加密后的字符串* @param {string|object} data - 需要加密的数据,可以是字符串或对象* @returns {string} 加密后的数据字符串*/
function encrypt(data) {// 如果数据是对象类型,则尝试将其转换为字符串if (typeof data === "object") {try {data = JSON.stringify(data);} catch (e) {// 如果转换过程中发生错误,打印错误信息并返回console.log(e);return;}}// 将数据转换为Utf8格式的密文const dataHex = CryptoJS.enc.Utf8.parse(data);// 使用AES算法加密数据const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {iv: SECRET_IV,mode: CryptoJS.mode.CBC, // 使用CBC模式padding: CryptoJS.pad.Pkcs7, // 使用Pkcs7填充});// 返回加密后的密文字符串return encrypted.toString();
}console.log(encrypt("a123456"));
// 输出如下
>> T6fdfWw2zktEch0jKSJkmA==

我们再看网站加密结果

encryptByDES("a123456")
// 输出如下
>> bb3mlkFBqqo=

很明显网站对加密做了改造,我们跟进去把整个加密扣出来
在这里插入图片描述
我们把整个文件的 js code 全部copy出来执行并打印 console.log(CryptoJS) 输出如下

{lib: {Base: {extend: [Function: extend],create: [Function: create],init: [Function: init],mixIn: [Function: mixIn],clone: [Function: clone]},WordArray: {init: [Function: init],toString: [Function: toString],concat: [Function: concat],clamp: [Function: clamp],clone: [Function: clone],random: [Function: random],'$super': [Object]},BufferedBlockAlgorithm: {reset: [Function: reset],_append: [Function: _append],_process: [Function: _process],clone: [Function: clone],_minBufferSize: 0,init: [Function (anonymous)],'$super': [Object]},Hasher: {cfg: [Object],init: [Function: init],reset: [Function: reset],update: [Function: update],finalize: [Function: finalize],blockSize: 16,_createHelper: [Function: _createHelper],_createHmacHelper: [Function: _createHmacHelper],'$super': [Object]},Cipher: {cfg: [Object],createEncryptor: [Function: createEncryptor],createDecryptor: [Function: createDecryptor],init: [Function: init],reset: [Function: reset],process: [Function: process],finalize: [Function: finalize],keySize: 4,ivSize: 4,_ENC_XFORM_MODE: 1,_DEC_XFORM_MODE: 2,_createHelper: [Function: _createHelper],'$super': [Object]},StreamCipher: {_doFinalize: [Function: _doFinalize],blockSize: 1,init: [Function (anonymous)],'$super': [Object]},BlockCipherMode: {createEncryptor: [Function: createEncryptor],createDecryptor: [Function: createDecryptor],init: [Function: init],'$super': [Object]},BlockCipher: {cfg: [Object],reset: [Function: reset],_doProcessBlock: [Function: _doProcessBlock],_doFinalize: [Function: _doFinalize],blockSize: 4,init: [Function (anonymous)],'$super': [Object]},CipherParams: {init: [Function: init],toString: [Function: toString],'$super': [Object]},SerializableCipher: {cfg: [Object],encrypt: [Function: encrypt],decrypt: [Function: decrypt],_parse: [Function: _parse],init: [Function (anonymous)],'$super': [Object]},PasswordBasedCipher: {cfg: [Object],encrypt: [Function: encrypt],decrypt: [Function: decrypt],init: [Function (anonymous)],'$super': [Object]}},enc: {Hex: { stringify: [Function: stringify], parse: [Function: parse] },Latin1: { stringify: [Function: stringify], parse: [Function: parse] },Utf8: { stringify: [Function: stringify], parse: [Function: parse] },Base64: {stringify: [Function: stringify],parse: [Function: parse],_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='}},algo: {MD5: {_doReset: [Function: _doReset],_doProcessBlock: [Function: _doProcessBlock],_doFinalize: [Function: _doFinalize],clone: [Function: clone],init: [Function (anonymous)],'$super': [Object]},EvpKDF: {cfg: [Object],init: [Function: init],compute: [Function: compute],'$super': [Object]},DES: {_doReset: [Function: _doReset],encryptBlock: [Function: encryptBlock],decryptBlock: [Function: decryptBlock],_doCryptBlock: [Function: _doCryptBlock],keySize: 2,ivSize: 2,blockSize: 2,init: [Function (anonymous)],'$super': [Object]},TripleDES: {_doReset: [Function: _doReset],encryptBlock: [Function: encryptBlock],decryptBlock: [Function: decryptBlock],keySize: 6,ivSize: 2,blockSize: 2,init: [Function (anonymous)],'$super': [Object]}},MD5: [Function (anonymous)],HmacMD5: [Function (anonymous)],EvpKDF: [Function (anonymous)],mode: {CBC: {init: [Function (anonymous)],'$super': [Object],Encryptor: [Object],Decryptor: [Object]}},pad: { Pkcs7: { pad: [Function: pad], unpad: [Function: unpad] } },format: {OpenSSL: { stringify: [Function: stringify], parse: [Function: parse] }},kdf: { OpenSSL: { execute: [Function: execute] } },DES: { encrypt: [Function: encrypt], decrypt: [Function: decrypt] },TripleDES: { encrypt: [Function: encrypt], decrypt: [Function: decrypt] }
}

然后把具体加密的那段代码也拷贝过来执行

var _key = 'k1fsa01v';
var _iv = 'k1fsa01v';
function encryptByDES(message) {var keyHex = CryptoJS.enc.Utf8.parse(_key);var encrypted = CryptoJS.DES.encrypt(message, keyHex, {iv: CryptoJS.enc.Utf8.parse(_iv),mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();
}
function decryptByDES(ciphertext) {var keyHex = CryptoJS.enc.Utf8.parse(_key);var decrypted = CryptoJS.DES.decrypt({ciphertext: CryptoJS.enc.Base64.parse(ciphertext)}, keyHex, {iv: CryptoJS.enc.Utf8.parse(_iv),mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return decrypted.toString(CryptoJS.enc.Utf8);
}
console.log(encryptByDES('a123456'));

结果报错了:

(base) qin@wuanjuns-MacBook-Pro jsprojects % node test.js 
/Users/qin/dev/jsprojects/jsprojects/test.js:527var b = a.createEncryptor;^
TypeError: Cannot read properties of undefined (reading 'createEncryptor')

因为我们是全扣的代码,不存在少扣的问题,这个时候把这段代码拷贝到浏览器里执行发现正常输出了
在这里插入图片描述
大家回想一下在具体的加密代码那个页面是不是还有一段 html 代码,我们去看看是什么东西

(function () {document.write("<script language=\"javascript\" type=\"text/javascript\" src=\"//assets.91118.com/js/rollups/tripledes.js\"></script><script language=\"javascript\" type=\"text/javascript\" src=\"//assets.91118.com/js/components/mode-ecb.js\"></script>");
})();

代码比较简单,就是一个自执行函数,引入了两个 js scripttripledes.js就是定义 CryptoJS 的文件,我们看另外一个 mode-ecb.js 是什么

CryptoJS.mode.ECB = (function () {var ECB = CryptoJS.lib.BlockCipherMode.extend();ECB.Encryptor = ECB.extend({processBlock: function (words, offset) {this._cipher.encryptBlock(words, offset);}});ECB.Decryptor = ECB.extend({processBlock: function (words, offset) {this._cipher.decryptBlock(words, offset);}});return ECB;
}());

补充了 CryptoJSECB mode,我们在刚才代码中补上这段代码再执行结果如下

>> node test.js
>> bb3mlkFBqqo=

返回了正确的加密后的结果
另外,在接口请求参数中还有一个验证码参数 ckcode ,这个验证码是一个 img 元素,直接请求网址https://www.91118.com/Passport/Account/Login 并解析返回的 html 内容即可拿到 img 这里我门就不做赘述了,像这种简单的验证码推荐大家使用免费的验证码识别库 ddddocr(https://github.com/sml2h3/ddddocr),这里直接给出识别代码

# -*- coding: utf-8 -*-
import ddddocrocr = ddddocr.DdddOcr()image = open("code.jpg", "rb").read()
result = ocr.classification(image)
print(result)

在这里插入图片描述
识别成功

逆向结果

到这里整个逆向过程就全部结束了,整个流程走下来就两点

  1. 扣代码——CryptoJS加密模块,尤其是后面那个 CryptoJS.mode.ECB,真的是很有迷惑性;
  2. 验证码识别——这个没有什么可讲的,直接上 ddddocr 硬怼就行了

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

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

相关文章

MMO 地图传送,UI系统框架设计

地图传送 创建传送点 建碰撞器触发 //位置归零 建一个传送门cube放到要传送的位置&#xff08;这个teleporter1是传出的区域 这是从另一张地图传入时的传送门 创建一个脚本TeleporterObject给每个传送cube都绑上脚本 通过脚本&#xff0c;让传送门在编辑器下面还能绘制出来 …

GIT | git提交注释自动添加信息头

GIT | git提交注释自动添加信息头 时间&#xff1a;2024年9月6日10:20:11 文章目录 GIT | git提交注释自动添加信息头1.操作2.commit-msg文件 1.操作 2.commit-msg文件 #!/bin/sh # # An example hook script to check the commit log message. # Called by "git commit&q…

基于SpringBoot+Vue+MySQL的流浪猫狗宠物救助救援网站管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 在当今社会&#xff0c;随着宠物数量的激增及人们关爱动物意识的提升&#xff0c;流浪猫狗问题日益严峻。为解决这一问题&#xff0c;构建一套高效、便捷的流浪猫狗宠物救助救援网站管理系统显得尤为重要。本系统基于SpringBoot…

CSP-CCF★★★201812-2小明放学★★★

目录 一、问题描述 二、解答 &#xff08;1&#xff09;注意&#xff1a; &#xff08;2&#xff09;80分版&#xff1a; &#xff08;3&#xff09;100分版&#xff1a; 三、总结 一、问题描述 二、解答 &#xff08;1&#xff09;注意&#xff1a; 题目的n小于等于10的…

m3u8网页视频文件爬取与视频合成

文章目录 m3u8网页视频文件爬取与视频合成下载m3u8文件下载m3u8文件列表所对应的ts文件下载ffmpeg m3u8网页视频文件爬取与视频合成 我们经常在网络上找到的自己想要的视频素材却无法下载&#xff0c;并且打开控制台一看视频是通过分割成一份份的.ts文件发送过来的。 下载m3u8…

零信任安全:重新思考数字世界的访问

目录 ​编辑 网络安全形势的演变 数字安全的变化 引入零信任安全 零信任的当今意义 了解零信任原则 零信任架构的核心概念 实施微分段 持续验证&#xff1a;积极主动的立场 与传统安全模型的对比 在现代企业中实施零信任 零信任实施基础知识 多重身份验证 (MFA) 的…

c++(继承、模板进阶)

一、模板进阶 1、非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中…

非监督式机器学习:群集

聚类分析是一种非监督式机器学习形式&#xff0c;在此形式下&#xff0c;基于观察值的数据值或特征的相似性&#xff0c;将观察值分组到群集中。 这种就是非监督式机器学习&#xff0c;因为它不使用先前已知的标签值来训练模型。 在聚类分析模型中&#xff0c;标签是群集&#…

帧缓冲 framebuffer

一、基本概念 framebuffer: 帧缓存、帧缓存&#xff08;显示设备&#xff09; Linux内核为显示提供的一套应用程序接口。&#xff08;驱动内核支持&#xff09; 分辨率&#xff1a; 像素点 显示屏&#xff1a;800 * 600&#xff08;横向有800个像素点&#xff0c;纵向有60…

DAY73

作业 pro文件&#xff1a; QT texttospeech 头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPushButton> //按钮类 #include <QLabel> //标签类 #include <QLineEdit> //行编译器类 #include…

阿里中间件——diamond

一、前言 最近工作不忙闲来无事&#xff0c;仔细分析了公司整个项目架构&#xff0c;发现用到了很多阿里巴巴集团开源的框架&#xff0c;今天要介绍的是中间件diamond. 二、diamond学习笔记 1、diamond简介 diamond是一个管理持久配置&#xff08;持久配置是指配置数据会持久化…

【Datawhale X 李宏毅苹果书 AI夏令营】《深度学习详解》Task3 打卡

文章目录 前言学习目标一、优化策略二、模型偏差三、优化问题三、过拟合增加训练集给模型一些限制 四、交叉验证五、不匹配总结 前言 本文是【Datawhale X 李宏毅苹果书 AI夏令营】的Task3学习笔记打卡。 学习目标 李宏毅老师对应视频课程&#xff1a;https://www.bilibili.…

QDY421F-16P-25液氨不锈钢液动紧急切断阀

一、产品概述 QDY421F-16P-25液氨不锈钢液动紧急切断阀&#xff0c;采用先进的液动驱动技术&#xff0c;结合高质量的不锈钢材质&#xff0c;专为满足液氨等腐蚀性介质的紧急切断需求而设计。该阀门的工作压力可达16MPa&#xff0c;适用于DN25&#xff08;即25毫米&#xff09;…

系统架构师考试学习笔记第四篇——架构设计实践知识(18)面向服务架构设计理论与实践

本章考点&#xff1a; 第18课时主要学习面向服务架构设计理论与实践。根据考试大纲&#xff0c;本课时知识点会涉及单选题型&#xff08;约占2~5分&#xff09;和案例题&#xff08;25分&#xff09;&#xff0c;本课时内容偏重于方法的掌握和应用&#xff0c;根据以往全国计算…

时序预测|基于小龙虾优化高斯过程GPR数据回归预测Matlab程序COA-GPR 多特征输入单输出 附赠基础GPR

时序预测|基于小龙虾优化高斯过程GPR数据回归预测Matlab程序COA-GPR 多特征输入单输出 附赠基础GPR 文章目录 一、基本原理二、实验结果三、核心代码四、代码获取五、总结 时序预测|基于小龙虾优化高斯过程GPR数据回归预测Matlab程序COA-GPR 多特征输入单输出 附赠基础GPR 一、…

mysql高级sql

文章目录 一&#xff0c;查询1.按关键字排序1.1按关键字排序操作(1)按分数排序查询&#xff08;不加asc默认为升序&#xff09;(2)按分数降序查询&#xff08;DESC&#xff09;(3)使用where进行条件查询(4)使用ORDER BY语句对多个字段排序 1.2使用区间判断查询&#xff08;and/…

如何通过内网穿透实现Pycharm远程服务器编译项目与服务器代码同步

文章目录 前言一、前期准备1. 检查IDE版本是否支持2. 服务器需要开通SSH服务 二、Pycharm本地链接服务器测试1. 配置服务器python解释器 三、使用内网穿透实现异地链接服务器开发1. 服务器安装Cpolar2. 创建远程连接公网地址 四、使用固定TCP地址远程开发 前言 本文主要介绍如…

Unity1 Prefab

修改预设体 进入预设体面板来改 在Hierarchy中可以给预制体添加对象 第一种方法&#xff1a;添加了之后把Hierarchy中的预制体拖到Project中的预制体上 就可以修改原本的预制体 第二种方法&#xff1a;添加了之后在inspector中 点revert 就是重置所有预制体 添加的就没有…

如何远程实时监控员工的电脑屏幕?远程桌面监控的五个可实现方法分享

想象一下&#xff0c;你在办公室喝着咖啡&#xff0c;员工的电脑屏幕却在数百公里之外实时呈现在你的眼前。你可以看到他们在干什么&#xff0c;是埋头工作还是悄悄摸鱼&#xff1f;远程桌面监控让这一切变得触手可及&#xff0c;简直像给了管理者一双“千里眼”&#xff01; 如…

Mysql(二) - 约束, 进阶查询

目录 一.约束 1.not null 2.unique 3.default 4.primary key 5. foreign key 6.check 7. 综合使用 二.进阶查询 1.新增(插入查询的结果) 2.聚合查询 a.聚合函数 b.使用 3.分组查询 4.联合查询 a.内连接 b.外连接 c.自连接 d.子查询 5.合并查询 三.总结 一…