文章目录
声明
本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!
目标
1号店登录接口
地址:aHR0cHMlM0EvL3Bhc3Nwb3J0LnloZC5jb20vcGFzc3BvcnQvbG9naW5faW5wdXQuZG8=
操作步骤
观察接口
通过观察我们发现,本次的目标是credentials.username、credentials.password、captchaToken。
credentials.username、credentials.password
全局搜索参数名
我们可以看到credentials.username、credentials.password都是一个加密方式得到的。
跟进这个加密
可以看出来其实就是RSA加密
熟悉的朋友很明显能看出来这个代码和jsencrypt
库里的RSA几乎是一致的。
所以我们完全可以用·sencrypt
这个库自己去实现用户名密码的加密。
但是这个publicKey
怎么来的呢
通过搜索我们可以发现它在html页面的代码里
代码实现
接下来就是代码实现加密过程
如果没安装jsencrypt
库,需要先安装
npm install jsencrypt
然后就是js代码
window = this;
var JSEncrypt = require("jsencrypt")
var pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXQG8rnxhslm+2f7Epu3bB0inrnCaTHhUQCYE+2X+qWQgcpn+Hvwyks3A67mvkIcyvV0ED3HFDf+ANoMWV1Ex56dKqOmSUmjrk7s5cjQeiIsxX7Q3hSzO61/kLpKNH+NE6iAPpm96Fg15rCjbm+5rR96DhLNG7zt2JgOd2o1wXkQIDAQAB"
var i = new JSEncrypt();
i.setPublicKey(pubkey);
var j = 13333333333
var k = 123456
j = i.encrypt(j);
k = i.encrypt(k);
console.log(j)
console.log(k)
运行结果
抠js代码实现
有小伙伴说了,我就想练练抠js代码!
没问题,马上安排!
首先,把关键代码复制下来
如下这段全复制下来
代码复制下来后,补环境只需要两个
window = this;
navigator = {};
最后加上我们要加密的代码
var k = '18812731329';
var j = 'qaZ123456!';
var pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXQG8rnxhslm+2f7Epu3bB0inrnCaTHhUQCYE+2X+qWQgcpn+Hvwyks3A67mvkIcyvV0ED3HFDf+ANoMWV1Ex56dKqOmSUmjrk7s5cjQeiIsxX7Q3hSzO61/kLpKNH+NE6iAPpm96Fg15rCjbm+5rR96DhLNG7zt2JgOd2o1wXkQIDAQAB";
var i = new JSEncrypt();
i.setPublicKey(pubkey);
j = i.encrypt(j);
k = i.encrypt(k);
console.log(j);
console.log('==================');
console.log(k);
接下来运行又报错了
只需要添加一行代码
这是因为其实这个对象上边已经实现了,但是上边定义为window.ASN1
,所以这里在给引用一下
这里改了之后呢,又会有新的错误
TypeError: Cannot read properties of null (reading 'bitLength')
那我们在报错的地方打印一下这个bitLength的调用者
发现它是空的
这时候吧就不太好确定是哪里出问题了,因为这个代码很多的try…catch捕获的异常都没有打印
但可以初步判断是设置key的时候有问题
那直接在setPublicKey这里打断点进行debug调试
一直跟进到parseKey
这个方法后发现了问题
查看这个异常的内容发现说是ReferenceError: Base64 is not defined
其实这个和那个ASN1的异常是一样的,所以这里直接改成window.Base64
就可以了
到这里就没问题了
获取captchaToken
接下来就是captchaToken参数的获取了,我们把鼠标放到window.jab.getData()这个方法上,跟进去看这个方法
可以看到它定位的是下边这个方法
可以看到是this["c"][2]
这个方法
继续跟进就能看到是这个ao
抠代码实现
我接下来采取的方法还是抠js代码
把整个js文件内容都复制下来
定义一个全局变量,让它等于ao
因为这个ao实在传参的第二个索引的方法里,所以要修改复制下来的文件最后传的参数
原始文件中是5,咱们要改成2
运行代码,环境该补的补,没啥难度,
如果报错:
TypeError: XMLHttpRequest is not a constructor
可以把与之相关的部分代码去掉,并不影响生成逻辑
还会报
TypeError: t is not a constructor
找到对应的地方
把这个new t()
给替换一下,在浏览器控制到打印new t()
注意,应该在调试进ao[2]这个方法里边后再输出new t(),不然没有结果
只需要把代码里的new t()改成{withCredentials:false}
即可
再次运行能输出结果了
但是我们发现这不对啊,明明应该是三部分拼接的啊
少了g[f[b("0x6c7", "]swn")]("_", "t")]
这个很容易发现其实就是window._t
关键是这个怎么生成的
hook一下window._t
,(如果hook不到,那只能一步步跟栈了)可以发现是下边这地方生成的
一步步的往下跟栈,(过程真是枯燥)
控制台输出一下相应的变量
发现F就是cookie里的_s_id
可以把av
的值固定下来,只替换里边的时间戳就可以了
就可以生成想要的值了
最后还要说一点,在运行这些之前,还运行了ao
里边的第一个函数,也就是ak
因此我们的代码中需要先手动运行一下ak
,至于它的传参,可以固定下来
打断点运行到ak
里边,然后控制台输出一下ap
把内容复制下来
var ap = {
"bizId": "PASSPORT_LOGIN",
"initCaptcha": true,
"apiServer": "//nocaptcha.jd.com",
"staticServer": "//js-nocaptcha.jd.com",
"jv": "20201218"
}
aaa[0](ap)
console.log(aaa[2]())
最后运行结果
至此 captchaToken的值也获取到了。
结论
抠js代码真是个枯燥乏味的活计,期间还各种报错,各种补环境,不过最终能成功,还是很欣慰的。