爬虫逆向实战(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
            }
        } else
            for (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
            }
        } else
            for (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
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Golang 开发实战day04 - Standard Library

Golang 开发实战day04 - Standard Library 接下来开始我们第四天学习&#xff0c;Go语言标准库提供了丰富的功能&#xff0c;可以帮助开发者快速完成各种任务。 golang就像其他语言一样&#xff0c;附带了一些非常轻量级的函数和特性&#xff0c;都是开箱即用的&#xff0c;这里…

探索仿函数(Functor):C++中的灵活函数对象

文章目录 一、仿函数定义及使用二、仿函数与函数指针的区别三、仿函数与算法的关系四、仿函数的实践用例 在C编程中&#xff0c;我们经常需要对数据进行排序、筛选或者其他操作。为了实现这些功能&#xff0c;C标准库提供了许多通用的算法和容器&#xff0c;而其中一个重要的概…

AWS云上面的k8s统一日志收集(Fluent Bit+EKS+CW)

目标 k8s上面的常见的统一日志方案是EFK&#xff0c;具体如下&#xff1a; E:elasticsearch;F:fluentd;K:kibana 这里我们变成了使用fluentd的AWS替代品Fluent Bit&#xff0c;直接将日志输出到CloudWatch组。不需要E和K了。不过&#xff0c;这样仅仅用于AWS EKS。 步骤 给…

【C语言】字符与字符串---从入门到入土级详解

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 目录 一.字符类型和字符数组&#xff08;串&#xff09;简介 1.ASCII 2.定义&#xff0c;初始化&#xff0c;使用 1>字符的定义及初始化 2>字符串的定义及初始化 二.…

Linux——信号量

目录 POSIX信号量 信号量原理 信号量概念 信号量函数 基于环形队列的生产者消费者模型 生产者和消费者申请和释放资源 单生产者单消费者 多生产者多消费者 多生产者多消费者的意义 信号量的意义 POSIX信号量 信号量原理 如果仅用一个互斥锁对临界资源进行保护&#…

19.ADC模数转换器知识点+AD单通道AD多通道应用程序示例

0. 江协科技/江科大-STM32标准库开发-各章节详细笔记-查阅传送门_江协科技stm32笔记-CSDN博客文章浏览阅读2.9k次&#xff0c;点赞44次&#xff0c;收藏128次。江协科技/江科大-STM32标准库开发-各章节详细笔记-传送门至各个章节笔记。基本上课程讲的每句都详细记录&#xff0c…

PHP微信朋友圈广告植入源码 – 提供高效的广告植入解决方案,助力微信朋友圈广告推广

内容介绍 管理后台 可以无限制帮用户开户&#xff0c;也可以理解为多用户版。 可以管理用户发布文章条数&#xff0c;也可以无限制发布。 前端用户 用户可以上传多个广告&#xff0c;每个广告分别进行统计展示及点击。 用户一键植入&#xff0c;不用粘贴网址&#xff0c;每篇…

Spring Security自定义认证授权过滤器

自定义认证授权过滤器 自定义认证授权过滤器1、SpringSecurity内置认证流程2、自定义Security认证过滤器2.1 自定义认证过滤器2.2 定义获取用户详情服务bean2.3 定义SecurityConfig类2.4 自定义认证流程测试 3、 基于JWT实现无状态认证3.1 认证成功响应JWT实现3.2 SpringSecuri…

从大厂到高校,鸿蒙人才“红透半边天”!

截至目前&#xff0c;继清华大学、北京航空航天大学、武汉大学等985高校开设鸿蒙相关课程后&#xff0c;已经或将要开设鸿蒙相关课程的985、211高校达到近百所&#xff0c;为鸿蒙人才培养提供沃土。 随着鸿蒙系统即将摒弃安卓&#xff0c;鸿蒙原生应用将全面启动的背景下&…

4款实用性前端动画特效分享(附在线演示)

分享4款非常不错的项目动画特效 其中有jQuery特效、canvas特效、CSS动画等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 全屏图片视差旋转切换特效 基于anime.js制作全屏响应式的图片元素布局&#xff0c;通过左…

javaweb学习(day09-Web开发会话技术)

一、会话 1 基本介绍 1.1 什么是会话&#xff1f; 会话可简单理解为&#xff1a;用户开一个浏览器&#xff0c;点击多个超链接&#xff0c;访问服务器多个 web 资源&#xff0c;然 后关闭浏览器&#xff0c;整个过程称之为一个会话。 1.2 会话过程中要解决的一些问题&#…

[LVGL]:MACOS下使用LVGL模拟器

如何在MACOS下使用lvgl模拟器 1.安装必要环境 brew install sdl2查看sdl2安装位置&#xff1a; (base) ➜ ~ brew list sdl2 /opt/homebrew/Cellar/sdl2/2.30.1/bin/sdl2-config /opt/homebrew/Cellar/sdl2/2.30.1/include/SDL2/ (78 files) /opt/homebrew/Cellar/sdl2/2.3…

权威发布!艾媒咨询最新报告显示65.1%的消费者还在睡硬床

一直以来,“睡硬床好”观念在中国盛行,国民较多青睐硬床,床垫厂商为迎合大众,大批量生产硬床垫。日前,全球新经济产业第三方数据挖掘和分析机构iiMedia Research(艾媒咨询)发布《2024年中国硬床垫使用现状及潜在危害调研》(以下简称:报告),数据显示,75.1%的消费者对“睡硬床对腰…

DM数据库安装及使用(Windows、Linux、docker)

Windows 先解压安装包 点击setup安装 下一步 勾选接受然后下一步 下一步 选择典型安装下一步 下一步 搜索DM数据库配置助手然后一直下一步 然后搜索DM管理工具 登录 登录成功 widows版本安装成功 Linux安装 操作系统CPU数据库CentOS7x86_64 架构dm8_20230418_x86_rh6_64 …

Nacos源码流程图

1.Nacos1.x版本服务注册与发现源码 流程图地址&#xff1a;https://www.processon.com/view/link/634695eb260d7157a7bc6adb 2.Nacos2.x版本服务注册与发现源码 流程图地址&#xff1a;https://www.processon.com/view/link/634695fb260d7157a7bc6ae0 3.Nacos2.x版本GRPC…

【深度学习笔记】10_11 注意力机制

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 10.11 注意力机制 在10.9节&#xff08;编码器—解码器&#xff08;seq2seq&#xff09;&#xff09;里&#xff0c;解码器在各个时间…

Leet code 1658 将x减到0的最小操作数

解题思路&#xff1a;滑动窗口 主要思想&#xff1a;正难逆简 题目需要左找一个数 右找一个数 我们不如直接找中间最长的一连串子数让这串子树和为 数组子树和减去X 找不到就返回 -1 滑动窗口双指针从左端出发&#xff0c;进行 进窗口 判断 出窗口 更新结果四个步骤 代码…

用机床测头为什么能提升加工中心精度?提高生产效率?

制造业的蓬勃发展为企业提出了更高的精度和效率要求。在现代制造业中&#xff0c;机床测头作为一种关键的检测装置&#xff0c;能够实时监控加工过程中的误差&#xff0c;及时调整&#xff0c;保证加工质量的稳定性&#xff0c;提高加工中心的精度&#xff0c;进而提升生产效率…

QT 如何在QPushButton上播放gif(终极版)

在平时浏览网站&#xff0c;或者使用软件的时候&#xff0c;经常可以见到&#xff1a;在点击了某个按钮之后&#xff0c;按钮上会显示动图以及提示文字。在QT中&#xff0c;比较常见且简单的做法就是&#xff1a;给按钮设置一个layout&#xff0c;然后在这个layout里面添加QLab…

openssl3.2 - note - Getting Started with OpenSSL

文章目录 openssl3.2 - note - Getting Started with OpenSSL概述笔记openssl 历史版本Configure 选项开关支持的OSopenssl 文档简介安装新闻每个平台的安装文档支持的命令列表配置文件格式环境变量 END openssl3.2 - note - Getting Started with OpenSSL 概述 看到官方文档…