【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.mzph.cn/bicheng/53741.shtml

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

相关文章

鸿蒙界面开发——组件(7):组件导航 页面路由

组件导航 (Navigation)(推荐) Navigation() Navigation(pathInfos: NavPathStack)Navigation是路由容器组件&#xff0c;一般作为首页的根容器&#xff0c;包括单栏(Stack)、分栏(Split)和自适应(Auto)三种显示模式。Navigation组件适用于模块内和跨模块的路由切换&#xff0c…

ApacheKafka中的设计

文章目录 1、介绍1_Kafka&MQ场景2_Kafka 架构剖析3_分区&日志4_生产者&消费者组5_核心概念总结6_顺写&mmap7_Kafka的数据存储形式 2、Kafka的数据同步机制1_高水位&#xff08;High Watermark&#xff09;2_LEO3_高水位更新机制4_副本同步机制解析5_消息丢失问…

ollama 本地部署

ollama 本地模型部署 下载安装: [link](https://ollama.com/download)下载说明 部署使用在终端查看ollama是否安装完成终端查看ollama 命令说明查看当前支持下载的模型启动对话模式默认情况下&#xff0c;ollama启动了server 的api访问功能 外部 api访问使用postman网页版本for…

【MATLAB】模拟退火算法

模拟退火算法的MATLAB实现 模拟退火算法简介模拟退火算法应用实例关于计算结果 模拟退火算法简介 1982年&#xff0c;Kirkpatrick 将退火思想引入组合优化领域&#xff0c;提出了一种能够有效解决大规模组合优化问题的算法&#xff0c;尤其对 NP 完全问题表现出显著优势。模拟…

电商平台如何实现自动监控订单签收状态,加快资金划拨进程?

资金划拨作为交易流程的核心环节之一&#xff0c;直接关系到商家资金回笼的速度、消费者购物体验的满意度以及平台自身的信誉与稳定性。 区别于自营电商&#xff0c;电商平台入驻了许多第三方商家&#xff0c;为了保障交易安全和控制风险&#xff0c;在交易未完成之前&#xff…

超声波测距模块HC-SR04(基于STM32F103C8T6HAL库)

超声波测距模块参考资料 1.电路连接及引脚配置 触发信号PA3只需要输出10us的高电平&#xff0c;所以直接设置成 普通的GPIO端口即可&#xff1b;回响信号使用外部中断&#xff0c;上升沿信号产生外部中断&#xff0c;打开定时器&#xff0c;下降沿再产生一次中断&#xff0c;读…

数据丢失?别慌!EasyRecovery带你轻松寻回!

&#x1f31f; 意外总在不经意间降临 &#x1f31f; 亲爱的小伙伴们&#xff0c;你是否有过这样的经历&#xff1a;正专心致志地处理着电脑文件&#xff0c;突然一次误操作&#xff0c;重要的资料就这样不见了&#xff0c;那种心如刀绞的感觉瞬间涌上心头。&#x1f616; 使用…

MySQL事务【后端 13】

MySQL事务 在数据库管理系统中&#xff0c;事务&#xff08;Transaction&#xff09;是一个非常重要的概念&#xff0c;它确保了数据库操作的完整性和一致性。MySQL作为一种流行的关系型数据库管理系统&#xff0c;自然也支持事务处理。本文将深入探讨MySQL事务的基本概念、特性…

StorageSync数据缓存API

uni.setStorageSyncs参数:将 data 存储在本地缓存中指定的 key 中&#xff0c;会覆盖掉原来该 key 对应的内容&#xff0c;这是一个同步接口。 uni.setStorageSync函数里面写两个参数,分别是key和值,两个参数名称可以随便取,如果有同名的key,那么后面key的值会覆盖掉前面key的值…

毫欧表设计整体思路

原因 对于焊接设备的低阻值测量&#xff0c;一般都是mΩ级别的&#xff0c;但万用表的电阻档一般都是以200Ω做为最小档位 设计原理及软件实现设计 设计思路原理图 通过串联在电路中的电流相等&#xff0c;根据阻值和电压的关系得到电阻对应大小 设计中需要考虑的问题 1…

Why I‘m getting 404 Resource Not Found to my newly Azure OpenAI deployment?

题意&#xff1a;为什么我新部署的Azure OpenAI服务会出现404资源未找到的错误&#xff1f; 问题背景&#xff1a; Ive gone through this quickstart and I created my Azure OpenAI resource created a model deployment which is in state succeedded. I also playaround …

【C++ Primer Plus习题】14.3

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include "queuetp.h&quo…

JavaWeb后端开发总结(3)

AOP基础 AOP概述 首先我们要知道AOP是什么&#xff1f; 看下图 个人解析&#xff1a; AOP叫做面向切面编程&#xff0c;但是实际上就是面向方法编程 图中下面一部分是一个AOP的案例 AOP快速入门案例代码实现 案例&#xff1a;测出业务中各个业务方法所需的执行时间 如果…

进程与计划任务

top 查看进程 x users 表示有几个shell开启 x stopped 前台任务在后台暂停firefox & 在后台运行&#xff0c;不在前面显示 ​​​​​​​这种方式常用于需要长时间运行且不需要即时交互的程序或命令&#xff0c;以便用户可以在终端中使用其他命令或进行其他操作&#…

Linux平台屏幕|摄像头采集并实现RTMP推送两种技术方案探究

技术背景 随着国产化操作系统的推进&#xff0c;市场对国产化操作系统下的生态构建&#xff0c;需求越来越迫切&#xff0c;特别是音视频这块&#xff0c;今天我们讨论的是如何在linux平台实现屏幕|摄像头采集&#xff0c;并推送至RTMP服务。 我们知道&#xff0c;Linux平台&…

debug对于开发工程师很重要

在日常开发中&#xff0c;总会遇到一些出人意料的bug&#xff0c;程序跑飞&#xff0c;上电就挂&#xff0c;程序没有按预期执行诸如此类的问题&#xff0c;没有好的调试方法&#xff0c;真的很难定位问题&#xff0c;更别说解决了。在这里分享我用过的一些调试方法&#xff0c…

“论剑”智算时代,长沙已经站在计算产业的“华山之巅”

文 | 智能相对论 作者 | 陈泊丞 共赴全新十年之约&#xff0c;长沙又来搞大事情了&#xff01; 2024互联网岳麓峰会以“AI汇湘江 数智领航未来”为主题&#xff0c;全面聚焦在“AI”时代把握数字化、网络化、智能化发展机遇&#xff0c;积极响应当前人工智能技术迅猛发展的势…

Qt5.4.1连接odbc驱动操作达梦数据库

Qt5.4.1连接odbc驱动操作达梦数据库 1 环境介绍2 Qt5.4.1 安装2.1 图形化界面安装Qt5.4.12.2 配置Qt5.4.1 环境变量2.3 Qt5.4.1 生成 libqsqlodbc.so 并配置2.3.1 生成Makefile2.3.2 查看 libqsqlodbc.so 文件并配置 3 配置Qt测试用例4 达梦数据库学习使用列表 1 环境介绍 CPU…

实现卷积层的前向传播(Pythom版)

在TensorFlow框架中&#xff0c;实现卷积层&#xff08;2维&#xff09;的代码是 tf.keras.layers.Conv2D()。它主要接收如下几个参数&#xff0c; filters&#xff1a;卷积核的个数&#xff0c;也就是卷积层输出的通道数&#xff08;沿axis-1的维度&#xff09; kernel_size&a…

性能碾压pandas、polars的数据分析神器来了

来源&#xff1a;python大数据分析 费弗里 1 简介 就在几天前&#xff0c;经过六年多的持续开发迭代&#xff0c;著名的开源高性能分析型数据库DuckDB发布了其1.0.0正式版本。 DuckDB具有极强的单机数据分析性能表现&#xff0c;功能丰富&#xff0c;具有诸多拓展插件&#xf…