7

不带括号调用 JavaScript 函数的第七种方式

 1 year ago
source link: https://blog.p2hp.com/archives/10272
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

不带括号调用 JavaScript 函数的第七种方式

  • 更新时间: UTC 时间 2022 年 9 月 18 日 17:20
具有渐变背景的 JavaScript 代码

我以为我知道所有不带括号调用函数的方法:

alert`1337`
throw onerror=alert,1337
Function`x${'alertx281337x29'}x```
'alertx281337x29'instanceof{[Symbol['hasInstance']]:eval}
valueOf=alert;window ''
x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript' ':' x
// or any DOMXSS sink such as location=name

在这篇文章中,我将向您展示另一种令人惊讶的方式,并帮助您了解标记模板字符串的工作原理。本文中的技术不会直接启用漏洞利用,但它们可用于加深对 JavaScript 语言的理解,为规避 JavaScript 沙箱和 WAF 奠定基础。这一切都始于我关于执行不带括号的非字母数字 JavaScript 的帖子。我发现您可以将字符串传递给标记模板,标记模板仅意味着使用在模板字符串文字之前添加前缀的函数。例如alert`123`,有一个标记模板调用了alert带有 123 的函数。我在上一篇文章中的认识是,您可以仅使用字符串将多个参数传递给这些函数,如下面的代码所示:

function x(){
alert(arguments[0]);
alert(arguments[1]);
}
x`x${'ale' 'rt(1)'}x`

这里发生的是所有字符串都作为数组添加到第一个参数中,第二个参数获取字符串alert(1)但是等等为什么字符串alert(1)作为第二个参数传递给函数?好吧,字符串与占位符的处理方式不同,没有占位符的普通字符串将作为数组添加到第一个参数,而占位符将作为新参数添加到它们的类型中。最后一点很重要,当时我没有意识到占位符是作为参数添加的,其类型不是字符串!以下代码演示了这一点:

function x(){
alert(arguments[0]);
arguments[1]('hello')
}
function y(str){
alert(str);
}
x`x${y}x`

太棒了,这是很酷的行为,这意味着我们可以调用函数并传递任何类型的多个参数。但是我们有一个问题,当在标记模板中使用字符串时,它们总是被添加为第一个参数,从而破坏了使用第一个参数的函数。我们的目标是使用我们选择的参数调用函数。例如,我们可能想要调用setTimeout,因为第一个参数接受一个函数或一个字符串,而第三个参数使用该值调用该函数:

setTimeout(alert, 0, 'I get passed to alert')

让我们尝试调用setTimeout

setTimeout`${alert}${0}${1}`//Uncaught SyntaxError: Unexpected token ','

我们可以再次使用自定义函数来查看发生了什么:

function x(){
console.log(arguments);
}
x`${alert}${0}${1}`

显示发送到函数的参数的控制台屏幕截图

所以我们可以看到第一个参数包含一个空白字符串数组,最后的另一个数组也充满了空白字符串。当setTimeout将这些数组转换为字符串时,我们会得到一堆逗号,这会导致语法错误。不知何故我们需要setTimeout函数忽略第一个参数,你是怎么做到的?好吧,你可以使用setTimeout.call,因为第一个参数将是分配给函数“this”的数组setTimeout,现在 alert 将作为第一个参数传递给函数但是......

setTimeout.call`${alert}${0}${1}`//Illegal invocation

该死的,因为你不再直接调用该函数,JavaScript 将抛出一个异常阻止你调用该函数,因为“this”不再是一个窗口对象。我以为游戏结束了,然后我意识到过去我[].sort和其他人做过一些 JS 黑客攻击。它们允许您调用函数而不会出现非法调用错误:

[].sort.call`${alert}1337`

您当然可以使用其他函数,例如eval和其他数组方法,例如map

[].map.call`${eval}\u{61}lertx281337x29`

后来我发现你Reflect也可以使用:

显示一些使用 Reflect.apply 调用导航函数的代码

上面使用了navigation.navigateChrome 中的新方法来使用来自window.name. 为了调用navigate您需要向函数提供正确的“thisObject”,这是在Reflect.apply. 在第三个参数中使用,它window.name必须是发送到函数的参数数组。使用Reflect方法 set 和 apply 你可以分配给几乎任何对象或调用任何函数!请注意,我使用“window.name”来隐藏有效载荷,通常有效载荷将来自另一个页面或域,方法是将其传递到跨域传递的 window 的“name”属性中。

令人惊讶的是,模板字符串支持这种行为并且浏览器允许您以这种方式使用排序和其他功能。通过破解 JavaScript,您可以学习滥用 JavaScript 功能以产生意想不到的结果的新的有趣方法。

我希望并期待看到有人找到第 8 种不带括号的 JavaScript 执行方式!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK