手把手带你模拟36氪登录

最近收到粉丝私信,想多学习下js逆向相关的知识和案例,应大多数粉丝要求:今日份js逆向练习,36氪登录模拟

目标地址:https://36kr.com/

初步探测

  1. 点击登录按钮,切换到账户密码登录

  2. 随便输入一个手机号码和6位数以上的密码,点击登录

    可以看到XHR请求已经发出来了byMobilePassword

  3. 查看byMobilePassword相关的request header和payload request header中并未发现特殊加密的参数

    很明显payload中mobileNo和password是经过加密的

牛刀小试

  1. 先来第一枪,根据关键字搜索mobileNoonly一个,点击文件进去试一下

  2. 格式化下代码

  3. 打上断点,点击登录按钮

  4. 断点成功断住,从chrome控制台可以看到o.a.get(t, "mobileNo")就是我们的明文手机号码,Object(i.b)()就是加密明文的方法,因此我们的重点任务就是破解Object(i.b)()这个方法

重点突破

  1. 鼠标光标放到Object(i.b)()上,点击弹出来的浮窗进入文件

  2. 文件定位到这段代码

    简单分析下这段代码:

ar r = n(14)
    , o = n(4)
    ,
    i = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeiLxP4ZavN8qhI+x+whAiFpGWpY9y1AHSQC86qEMBVnmqC8vdZAfxxuQWeQaeMWG07lXhXegTjZ5wn9pHnjg15wbjRGSTfwuZxSFW6sS3GYlrg40ckqAagzIjkE+5OLPsdjVYQyhLfKxj/79oOfjl/lV3rQnk/SSczHW0PEyUbQIDAQAB"
    , a = function () {
        var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
        if (!Object(o.isNodeEnv)()) {
            var t = n(769)
                , r = new t.JSEncrypt;
            r.setPublicKey(i);
            var a = r.encrypt(e);
            return a
        }
    }
  1. 当我们看到r = new t.JSEncrypt;这行代码的时候,有经验的一看就应该明白这可能是标准的RSA加密; r.setPublicKey(i);是设置公钥,这里的i的值在上面也很清晰的写死了

i = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeiLxP4ZavN8qhI+x+whAiFpGWpY9y1AHSQC86qEMBVnmqC8vdZAfxxuQWeQaeMWG07lXhXegTjZ5wn9pHnjg15wbjRGSTfwuZxSFW6sS3GYlrg40ckqAagzIjkE+5OLPsdjVYQyhLfKxj/79oOfjl/lV3rQnk/SSczHW0PEyUbQIDAQAB"

三种方式来破解登录

JSEncrypt库

这种方式最直接,也最简单,不过需要对相关加密库比较熟悉 在node.js环境中使用jsEncrypt库 首先, Node.js 环境中使用 JSEncrypt 需要先安装该库,可以通过 npm 安装: npm install jsencrypt 补一个window环境就可以直接使用了

代码如下:

window = global

function get_encrypt(message) {
    const JSEncrypt = require('jsencrypt');
    const encrypt = new JSEncrypt();
    p_k = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeiLxP4ZavN8qhI+x+whAiFpGWpY9y1AHSQC86qEMBVnmqC8vdZAfxxuQWeQaeMWG07lXhXegTjZ5wn9pHnjg15wbjRGSTfwuZxSFW6sS3GYlrg40ckqAagzIjkE+5OLPsdjVYQyhLfKxj/79oOfjl/lV3rQnk/SSczHW0PEyUbQIDAQAB'
    encrypt.setPublicKey(p_k)
// 使用公钥加密数据
    return encrypt.encrypt(message);
}

console.log(get_encrypt('1'));

通过python调用,看到这个结果,就已经说明我们模拟的加密已经通过了36kr服务器的验证,只是输入的账户不对,换成你们正确的账户就行

硬扣

如果不知道是RSA加密,也没有关系,我们用其他的方法,那就硬扣呗;

  1. 这几行代码n(**)差不多可以知道是webpack加载器n来的,在几个n处打上断点,刷新页面

  1. 断点成功进入,点击浮窗进入代码文件

    成功定位到加载器

  2. 把runtime.****.js文件内容都拷贝下来

