直接输入随机账号密码,查看网络请求,主要有两个数据包:
请求passkey接口,返回pass_key和ssid。
还有一个safe_verify请求,请求体中包含ssid,password,account等参数,其中ssid与第一个请求中返回的ssid一致,这里主要关注password的加密方式。
关键的请求包为XHR的形式:
首先还是下一个XHR断点:
刷新,重新登录,从栈顶依次往下看:
先看到send,可以看到e.data里已经包含了加密之后的各参数,继续往前:
同样,b.data中的数据已经是加密之后的。
直到第三个匿名函数,已经无法跟到与password相关的值,下断点:
刷新后发现,直接会在验证码加载时就断住,暂时放弃XHR跟栈,下面通过搜索password来找加密的部分。
共有9处结果:
很容易定位到common.19c277c4.js中的a.password = c.encrypt(b),
行.
下断:
右侧能够看到,a中的各参数值即为请求体中的内容,而a.password=c.encrypt(b)
,b的值为明文密码,即123456.
代码如下:
success: function(a) {
if ("ok" == a.result) {
var c = new JSEncrypt;
c.setPublicKey(a.pass_key),
a.password = c.encrypt(b),
"undefined" != typeof $ && $("body").trigger("encryptPassword", a)
}
},
跟进encrypt:
继续下断点,步入:
选中的部分即为加密代码,这两处均在jsencrypt.js中。
直接将整个js文件复制,本地尝试运行:
navigator is not defined。
直接在文件开头加上var navigator = {};
,运行继续报错window is not defined,加上var window = {};
至此能够成功运行:
再把前面的加密代码补上:
JSEncrypt is not defined,而原来的js中将db赋值给window.JSEncrypt,修改js代码并删除无关部分:
得到加密的password,但是每次运行的结果都不同。
先加几个console.log看看哪里会变化:
问题在b中,每次运行都会返回一个看起来随机的值。在function(a,b)的最后一行,new J(c),打个断点跟进去查看J函数:
里面有近1000行代码,进行了各类运算,其中看到下面一行:
f.fromInt(H[Math.floor(Math.random() * H.length)]);
,存在Math.random(),每次都会获取一个随机值,因此每次加密的结果都是不同的。
原文始发于微信公众号(Crush Sec):js逆向系列09-WPS