实用JSONP注入

2020-03-28  本文已影响0人  z0f4k

  这篇文章是翻译文章,看着比较基础,主要是入门了解,手翻加机翻,如有问题,那也只能凑合着看了,或是看原文: Practical JSONP Injection


JSONP注入是一个鲜为人知但相当普遍且危险的漏洞,由于JSON的采用率很高,Web API以及对跨域通信的迫切需求,它在最近几年浮出水面。

什么是JSONP?

假设每个人都知道JSON是什么,那么让我们来谈谈JSONP。 JSONP是填充的JSON,它的创建是为了绕过常见限制,例如对XMLHttpRequest(AJAX请求)强制实施的同源策略。(注:JSONP可以看文章: JSONP 教程)

举例说明,比如在线银行应用 http://verysecurebank.ro, 有个实现返回当前用户交易信息的API接口。

发送到http://verysecurebank.ro/getAccountTransactions的HTTP请求向我们展示了JSON格式的交易:(下图)

json-transactions.png

如果我们的报告应用程序(可从http://reports.verysecurebank.ro访问)希望获取交易详细信息,则由于同源策略(不同的目标主机),则无法使用AJAX的方式调用该请求。(下图:)

sop-json.png

为了解决这个问题,JSONP开始发挥作用。由于允许跨域脚本包含(通常用于外部加载jQuery,AngularJS等JavaScript库),但不建议这样做,因此,一个巧妙的技巧显然解决了整个问题:在响应之前加上回调

注意:即使很明显,也值得一提的是,当跨域包含脚本时,脚本是运行在当前的页面中,而不是请求的页面中。(注:如果不明白这个点,可以看上面给的JSONP教程中例子)

向返回JSON数据格式的API中增加一个回调处理,可以使我们在脚本标签之间加载API响应,并通过定义自己的回调函数来处理其内容。

利用

以下是你能碰到的从常见情况:

  1. 回调函数是在响应数据中硬编码

    1. 基本函数调用
    2. 对象方法调用
  2. 回调函数是动态设定的

    1. 可以通过URL(GET方法参数)进行完全控制
    2. 可从通过URL(GET方法参数)部分控制,但需要附加一个数字
    3. 可通过URL(GET方法参数)控制,但最初未显示在请求中

基本函数调用

一个非常常见的示例,其中myCallback回调在响应中进行了硬编码,并以JSON格式的数据包装:

callback-example.png

我们可以通过先定义myCallback函数,然后在脚本标签内引用API调用来轻松利用此功能:

callback-example-code.png

注意:请确保在包含响应之前定义函数,否则将调用未定义的函数,并且不会获取任何数据。 当登录的受害者访问我们的恶意页面时,我们将获取他的数据。为了简洁起见,我们在当前页面中以整齐的格式显示数据。

callback-example-result.png

对象方法调用

我们只需为TransactionData对象创建Fetch方法,该对象已经是System对象的一部分。

multiple-callback-code.png

注:System为自定义的东西,这个不需要关注这个问题

上面的结果类似的,这里就不截图了。

可以通过URL(GET方法参数)进行完全控制

这是您会遇到的最常见的情况。回调函数在URL中指定,我们可以完全控制它。 callback URL参数允许我们更改回调的名称,因此我们将其设置为testing并在响应中看到它已更改:

specified-callback-example.png

我们基本上可以使用相同的利用代码,只是在包含带有脚本标签的响应时不要忘记添加回调参数。

specified-callback-code.png

可从通过URL(GET方法参数)部分控制,但需要附加一个数字

在这种情况下,回调函数名称后面会附加一些东西,通常是一个数字。在大多数情况下,我们会得到类似jQuery的内容,并在其后附加一个短数字,例如12345,回调将变成jQuery12345。

appended-callback-code.png

逻辑上,漏洞利用代码保持不变,我们只需要在回调函数名称中添加12345,而在添加脚本时则无需添加。

appended-callback-code.png

但是,如果数字不是硬编码的怎么办?如果每次会话都是动态的且不同的怎么办?如果数量相对较少,我们可以通过编程方式为每种可能性预定义功能。假设附加数字最多为99999。我们可以以编程方式创建所有这些函数,因此无论附加什么数字,我们都已经有一个回调函数。这是示例代码,我使用了一个更简单的回调来说明结果:

appended-callback-code-generate.png

这里发生了什么:我们硬编码的回调名称jQuery,我们为函数数量设置了限制。在第一个循环中,我们生成callbackName回调函数名称数组。然后,我们遍历数组并将每个回调名称转换为全局函数。请注意,为了缩短代码,我仅提醒第一笔交易中发送的金额。让我们看看它是如何工作的:

appended-callback-alert.png

在我的机器上,花了大约5秒钟来显示警报,回调名称为jQuery12345。这意味着Chrome在不到5秒的时间内创建了10000个函数,因此,我要大胆地说这是一个可行的利用方法。

可通过URL(GET方法参数)控制,但最初未显示在请求中

最后一种情况涉及一个没有回调的API调用,因此没有可见的JSONP。当开发人员与其他软件保持“隐藏”的向后兼容性,或者重构时根本没有删除代码时,可能会发生这种情况。因此,当看到没有回调的API调用时,尤其是如果JSON格式的数据已经在括号之间时,请手动将回调添加到请求中。

如果我们具有以下API调用http://verysecurebank.ro/getAccountTransactions,我们可能会尝试猜测回调变量:

这里列举了一些常用的回调名称,你可以随意地猜其他回调名称。如果请求返回中出现我们的回调内容,那说明已经成功了,可以获取一些重要的数据了。

基本数据抓取

由于我们到目前为止仅显示数据,因此让我们看看如何将其发送回给我们。这是获取JSONP数据的最小示例,可以用作概念证明。

steal-code.png

我们使用data参数中的应用程序响应(事务)向数据采集器发出GET请求。

注意:请确保您在数据上使用JSON.stringify(),因为它是对象,并且我们不想在文件中只包含[object Object]。

注意:如果响应数据很大,请确保切换到POST,因为HTTP GET大小限制可能无法接收到完整的数据。

这是我们的grabData.php代码,我们将接收到的数据添加到data.txt文件中:

steal-php.png

常见问题

在寻找JSONP漏洞的Web应用程序时,我们可能会遇到一些问题。在这里,我们尝试解决它们。

Content-Type and X-Content-Type-Options

如果在API请求的响应标头中,X-Content-Type-Options设置为nosniff,则Content-Type必须设置为JavaScript(文本/ javascript,应用程序/ javascript,文本/ ecmascript等)才能正常工作所有浏览器。发生这种情况是因为通过在响应中包含回调,响应不再是JSON,而是JavaScript。

(注:X-Content-Type-Options)

如果您想知道浏览器将哪种内容类型解释为JavaScript,请将您的浏览器指向https://mathiasbynens.be/demo/javascript-mime-type

content-type-error.png

最新版本的Google Chrome,Microsoft Edge和Internet Explorer 11成功阻止了脚本执行。但是,Firefox 50.1.0(当前为最新版本)没有。

注意:如果未设置X-Content-Type-Options:nosniff标头,则它将在所有上述浏览器上运行。

注意:由于最近已实现X-Content-Type-Options,因此较旧版本的浏览器未考虑严格的MIME类型检查。根据Mozilla的说法,这是浏览器的兼容性:

browser-compatibility.png

响应编码

有时我们可能会得到200以外的其他响应代码,尤其是因为我们弄乱了响应。我在这些浏览器上进行了一些测试:

发现这些不一致之处:

Response Code Works in
100 Continue Internet Explorer, Microsoft Edge, Google Chrome
101 Switching Protocols Google Chrome
301 Moved Permanently Google Chrome
302 Found Google Chrome
304 Not Modified Microsoft Edge

因此,即使我们没有获得200 HTTP代码,该漏洞仍可在其他浏览器中利用。

Referrer头检查绕过

  1. 使用数据URI方案(Data URI scheme)

如果有HTTP Referer检查,我们可以尝试不发送它以绕过验证。我们该怎么做?数据URI简介。 我们可以滥用数据URI方案,以便在没有HTTP Referer的情况下发出请求。由于我们要处理的代码包括引号,双引号和其他语法破坏字符,因此我们将对base64编码有效负载(回调定义和脚本包含)。

使用语法:data:text/plain;base64,our_base64_encoded_code

iframe-src.png

以下是三个主要的HTML标记,这些标记允许我们使用数据URI方案:

我们可以看到没有Http Referrer头的请求发送到API。


referer-browser.png
  1. 从Https到Http的请求

如果可以通过HTTP访问目标网站,我们还可以通过将代码托管在HTTPS页面上来避免发送HTTP引用。如果我们从HTTPS页面发出HTTP请求,则指示浏览器不要发送Referer标头,以防止信息泄漏。 我们要做的就是将恶意代码托管在启用HTTPS的网站上。(注:在https页面给http发送请求不发送Referrer头的问题是老版本浏览器问题)

注意:由于采用了混合内容安全机制,因此在具有默认设置的现代Web浏览器中无法使用此功能。受害者需要手动接受浏览器的安全警告。

mixed-content.png

上面只能运行在旧版本的浏览器中,没有Http Referrer头的请求被发送,我们能看到:

https-to-http.png

怎么修复这个问题?(JSONP注入)

最后,我们看看如何防止这种情况发生呢,最现代的方式是CORS(跨站资源共享)

1. 完全移除JSONP功能
2. 添加 Access-Control-Allow-Origin 头信息在你的API响应中
3. 使用跨域AJAX请求

在页面http://reports.verysecurebank.ro 中嵌入发送到http://verysecurebank.ro/getAccountTransactions跨域AJAX请求:

ajax-request-code.png

这个API响应中包含 Access-Control-Allow-Origin: http://reports.verysecurebank.ro 头信息:

ajax-request-headers.png

我们能得到从 http://verysecurebank.ro/getAccountTransactions返回的内容:

ajax-request-content.png

结论

尽管JSONP的使用率在下降,但是仍有大量网站仍在使用或支持JSONP。最后一点,在处理JSONP时,请不要忘记检查Reflected File Download和Reflected Cross-Site Scripting漏洞。

上一篇下一篇

猜你喜欢

热点阅读