高级CORS漏洞利用技巧

前言

我之前看过linussarudbo9om对于Safari未能正确处理特殊字符的利用的研究:

https://labs.detectify.com/2018/04/04/host-headers-safari/ 

https://lab.wallarm.com/the-good-the-bad-and-the-ugly-of-safari-in-client-side-attacks-56d0cb61275a

上述文章深入的剖析了safari在某些特殊的情况下会导致xss或者是cookie注入。希望本文能在这方面带给大家更多的思考和创造的空间。

 

简介

去年11月份,我写了一篇文章关于如何利用safari未能正确处理特殊字符实现绕过yahoo view同源配置。接下来的一段时间,我发现了有更多的技巧去绕过这些配置策略,在此我决定公开一些我使用的技巧。

在此假设你对于cors有些基础的了解,知道怎么去利用这些错误的配置。这里有一些文档你可以去了解相关知识:

http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html

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

 

背景知识:dns和浏览器

简介

域名系统就像是一个服务器的地址目录,它实现域名和ip之间的转换,使得互联网使用起来更方便。

当你尝试通过浏览器访问一个url时,dns完成了一次地址转换—>初始化一个tcp链接—->服务器响应syn+ack—->浏览器发送http请求—->渲染响应内容。

DNS服务器会响应任意请求,这样你可以在子域名发送任意字符,只要有响应的dns记录就会响应。

例如:dig A “<@$&(#+_`^%~>.withgoogle.com” @1.1.1.1 | grep -A 1 “ANSWER SECTION”

浏览器

我们已经知道dns服务器会响应这些请求,那么浏览器会怎么处理呢?大部分浏览器在发出请求之前会校验域名的有效性,例如:

Chrome

Firefox

Safari

注意我说的是大部分浏览器会校验域名的有效性,而不是全部,safari就是个例,它并不会校验域名的有效性,而是直接发送请求:我们可以使用不同字符的任意组合,甚至是不可打印字符:

,&'”;!$^*()+=`~-_=|{}%

// non printable chars

%01-08,%0b,%0c,%0e,%0f,%10-%1f,%7f

 

深入cors配置

大部分cors配置都会包括一个可访问的白名单信息,这个白名单通常用正则表达式来实现。

例如1^https?://(.*.)?xxe.sh$

目的:匹配到来自xxe.sh和任何子域名的访问

攻击者要想从这里获取数据就必须有一个相关域的xss漏洞。

例如2^https?://.*.?xxe.sh$

目的:和例1一样,匹配来自xxe.sh和任何子域的请求,但这个正则有个问题,会造成漏洞,问题存在于:.*.?

由于.*.并不是整体,?只对.之后的符号有影响,因此xxe.sh之前可以有任意字符。这也意味着攻击者可以发送任意以xxe.sh结尾的请求,实现跨域。这是一个非常普通的绕过技术,这里有一个相关案例:https://hackerone.com/reports/168574

例如1^https?://(.*.)?xxe.sh:?.*

目的:匹配到来自xxe.sh和任何子域名的访问

你能发现问题吗?

和第二个例子一样,?仅仅影响:。因此只要我们在xxe.sh后加上任意字符都能被接受。

 

关键性问题

怎么利用safari对于特殊字符的不当处理,实现对cors配置不当漏洞的利用呢?

假设以下是apache的配置文件:   目的也是为了接受xxe.sh和子域的访问。

这个案例并不像先前的几个例子能够通过一样的技巧绕过,除非有一个子域的xss,但让我们再思考一下。

我们知道在xxe.sh后的任意字符(. – a-z A-Z 0-9)都不会被信任,那如果是一个空格呢?

可以看到我们成功了,但这样一个域名任何浏览器都不会支持。

由于正则表达式仅仅匹配ascii字符还有. –,那任何特殊字符都是可以被接受的。

这样的域名就能被safari浏览器支持了。

 

漏洞利用

事先准备:1.dns记录指向你的主机 2.nodejs

和大多数浏览器一样,Apachenginx也不支持特殊字符,因此用nodejs实现比较容易。

Serve.js  

同一目录下的cors.html:

通过nodejs执行如下命令:node serve.js &

和之前描述的一样,由于正则匹配的是ascii. –,在xxe.sh后的特殊字符是被信任的。如果我们打开safari,访问http://x.xxe.sh{.<your-domain>/cors-poc,我们可以看到成功的获取到了数据:

令我注意的是不仅仅safari支持_chromefirefox也支持因此http://x.xxe.sh_.<your-domain>/cors-poc能被大多数浏览器支持。

 

实践

当记住这些特殊字符后,找出哪些域名会受影响就只是时间问题了。为了节约时间,我写了一个fuzz,用来找出这些问题,这个fuzz可以在我的github上找到—— https://github.com/sxcurity/theftfuzzer

审核人:yiwang   编辑:边边

(完)