爬虫逆向实战(28)-某税网第一步登录(sm2、sm4、HMacSHA256)

news2024/11/17 17:42:57

一、数据接口分析

主页地址:某税网

1、抓包

通过抓包可以发现登录接口是factorAccountLogin
在这里插入图片描述

2、判断是否有加密参数

  1. 请求参数是否加密?
    通过查看载荷模块可以发现有一个datagram 和 一个signature加密参数
    在这里插入图片描述
  2. 请求头是否加密?
    通过查看“标头”模块可以发现,请求头中有DeviceidentynoX-App-ClientidX-Temp-Info三个加密参数
    在这里插入图片描述
  3. 响应是否加密?
    登录失败是无加密,登录成功时datagram是加密参数
  4. cookie是否加密?

二、加密位置定位

1、加密参数以及部分请求头

(1)看启动器

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

(2)搜索关键字

通过搜索关键字datagram=可以发现在请求拦截器中会对datagram进行赋值,并且此处还有signature参数以及部分请求头,所以此处大概率是加密位置。
在这里插入图片描述
在此处下断点,发现可以断住,并且生成位置就在上方,所以此处就是加密位置
在这里插入图片描述

2、请求头Deviceidentyno

搜索关键字

通过搜索关键字Deviceidentyno可以找到设置请求头的位置。
在这里插入图片描述

3、响应解密

因为定位到的加密位置是在请求拦截器中,所以解密位置大概率会在响应拦截器中,我们可以在请求拦截器的js文件中搜索interceptors.response就可以找到响应拦截器的位置。并且可以发现,在响应拦截器中确实有解密操作。
在这里插入图片描述

三、扣js代码

1、本地存储

我们在扣js代码时,可以发现网站会从本地缓存中取出一些数据,但是其中只有new_key16clientIdnatureuuid是有值的,其他都是空。同时我们可以看到,网站将new_key16取出的值赋值给了a,然后在下方代码中,又判断a是否为空,如果为空就使用Object(A["b"])()方法生成,所以我们就可以直接将这个生成方法扣出,使用这个方法生成。clientId仔细观察可以发现,这个值是固定不变的,可以写死。所以我们只需要关心natureuuid即可。
在这里插入图片描述
进入控制台的“应用”标签页中的“本地存储空间”,将本地存储全部清除
在这里插入图片描述
然后对localStorage.setItem进行hook
hook代码:

var my_setItem = localStorage.setItem;
localStorage.setItem = function (key, value) {
    if (key == 'natureuuid'){
        debugger
    }
    return my_setItem.call(localStorage, key, value);
};

运行hook代码,再次点击登录,发现可以断住
在这里插入图片描述
接着调试执行,可以发现设置natureuuid的位置,同时可以看出这段代码是在回调中执行的。
在这里插入图片描述
再次观察发包可以发现,网站是请求了一个getPublicKey接口,返回了uuidpublicKey,虽然目前来看我们没有用到publicKey,但是肯定是有用到的地方,所以我们也先保存一下。
在这里插入图片描述

2、请求流程

当我们将本地存储清空之后,再次登录可以发现,网站是发送了三个请求,先请求了getPublicKey和sendSm4这两个接口之后才请求了登录接口。
在这里插入图片描述
所以我们在请求登录之前也需要先请求这两个接口。
观察这两个接口的“载荷”,可以发现这两个接口携带的参数与登录接口是一样的,只不过其中的数据不同,同时,网站在请求前两个接口时,也会经过我们上面定位出来的加密位置,只不过datagram的生成不太一样,前两个接口只是转成了json字符串,只有登录接口才加密。
在这里插入图片描述
在观察前两个接口的发包过程时,可以发现第一个接口getPublicKey的datagram就只是一个空字典,然后转成json字符串。但是,网站在给sendSm4接口发包时,是有数据的,而且还有一个我们不知道的参数secret
在这里插入图片描述
我们通过搜索关键字的方式,搜索secret:就可以找到生成位置了,同时这个参数生成的时候还用到了之前通过请求getPublicKey接口获取到的publicKey
在这里插入图片描述

3、坑

在对这三个请求发包时,使用的new_key16以及deviceIdentyNo的值都要使用同一个。

4、加密算法

通过扣js代码可以发现,网站使用了sm2、sm4以及HmacSHA256三种加密算法,解密时使用的是sm4解密,而且这些算法都是标准算法,所以我们可以直接使用标准模块进行加解密。

四、源代码

JavaScript源码:

const {sm2, sm4} = require("sm-crypto");
const CryptoJS = require("crypto-js");

function func_i(e, t) {
    var n, a, r = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""), i = [];
    if (t = t || r.length,
        e)
        for (n = 0; n < e; n++)
            i[n] = r[0 | Math.random() * t];
    else
        for (i[8] = i[13] = i[18] = i[23] = "-",
                 i[14] = "4",
                 n = 0; n < 36; n++)
            i[n] || (a = 0 | 16 * Math.random(),
                i[n] = r[19 == n ? 3 & a | 8 : a]);
    return i.join("")
}


function object_A_d(e, t) {
    r = sm4.encrypt(e, t);
    return r
}

function object_A_i(e) {
    for (var t = "", n = 0; n < e.length; n++)
        "" === t ? t = e.charCodeAt(n).toString(16) : t += e.charCodeAt(n).toString(16);
    return t
}

function object_A_a(e, t) {
    var n = CryptoJS.HmacSHA256(e, t).toString();
    return n
}

function object_A_e(e, t) {
    r = sm4.decrypt(e, t);
    return r
}

function padZero(num) {
    return num < 10 ? "0" + num : num;
}

var clientId = 's44fftt3bc634tcab4teasbaasba7ft4'

function get_headers(natureuuid, ded) {
    if (!ded) {
        ded = func_i(32)
    }
    var t = {
        headers: {},
    }
    t.headers["deviceIdentyNo"] = ded;
    t.headers["X-APP-CLIENTID"] = clientId
    if (natureuuid) {
        t.headers["X-TEMP-INFO"] = natureuuid
    }
    return [t.headers, ded]
}
var v = 'GwdK^R4q'
function get_params(t_data, is_get_key, g) {
    if (!g) {
        g = func_i(16, 61)
    }
    var currentDate = new Date();
    var formattedDate = currentDate.getFullYear() +
        padZero(currentDate.getMonth() + 1) +
        padZero(currentDate.getDate()) +
        padZero(currentDate.getHours()) +
        padZero(currentDate.getMinutes()) +
        padZero(currentDate.getSeconds());

    c = {}

    p = g.substring(0, 8) + v
    u = ""
    c["zipCode"] = "0"
    if (is_get_key) {
        c["encryptCode"] = "0";
        c.datagram = JSON.stringify(t_data);
    } else {
        f = JSON.stringify(t_data);
        u = object_A_d(f, object_A_i(p));
        c.datagram = u;
        c["encryptCode"] = "2";
    }
    c["timestamp"] = formattedDate
    c["access_token"] = ""
    c["signtype"] = "HMacSHA256"
    c["signature"] = object_A_a(c["zipCode"] + c["encryptCode"] + u + c["timestamp"] + c["signtype"], g)
    return [c, g]
}

function func_l(e, t, a) {
    if (t) {
        var i = sm2.doEncrypt(e, t, a);
        return i
    }
    return ""
}

function get_secret(pubkey, g) {
    new_key16 = g
    secret = func_l(new_key16, pubkey, 1)
    return secret
}

function get_data(g, datagram) {
    var a = g.substring(0, 8) + v;
    return object_A_e(datagram, object_A_i(a))
}

Python源码:

"""
Author:陈帅超
Email:912917367@qq.com
Date: 2023/8/29 16:25
"""
import json

import execjs
import requests


class Spider:
    def __init__(self):
        self.session = requests.session()
        self.session.headers = {
            "Accept": "application/json, text/plain, */*",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "Authorization": "",
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Content-Type": "application/json",
            "Origin": "https://tpass.jiangsu.chinatax.gov.cn:8443",
            "Pragma": "no-cache",
            "Referer": "https://tpass.jiangsu.chinatax.gov.cn:8443/",
            "Sec-Fetch-Dest": "empty",
            "Sec-Fetch-Mode": "cors",
            "Sec-Fetch-Site": "same-origin",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
            "X-LANG-ID": "null",
            "X-NATURE-IP": "",
            "X-SM4-INFO": "0",
            "X-TICKET-ID": "null",
            "hUid": "",
            "sec-ch-ua": "^\\^Chromium^^;v=^\\^116^^, ^\\^Not)A;Brand^^;v=^\\^24^^, ^\\^Google",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "^\\^Windows^^"
        }
        with open('reverse.js', 'r', encoding='utf-8') as f:
            self.js_obj = execjs.compile(f.read())
        self.uuid = ''
        self.publicKey = ''
        self.g = ''
        self.ded = ''

    def get_public_key(self):
        url = "https://tpass.jiangsu.chinatax.gov.cn:8443/sys-api/v1.0/auth/oauth2/getPublicKey"
        headers2 = self.js_obj.call('get_headers', self.uuid)
        self.ded = headers2[0]
        self.session.headers = headers2[0] | self.session.headers
        data = self.js_obj.call('get_params', {}, True)
        self.g = data[1]
        response = self.session.post(url, json=data[0])
        datagram = json.loads(response.json()['datagram'])
        self.uuid = datagram['uuid']
        self.publicKey = datagram['publicKey']
        print('uuid:', self.uuid)
        print('publicKey:', self.publicKey)

    def send_sm4(self):
        url = "https://tpass.jiangsu.chinatax.gov.cn:8443/sys-api/v1.0/auth/white/sendSm4"
        headers2 = self.js_obj.call('get_headers', self.uuid, self.ded)
        self.session.headers = headers2[0] | self.session.headers
        secret = self.js_obj.call('get_secret', self.publicKey, self.g)
        data = self.js_obj.call('get_params', {'uuid': self.uuid, 'secret': secret}, True, self.g)
        response = self.session.post(url, json=data[0])

        print(response.text)
        print(response)

    def login(self):
        t_data = {
            "client_id": 's44fftt3bc634tcab4teasbaasba7ft4',
            "account": '登录用户名',
            "password": '登录密码',
            "redirect_uri": "https://etax.jiangsu.chinatax.gov.cn/sso/kxLogin/authorize",
            "creditCode": '税号'
        }
        url = "https://tpass.jiangsu.chinatax.gov.cn:8443/sys-api/v1.0/auth/enterprise/quick/factorAccountLogin"
        headers2 = self.js_obj.call('get_headers', self.uuid, self.ded)
        self.session.headers = headers2[0] | self.session.headers
        data = self.js_obj.call('get_params', t_data, False, self.g)
        response = self.session.post(url, json=data[0])

        response_data = self.js_obj.call('get_data', self.g, response.json()['datagram'])
        print(response_data)


