一次js混淆测试记录

admin 2024年4月28日11:23:19评论4 views字数 4207阅读14分1秒阅读模式
0x01 前言
这是一次js混淆的测试记录,也算是对自己的一次挑战,遇到问题就要迎难而上,方能知道自己到底有多菜。本次属于授权测试,任何未授权的测试都是违法行为!

0x02 测试

01 初步测试

拿到手的是一个h5站点,以熟练到让人心疼的速度打开burp、浏览器,开启了本次的测试之旅。
浏览器访问,查看burp抓包结果,就发现了事情的不简单,请求参数加密、响应数据加密,外加sign签名校验,看来又是一块难啃的骨头。
一次js混淆测试记录
如果想要进一步测试,那就必须把这第一道关打通,不然后面就只能干瞪眼了,所以我决定对js文件下手,这个总归比app逆向来的简单,但后面我被这个想法啪啪打脸,等会会说。

02 加密基础知识

在寻找加解密密钥之前,我想斗胆给各位大佬们科普一下加解密的基础知识,主要是讲给我自己听,给菜菜的自己补习。
加密
数据加密 的基本过程,就是对原来为 明文 的文件或数据按 某种算法 进行处理,使其成为 不可读 的一段代码,通常称为 “密文”。通过这样的途径,来达到 保护数据 不被 非法人窃取、阅读的目的。
解密
加密逆过程解密,即将该 编码信息 转化为其 原来数据 的过程。
这里我主要讲一下AES加密算法,这样对大家理解这篇文章会起到一点帮助。
AES 加密算法是密码学中的 高级加密标准,该加密算法采用 对称分组密码体制,密钥长度的最少支持为 128 位、 192 位、256 位,分组长度 128 位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的 区块加密标准。AES最常用的工作模式是ECB、CBC、CFB和OFB四种。
这里我重点讲一下cbc模式,CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与一个叫初始化向量的数据块异或。
这里就有一个比较重要的基础知识点了,那就是AES加密算法的CBC模式下,必然会有两个加密参数:一个是key,另一个就是iv。
key的长度是会随着密钥的长度改变而改变的,比如:密钥长度为128位,那么key长度就是16个字节;密钥长度为192为,那么key的长度就是24个字节;密钥长度为256为,那么key的长度就是32个字节。但是iv的长度却是不变的,它是根据加密模式的不同而改变,在这里CBC模式,iv的固定长度为128位,也就是16个字节。
所以在nodejs中,如果你使用crypto模块加解密的话,可能就会看到,crypto.createCipheriv('aes-128-cbc', key, iv),这里就是将密钥的长度固定为128位16个字节,而且值得一提的是,nodejs中默认的填充方式是PKCS7Padding,不需要手动指定,如果想自定义的话也可以改。
最后再补充一个小知识点,就是java中使用AES/CBC模式加解密时,当想使用PKCS7Padding填充时,可以用PKCS5Padding代替,不然会报错,因为java中没有PKCS7Padding这个选项。

03 寻找加解密密钥

