篇幅有限
完整内容及源码关注公众号:ReverseCode,发送 冲
抓包
登录URL:
POST https://passport.5173.com/?returnUrl=http%3A//www.5173.com/
参数:
smsLogin: 0
userName: 15806204095
password: 6a771c7ecf7ebe2c3d4c0075cdb96ae5
mobileNo:
smsCaptcha:
category:
passpod:
__validationToken__: 1680e6a3947c43aea45d83e69b0d7291
__validationDna__:
分析
password
password有32位,有可能是md5
搜索password,出现的地方太多了,懒得看,放弃。
点击登录按钮,肯定触发事件发送请求,搜索submit-btn
无效结果。
搜索tnSubmit
加上断点,点击登录按钮时,果然断在了这个function中,不过此刻Network面板的请求包已经发送出去了,gg了,没能拦截到https://passport.5173.com/?returnUrl=http%3a%2f%2fwww.5173.com%2f
请求发送前的时间点。
再一次尝试,在加密password时肯定要获取该输入框的值,通过id获取元素的话,我们搜索#txtPass
在所出现的位置都打上断点
点击登录时查看Network已经拦截在了ValidateSlide请求,还没有到登录请求
查看断点时打印o为aec712a02d8c835b92369e5d7e5494cf
,并直接跳到return $[["ajax"]]
处,查看此时提交的data中的a[["serialize"]]()
为"smsLogin=0&userName=15806204095&password=aec712a02d8c835b92369e5d7e5494cf&mobileNo=&smsCaptcha=&category=&passpod=&__validationToken__=31004cd552c94687ba27d1c7258576f7&__validationDna__="
,其中的password就是之前打印的o参数。
由于password=o,现在只需要追踪这个o参数来源即可。往上追溯是onsubmit: function(f, o)
中作为第二个参数o传递进来的,通过调用的堆栈查看上一级调用方法submitHandle。
submitHandler这段代码返回a.onsubmit(a, c),其中c就是onsubmit: function(f, o)
中的o=password。由于a.usingTpm || a.passwordHash
是true,那么这个c就是通过a.getPassword(a.pkey)
获取。
进入getPassword后,this.ready && this.activeTpm && this.usingTpm
为false,必然进入的是else中的c = hex_md5(hex_md5(c).substr(8, 16) + a);
实现加密。
(c = b("#" + this.passwordControlId).val()) && this.passwordHash
赋值必然是true,其中(c = b("#" + this.passwordControlId).val())
的结果为123456,即我们输入的密码,由于传入的a为42m2gl
,所以加密逻辑整理为c = hex_md5(hex_md5("123456").substr(8, 16) + "42m2gl")
那么问题来了,传入的a是哪里来的,通过搜索42m2gl,原来每次页面生成的时候页面会加载PasswordKey,通过PasswordKey和SecurityToken等key实现相互验证进行校验。
__validationToken__
__validationToken__这个字段6b16902a6b134dc9a2c333b965c9405f
在请求里面无法搜到是因为页面已经刷新,通过fiddler抓包https://passport.5173.com/?returnUrl=http%3a%2f%2fwww.5173.com%2f
历史可以看到首页加载时传入该参数
爬虫实现
首次先请求https://passport.5173.com/?returnUrl=http%3a%2f%2fwww.5173.com%2f
获取页面中的PasswordKey的值和SecurityToken的值,通过两次md5密码hex_md5(hex_md5("123456").substr(8, 16) + "42m2gl")
拿到password加密结果,发起请求。
def hex_md5(s):
m = hashlib.md5()
m.update(str(s).encode("utf-8"))
return m.hexdigest()
headers = {
'Host': 'passport.5173.com',
'Origin': 'https://passport.5173.com',
'Pragma': 'no-cache',
'Referer': 'https://passport.5173.com/?returnUrl=http%3A//www.5173.com/',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
}
login_url = 'https://passport.5173.com/?returnUrl=http%3A//www.5173.com/'
html = requests.get(login_url).text
# print(html)
securityToken = re.findall('SecurityToken:"(.*?)",', html, re.M | re.S)[0]
passwordKey = re.findall('PasswordKey:"(.*?)",', html, re.M | re.S)[0]
print(passwordKey)
print(securityToken)
# 滑块 'https://passport.5173.com/Sso/ValidateSlide?token={}'.format(securityToken)
# hex_md5(hex_md5("123456").substr(8, 16) + "42m2gl")
password = hex_md5(hex_md5("123456")[8:8 + 16] + passwordKey)
userName = '15806204096'
data = {
'smsLogin': '0',
'userName': userName,
'password': password,
'mobileNo': '',
'smsCaptcha': '',
'category': '',
'passpod': '',
'__validationToken__': securityToken,
'__validationDna__': ''
}
r = requests.post(login_url, data, headers=headers)
print(r.text)
虽然password逻辑已经破解,不过登录时还需要验证码滑块的校验,以后有时间再写吧。。。
本文由博客群发一文多发等运营工具平台 OpenWrite 发布