0x00 前言
在最大化收集Vue框架(SPA类型)下的js中我提出了一个重要观点:想要最大化且快速的收集Vue框架(SPA类型)下的js就需要进入目标站点下的所有路由,当你访问这些路由时就会加载各个路由所需的js,就不用我们手动去拼接或者去代码中找了。那么现在就引出了一个新的问题:如何最大化获取Vue框架(SPA类型)下的路由?这也是我本文要讲的核心内容,其中,访问各个路由还能让我们快速的测试目标站点是否存在未授权接口,也就是说它不止有能拿到js的好处。
注:
1.本文不会去讲vue基础语法。2.本文主要针对的是用vue框架构建的单页应用(SPA)。3.本文假设读者已经掌握了html、js、vue基础知识或已读过最大化收集Vue框架(SPA类型)下的js。4.本文将涉及到路由守卫(不会涉及到绕过,上一期文章已经讲过)、添加未加载的路由、解决跳转问题、Router多实例情景、白名单伪造。5.如有读者时间匆忙,可以直接跳到最后的0x08总结,但我还是建议读一遍文章,我认为本文还是有很多内容值得学习的。
目录:
0x01 正文
0x02 再谈路由守卫
0x03 动态路由
0x04 跳转问题
0x05 Router多实例问题
0x06 我的插件
0x07 白名单伪造杂谈
0x08 总结
0x01 正文
首先我想问大家一个问题,各位是否使用过类似于Vue Crack或者vue devtools的插件去获取目标站点的路由,例如:


如果使用过,那么我想问问各位是否认为这些插件获取的目标站点的路由是全的?从某种意义上来说,它们获取的确实是全的,不过获取的是已加载的路由,而未加载的路由就获取不到了(后文会讲什么是已加载和未加载的路由),例如我上图给大家看的目标站点的路由,显而易见在Vue Crack或vue devtools显示出来的只有类似于/login或/tokenLogin这种登录路由,如果说这些插件获取到目标站点的路由是全的,那么一个后台管理系统只有这几个路由就有点说不过去吧,全都是一些登录路由,这说明确实是有蹊跷的。我们现在通过findsomething看一下是否有一些路由在这些插件当中是看不到的(上文我已经讲过findsomething能匹配到vue框架下的顶级路由,这是因为顶级路由在定义时需要加上/):

可以看到在findsomething中能匹配到很多我们在Vue Crack或者是vue devtools插件中匹配不到的路由,例如我们现在去代码中搜一下/dashboard:

很明显,Y_里存放了关于/dashboard路由的信息,有component以及子路由等等,而我们在那些vue信息收集插件中并没有看到/dashboard路由的信息,这很明显说明了这些插件获取的路由并不全,以及我们再往下翻依然能翻到很多在这些插件当中看不到的路由:

接下来我们尝试访问一个在vue信息收集插件当中没看到的路由,例如/dashboard,看看是否能访问成功:

很明显并不能成功访问,显示出404,但是我们明明在代码中看到了开发定义了这些路由,连所需的组件js也写上了,但是我们就是访问不了,这也就是我接下来要讲的:此类站点为什么要这么做以及我们该如何加载并正常访问到这些路由。
0x02 再谈路由守卫
我们先来看一下上面这个站点在实例化路由器时传入的路由是什么:

可以看到传入的是d7,我们打个断点看一下d7里都有什么:


从上图我们可以看到,开发将我们在插件当中看到的那些路由放到了一个数组里,并在实例化路由器时传入了进去,而上面那些在插件当中没看到的路由例如/dashboard一个都没有被包裹进来,但是在代码中又定义了这些路由,说明这些路由其实是有用的,只不过在实例化时并没有传入进去,这就导致这些路由并没有被加载,导致我们在插件当中获取不到,这就是我上文所说的未加载的路由,所以这也是为什么我们在插件中没有看到这些路由。那么该如何判断一个路由有没有被加载,其实很简单。实际上,vue router提供了一个方法供我们快速获取路由:


例如:

但是这个方法只能获取到已加载的路由,也就是我们在插件当中看到的那些路由,Vue Crack和我自己写的脚本也用了这个方法去获取到目标站点加载的路由:


可以看到在Vue Crack里还用了其他不同的方法去获取路由,但不管哪种方法其实都只能获取到已加载的路由。例如下面是一个示例:


可以看到,我将/content路由对象单独拿了出来,并没有在实例路由器时传进去,我们现在看看Vue Crack和vue devtools是否能读取到:


可以看到根本没有获取到/content,这足以证明不管用上面那段代码的哪种方式,都获取不到未加载的路由。那么我们该如何才能获取到,可能已经有读者朋友意识到了,上述其实也反向证明了在vue router中是有函数能做到动态添加路由的,因为我们在上文也看到了,如果你不加载,强行访问只会显示404,所以必然是有函数能实现动态添加那些未加载的路由。当然我们先不谈如何实现,我们先来讨论一下站点为什么要这么做。实际上这么做就是为了实现权限分离,我来给大家介绍一个后台开发框架—-JeeSite,该框架使用的就是Vue Router 4.x,我们来看一下该框架的动态路由的核心架构:

当我们访问页面后,遇到的第一个拦截就是权限守卫,也就是路由守卫,如果我们访问的是非白名单的路由就会检验我们的Token是否有效,有效就获取用户信息,无效就重定向到登录页。接着如果获取到了用户信息就判断是否添加了动态路由,如果没有添加就构造动态路由并添加。
从上篇文章中我们也知道,我们能直接利用我的脚本绕过路由守卫,但其实动态添加路由完全是能在路由守卫里实现的,例如:

该站点使用了全局前置守卫(beforeEach),在代码中其实就做了一个动态加载路由的操作。首先判断用户是否登录,如果登录了就进行动态路由加载,也就是then里面的操作。我来给大家断个点走一下,现在我们是一个未登录的状态所以没有用户信息:

可以看到代码此时要获取localStorage的userInfo键值,当然我们现在没有所以就是null:

接着直接跳到了最后并没有进入then回调函数:

现在我们向localStorage添加userInfo键值假定我们已经登录了:


可以看到这里成功让前端认为我们已经登录了,接着走:

现在就会进入then回调函数进行动态路由添加。
而如果直接使用我的脚本去进行hook绕过,是根本到不了这一步的,看过上篇文章的朋友都知道,我那个脚本能直接使全局前置守卫(beforeEach)和全局解析守卫(beforeResolve)设置的函数失效,所以有些朋友可能发现用我的脚本进行hook绕过后并没有加载路由(例如访问响应404)或是进入后台后没有加载菜单,这是正常的,因为我的脚本本身就只是做了一个清除路由守卫的功能,另外我刚刚有提到加载菜单,实际上路由守卫也时常被充当加载菜单的功能,比如这个站点:

这段代码实际上就存储了用户可访问的菜单和具备的权限,当进入后台后就会根据权限加载相对应的菜单。
那么说了这么多,读者也应该明白了开发为什么要实现动态加载路由,实际上就是为了进行权限分离,例如:
admin --> 管理权限 -----> /admin/role
user --> 普通权限 --x--> /admin/role
admin用户具备管理权限,所以能访问/admin/role,所以后台也会加载相对应的菜单供admin快速访问/admin/role,user用户不具备管理权限,所以进入后台后并不会动态加载相对应的菜单和路由,也就不会访问到/admin/role,这就是为什么开发要做成这样。
0x03 动态路由
通过上文我们知道,上述的两个vue相关信息收集插件都只能获取到已加载的全部路由,而未加载的就获取不到了,所以我们接下来要做的就是动态添加这些路由,我们来看一下官方文档:


路由器实例上的addRoute方法就是我们实现动态添加路由的核心方法,调用时在里面写上路由对象即可。我们现在尝试一下对本文最开始提到的那个案例进行动态添加路由:

ee是路由器实例,我们接下来调用它的addRoute方法实现动态添加:

在代码中我调用了路由器实例的addRoute方法,动态添加了Y_路由,也就是/dashboard:

现在我们保存js并访问一下/dashboard看看是否能访问成功:

可以看到此时就成功进入后台,也没有响应404,我们现在再看看Vue Crack或者vue devtools加载的路由都有什么:


可以看到现在就加载了那些未加载的路由,我们再添加一个看看:


注意我们只能一个一个添加,因为addRoute一次只能添加一个路由:

刷新访问/system:

成功访问,看一下插件内加载的路由:


成功加载了那些未加载的路由,现在我们就能正常进入这些路由了。
但是其实上述方案还是有缺陷的,我们现在退回到login页面,看看插件输出的路由都是什么:


我们可以看到,虽然我们在代码中进行了动态添加,但是插件依然获取不到我们新添加的路由,这其实是因为:

我让GPT替我们总结了一下:

所以说我们必须得访问一次新添加的路由,触发解析才能通过getRoutes方法获取到新添加的所有被解析的路由,这也是为什么我们在上文访问这些新添加的路由时会在插件中直接加载出这些路由。所以我说这种方案其实是有缺陷的,那么有没有更好的方案呢,答案是有的。
当我们在实例化路由器时是需要将我们要加载的路由传进去,例如:

所以我们为什么不直接在实例化路由器时就配置好所有路由?这样直接一劳永逸,毕竟我们是能直接修改js的,现在我们就来实操一下。可以看到实例化路由时传入的是d7,d7是一个数组,里面存放的就是一个个路由对象,现在我们将上述所说的那几个未添加的路由对象也放进去:


添加:

现在我们重新访问一下/login:


可以看到无论是在Vue Crack还是vue devtools都获取到了先前未加载的路由,尝试访问一个:

成功访问,也没有响应404,现在我们就成功的加载了这些本身未加载的路由。
那么问题来了:我们能否自动化完成以上操作?其实我比各位更加渴望能完全实现自动化添加路由,可惜我做不到,在这个过程中有很多限制,例如有些vue框架的站点是通过模块化导入的js,导致这些路由都只在局部作用域被声明,通过油猴注入是完全拿不到的,虽然我能拿到这些模块export出去的内容,但是我不敢保证所有站点都会将未加载的路由export出去,比如这个站点就不会,所以我在这里只提供给大家手动替换js实现动态添加路由的方案,自动化实现我做不到。
另外我再给大家讲一些别的内容,我之前有问过很多干前端开发的朋友,其实有部分站点会采用后端响应的方式进行动态添加,也就是用户请求接口,让后端返回要添加的路由path、component,然后前端去接受这些数组并自动拼接好进行动态添加,所以往往在真实的站点中想要真正的最大化获取Vue框架下的路由多多少少都得需要懂点代码,我在这里提供的方案只针对在代码中已经写死了的路由,包括未加载的路由,其他的解决方案我就不提了,每个开发每家公司写代码的风格都不同,列举不同的添加方式没什么意义,本文涉及到的这种情况还是占多数的。
0x04 跳转问题
很多朋友应该都有过这么一段经历:当直接进入某个路由后会被直接送回到/login页面,这其实就有可能调用了vue router提供的三个方法:

这三个方法都能将我们导航到不同的位置,我们这里不管该如何调用他们去实现跳转,我在这里只给大家讲一下如何清除。其实很简单,我们只要进入网页后第一时间获取到目标站点的router实例并hook掉这三个方法即可:

例如这是我在我的获取vue router脚本中的代码,当我获取到router实例后就第一时间hook掉这三个方法,这样就能绕过网站对我们进行的跳转,其实我对此也有过顾虑,如果网站在未加载完毕的时候就调用了上述跳转方法,此时可能脚本还没有完全注入到页面中,理论上还会造成跳转,所以可能也不是十全十美的,不过我目前也没有遇到这种情况,真正遇到了就可以考虑在代码中自行替换删除,例如:

我们直接在实例化路由器后的第一时间清除掉这三个方法,这样就不可能避免不了站点使用这三个方法跳转的问题:

如果清除后依然会跳转,可能是由于在代码中调用的不是vue router的跳转函数,此时可以考虑开启我的Antidebug_Breaker中的hook close或hook history脚本,再或者打开页面跳转JS代码定位通杀方案脚本,定位到跳转的函数并替换清除:

0x05 Router多实例问题
这个问题是我不得不讲的,因为这个会影响到我们获取vue router实例,例如下面这个站点就是一个比较好的案例:

各位可以看到我通过Vue Crack并不能有效获取到该站点的vue router,那么是否说明该站点没有使用vue router呢?答案是错误的,其实这是因为该站点挂载了两个vue实例,但是只有一个使用了vue router,而Vue Crack获取到一个vue实例时就会直接return停止扫描,比如上述站点就是一个很好的例子,这就导致另一个使用了vue router的vue实例不能被有效获取到。我在我的脚本当中优化了此类问题:

可以看到同一个站点,我的脚本成功获取到了vue router实例,这是因为当我的脚本获取到了一个vue实例时仍然会继续检测,防止页面中存在多个vue实例。那么一个站点能不能有多个router实例呢?我也好奇过这个问题,刚刚我讲过一个页面能有多个vue实例,那么这些实例每个都注册一个vue router不就有多个vue router实例了,下面是一个实例:


可以看到我将页面上的几个div都挂载成了vue应用,然后给他们每个都注册了vue router插件,现在用我的脚本获取一下看看是否能获取到:

可以看到确实获取成功了,这说明一个页面确实能有多个vue router实例。
0x06 我的插件
基于对以上问题的研究,我对我的Antidebug_Breaker插件进行了升级,增加了Vue板块:


切换实例:

可以看到,目前我的插件支持:获取路由、清除跳转、清除路由守卫、支持多router实例。但只有一个没涉及到:动态路由添加,其实还是上文说过的原因,我这里就不重新复述了。
插件地址:https://github.com/0xsdeo/AntiDebug_Breaker
0x07 白名单伪造杂谈
我曾经看到过很多文章用白名单伪造绕过路由守卫,例如:

在上文我也给大家看过JeeSite的动态路由的核心架构:

可以看到当用户访问的是白名单会直接放行,所以说白名单伪造还是有用的,比如这个站点:

可以看到f定义了一个数组,里面是四个路由,我用我的插件获取一下目标站点已加载的路由:

可以看到有一个/dashboard,这个路由就没在里面,说明那个数组大概率是一个白名单,现在我们直接访问是不行的:

会直接退回到/login,现在我们在这个白名单多增加一条路由/dashboard:

刷新访问:

成功访问,所以伪造白名单也确实是一个比较经典的绕过路由守卫的办法。
但是我依然需要提醒一下各位:一般白名单里存的都是一些访客也能访问的路由,也就是已加载的路由,那些未加载的路由可能不会放在这里,所以如果目标路由并没有加载上,伪造了也没什么用,所以说还是得考虑到站点是否加载了你想访问的路由。
0x08 总结
添加路由
由于有些站点为了实现权限分离,导致有些路由并没有被加载上,继而导致vue相关信息搜集插件获取的路由并不是很全,所以我们需要替换js加载这些未加载的路由,我提供了两种方案进行加载:
1.addRoute()2.在实例化路由器时就将想要加载的路由添加进传进去的路由表即可。
相较于第一种方案,第二种方案更为直接,第一种方案需要触发解析才能通过getRoutes方法获取到新添加的所有被解析的路由,所以就算添加了路由,插件也可能获取不到新添加的路由,而第二种方案就可以避免此类情况。
另外是关于能否自动化实现加载未加载的路由,由于限制太多,例如模块导入、后端响应加载等等,我这里做不到,所以我还是建议大家手动分析代码并替换js实现添加未加载的路由。
跳转问题
当我们未授权访问这些路由时,可能会直接退回到/login,这里我依旧是提供了三种方案避免跳转问题:
1.hook删除掉push、replace 和 go 三个可导航的方法。2.替换js删除。3.使用我的Antidebug_Breaker插件进行hook。
第二种方案更为直接,第一种方案有可能会由于脚本还未注入代码就已经执行到了跳转,不过我的脚本目前还没有遇到这样的情况。如果清除了依然会跳转,可能是由于在代码中调用的不是vue router的跳转函数,此时可以考虑第三种方案,也就是开启我的Antidebug_Breaker中的hook close或hook history脚本,再或者打开页面跳转JS代码定位通杀方案脚本,定位到跳转的函数并替换清除:

插件地址:https://github.com/0xsdeo/AntiDebug_Breaker
Router多实例问题
可能有些站点会存在Vue多实例或Router多实例的情况,所以我们在写脚本时尽量杜绝获取到一个实例就停止扫描获取。
白名单伪造
其实白名单伪造本质上绕过的是路由守卫,而如果目标路由未加载,绕过了也没多大用,大概率显示404,所以如果遇到了还是建议手动添加下未加载的路由。

















请登录后查看评论内容