JS调试之某众测前端签名绕过分析

JS调试之某众测前端签名绕过分析

写这篇文章是因为去年遇到的一个很典型的前端签名加密的挖洞案例,但因为众测要求保密,而且当时是帮某位师傅做的,当时不太好写下来。但是觉得这么典型的案例不写下来太可惜了,反正现在也过去大半年了,根据当时的截图再复现签名绕过的流程。

此图像的alt属性为空;文件名为image-18.png

开始的一个小插曲。PS:由于不能透露师傅的信息,下面都简称为a师傅。

因为这个众测是要求保密的,也需要用提供的测试账号才能访问,但是分析涉及到js。所以a师傅一开始发来一个t.js的文件让我帮忙看看,数据包是如何签名校验的。

打开js直接根据Signature定位到关键位置,从几个参数名上来看基本上就是这里了。

所有变量都是abcd这些字母,很明显是用webpack混淆过的。既然遇到这种情况,静态分析js代码肯定是非常困难的,如果可以调试的话就会方便很多。可惜a师傅又不能透露众测网站的相关信息,不然就违反了规定。

思来想去我也不能为难a师傅,所以自己就在这个js中寻找网站的相关信息,发现了网站的页脚信息。

好家伙,直接谷歌页脚信息。

我把这个网站链接发给了a师傅,直呼内行。

现在网站也被我知道了,而且也不是a师傅告诉我的。a师傅只好把后台的地址给我,让我去调试了。u1s1,js中确实能收集到很多有用的信息,在渗透测试中如果能利用好能起到事半功倍的效果。

下面开始进入正题,js调试!因为前面已经定位到signature大概的位置。

简单分析一下代码上下文,看到后面有个post,很明显是执行到6380行才发包,那我们就把断点下在这里。重新加载后,浏览器会断在这里此时上面的变量信息都是有值的。把光标放在变量l上可以看到加密签名前的原始信息,整个签名是调用了u()这个加密函数。

从右边的call stack可以看到当前函数的栈调用。我也跟进了u()看了加密逻辑。实在是过于复杂,但是反过来想一想我又不用把加密函数提取出来用代码重写一遍,那么我根据没必要看过他的内部逻辑。毕竟我只要能在前端调试出来具体的签名值即可。

我的核心思想是:把加密函数看做一个黑盒子,也就是一个整体。不用看懂内部的加密逻辑,我们只要给这个黑盒子一个输入,拿到我们想要的输出就行了。很多小伙伴可能在分析的时候,看到加密代码逐步跟进,一层层的嵌套可能就陷进去了,最后就被绕晕了。我在调试js时用这种思路解决了大部分的问题。

这时a师傅发来消息,但我还没有调试出来。挖到了不少漏洞,但全都被数据包签名给挡住了。看来得加把劲了。

上面知道加密前的数据是放在变量l中的,我们跟踪l到定义的位置。

可以看到实际是由很多个变量拼接在一起的。并且其中有个变量是用的本地的token值。

window.localStorage.getItem(“token”)解释一下就是获取当前token值。localStorage是保存了当前浏览器的cookie信息的。localStorage 和 sessionStorage的区别不了解的小伙伴可以谷歌学习一下,之前准备面试的时候好像也遇到过。

确实在不用批量利用的情况下,只要将包含payload的签名计算出来就算成功了。经过我的推断分析。

signature 在加密前由四部分组成
第一个参数是 请求的对象
第二个参数是 token
第三个参数是 时间戳
第四个参数是 随机6位数字
时间戳和随机数的值不用管 是用于服务端校验的

接着继续测试后台的某个搜索框。

断点还是下在原来的位置。

可以看到变了l的某个拼接参数确实是我们的搜索数据。

那么看似复杂的问题便有了头绪,只需要替换变量l的参数为我们的payload,再通过加密函数u计算出来的就是payload的签名了。

那么如何调用签名函数来为我们的恶意payload进行签名呢?

还是需要下断点的,因为我们分析不出来加密函数的逻辑。当断点断在生成签名发包前时,整个签名函数都是放在内存中没有被销毁的,我们是可以在chrome的控制台直接调用这个签名函数的。

但前提是断点一定是断在加密函数定义调用位置之后的!不然控制台会提示未定义。

如上图,我们直接调用加密函数u()。假设定义sign0变量的值就是我们的payload。

var sign0 = ‘{“benefitParam”:”sssssssssss”,”childCategoryNos”:[],”pagination”:{“pageSize”:10,”pageNum”:1}}6502e3e7-4bb5-497b-bd5f-665a1df4b4921602770129338177251’

其中sssssssssss就是我们修改的参数。上图中我同时对原本的l用u加密,签名之后的值和signature是完全相同的,这就证明了我的思路是正确的,同理对sign0签名得到的就是我们payload的值了。

但是下了断点后,没办法发包继续测试怎么办?

我给a师傅提供了一个思路,同时开两个浏览器一个浏览器先断在加密函数的位置,另一个浏览区用来替换payload签名发包测试。

后续就是发包替换为payload签名证明漏洞是否存在了。因为a师傅本来就挖到漏洞了的,之是被签名给挡住了。弄了一晚上总算把签名给研究出来了。

第二天一早a师傅发来消息,收到了漏洞奖金,让我不要再碰他们的系统了。研发专家们开始拉讨论组分析漏洞成因修复了。虽然分析了一晚上才研究出来,但是做出来挺有意思的,也很有成就感。

举一反三:

在上面的案例中,我们只是通过下断点手工替换payload的方式生成了签名值。但实际过程中还是非常麻烦的,如果遇到了大量的payload测试数据都需要签名怎么办呢?

我在一晚上的思考后想出了一种新思路!

snippets是一个代码片段脚本,从控制台创建js小脚本Chrome的snippets是小脚本,还可以创作并在Chrome DevTools的来源面板中执行。可以访问和从任何页面运行它们。当你运行一个片段,它从当前打开的页面的上下文中执行。可能很多小伙伴都不知道。

利用chrome的控制台的sources面板中的snippets新建一个snippet脚本,这个脚本调用加密函数u()遍历包含payload的数组,并打印出所有的签名值。

这样就可以批量的生成签名值,更方便快速的测试甚至进行一些爆破操作。看似无懈可击的签名验证在这种方式下也可以成功绕过!

赞赏

微信赞赏支付宝赞赏

Zgao

愿有一日,安全圈的师傅们都能用上Zgao写的工具。

2条评论

匿名 发布于7:21 上午 - 6月 6, 2021

Zgao yyds!!

匿名 发布于12:35 上午 - 6月 6, 2021

Zgao yyds!