补环境

  1. 代码拷贝下来后,直接运行js文件

    提示ReferenceError: window is not defined

  2. 补一个window = global再次运行,代码ok

  3. 格式化代码,缩近代码,可以看到是一个[]空数组

    加密函数的文件看到这里的代码都是在[]数组中,

  4. 这里是webpack的数组方式,因此把这些function都拷贝到[]数组中

ReferenceError: navigator is not defined

  1. 导出加载器函数,加载器函数是n,

    _ps = n后面就可以使用_ps全局对象来调用对应的函数了

  2. 因为加载器中是数组对象,搜索下 r = new t.JSEncrypt 我们所需要的方法是在哪个functuion

    数组跟python中一样,也是从0开始的,所以我们需要的是第7个 _ps(7)打印出来的结果就是三个方法

{ a: [Getter], b: [Getter], c: [Getter] }

b方法返回的就是a对象,而a对象就是我们所需要的加密方法

7. 因此_ps(7).b('123345')就可以得到加密结果 构造一个函数返回加密结果给python程序调用

function get_encrypt(message) {
    return _ps(7).b(message)
}
  1. 接下来就是我们通过python程序来进行登录,看到这个结果,就已经说明我们模拟的加密已经通过了36kr服务器的验证,只是输入的账户不对,换成你们正确的账户就行;

    附上相关的python代码,js代码因此太长了,就不附上了,有需要学习的朋友可以私信我。

import requests
import json
import time
import execjs

headers = {
    "authority": "gateway.36kr.com",
    "accept": "*/*",
    "accept-language": "zh-CN,zh;q=0.9",
    "cache-control": "no-cache",
    "content-type": "application/json",
    "origin": "https://www.36kr.com",
    "pragma": "no-cache",
    "referer": "https://www.36kr.com/",
    "sec-ch-ua": "\"Chromium\";v=\"110\", \"Not A(Brand\";v=\"24\", \"Google Chrome\";v=\"110\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"macOS\"",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-site",
    "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
}

url = "https://gateway.36kr.com/api/mus/login/byMobilePassword"

round(time.time() * 1000)

mobileNo = '18814378681'
password = '123456'
exjs = execjs.compile(open('36ke.js', encoding='utf-8').read())
mobileNo = exjs.call('get_encrypt', mobileNo)
password = exjs.call('get_encrypt', password)
data = {
    "krtoken": "",
    "partner_id": "web",
    "timestamp": round(time.time() * 1000),
    "param": {
        "countryCode": "86",
        "mobileNo": mobileNo,
        "password": password
    }
}
data = json.dumps(data, separators=(',', ':'))
response = requests.post(url, headers=headers, data=data)

print(response.text)

Websocket方式

  1. 导出加密函数

  1. 启动我们的sekiro工具

可以看到启动日志是正常的,我这里是sekiro3,默认启动的netty端口是5612

  1. 在浏览器控制台注入sekiro_web_client.js和我们自己的脚本文件

function guid() {
        function S4() {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        }

        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
    }

    var client = new SekiroClient("ws://127.0.0.1:5612/business/register?group=ws-group&clientId=" + guid());

    client.registerAction("sss", function (request, resolve, reject) {
        const {param1} = request.params;
        resolve(sss(param1));
    })

控制台提示已经和服务端建立了websocket连接

  1. 接下来我们就可以通过python发送我们的请求获取加密的手机号和密码了

然后可以通过加密后的数据请求登录接口了。。 这种方式的缺点就是刷新浏览器的时候注入的脚本就消失了,需要重新注入,当然我们也可以通过Tampermonkey注入,不过这个小小的登录用这些,感觉就有点大炮轰蚊子了

总结:

js逆向根据实际情况,可以有多种方式破解方式,可以按照自己熟悉的来,前提要了解各种破解套路,才能找到对应最合适的。

更多资源信息可关注公众号:python君

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值