最近和几位大佬一起学习js逆向,有很多列子,今天记录此篇文章。本篇文章主要讲解某团网页版登录的加密参数h5Fingerprin及password,h5Fingerprin这个参数长度大约在4070左右不定,而password采用了RSA非对称加密;相对与之前几篇文章所涉及的东西确实是有些棘手。
本文章仅供学习研究,如若侵犯到贵公司权益请联系[email protected]第一时间进行删除;切忌用于一切非法途径,否则后果自行承担!
地址:https://passport.meituan.com/account/unitivelogin
打开网页输入账号:138xxxx8888,密码:123456789点击登录抓包
h5Fingerprint和password的模样基本上就是这个亚子的了,正片请往下看…
搜索password参数:
发现 encrypt.encrypt(dataJson.password)加密关键字(encrypt),点击绿色标注的地方进入js文件代码段:
打下断点,并点击登录重新抓包,看看是否能够使断点生效:
发现断点生效:dataJson.password = encrypt.encrypt(dataJson.password),控制台打印dataJson.password看看
接下来单步执行:
到这里已经很明了的看到了,函数传入参数str = 123456789(密码),继续单步执行
到这里就已经很明了了,RSA加密。对于RSA,没有必要使用JS进行模拟还原,这里使用python还原即可(当然这里只针对原生的RSA加密生效,如果网站开发人员对算法有所改写的话另说),所以先使用python还原,最后验证提交是否正确即可。
对于RSA算法原理请移步大佬文章参考, 所以我们只需要知道私钥即可进行算法还原,接下来返回开始的断点函数:
鼠标指针放置this.publicKey上面
控制台打印this.publicKey
python还原RSA:
def Rsa_Password(pwd) ->str:
"""
RSA——Python还原算法
:param pwd: 密码明文
:return: 加密字符串
"""
publickey= 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCRD8YahHualjGxPMzeIWnAqVGMIrWrrkr5L7gw+5' \
'XT55iIuYXZYLaUFMTOD9iSyfKlL9mvD3ReUX6Lieph3ajJAPPGEuSHwoj5PN1UiQXK3wzAPKcpwrrA' \
'2V4Agu1/RZsyIuzboXgcPexyUYxYUTJH48DeYBGJe2GrYtsmzuIu6QIDAQAB'
rsaPublickey = '-----BEGIN RSA PRIVATE KEY-----\n'+publickey+'\n-----END RSA PRIVATE KEY-----'
key = RSA.importKey(rsaPublickey)
cipher= PKCS1_v1_5.new(key)
encode_str = base64.b64encode(cipher.encrypt(pwd.encode()))
pwd_encode = str(encode_str,encoding='utf-8')
print(pwd_encode)
print('长度:'+ str(len(pwd_encode)))
return pwd_encode
搜索h5Fingerprint
打下断点点击登录:
通过控制台输出可以看的长度很像了,其实他就是h5Fingerprint。单步执行
进入新函数,参数rul是一个网址,在return处打上断点,执行到断点处并打印返回值
加密定位完成,下面讲解参数情况
这里先执行完所有断点,重新进入这个函数
这里的 Rohr_Opt.reload和rohr.reload两个匿名函数如下
通过Rohr_Opt.reload进入函数观察
再通过rohr.reload进入函数观察发现其实他们都是执行同一个函数:
在函数return的地方打下断点,并执行到此处
单步执行进入下一步,代码跳到了上面的x(e)方法中
这里参数e变成了一个对象:
其实这里的逻辑就是将原本的e(url)参数先进行一次x(e)加密,然后再将加密之后的字符串赋值给新的e(对象)的sign值,然后再对对象e进行一次x(e)加密,下面看看x方法
这里先将参数e转字符串然后子在给Oe方法进行处理再赋值给e变量
紧接着再调用ZcGxo(x,e)方法进行处理(参数是一个btoa和e),并赋值给e,最后e即是h5Fingerprint的值
进入ZcGxo方法看看
打下断点,并执行到这里
控制台输出:
到这里已经将加密逻辑过的差不多了,下面讲一讲e参数。
e是一个对象
其中cts,ts为时间戳,mT为滑块轨迹(由于登录需要过滑块验证,这里不对滑块进行讲解)可以写死进行提交测试即可,其余参数也可写死进行测试。
所有东西准备就绪,将涉及加密的js方法代码拿出来改写即可,下面node运行结果:
模拟登录代码:
# -- coding: utf-8 --
# @Time : 2021/3/4 15:49
# @Author : Los Angeles Clippers
# @Email: [email protected]
# @sinaemail: [email protected]
import execjs
import base64
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
import requests
import re
session = requests.session()
"""
https://passport.meituan.com/account/unitivelogin
"""
def Rsa_Password(pwd) ->str:
"""
RSA——Python还原算法
:param pwd: 密码明文
:return: 加密字符串
"""
publickey= 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCRD8YahHualjGxPMzeIWnAqVGMIrWrrkr5L7gw+5' \
'XT55iIuYXZYLaUFMTOD9iSyfKlL9mvD3ReUX6Lieph3ajJAPPGEuSHwoj5PN1UiQXK3wzAPKcpwrrA' \
'2V4Agu1/RZsyIuzboXgcPexyUYxYUTJH48DeYBGJe2GrYtsmzuIu6QIDAQAB'
rsaPublickey = '-----BEGIN RSA PRIVATE KEY-----\n'+publickey+'\n-----END RSA PRIVATE KEY-----'
key = RSA.importKey(rsaPublickey)
cipher= PKCS1_v1_5.new(key)
encode_str = base64.b64encode(cipher.encrypt(pwd.encode()))
pwd_encode = str(encode_str,encoding='utf-8')
print(pwd_encode)
print('长度:'+ str(len(pwd_encode)))
return pwd_encode
def get_h5Fingerprint(url) -> str:
with open('h5m.js', 'r', encoding='utf-8') as f:
js = f.read()
h5Fingerprint = execjs.compile(js).call('get_h5Fingerprint', url)
print('h5Fingerprint:', h5Fingerprint)
print(len(h5Fingerprint))
return h5Fingerprint
def get_encUrl():
url = "https://passport.meituan.com/account/unitivelogin"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
}
response = session.get(url, headers=headers).text
encUrl_ = "https://passport.meituan.com" + re.search(r'id="J-normal-form" action="(.*?)"', response).group(1)
encUrl = encUrl_.replace('=', '=').replace('amp;', '')
print('encUrl:', encUrl)
csrf = re.search(r'"csrf" value="(.*?)"', response).group(1)
uuid = re.search(r'uuid=(.*?)&', encUrl).group(1)
token_id = re.search(r'token_id=(.*?)&', encUrl).group(1)
continues = encUrl.split('continue=')[1]
print('csrf:', csrf)
return (encUrl, csrf, uuid, token_id, continues)
def login(dat, h5m, pwd, username):
url = "https://passport.meituan.com/account/unitivelogin?"
data = {
'countrycode': '86',
'email': username,
'password': pwd,
'origin': 'account-login',
'csrf': dat[1],
'requestCode': '',
'responseCode': '',
'h5Fingerprint': h5m,
'device_name': '',
'device_type': 'Chrome',
'device_os': 'Window',
'sdkType': 'pc',
}
params = {
'risk_partner': '0',
'risk_platform': '1',
'risk_app': '-1',
'uuid': dat[2],
'token_id': dat[3],
'service': 'www',
'continue': dat[4],
}
headers = {
'Host': 'passport.meituan.com',
'Origin': 'https://passport.meituan.com',
'Referer': 'https://passport.meituan.com/account/unitivelogin',
'sec-ch-ua': '"Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
'X-CSRF-Token': dat[1],
'X-Requested-With': 'XMLHttpRequest',
}
print(data)
print(params)
response = session.post(url, json=data, params=params, headers=headers).text
print(response)
if __name__ == '__main__':
p = '123456789'
username = ''
pwd = Rsa_Password(p)
dat = get_encUrl()
h5m = get_h5Fingerprint(dat[0])
login(dat, h5m, pwd, username)
网页结果:
与网页结果对比,验证了我们的RSA还原正确,且h5Fingerprint参数也通过了验证。
good good xuexi,day day up,少掉头发。
码字不易,如果本篇文章对你有帮助请动动小手点个赞8,谢谢~
合作及源码获取vx:tiebanggg 【注明来意】
QQ交流群:735418202
需要源码请关注微信公众号回复【美团JS】获取 :
*注:本文为原创文章,转载文章请附上本文链接!否则将追究相关责任,请自重!谢谢!