JS逆向——webpack实战

声明:本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除!由于本人水平有限,如有理解或者描述不准确的地方,还望各位大佬指教!!


练习网站:DQpDcmF6eSBQcm9Nb25rZXkgaHR0cHM6Ly9tLnphaXRpYW5qaW4ubmV0LyMvdGVtcGxhdGUvP3R5cGU9MSZtZW51PTQmY2F0ZT0xOSZwYXJhbT1iS3ZVa0tWYkI4SThaU1BC

网站分析:

打开开发者工具,点击翻页,发现数据是通过ajax接口异步传输的,不过该接口的post请求参数和结果数据均进行了加密操作,如图

对于这种情况,根据加密参数格式以及长度,大佬就会想到常见的非对称加密,如RSA、DES、AES、DSA等等,然后就可以通过关键词搜索、DOM断点、hook方法、启动器启动等方式寻找入口,当然,我们可以根据某种方法会遇到的问题,去选择其他捷径方法作为最优解(比如异步操作导致跟栈困难等问题)。这里小编就直接步入正题,加密参数的入口如下图

JS逆向——webpack实战_第1张图片

JS逆向——webpack实战_第2张图片

JS逆向——webpack实战_第3张图片

这里可以看出来,该两个请求参数body和signature基本上是由密钥n(随机生成)、时间戳o、传参r(由定值key、page、定值页展示limit组成)等参数进行了AES-ECB 加密生成的。乍一看加密很简单,但是这只是body的值,而l方法的断点后续还没运行(即y.encrypt(o)还未执行,这是生成signature值的过程),我们让该方法执行完就会发现signture的值,如图

JS逆向——webpack实战_第4张图片

那么,我们就需要找y方法是谁,网上找就会发现熟悉的代码格式,没错,这就是webpack

JS逆向——webpack实战_第5张图片

JS逆向——webpack实战_第6张图片

在n("9816")处打断并刷新进入,就会看到该webpack的加载器

JS逆向——webpack实战_第7张图片

那么,接下来的过程就比较简单了,我们把webpack的自执行函数扣到本地,将y.encrypt需用到的“9816”等模块放入自执行函数下边用作实参传入,如图

JS逆向——webpack实战_第8张图片

JS逆向——webpack实战_第9张图片

然后再将AES加密补齐

function oo(e) {
    e = e || 32;
    for (var t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678", n = t.length, o = "", r = 0; r < e; r++)
        o += t.charAt(Math.floor(Math.random() * n));
    return o
}

function webpack_sdk(i) {
    var O = my_sign,
    k = {
        debug: !1,
        host: "https://business-project.zaitianjin.net",
        loginPage: "/login",
        aes_mode: "AES-ECB",
        logColor: "background: #222; color: #bada55",
        pemVersion: "rsa.20230731100736",
        rand_key: oo(32),
        publicKey: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaqdDedX9L8lUwun4dxj\nUnHuTTU8VnKWo9c9kRPxuJJcg2T1tJNSYetLUALbJWCE3EW58qr3wpSjkuSxTZCT\ntD+IYKVvdJqdftbf2i0lViplS1j0ZfqvLxQHxb6ij0jPZ9PmbkxrOjPMM8BIrQzh\nkIGoYBfVV113Err4EOk5Mt2F9TystJICPPJm2+NcX8fadXP8p+kcFNNRuki+1Gwc\nrp01gM+YXikSapKbZztEeTabH5JCcS5ZDriiIHCVNPthlKLdrBp9JuL2OJCgIWzS\nzHUHQ3UJgS6wWl8LR/zR4+E5/VSiZLPO4xZh6jeUrIMSYRvUlVnYc/pQUKjv5Pws\noQIDAQAB\n-----END PUBLIC KEY-----",
        privateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC05GAiIUnCvC9/\nxnbzJ+aQBTn9X5BjjMEeYItKhoNgmcmSieKrRLoAc4GkhkPN2AxUSD9kUYOw+qCx\nTYyqdFgCLGEdqBfBwWeGV5KRxYQ98X7Dd7Zm95YLNuvLwN6WuZhRmxvFChnBjV/U\n5vLrZDcFaCp94UoCwObXMSrYM67NEYNlk3EfnYui+n9ZkNxmIAm3u/j0J/4En23/\n4X1e+Nrl4vrI5SmkRlALGCgCZ/M3k47tGElIUh7SGKcwuO8DzTu1gQB6rHmaPx4h\ndRwk7UsHrlVxaXtNl3Mo2vysQDnYW+AuInM7YCv3JGSvakfXYKOQvrAF1hjXU6u/\nJ4Oi2okBAgMBAAECggEAW7NWRJcJdG2/yo+Kp3N3v1TW8+opIT4ufD7G/g24thTg\nCahavyYFAMuNUiE6aDR485T4hduI3gP/yEIe6B44q0liJg2blX59A66LP9iYVGqD\nL4YVcpdaee7qlAz/CfumCuCNsFKRgfwwM5asWMYh2lzXBZ9azJCLtVVYeeehWpUG\n0cj70QMj8nrzqSuXJMzxhYvCocZ6Zw4Lqfm7wl5E8b3iwtgNpyNuYIPvySMXKxV+\nnP2lJu1QtZRF+q/f5PNY9z1Jv3YyDYoz9td9fpzhytfXSHllyxMYjFK2l+b7fsMA\n2D33JT0CSYCeRD/GP12ZloulcUzZPqx8JlmSV0OazQKBgQDhkhrOUnNw96BqX6mO\n7+59wkKf45Tf+Nb/4tuia/6J/Iq+5VF8ChW0NIq/S2NQRbr54jOL2rUdzljXErF4\nVAZ8YlI8EuPffkhnyqS/8LOdSekwLbo+59PsM6iM5T+74GcWYkUtUVqRh051YOGo\n5vQHQ7i/5sGkm5CVEAuGwDtGewKBgQDNS1T2Z/vbJeih+Hfm1D0SWMnA5G3SRBdg\nDPggSFDoeoxrYU0jWzpAhzy47bxhL0D4lBp8GLPmWrqpUAv1izBSNeBu4klBwJMP\nj5G0QQdpnIAkTHyV6KKK9iCbUvnHCrcb1cCBZioB+sBSl93c78NEW1iOdlW1L9QM\nvsThJY1zswKBgQCqI6HEbbxVQPHmSjGCdsbUZGoMX4QzS2Yfq+UuJXbgbXPZeO51\nOMYWHmtozlwid/YH9O4cVuK1kKbB0n+52ubpet+8ICNwt7e1UcviWpOf19fjVxpb\nyFC4oF5Jp8Di3Ofkokq7W9mMWxp6vpB27Xyy3gnD9TGqDwyG4otPID+VcQKBgGrG\n/tb2uLmAWyI7oOmPhIBRbAaHCVPvFJVhyYDI/EQe0YBcaIm2PnMno/6vsGZ/9HQW\nXDwlgRSUJjhAKSg6kBSCb0xdKCsp5ZOXYfp2REu7Ga9HlRlHmZtbbxQ6sS3Etf6l\nS+5B3CGRcYzD7qKmllKsjD/07plB2jIS20YbiRofAoGAaVOZwGERxYFP2qigRY4Y\nCCWMx+cXL5DU+OeDdp4kBrwNWv4nSnYcMiGCYV9BkZfM9pxUF9hZsTxiKOJ09i1G\nB2HNgmv9FvVdxaeGodkl7kc4b18BsQlma61CrZJRBQ+4QvPwpPea0bwIp2FWUv1X\nDScG/EAX8/CCjd0SloVvkyQ=\n-----END PRIVATE KEY-----"
    }, y = new O["a"];
    y.setPublicKey(k.publicKey)
    result = y.encrypt(i)
    return result
}

function cc() {
    return parseInt((new Date).getTime() / 1e3)
}

a = function(e, t) {
    var n = CryptoJS.enc.Utf8.parse(t.substring(0, 16))
      , o = CryptoJS.enc.Utf8.parse(t.substring(16, 32));
    var e2 = CryptoJS.enc.Utf8.parse(e),
    e3 = CryptoJS.AES.encrypt(e2, n, {
        iv: o,
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    })
    return e3.ciphertext.toString()
}

rrr = function(e){
    return CryptoJS.MD5(e).toString()
}

l = function(e, t, n) {
    var o = JSON.stringify({
        aes_mode: "AES-ECB",
        time: t,
        rand_key: n,
        hash: rrr(e + "https://m.zaitianjin.net"),
        origin: "https://m.zaitianjin.net"
    });
    return webpack_sdk(o);
}

function fjm_sdk(data) {
    var n = oo(32)
      , o = cc()
      , r = JSON.stringify(data ? data : {})
      , c = a(r, n)
      , s = l(c, o, n);
    return {
        body: c,
        signature: s
    }
}

console.log("请求加密参数")
console.log(fjm_sdk(
    {
    'key': 'bKvUkKVbB8I8ZSPB',
    'page': '6',
    'limit': '6',
}
))

那么加密参数body和signature就都破解了,如图

然后,用python的exec正常调用该加密,响应结果也就能正常返回了,如图

但是响应结果也是加密的,那我们就需要再解密一下,经过再次跟栈,找到解密入口

JS逆向——webpack实战_第10张图片

然后就能正常返回数据啦

JS逆向——webpack实战_第11张图片

那么,今日的分享就到这里,想要学习更多的python爬虫和js逆向的相关技巧和知识的小伙伴们一定要点下关注哟,后期会不定时分享相关干货内容

你可能感兴趣的:(python,javascript,js逆向,javascript,webpack,python,爬虫)