第一步还是抓包,发现加密字段pass
通过Initiator结合函数栈断点找到对应的关键代码,但是这里尝试在f.send方法处下断点的话,会不断地断在这个位置,原因是前端会不停地请求二维码的数据包,导致无法分析
使用xhr/fetch breakpoints断点来打断点,点击登录之后成功断下来,可以在console的位置处看到参数
接着回溯函数栈,找到h方法的const [L,U] = await pn("/sso/v2/login", C);代码
这里的C可以在上面看到,是一个对象,包含需要的各种属性
在 if (n.curType === "show_pw") 处断点,执行
进入Qh("".concat([cp(), ap()].join(" "), "\n").concat(s.form.password), n.pubkey)的Qh函数,下断点之后继续执行
console查看参数也不难发现,这是一个RSA的加密
而且参数t的值是'1741921196\t25XVEH\n111111',前面是时间戳,中间目前不知道,后面是密码
要想知道参数的含义,需要分析Qh函数的参数,也就是 "".concat([cp(), ap()].join(" "), "\n").concat(s.form.password) 里的cp()函数和ap()函数
函数定义如下
这是ES6的代码写法,代表调用cp函数的时候直接返回en,调用ap函数的时候直接返回br
br函数和en函数均在上面有使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 let br;const op = t => { if (Qe || (Qe = new _a (!0 )), t === 0 ) return Qe .clear (), en = t, !0 ; if (t < 1294935546 ) return !1 ; const e = function ( ) { en && Qe && (en += is / 1e3 , Qe .start (is, e)) }; en = t, Qe .start (is, e) } , lp = t => { br = t }
上面代码的意思是,br是在lp函数中被赋值为t变量,要想知道br是什么,还需要知道lp函数的参数t是什么,对于en函数同理,需要找到lp函数和op函数被调用的地方
在代码中全局搜索lp(,找函数被调用的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Ks (async () => { n.entry = e.query .entry , n.source = e.query .source ; const [C,L] = await pn ("/sso/v2/web/config" , { method : "POST" , entry : n.entry , source : n.source }); C || L.data .retcode !== 2e7 || (n.show_pw = !!L.data .data .show_pw , n.show_qq = !!L.data .data .show_qq , n.show_qr = !!L.data .data .show_qr , n.show_sms = !!L.data .data .show_sms , n.show_wechat = !!L.data .data .show_wechat , n.curType = L.data .data .first_show , n.regUrl = L.data .data .reg_url || Wh , n.forgetUrl = L.data .data .forget_url || Gh , n.iconUrl = L.data .data .icon_url || Zh , n.pubkey = L.data .data .pubkey , n.rsakv = L.data .data .rsakv , document .title = "登录 - " .concat (L.data .data .title ), i.countryCodeMenu = L.data .data .country_code .map (U => ({ code : U.country_code , text : U.local .zh_CN })), lp (L.data .data .nonce ), op (L.data .data .servertime )) }
可以看到参数是通过请求/sso/v2/web/config这个接口返回的,可以抓包校验一下
这里抓包注意是刷新页面的时候看数据包,点击登录之后包就被莫名其妙丢了,或者用抓包工具抓
那么现在要做的就是把这里的代码给扣下来,找到Hh函数定义的js代码,有时候扣下来的代码不一定能直接运行,比如函数内部本来应该报错,但是被catch到了,导致运行的时候结果不对,这个时候就需要调试,如果报错缺少变量,说明扣少了
1 2 3 4 5 6 7 8 9 , Qh = (t, e ) => { if (!e || !t) return ; const n = new Hh ({ default_public_exponent : "10001" }); return n.setPublicKey (e), Jh (n.encrypt (t)) }