讲完了基础,现在我们进入正题,我会尽可能以我第一心理的视角,去讲解我是如何寻找加解密函数以及密钥的。
前面的burp数据包截图大家应该都看到了,其中包含请求的接口以及参数,一般我会有两种查找思路。第一种,我会直接全局搜索加解密函数关键字,比如:encrypt、encode、decrypt、decode、cipher等等。不过在这里并没有得到理想的答案。
一次js混淆测试记录
这里虽然找到了看似加解密函数的地方,但是debug之后发现并没有触发,那就说明不在这个位置。
后面也尝试了其他的一些函数关键字,但都无法触发,没有定位到真正加解密的地方,这个时候就得用第二种方法了。
第二种,我会根据数据包中请求的参数、接口等信息作为关键字进行全局搜索,这个方法也是经验总结,屡试不爽。
这里也确实比较幸运,通过 pwa 关键字,一下子就准确定位到了加密函数的大概位置,之所以用大概,是因为它的代码是经过混淆的,我一开始也不能百分百确定。
一次js混淆测试记录
咱就说,就这段代码,谁看不迷糊啊,如果不是参数名没混淆,真的要找一阵子了。
通过咱的顶级理解,“l”必定是加密后的数据了,知道了这个要素之后,后面就要盯着“l”找了,要知道它从哪里来,要到哪里去。
先格式化一下代码,虽然混(看)淆(不)了(懂),但也不能忘了优雅。
一次js混淆测试记录
可以看到最外层定义的函数名为bLu,其实不重要,那个a参数,我这里盲猜应该是加密前的请求参数,打个断点看看。
一次js混淆测试记录
果不其然,看代码还是一如既往的准,看到pwa、token就可以断定这个是请求参数没错了。知道了参数在哪,下面就要研究在哪个步骤加密以及如何加密的了。
第一行可以看到定义了一些变量:var s = 0, r = A.A(t.z), q, p, o, n, m, l, k, j。这里和加解密没啥关系,继续往下看。
一次js混淆测试记录
这里的 cbc 引起了我的主意,让我想起了工商银行,哦不,让我想起了AES/CBC加密模式,前面我们刚说过,忘记了可以往上翻翻。
这里我猜测应该是在创建加解密对象,那么$.bQf()就很可能是我们要找的东西,跟进去看一下
一次js混淆测试记录
可以看到返回一个长度为16字节的数组,16字节?是不是有点熟悉又陌生的感觉,这里我先假定它为key,混(看)淆(不)了(懂)就只能靠猜了。
然后再进入A.au9函数看看做了什么操作
一次js混淆测试记录
哎!看到了吗,那熟悉的AEC/CBC/PKCS7,看来是找到组织了,到这里就更加坚定我的猜想了
返回au8对象之后,我们回到上一层,看一下aOQ函数,这里我选择优先看$.bQe函数,因为根据前面的经验,这个极有可能是iv,跟入
一次js混淆测试记录
果然,返回的也是一个16字节的数组,看到这里我大概可以判断,它应该使用的是aes-128-cbc模式加解密的。如何验证我的猜测对不对呢?其实也很简单,我们把key、iv单独拿出来,自己写一个脚本测试一下就知道了。
这里的key和iv我是这样取得,因为他是16字节数组嘛,所以我们把它打印出来,再将每个元素转为字符,key如图
一次js混淆测试记录
一次js混淆测试记录
iv转换如图
一次js混淆测试记录
一次js混淆测试记录
如果你非要问我为什么如此断定$.bQf()是key而$.bQe()是iv呢,那我只能告诉你,总共就两个参数,不是key就是iv,搞错了就颠倒一下,试错成本很低(笑哭)
有了key和iv,就可以写一段代码测试了
一次js混淆测试记录
尝试运行看看
一次js混淆测试记录
解密成功,到这里已经算成功一半了,为什么是一半呢,因为还有签名算法没弄出来

04 尝试硬刚签名

加解密完成了,现在就只剩签名了,这个签名真的是我不能提及的痛啊,我讲一点我的尝试思路和过程吧,结果不重要(哈哈)
先来看一下签名在哪里生成的
一次js混淆测试记录
单从图片中看,我觉得大家可以放弃了(开个玩笑)。这里的步骤是先将请求参数和一个32位的md5字符串进行拼接,类似这样“client=pwa&data=加密参数&timestamp=时间戳+32位md5”,然后在经过一系列函数洗礼。大家千万别被表象给迷惑了,看似一个函数,七十一个函数,再看看就九十一个函数了。
我这里主要讲一下第一步吧,“B.k8.gep().bg(m.a)”,看看这个函数做了什么操作,跟入gep函数
一次js混淆测试记录
返回了一个对象,再跟入bg函数
一次js混淆测试记录
这里一开始先获取参数a的长度,赋值给s、r、q,然后再赋值给p,然后再实例化一个新的Uint8Array数组,元素长度位参数a长度乘以3,这里都是字面意思,不难理解,之后实例化了aqG对象,浅看一眼
一次js混淆测试记录
就是简单做了赋值,没有其他特别的操作,继续往下看,调用了r.a03(a, 0, q)函数,传入了参数a、0和参数长度p
一次js混淆测试记录
这里主要操作就是将参数a的值挨个转为ascii码值,然后赋值给s数组,可以在q.ab函数中看到
一次js混淆测试记录
再回到刚才的函数
一次js混淆测试记录
循环结束之后,可以看到参数a的值已经全部转变为ascii值赋值给了数组s,然后再回到bg函数
一次js混淆测试记录
可以看到返回了一个B.A.bj对象,可以跟进去看一下
一次js混淆测试记录
可以看到就是从新创建了一个Uint8Array数组,内容为a数组从0截取到参数长度,可以理解为去除了多余的空元素,最后返回一个参数数组
一次js混淆测试记录
到这里“B.X.gep().bg(o)”也就分析完了,再往后我也进行了一些尝试,最后结果显而易见,我被绕晕了......

