裁判文书网全站逆向

默认分类·爬虫与逆向 · 2023-01-01 · 3396 人浏览

登陆加密

首先进入登陆页面,输入好登陆信息后点击登陆,查看f12,发现表单提交的密码被加密,多次进行提交,发现结果每次都不同,说明可能是rsa des等非对称加密

image-20240909111029880

切换至源代码板块,添加xhr断点

image-20240909111135152

找到断点位置数据

image-20240909111406838

向上跟栈,找到请求位置,发现依然被加密

image-20240909111516443

继续跟栈,发现在a函数中传入了原始的密码

image-20240909113703163

在控制台中构造一个promise运行一下试试,果然这个a函数就是我们的加密函数

image-20240909114351287

继续跟栈,发现了一个可疑函数

image-20240909114728805

执行一下,果真拿到了数据

image-20240909114810562

点进去后,很明显这段代码使用了RSA公钥加密算法来加密密码。具体操作是使用RSA公钥加密传入的密码 e,然后 encodeURIComponent 对加密后的字符串进行URL编码。

image-20240909114902825

我们可以使用python进行一下改写

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
import urllib.parse

def encode_password(password):
    public_key = """-----BEGIN PUBLIC KEY-----
此处为密钥
-----END PUBLIC KEY-----"""
    rsa_key = RSA.import_key(public_key)
    cipher = PKCS1_v1_5.new(rsa_key)
    encrypted_password = cipher.encrypt(password.encode('utf-8'))
    encoded_password = base64.b64encode(encrypted_password).decode('utf-8')
    return urllib.parse.quote(encoded_password)

验证参数正确,登陆逆向到此完成

image-20240909120047413

SESSION的获取

查看一下登陆接口返回的内容,在set-cookie字段中返回了HOLDONKEY,然而这并不是我们需要的参数

image-20240909125808459

实际上,我们在请求具体的文书数据时,能够发现实际上是携带一个SESSION的cookie来作为鉴权参数的,然而,在/api/login接口中,并没有返回相应的参数,我们将SESSION的值进行搜索,检索结果中仅在/tongyiLogin/authorize有一个Set-Cookie,那么可以说明这个cookie的获取就是这个接口

image-20240909125302312

请求接口后,除了返回了一个SESSION外,还返回了一条url,直接使用接口返回的SESSION是无法请求数据的

image-20240909130347753

查看请求流程,返现这条url进行了一次302重定向,在整个请求过程中用到了HOLDONKEYSESSION,那么这个可能就是我们的用户SESSION激活接口了

image-20240909130713396

image-20240909130753356

编写python代码即可实现登陆

注:在请求数据时,有可能被waf拦截,这时除了SESSION还需要携带wzws_cid

数据接口加密分析

响应体解密

发起列表页请求,查看请求url和参数

image-20240909151304275

hook一下xhrhttps://wenshu.court.gov.cn/website/parse/rest.q4w,向上寻找了,在getData中便找到了我们需要的参数

image-20240909151457169

很明显这里就是我们要找的响应体加密方式了

image-20240909151611525

不过,还有另一个问题,虽然我们知道了加密方式,但是3DES除了明文和密钥以外,还需要以下三个参数

  1. 初始化向量(IV):在使用某些模式(如CBC模式)时,需要一个初始化向量来增加加密的随机性。
  2. 填充模式(padding):在不足某些位数时的填充方式
  3. 加密模式(Mode of Operation):常见的模式包括ECB(Electronic Codebook)和CBC(Cipher Block Chaining)。不同的模式会影响加密和解密的过程。

直接寻找太麻烦了,我们可以通过重写CryptoJS.TripleDES.encrypt方法来hook传入的密钥等,直接定位加密的位置

// 保存原始的CryptoJS.TripleDES.encrypt方法
const originalEncrypt = CryptoJS.TripleDES.encrypt;

// 重写CryptoJS.TripleDES.encrypt方法
CryptoJS.TripleDES.encrypt = function() {
    // 打印传入的参数
    console.log('CryptoJS.TripleDES.encrypt called with arguments:', arguments);
    // 打断点
    debugger;
    // 调用原始的encrypt方法
    return originalEncrypt.apply(this, arguments);
};

用这种方式我们一下就找到了加密的位置和参数

image-20240909152952879

image-20240909153149124

由此我们可以得知

  • 加密模式:CBC
  • 填充模式:pkcs7(pkcs7padding)
  • iv:CryptoJS.enc.Utf8.parse(a || DES3.iv())

再继续追寻一下iv的值,即a || DES3.iv(),此处分析过程非常简单,直接放结论

image-20240909153615301

最后可以得出,iv的值为当日日期,最后我们编写一下python代码解密响应

# 对响应中的result进行解密
def result_decode(crypto_text, key):
    text = base64.b64decode(crypto_text)
    des3 = DES3.new(key, mode=DES3.MODE_CBC, iv=get_iv())
    result_hex: bytes = des3.decrypt(text)
    result_str = result_hex.decode("utf-8")
    return result_str

请求体加密

回顾一下请求体,我们只需要找出ciphertext的加密方式,因此最简便的方式还是回到刚刚的hook方式上,从xhr一层一层逐级向上寻找

image-20240909154249290

依旧是老样子跟栈寻找,找到了疑似的生成函数

image-20240909154455584

进入cipher所在的js文件,加密方式一目了然

function cipher() {
    var date = new Date();
    var timestamp = date.getTime().toString();
    var salt = $.WebSite.random(24);
    var year = date.getFullYear().toString();
    var month = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date
            .getMonth()).toString();
    var day = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate())
            .toString();
    var iv = year + month + day;
    var enc = DES3.encrypt(timestamp, salt, iv).toString();
    var str = salt + iv + enc;
    var ciphertext = strTobinary(str);
    return ciphertext;
}
function strTobinary(str) {
    var result = [];
    var list = str.split("");
    for (var i = 0; i < list.length; i++) {
        if (i != 0) {
            result.push(" ");
        }
        var item = list[i];
        var binaryStr = item.charCodeAt().toString(2);
        result.push(binaryStr);
    };
    return result.join("");
}
  • cipher函数通过3des生成一个加密的密文,并将其转换为二进制表示。
  • strTobinary 函数将一个字符串转换为其二进制表示。
  1. 获取当前时间戳

    var date = new Date();
    var timestamp = date.getTime().toString();

    获取当前的时间戳,并将其转换为字符串。

  2. 生成随机盐值

    var salt = $.WebSite.random(24);

    生成一个24字符长的随机盐值。

  3. 获取当前日期的年、月、日并生成初始化向量(IV)

    var iv = year + month + day;
  4. 使用3DES加密

    var enc = DES3.encrypt(timestamp, salt, iv).toString();

    使用3DES算法对时间戳进行加密,使用盐值作为密钥,IV作为初始化向量。将加密结果转换为字符串。

  5. 拼接最终的密文并转换为二进制表示

    var str = salt + iv + enc;
    var ciphertext = strTobinary(str);
    return ciphertext;

    调用strTobinary函数,将拼接后的字符串转换为二进制表示,并返回结果。

而剩下的__RequestVerificationToken经校验来自请求网站固定回传的值,并未进行校验,所以无需提交,至此我们的分析就结束了

  1. cheeleong 27 天前

    wzws_cid怎么获取呢

    1. dream (作者)  27 天前
      @cheeleong

      不携带参数情况下,关闭重定向请求首页,就能获取到了

Theme Jasmine by Kent Liao