爬虫逆向实战(36)-某建设监管平台(RSA,魔改)

2024-03-16 06:28

本文主要是介绍爬虫逆向实战(36)-某建设监管平台(RSA,魔改),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、数据接口分析

主页地址:某建设监管平台

1、抓包

通过抓包可以发现网站首先是请求了一个/prod-api/mohurd-pub/vcode/genVcode的接口,用于获取滑块验证码的图片
在这里插入图片描述
滑块验证之后,请求了/prod-api/mohurd-pub/dataServ/findBaseEntDpPage这个接口,来获取数据
在这里插入图片描述

2、判断是否有加密参数

  1. 请求参数是否加密?
    通过查看“载荷”模块可以发现,这两个接口都是只有一个params的加密参数
    在这里插入图片描述
  2. 请求头是否加密?
  3. 响应是否加密?
  4. cookie是否加密?

二、加密位置定位

1、看启动器

查看启动器发现里面包含异步,所以无法正确找到加密位置
在这里插入图片描述

2、搜索关键字

通过搜索关键字,发现可以搜出来很多位置,无法准确定位到加密位置
在这里插入图片描述

3、Hook

因为请求参数中只有一个params参数,所以网站大概率会使用JSON.stringify方法将明文数据转json之后再加密。
通过hook,我们可以找到加密位置
在这里插入图片描述
同时,可以发现params是进行了双重加密,首先使用W_e().encrypt进行了一次加密(此处有点类似于AES或DES加密,但是通过测试,发现加密结果不一致,所以可能是魔改加密算法),然后将加密结果再使用X_e进行二次加密(此处是标准RSA加密)。

三、扣js代码

W_e().encrypt方法扣出,缺啥补啥即可,X_e方法可以扣网站代码,也可以直接使用标准模块。
注:
此网站的滑块验证码,仅需将缺口距离在第二次数据接口请求时带上即可
源代码:

const JSEncrypt = require('jsencrypt');
const G_e = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC29miF1Wp9XlhCECo+FYpCHad1ipEMgXf4IdgYjMIQwczzo9GXdcZ4eeV+9lkh6+aTqzzU843rdkMt0vrSnujU+GOuDPLfa5LZ6SfanAoysi6xxTX02Xizb3k+Z1USIzm9QAwE+SR1AQ78rGTRFHWFu7OGPkVNeF+vrX3inQTiawIDAQAB";function Jbe(e) {var t = n7(e), n = t[0], o = t[1];return (n + o) * 3 / 4 - o
}function exe(e) {var t, n = n7(e), o = n[0], r = n[1], s = new Xbe(Qbe(e, o, r)), a = 0, l = r > 0 ? o - 4 : o, i;for (i = 0; i < l; i += 4)t = oo[e.charCodeAt(i)] << 18 | oo[e.charCodeAt(i + 1)] << 12 | oo[e.charCodeAt(i + 2)] << 6 | oo[e.charCodeAt(i + 3)],s[a++] = t >> 16 & 255,s[a++] = t >> 8 & 255,s[a++] = t & 255;return r === 2 && (t = oo[e.charCodeAt(i)] << 2 | oo[e.charCodeAt(i + 1)] >> 4,s[a++] = t & 255),r === 1 && (t = oo[e.charCodeAt(i)] << 10 | oo[e.charCodeAt(i + 1)] << 4 | oo[e.charCodeAt(i + 2)] >> 2,s[a++] = t >> 8 & 255,s[a++] = t & 255),s
}
function txe(e) {return Vo[e >> 18 & 63] + Vo[e >> 12 & 63] + Vo[e >> 6 & 63] + Vo[e & 63]
}
function nxe(e, t, n) {for (var o, r = [], s = t; s < n; s += 3)o = (e[s] << 16 & 16711680) + (e[s + 1] << 8 & 65280) + (e[s + 2] & 255),r.push(txe(o));return r.join("")
}
function oxe(e) {for (var t, n = e.length, o = n % 3, r = [], s = 16383, a = 0, l = n - o; a < l; a += s)r.push(nxe(e, a, a + s > l ? l : a + s));return o === 1 ? (t = e[n - 1],r.push(Vo[t >> 2] + Vo[t << 4 & 63] + "==")) : o === 2 && (t = (e[n - 2] << 8) + e[n - 1],r.push(Vo[t >> 10] + Vo[t >> 4 & 63] + Vo[t << 2 & 63] + "=")),r.join("")
}var jc = {};
jc.byteLength = Jbe;
jc.toByteArray = exe;
jc.fromByteArray = oxe;
const O6 = jc;
var Vo = [], oo = [], Xbe = typeof Uint8Array != "undefined" ? Uint8Array : Array, Lu = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (var js = 0, Zbe = Lu.length; js < Zbe; ++js)Vo[js] = Lu[js],oo[Lu.charCodeAt(js)] = js;
class V_e {static stringToArrayBufferInUtf8(t) {const n = typeof window == "undefined" ? yd.TextEncoder : window.TextEncoder;return new n().encode(t)}static utf8ArrayBufferToString(t) {const n = typeof window == "undefined" ? yd.TextDecoder : window.TextDecoder;return new n("utf-8").decode(t)}static arrayBufferToBase64(t) {return O6.fromByteArray(t)}static base64ToArrayBuffer(t) {return O6.toByteArray(t)}
}const Sr = V_e, to = 16, Di = Uint8Array.from([214, 144, 233, 254, 204, 225, 61, 183, 22, 182, 20, 194, 40, 251, 44, 5, 43, 103, 154, 118, 42, 190, 4, 195, 170, 68, 19, 38, 73, 134, 6, 153, 156, 66, 80, 244, 145, 239, 152, 122, 51, 84, 11, 67, 237, 207, 172, 98, 228, 179, 28, 169, 201, 8, 232, 149, 128, 223, 148, 250, 117, 143, 63, 166, 71, 7, 167, 252, 243, 115, 23, 186, 131, 89, 60, 25, 230, 133, 79, 168, 104, 107, 129, 178, 113, 100, 218, 139, 248, 235, 15, 75, 112, 86, 157, 53, 30, 36, 14, 94, 99, 88, 209, 162, 37, 34, 124, 59, 1, 33, 120, 135, 212, 0, 70, 87, 159, 211, 39, 82, 76, 54, 2, 231, 160, 196, 200, 158, 234, 191, 138, 210, 64, 199, 56, 181, 163, 247, 242, 206, 249, 97, 21, 161, 224, 174, 93, 164, 155, 52, 26, 85, 173, 147, 50, 48, 245, 140, 177, 227, 29, 246, 226, 46, 130, 102, 202, 96, 192, 41, 35, 171, 13, 83, 78, 111, 213, 219, 55, 69, 222, 253, 142, 47, 3, 255, 106, 114, 109, 108, 91, 81, 141, 27, 175, 146, 187, 221, 188, 127, 17, 217, 92, 65, 31, 16, 90, 216, 10, 193, 49, 136, 165, 205, 123, 189, 45, 116, 208, 18, 184, 229, 180, 176, 137, 105, 151, 74, 12, 150, 119, 126, 101, 185, 241, 9, 197, 110, 198, 132, 24, 240, 125, 236, 58, 220, 77, 32, 121, 238, 95, 62, 215, 203, 57, 72]), L_e = Uint32Array.from([462357, 472066609, 943670861, 1415275113, 1886879365, 2358483617, 2830087869, 3301692121, 3773296373, 4228057617, 404694573, 876298825, 1347903077, 1819507329, 2291111581, 2762715833, 3234320085, 3705924337, 4177462797, 337322537, 808926789, 1280531041, 1752135293, 2223739545, 2695343797, 3166948049, 3638552301, 4110090761, 269950501, 741554753, 1213159005, 1684763257]), Oi = Uint32Array.from([2746333894, 1453994832, 1736282519, 2993693404]);class R_e {constructor(t) {let n = Sr.stringToArrayBufferInUtf8(t.key);if (n.length !== 16)throw new Error("key should be a 16 bytes string");this.key = n;let o = new Uint8Array(0);if (t.iv !== void 0 && t.iv !== null && (o = Sr.stringToArrayBufferInUtf8(t.iv),o.length !== 16))throw new Error("iv should be a 16 bytes string");this.iv = o,this.mode = "cbc",["cbc", "ecb"].indexOf(t.mode) >= 0 && (this.mode = t.mode),this.cipherType = "base64",["base64", "text"].indexOf(t.outType) >= 0 && (this.cipherType = t.outType),this.encryptRoundKeys = new Uint32Array(32),this.spawnEncryptRoundKeys(),this.decryptRoundKeys = Uint32Array.from(this.encryptRoundKeys),this.decryptRoundKeys.reverse()}doBlockCrypt(t, n) {let o = new Uint32Array(36);o.set(t, 0);for (let s = 0; s < 32; s++)o[s + 4] = o[s] ^ this.tTransform1(o[s + 1] ^ o[s + 2] ^ o[s + 3] ^ n[s]);let r = new Uint32Array(4);return r[0] = o[35],r[1] = o[34],r[2] = o[33],r[3] = o[32],r}spawnEncryptRoundKeys() {let t = new Uint32Array(4);t[0] = this.key[0] << 24 | this.key[1] << 16 | this.key[2] << 8 | this.key[3],t[1] = this.key[4] << 24 | this.key[5] << 16 | this.key[6] << 8 | this.key[7],t[2] = this.key[8] << 24 | this.key[9] << 16 | this.key[10] << 8 | this.key[11],t[3] = this.key[12] << 24 | this.key[13] << 16 | this.key[14] << 8 | this.key[15];let n = new Uint32Array(36);n[0] = t[0] ^ Oi[0],n[1] = t[1] ^ Oi[1],n[2] = t[2] ^ Oi[2],n[3] = t[3] ^ Oi[3];for (let o = 0; o < 32; o++)n[o + 4] = n[o] ^ this.tTransform2(n[o + 1] ^ n[o + 2] ^ n[o + 3] ^ L_e[o]),this.encryptRoundKeys[o] = n[o + 4]}rotateLeft(t, n) {return t << n | t >>> 32 - n}linearTransform1(t) {return t ^ this.rotateLeft(t, 2) ^ this.rotateLeft(t, 10) ^ this.rotateLeft(t, 18) ^ this.rotateLeft(t, 24)}linearTransform2(t) {return t ^ this.rotateLeft(t, 13) ^ this.rotateLeft(t, 23)}tauTransform(t) {return Di[t >>> 24 & 255] << 24 | Di[t >>> 16 & 255] << 16 | Di[t >>> 8 & 255] << 8 | Di[t & 255]}tTransform1(t) {let n = this.tauTransform(t);return this.linearTransform1(n)}tTransform2(t) {let n = this.tauTransform(t);return this.linearTransform2(n)}padding(t) {if (t === null)return null;let n = to - t.length % to, o = new Uint8Array(t.length + n);return o.set(t, 0),o.fill(n, t.length),o}dePadding(t) {if (t === null)return null;let n = t[t.length - 1];return t.slice(0, t.length - n)}uint8ToUint32Block(t, n=0) {let o = new Uint32Array(4);return o[0] = t[n] << 24 | t[n + 1] << 16 | t[n + 2] << 8 | t[n + 3],o[1] = t[n + 4] << 24 | t[n + 5] << 16 | t[n + 6] << 8 | t[n + 7],o[2] = t[n + 8] << 24 | t[n + 9] << 16 | t[n + 10] << 8 | t[n + 11],o[3] = t[n + 12] << 24 | t[n + 13] << 16 | t[n + 14] << 8 | t[n + 15],o}encrypt(t) {let n = Sr.stringToArrayBufferInUtf8(t), o = this.padding(n), r = o.length / to, s = new Uint8Array(o.length);if (this.mode === "cbc") {if (this.iv === null || this.iv.length !== 16)throw new Error("iv error");let a = this.uint8ToUint32Block(this.iv);for (let l = 0; l < r; l++) {let i = l * to, c = this.uint8ToUint32Block(o, i);a[0] = a[0] ^ c[0],a[1] = a[1] ^ c[1],a[2] = a[2] ^ c[2],a[3] = a[3] ^ c[3];let u = this.doBlockCrypt(a, this.encryptRoundKeys);a = u;for (let f = 0; f < to; f++)s[i + f] = u[parseInt(f / 4)] >> (3 - f) % 4 * 8 & 255}} elsefor (let a = 0; a < r; a++) {let l = a * to, i = this.uint8ToUint32Block(o, l), c = this.doBlockCrypt(i, this.encryptRoundKeys);for (let u = 0; u < to; u++)s[l + u] = c[parseInt(u / 4)] >> (3 - u) % 4 * 8 & 255}return this.cipherType === "base64" ? Sr.arrayBufferToBase64(s) : Sr.utf8ArrayBufferToString(s)}decrypt(t) {let n = new Uint8Array;this.cipherType === "base64" ? n = Sr.base64ToArrayBuffer(t) : n = Sr.stringToArrayBufferInUtf8(t);let o = n.length / to, r = new Uint8Array(n.length);if (this.mode === "cbc") {if (this.iv === null || this.iv.length !== 16)throw new Error("iv error");let a = this.uint8ToUint32Block(this.iv);for (let l = 0; l < o; l++) {let i = l * to, c = this.uint8ToUint32Block(n, i), u = this.doBlockCrypt(c, this.decryptRoundKeys), f = new Uint32Array(4);f[0] = a[0] ^ u[0],f[1] = a[1] ^ u[1],f[2] = a[2] ^ u[2],f[3] = a[3] ^ u[3],a = c;for (let d = 0; d < to; d++)r[i + d] = f[parseInt(d / 4)] >> (3 - d) % 4 * 8 & 255}} elsefor (let a = 0; a < o; a++) {let l = a * to, i = this.uint8ToUint32Block(n, l), c = this.doBlockCrypt(i, this.decryptRoundKeys);for (let u = 0; u < to; u++)r[l + u] = c[parseInt(u / 4)] >> (3 - u) % 4 * 8 & 255}let s = this.dePadding(r);return Sr.utf8ArrayBufferToString(s)}
}
var j_e = {sm4: R_e
}
function W_e() {const t = {};t.key = "B6*40.2_C9#e4$E3",t['mode'] = 'ecb',t.cipherType = "base64";const n = t, o = j_e['sm4'];return new o(n)
}function get_params(data) {e = W_e().encrypt(JSON.stringify(data))var encrypt = new JSEncrypt();encrypt.setPublicKey(G_e);const o = 117, r = Math['ceil'](e['length'] / o);let s = [];for (let a = 0; a < r; a++) {const l = e.slice(a * o, (a + 1) * o), i = encrypt.encrypt(l);s.push(i)}return s
}

这篇关于爬虫逆向实战(36)-某建设监管平台(RSA,魔改)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/814579

相关文章

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

如何解决线上平台抽佣高 线下门店客流少的痛点!

目前,许多传统零售店铺正遭遇客源下降的难题。尽管广告推广能带来一定的客流,但其费用昂贵。鉴于此,众多零售商纷纷选择加入像美团、饿了么和抖音这样的大型在线平台,但这些平台的高佣金率导致了利润的大幅缩水。在这样的市场环境下,商家之间的合作网络逐渐成为一种有效的解决方案,通过资源和客户基础的共享,实现共同的利益增长。 以最近在上海兴起的一个跨行业合作平台为例,该平台融合了环保消费积分系统,在短