if __name__ == '__main__':
    s = Spider()
    s.get_public_key()
    s.send_sm4()
    s.login()

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

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

相关文章

nvm管理(切换)node版本,方便vue2,vue3+ts开发

使用nvm切换node版本 1. 完全删除之前的node及npm&#xff08;清理干净Node: 应用程序&#xff0c;缓存的文件&#xff0c;环境变量 &#xff09; 2. 使用管理员身份安装nvm&#xff0c;下载如下 3. 安装完nvm之后找到nvm下载路径对应的文件 4. 使用管理员身份打开cmd&#xff…

中缀表达式转后缀表达式(逆波兰式)

方法一&#xff1a;加括号法示例 步骤&#xff1a; 1、根据运算符的优先级对中缀表达式加括号&#xff08;有几个运算符就有几对括号&#xff0c;原有的括号不用加&#xff09; 2、将运算符移到对应括号后面 3、去掉所有括号&#xff0c;即为后缀表达式 以下面的中缀表达式为…

2023 年全国大学生数学建模A题目-定日镜场的优化设计

A题目是个典型的优化问题 大致思路&#xff08;非完整&#xff09; 先说题目的模型&#xff0c;有点类似一个人拿着镜子&#xff0c;这个镜子最终要映射到某个点上&#xff0c;有点类似下面这个玩意儿&#xff0c;只不过是个大型的而已 规划的吸收塔类似这个烧水壶&#xff0c;…

纷享销客华为云 | 聚力前行 共创云上新价值

近日&#xff0c;由华为云联合上万家生态伙伴举行的“第二届828 B2B企业节”在深圳盛大开幕&#xff0c;纷享销客作为华为云的战略合作伙伴出席了本次企业节的开幕&#xff0c;并斩获“华为云创新中心优秀制造解决方案伙伴”等多个奖项。纷享销客联合创始人 & 经营中心副总…

CTFHUB ICS(3)

1.S7协议恶意攻击分析 因为是plc的关机&#xff0c;我们直接过滤s7comm协议的内容 然后是提供info的排序我们可以根据这个进行分析 在plc中ack_data是对于job的响应这里ack_data返回了plc的stop即题目中描述的plc关机&#xff0c;而关机的发出属于job的信息所以我们去查找job里…

java八股文面试[设计模式]——创建型模式

创建型模式的作用就是创建对象&#xff0c;说到创建一个对象&#xff0c;最熟悉的就是 new 一个对象&#xff0c;然后 set 相关属性。但是&#xff0c;在很多场景下&#xff0c;我们需要给客户端提供更加友好的创建对象的方式&#xff0c;尤其是那种我们定义了类&#xff0c;但…

29 | 聊聊性能测试的基本方法与应用领域

并发用户数、响应时间、系统吞吐量之间的关系 当系统并发用户数较少时&#xff0c;系统的吞吐量也低&#xff0c;系统处于空闲状态&#xff0c;这个阶段被称为 “空闲区间”。 并发用户数进一步增长&#xff0c;系统的处理能力逐渐趋于饱和&#xff0c;因此每个用户的响应时间会…

2023全国大学生数学建模竞赛A题思路模型代码

