提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
声明
本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!
目标
贝壳登录密码加密逆向。
地址:aHR0cHMlM0EvL2JqLmtlLmNvbS8lM0Z1dG1fc291cmNlJTNEYmFpZHUlMjZ1dG1fbWVkaXVtJTNEcGluemh1YW4lMjZ1dG1fdGVybSUzRGJpYW90aSUyNnV0bV9jb250ZW50JTNEYmlhb3RpbWlhb3NodSUyNnV0bV9jYW1wYWlnbiUzRHd5YmVpamluZw==
操作步骤
1.切换到密码登录
2.点击登录,查看接口
3.分析接口
通过接口请求参数可以看出password,loginTicketId,srcId,dataId是密文
接口多次请求测试可以发现
loginTicketId 是上一个接口返回结果中的数据
srcId 一直是固定值
context中的dataId 可以忽略,因为整个context可以置为空对象{}
4.下面主要看password的加密过程
跟栈可以发现密码加密是下边这一行
多次尝试发现o.publicKey是固定值
o.publicKey:
'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCB81pk1Go/d7K8unYqeB6YyQdDgIRsLji7BxlBfMC2U8/0lyOLxJ6sQb1RmKaILuxN0hRci4zWPfkkPhttWaogq3XABYiDYbx0843ge4D79pG21+qWplw43uHZNs0B6iUChJW1O3DDJPXGwj50L1ySTVt7G7iqsIr9PLZVRSZmQIDAQAB'
跟进o.ec.encrypt
查看这个结构能看出有公钥、私钥、签名、验证、加密、解密等方法
能看出是rsa加密 然后断点到encrypt方法内
查看l方法
很明显l方法是base64加密
也就是说密码就是先经过rsa加密再base64加密
那么获取密码的密文可以采用抠js代码或者直接python实现
获取密码的密文的方式
通过分析,我们能够看出密码的加密逻辑就是:对明文密码进行RSA加密,然后对加密后的结果进行base64加密得到最终的密文,那么根据这个逻辑我们可以通过编写python实现、编写js代码实现或者抠js代码来实现
1. 纯python实现
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
def get_key():
# 这个是获取到的o.publicKey
PublicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCB81pk1Go/d7K8unYqeB6YyQdDgIRsLji7BxlBfMC2U8/0lyOLxJ6sQb1RmKaILuxN0hRci4zWPfkkPhttWaogq3XABYiDYbx0843ge4D79pG21+qWplw43uHZNs0B6iUChJW1O3DDJPXGwj50L1ySTVt7G7iqsIr9PLZVRSZmQIDAQAB'
data = base64.b64decode(PublicKey) # 获取,密钥信息
key = RSA.importKey(data)
return key
def encrypt_data(msg):
public_key = get_key() # 读取公钥信息
cipher = PKCS1_cipher.new(public_key) # 生成一个加密的类
encrypt_text = base64.b64encode(cipher.encrypt(msg.encode())) # 对数据进行加密
return encrypt_text.decode() # 对文本进行解码码
password = encrypt_data('1234567890')
2. 编写js代码实现
因为知道是rsa加密
因此先安装jsencrypt,这个包提供RSA算法的相关方法
npm install jsencrypt
编写加密方法
var JSEncrypt = require("jsencrypt");
myencrypt = function(t) {
let PUBLIC = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCB81pk1Go/d7K8unYqeB6YyQdDgIRsLji7BxlBfMC2U8/0lyOLxJ6sQb1RmKaILuxN0hRci4zWPfkkPhttWaogq3XABYiDYbx0843ge4D79pG21+qWplw43uHZNs0B6iUChJW1O3DDJPXGwj50L1ySTVt7G7iqsIr9PLZVRSZmQIDAQAB'
// 加密
const encrypt = new JSEncrypt()
encrypt.setPublicKey(PUBLIC)
let cipher = encrypt.encrypt('message')
return cipher;
};
3. 抠js代码实现
3.1 先把对应的js代码保存到本地
在overrides中添加个本地文件夹
开发者工具左侧,点击’>>',选择overrides,然后创建个文件夹
勾选上Enable Local Overrides
在对应的js文件上点右键,有个save for overrides,因为我的文件已经保存了,拿个别的文件截个图
将js文件保存到本地的目的是方便我们调试
3.2 调试webpack代码
很多webpack都可以用这种方式调试
单文件webpack格式一般是一个很大的自执行函数,如下
!function("形参"){"加载器";}(["模块“])
或
!function("形参"){"加载器";}({"模块“})
后边的大量模块(也就是要执行的方法)可能是数组形式也可能是对象形式,
当是对象形式时,可以直接找到对应的key,
如果是数组形式,我们需要找到它的索引。
3.3 定义一个全局变量,使它等于加载器
打断点运行到包含o.ec.encrypt(t.password))的那里
在浏览器控制台输入
aaa.m.forEach(function (el,index) {
if (el.toString().indexOf("o.ec.encrypt(t.password))") != -1){
console.log(index)
}})
可以看到索引是53
此时我们可以把整个文件复制下来,
找到索引是53的函数,找到它初始化o并给o添加属性的地方,
然后再定义一个全局变量使它等于o。
然后初始化第53个模块,
定义一个方法获取加密密码
aaa(53).default();
function get_pw(message) {
var e = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCCB81pk1Go/d7K8unYqeB6YyQdDgIRsLji7BxlBfMC2U8/0lyOLxJ6sQb1RmKaILuxN0hRci4zWPfkkPhttWaogq3XABYiDYbx0843ge4D79pG21+qWplw43uHZNs0B6iUChJW1O3DDJPXGwj50L1ySTVt7G7iqsIr9PLZVRSZmQIDAQAB"
bbb.ec.setPublicKey(e)
bbb.publicKey = e
return bbb.ec.encrypt(message)
}
console.log(get_pw("123213213"))
运行js代码,环境该补的补,本次主要讲解webpack的逆向思路,不详细说明补环境的过程,不过宗旨基本就是缺什么补什么,或者删除不影响结果的环境,一些不需要的初始化内容可以删掉。
类似上边这样的报错,不影响密码加密的,可以直接置为空或者删除
运行结果:
总结
像这种比较简单的其实直接python实现就可以了,如果比较复杂,5万行以内的js代码其实全抠也还是比较快的。