篇幅有限
完整内容及源码关注公众号:ReverseCode,发送 冲
抓包
登录URL:
POST https://passport.5173.com/?returnUrl=http%3A//www.5173.com/
参数:
1 | smsLogin: 0 |
分析
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加密结果,发起请求。
1 | def hex_md5(s): |
虽然password逻辑已经破解,不过登录时还需要验证码滑块的校验,以后有时间再写吧。。。