05 打不过就开挂,解决问题

虽然硬刚失败了,但是啊,打过游戏的小伙伴应该都知道,当你打不过一个人但又想赢的时候,应该怎么办?答案就是开挂!大G一开,统统散开!
他就算js混淆的再完美、再无懈可击,但他终究也是个对象,是对象那就可以被实例化,被调用。
这里我们可以先预习两个小的知识点,那就是如何导出函数以及导出对象。导出函数我们可以这么写
一次js混淆测试记录
然后在外部导入使用函数
一次js混淆测试记录
一次js混淆测试记录
导出对象可以这么写
一次js混淆测试记录
外部使用
一次js混淆测试记录
一次js混淆测试记录
然后就是尝试本地引入js文件调试了,这里我先引入了script标签中,在浏览器方便调试,原生引用打开发现报错
一次js混淆测试记录
细看了一下,都是静态资源文件未找到报错,根据报错信息,我在当前目录根据路由创建了目录和静态文件
一次js混淆测试记录
再次访问,发现之前的几个静态文件报错没了,不过还是有其他报错在
一次js混淆测试记录
一个是cors策略报错,另一个是不能加载某json文件,我全局搜索了一下json文件名,发现有几处引用
一次js混淆测试记录
我浅看了一下该文件,发现没哈鸟用,所以我的策略就是删除,然后返回空
一次js混淆测试记录
然后再来刷新页面看看
一次js混淆测试记录
可以看到已经不报错了,简单粗暴、直接有效!
解决了报错,就要看看源码结构了
一次js混淆测试记录
一次js混淆测试记录
发现他是立即调用的形式,就是定义完之后,自己调用了,最外层是dartProgram函数,也可以理解成dartProgram对象,这里我们需要微调一下,不过在调整之前我要先做个测试,看看直接调用函数能不能正常运行,先将关键函数暴露出来
一次js混淆测试记录
然后最外面定义一个变量去接收返回的对象
一次js混淆测试记录
这样子就可以在外部愉快的调用内部函数了
一次js混淆测试记录
一次js混淆测试记录
成功生成了签名,对比过没有问题,现在就剩最后一步了,让我能在nodejs环境中调用,需要再做一点微调,先将最外层的括号全部删掉
一次js混淆测试记录
然后将dartProgram作为对象导出
一次js混淆测试记录
最后在nodejs中以模块的形式导入调用即可
一次js混淆测试记录
运行看一下
一次js混淆测试记录
ok,到这里就要先告一段落了,加解密、签名我们都已经完成复用了,如果后续有更精彩的故事,我会再发出来。

0x03 总结

看完之后我想问一下大家,你是一个人来看文章的吗,一个人看文章算几级孤独呢?哈哈,没有啦,一个人学习的样子也很酷的好吧!本次没有什么多余的话,与君共勉吧。

0x04 参考文章

浅谈常见的七种加密算法及实现
https://zhuanlan.zhihu.com/p/347114235

原文始发于微信公众号(伟盾网络安全):一次js混淆测试记录

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月28日11:23:19
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   一次js混淆测试记录http://cn-sec.com/archives/2693885.html

发表评论

匿名网友 填写信息