【JS逆向】聚享游RSA | 每日JS

已迁移平台:segmentfault,搜索 erma0
换平台了,发什么都锁定,广告一堆,趁早倒闭吧。


第一天

JavaScript逆向练习1

0x01 目标网址

http://www.juxiangyou.com/login/index

0x02 定位JS

1. 随便输入账号密码验证码,点击登录,查看提交的参数

1

可以看到,发出了两个请求,第一个是获取key,第二个是登录,在登录包里有加密过 的password参数。

2. Ctrl+Shift+F调出搜索面板,搜索jxy_parameter,有三条结果,依此打开查看,发现第三个才是需要的。直接在这里下一个断点。

2

3. 重新输入账号密码验证码,点击登录,JS被断了下来。F11跟进,或者鼠标悬停在断点处函数名上,点击弹出的内容,也能跳转进去。

3

这里可以看到e就是之前的第一个请求包的返回内容,而n就是待加密的明文密码。加密函数的调用核心就是在这里。

4. 同上,F11跟进,进入一个JSEncrypt.min.js,传入参数为第一步返回的hash + 明文密码

4

这里一看到JSEncrypt,再看一下上下文,可以确认是AES加密(可以百度一下JSEncrypt),那就直接把整个JSEncrypt.min.js拿走,再改写一个调用的函数就行了。

0x03 改写JS

1. 仿照图3的位置,写一个调用函数。

function getrsa(pKey, password) { // 也可以把key写死,这个公钥是不会变的
    var encrypt = new JSEncrypt();
    encrypt.setPublicKey(pKey);
    var encrypted = encrypt.encrypt(password);
    return encrypted
}

此时在多数情况下就能正常运行了

2. 练习在Python中调用时发现,这样会报错JSEncrypt is not defined,一下整懵了,尝试直接赋值一个空对象,结果不行,仔细看了一下代码,发现第一部分是在判断客户端。

! function(t, e) {
    "function" == typeof define && define.amd ? define(["exports"], e) : e("object" == typeof exports && "string" != typeof exports.nodeName ? module.exports : t)
}(this, function(t) {**函数主体**});

浏览器中调试发现"function" == typeof define && define.amdtrue,那就直接把函数给改一下,把函数主体暴露出来。

var JSEncryptExports = {};
(function(t) { 
    **函数主体**
})(JSEncryptExports);
var JSEncrypt = JSEncryptExports.JSEncrypt;

此时JSEncrypt就是一个构造函数了,接着把上面5中的代码贴在下面,就可以在Python中运行了。

0x04 Python代码

一开始尝试了js2py,报错,可能是js代码比较多,所以又直接改用execjs了。

PS. 其实可以尝试直接调用Python的AES加密库,如果这个JS没改过,结果应该是能用的(也就是另一个思路:JS功能可以通过所使用的语言直接实现)。

# -*- encoding: utf-8 -*-
'''
@File    :   0x01-juxiangyou.com.py
@Time    :   2019/11/06 10:42:43
@Author  :   独孤孤独嘟咕噜犊子
@Version :   1.0
@Link    :   https://www.jianshu.com/u/6a4c6ef97be7
@Desc    :   聚享游www.juxiangyou.com 登录例子
'''

# start

import execjs
import requests
import time
import json

HEADERS = {
    'User-Agent':
    'Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; Mi Note 2 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.1'
}
s = requests.Session()
s.headers.update(HEADERS)
imageURL = 'http://www.juxiangyou.com/verify?v={}000'.format(int(time.time()))
keyURL = 'http://www.juxiangyou.com/login/getkey'
loginURL = 'http://www.juxiangyou.com/login/auth'

# 下载验证码
image = s.get(imageURL).content
with open('image.png', 'wb') as f:
    f.write(image)

# 获取公钥
publicKey = s.post(keyURL).json()
jskey = publicKey['key']
jshash = publicKey['hash']

# 登录
username = '[email protected]'
password = '******'
varifyCode = input('请输入验证码(当前目录下image.png):')
# varifyCode = '1111'
timestamp = int(time.time() * 1000)

with open('js/0x01-juxiangyou.com.js') as f:  # 坑0x01 相对路径前面不带/,带/不报错但读不出数据
    jscode = f.read()
ctx = execjs.compile(jscode)  # execjs载入js代码
xsign = ctx.call('get', timestamp)  # 坑0x02 这里传入的时间戳为整数型(老版本验证的参数,现在不计算也行)
# xsign = ctx.eval('get({})'.format(timestamp))  # 通过eval调用js代码里的函数
enPass = ctx.call('getrsa', jskey, jshash + password)  # 通过call调用js代码里的函数
data = {
    'jxy_parameter':  # 坑0x03 提交json格式参数需要转成json字符串,否则请求失败
    json.dumps({
        "c": "index",
        "fun": "login",
        "account": username,
        "password": enPass,
        "verificat_code": varifyCode,
        "is_auto": True
    }),
    'timestamp':
    timestamp
}
result = s.post(loginURL, data=data).json()
print(result)  # {'code': 10000} 登录成功

你可能感兴趣的:(【JS逆向】聚享游RSA | 每日JS)