目录 一.选题建议先发布&#xff0c;思路模型代码论文第一时间更新&#xff0c;获取见文末名片 二.选题建议&#xff0c;后续思路代码论文 A 题 定日镜场的优化设计 各题分析 获取完整思路代码见此处名片 一.选题建议先发布&#xff0c;思路模型代码论文第一时间更新&…

五大优化技巧,让你的视频直播app源码更加流畅

优化技巧一&#xff1a;性能调优 视频直播app源码在确保流畅体验方面是至关重要的。为了提升性能&#xff0c;以下是几项关键的优化技巧&#xff1a; 使用轻量级编码器和解码器&#xff1a;选择高效的编码器和解码器&#xff0c;以减少资源占用&#xff0c;并确保视频流畅播放…

2023全国大学生数学建模ABCDE选题建议,思路模型,小白要怎么选?难度怎么样

首先最重要的&#xff0c;难度C<B<A&#xff0c;D、E题推荐选E题 大家可以查看我们的视频讲解&#xff0c;在这里&#xff1a;【2023全国大学生数学建模竞赛选题建议&#xff0c;难度分析&#xff0c;小白应该怎么选】 https://b23.tv/S6O26uc 选题建议视频播放​b23.t…

Matlab如何导入Excel数据并进行FFT变换

如果你发现某段信号里面有干扰&#xff0c;想要分析这段信号里面的频率成分&#xff0c;就可以使用matlab导入Excel数据后进行快速傅里叶变换&#xff08;fft&#xff09;。 先直接上使用方法&#xff0c;后面再补充理论知识。 可以通过串口将需要分析的数据发送到串口助手&a…

【1++的数据结构】之哈希(一)

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的数据结构】 文章目录 一&#xff0c;什么是哈希&#xff1f;二&#xff0c;哈希冲突哈希函数哈希冲突解决 unordered_map与unordered_set 一&#xff0c;什么是哈希&#xff1f; 首先我们要…

(3)MyBatis-Plus待开发

常用注解 TableName MyBatis-Plus在确定操作的表时&#xff0c;由BaseMapper的泛型决定即实体类型决定&#xff0c;且默认操作的表名和实体类型的类名一致,如果不一致则会因找不到表报异常 //向表中插入一条数据 Test public void testInsert(){User user new User(null, &…

Android 10.0 禁用adb shell input输入功能

1.前言 在10.0的产品开发中,在进行一些定制开发中,对于一些adb shell功能需要通过属性来控制禁止使用input 等输入功能,比如adb shell input keyevent 响应输入事件等,所以就需要 熟悉adb shell input的输入事件流程,然后来禁用adb shell input的输入事件功能,接下来分…

yolov7添加注意力机制

yolov7结构图 方法:直接在common里改,在相关的后面加上就行 1、接受通道数的注意力机制 1、目的:在三个输出地方添加注意力 yolov7.yaml文件,换成其他模块 注意力链接 2、models下建SE.py 3、common.py下,先找class Conv,再复制一份修改,把模块导进来 4、yolo.…

生成式AI时代的新基础设施

生成式人工智能席卷了科技行业。 2023 年第一季度&#xff0c;随着数亿用户采用 ChatGPT 和 GitHub CoPilot 等应用程序&#xff0c;对新一代 AI 初创公司的投资高达 1.7B 美元。 技术领先的公司正在争先恐后地制定自己的生成式AI策略&#xff0c;许多公司都在努力将应用程序投…

基于Java+SpringBoot+Vue前后端分离校园资产管理设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

45位主播带货破亿,单日热销100w+单,8月榜单有哪些看点?

根据抖音官方数据&#xff0c;截至2021年1月&#xff0c;抖音在全球范围内的日活用户已经超过7亿。 从娱乐到学习&#xff0c;从社交到购物&#xff0c;抖音成为了人们生活中不可或缺的一部分。 那么&#xff0c;8月有哪些主播表现突出&#xff0c;哪些商品在畅销&#xff0c;哪…

【内存管理】C与C++的内存管理异同点

C/C程序内存区域划分 栈又称堆栈&#xff1a;存放非静态局部变量/函数参数/返回值等等&#xff0c;栈是向下增长的。内存映射段&#xff1a;高效的I/O映射方式&#xff0c;用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存&#xff0c;做进程间通信。堆&…

NATAPP使用详细教程(免费隧道内网映射)

NATAPP - https://natapp.cn/tunnel/lists NATAPP 在开发时可能会有将自己开发的机器上的应用提供到公网上进行访问&#xff0c;但是并不想通过注册域名、搭建服务器&#xff1b;由此可以使用natapp&#xff08;内网穿透&#xff09; 购买免费隧道 修改隧道配置 看自己的web…