原文:https://brutelogic.com.br/blog/advanced-javascript-injections/

简单的JavaScript注入技术,如'-alert(1)-'甚至\’-alert(1)//(请参见此处的案例#6和案例#7),只要脚本块内触发输入反射(input reflection),通常无需借助HTML注入攻击,就能引发易受攻击页面弹出警报框(具体请参见上面同一篇文章中的案例#5)。

但是在某些情况下,注入点可能会位于更加复杂的JS代码的中间,即在函数和条件语句内部(if或if+else),并且,它们还经常会嵌套在一起。

下面,我们将通过一个具体的示例,来讲解如何利用这种类型的漏洞。实际上,@gustavorobertux提供过一个现实中的漏洞,跟这里介绍的简直如出一辙。

https://brutelogic.com.br/tests/jsfix.php?keyword=xss

我们发现,借助于用户交互的情况下,这很容易做到,但是如果您不熟悉JS语言的话,事情可能会变得比较复杂。

因此,我们有以下几点思考。首先,它位于一些JS代码(keyword=aaaaa)的中间。

所以,我们可以尝试进行简单的JS注入,不过,双引号之前反斜杠将被转义。

Payload: -confirm`1`-

正如我们从Main XSS Cases (案例#_7)中所了解到的那样,下一个技巧就是在第一个引号之前添加一个反斜杠来“实现对转义的转义”。此外,我们还需要对其余的代码行进行注释。

Payload: \”-confirm`1`//

如果我们改变(通过用户交互)页面上的select元素,这种方法就能奏效。

但是,为了达到这个目的,我们还有一种更好的方法,因为这种“功能”并非在所有情况下都是可用的,并且,它还需要用户进行交互。

我们的计划如下:“括住”所有嵌套的函数/条件,然后插入我们自己的代码

confirm`1`

然后,我们必须修复剩余代码中的语法问题,才能运行我们的payload,因为只要存在任何语法错误,整个脚本块都无法正常运行。

为此,我们可以首先尝试\”}})}),这是我们代码段的最后三行(不需要分号),用来括住“if”语句、“on+change”函数和“document.ready”函数。其余部分与之前的尝试相同。

Payload: \”}})})-confirm`1`//

当然,它肯定无法奏效,因为我们的payload的构造工作只完成了一半(并且是最简单的部分)。但是,JS控制台(浏览器的Developer Tools——按F12键 )返回的错误消息,能够指导我们完成后面的任务。

通过点击消息右侧的链接,我们就能找到问题之所在。

问题出现在“else”语句中,因为它不应该出现在那里。我们已经括住了if语句和2个函数,所以,我们需要去掉它。

就这里来说,我们需要处理双重反射,因此,我们将尝试通过在第一个反射中打开一个注释,在第二个反射中关闭它,从而将它们组合在一起,使它们变成一个。这足以“干掉”这两个反射之间的代码,即在“else”行加上“document.location”属性。

对于JS来说,多行注释使用的是//,因此,只要在payload的末尾加上一个//就可以完成这项任务(在第一个反射中被解析为/,在第二个反射中被解析为*/ )。

Payload: \”}})})-confirm`1`/*/

让我们考察一下这个错误消息可能意味着什么。

正如我们所看到的,第一个反射的结尾到第二个反射的结尾之间的内容现在是以绿色显示的,表示被注释掉了。因此,这里

confirm`1`

之后被执行的代码,为&pageIndex=1&startFrom=0,其中&被解释为进行逐位AND运算,而后面的变量赋值操作是无效的( PageIndex = 1 )。

解决这个问题的方法并不复杂,只需在我们当前payload的末尾添加//来注释掉该行的其余部分即可,具体如下所示(添加了一个分号) :

Payload: \”}})})-confirm`1`;/*///

现在正如预期的那样,在注入分号之后,“if”语句的结尾处到“}”之间的代码都被注释掉了。因此,让我们在payload的后面、注释符之前添加一个“{”。

Payload: \”}})})-confirm`1`;{/*///

现在,解析器将跳到下一行,并报错!

为了解决这个问题,需要继续尝试修复被挂起的“})”,方法是在“{”之前添加“({”,以符合语法顺序。

Payload: \”}})})-confirm`1`;({{/*///

发生了什么事?由于新添加了 "({", 现在我们的第一个 "{" 失去了它作为 "if" 语句的 "修复码" 所具有的效果。为解决这个问题, 我们只需在 "({" 和 "{" 之间添加一个 "if ()"即可。

Payload: \”}})})-confirm`1`;({if(){/*///

太好了,现在我们进入最后一行了!这里,我们只需重复上一步所做的工作,在分号之后、“({if(){”之前添加另一个“({”即可。

Payload: \”}})})-confirm`1`;({({if(){/*///

这次,我们又搞砸了什么?实际上,我们以前见过这种情况,我们只是将以前的“修复”工作搞砸了。为了修复这个新问题,在前面添加的“(”和“{”之间加入一个“function()”即可。

Payload: \”}})})-confirm`1`;(function(){({if(){/*///

太棒了,我们成功了!

现在,我们将精简payload。

为此,我们可以删除分号(这样的话,会导致解析器抛出“uncaught error”消息,但仍然能够执行),并将“if()”替换为标签“b:”,同时,将“function()”替换为箭头函数选项“a=>”。其中,“a”和“b”两个名字都是完全任意的。

最终的 Payload: \”}})})-confirm`1`(a=>{({b:{/*///

完整的JS代码块如上所示,至此,我们就大功告成了。

源链接

Hacking more

...