某个tiktok数据分析平台登录加密逆向分析
在这个web系统里,登陆接口的密码进行了加密后传递给后端,换取token。
而在接口自动化测试中,如果没能知道加密算法计算出加密后的password,则后续很难展开。
本文对登陆接口:https:/api/v1/user/ocean/phone/password/login-auth
做一个密码逆向分析
测试账户/密码:huangjinlong@zhizh.com/1122
浏览器打开该系统的登录页:https://**/portal/login
我们知道刚才提交的数据中密码字段为password
,我们现在找到请求发送的代码位置以便后面做分析
并按F12来到Sources面板,ctrl+shift+F在所有文件中搜索password
在含有关键字password
文件中,可能在index.js或login.js中。在index.js文件搜索password并没有发现提交数据相关的,而在login.js中,很快就发现了这段代码:
g({
fromSystem: 8,
loginId: Z.email,
loginType: 2,
password: M(Z.pass),
reqType: "登录"
})
这个结构跟login接口发送的数据完全一致,能确定就是这里。
密码加密调用了M(Z.pass)
,再搜索M函数,看到新建了一个对象k,M调用了k的方法setPublicKey()
,l.encrypt(e.trim())
返回作为password。
其实这里已经能够看出RSA加密了,因为使用了公钥对消息进行加密
我们在return l.setPublicKey(F),l.encrypt(e.trim())
处打断点
接下来在页面使用正确的账户密码,点击Sign In
断点起作用,停留在return l.setPublicKey(F)
并给出了l函数的参数,这里的秘钥长度为1024
,使用的指数为010001
,这个信息看不出来也没关系,主要是验证前面的猜想,这两个参数都符合RSA加密的规则
按F11进入下一个回调函数,来到了element-plus.js,这里的key不一定是公钥,因为还没执行完
一路next,直到函数回到login.js,在l.encrypt(e.trim())
停下,这意味着前面的l.setPublicKey(F),
已执行完毕,这个时候在右侧Scope面板展开Module,看到F的值,这个就是公钥。
把公钥复制出来
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA88FgfNpx6fAdD34QWdlgo12G1w8b36nenjVDUOEoaYaE8d6r3ks0vi9z30uN7PMY824VX**HjHaVCcZ7CCTle0zMTAAttTF0eEUXEvamRKI8cV0NZaGQSIshWeGrOe/0iPVF4kps5s6eru8JGS27JjsCQ9kqKDnFLS6NsWX1eJDJSs5lOVbK5DxZrCuSwEDMZMXiyfL09dHoTODXTINIBBrxdDZGoyYDnZR0EasTO/hiDaKf0UbsdxJC975QA/y9k1y/nTksRXS5cTAOGqO6KffxFnwIDAQAB
现在有了公钥,我们就能python,使用公钥对密码进行加密
这里加密用的是pycryptodome
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.PublicKey import RSA
import base64
def js_encrypt(text):
# 通过拿到js中的RSA公钥,构造完整的公钥部分
key = """-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA88FgfNpx6fAdD34QWdlgo12G1w8b36nenjVDUOEoaYaE8d6r3ks0vi9z30uN7PMY824VX****HjHaVCcZ7CCTle0zMTAAttTF0eEUXEvamRKI8cV0NZaGQSIshWeGrOe/0iPVF4kps5s6eru8JGS27JjsCQ9kqKDnFLS6NsWX1eJDJSs5lOVbK5DxZrCuSwEDMZMXiyfL09dHoTODXTINIBBrxdDZGoyYDnZR0EasTO/hiDaKf0UbsdxJC975QA/y9k1y/nTksRXS5cTAOGqO6KffxFnwIDAQAB
-----END PUBLIC KEY-----"""
rsakey = RSA.importKey(key)
cipher = Cipher_pkcs1_v1_5.new(rsakey)
cipher_text = base64.b64encode(cipher.encrypt(text.encode(encoding="utf-8")))
# print(cipher_text)
value = cipher_text.decode('utf8')
return value
# 传入密码:1122
print("加密后的密码为:"+js_encrypt("1122"))
拿到加密后的密文
拿到postman里验证一下
换取到了token,至此,逆向分析完毕
遇到的一些坑
一开始我是没想着加密算法的,因为对密码加密的整个过程,断点停在element-plus.js里,为此把element-plus.js后掐掉不需要的内容,如图的顶部引用、底部和加密无关的内容
然后加上自己的代码
// 用秘钥加密密码
function getPwd(pwd){
var key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA88Fgf***0eEUXEvamRKI8cV0NZaGQSIshWeGrOe/0iPVF4kps5s6eru8JGS27JjsCQ9kqKDnFLS6NsWX1eJDJSs5lOVbK5DxZrCuSwEDMZMXiyfL09dHoTODXTINIBBrxdDZGoyYDnZR0EasTO/hiDaKf0UbsdxJC975QA/y9k1y/nTksRXS5cTAOGqO6KffxFnwIDAQAB"
var exponent = "010001"
St.prototype.setPublicKey(key,exponent);
return St.prototype.encrypt(pwd);
};
// 传入密码
getPwd("1122")
组成的完整代码如下(因为代码太长且无法收起,所以只简单展示一下截图)
打开浏览器控制台,把完整的JS代码粘贴进去运行
得到秘钥后在postman验证通过(这里就不展示了),
本想着借助python运行JS的库PyExecJS计算密码密文,这样可以省去看JS代码的时间,但是实际这里花的时间非常多,包括找不到windows对象,这个因为是浏览器对象,引擎直接运行JS找不到很正常,看了代码发现跟加密无关就删除解决了;然后再是运行提示globalThis未定义问题,排查到需要Nodejs引擎运行;引擎问题解决了,然后是加密结果总是False。个人对JS不是很懂,所以这个方案页只能分析到这里为止。
如果有大佬明白其中的问题,请多多指点。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