CORS跨域资源共享攻击

admin 2023年11月9日09:26:14CORS跨域资源共享攻击已关闭评论0 views字数 4811阅读16分2秒阅读模式

前置知识

跨域

域(Domain)是由三部分组成的标识:协议、域名和端口。

例如这两个ip就属于不同的域:

因为它们的协议不同(一个是HTTP,另一个是HTTPS),并且它们的端口也有差异(HTTP默认端口为80,HTTPS默认端口为443)。因此,这两个域之间的请求被认为是跨域请求。

而没有限制的跨域请求,就会有很多的弊端,例如导致CSRF等。为了解决这个问题于是引入了同源策略这个概念。

同源策略

同源策略(Same-Origin Policy)是浏览器的一项安全措施,它限制了网页中的脚本只能与加载该脚本的页面具有相同的协议域名端口,才能进行无障碍的跨域资源访问。同源策略的目的是保护用户的信息和隐私,防止恶意网站利用浏览器漏洞获取或修改其他网站的数据。

例如下表中与`http://example.com/api/v1/index.html 属于相同来源的是:

| URL | 结果 | 原因 |
| :----------------------------------------------- | :----: | :---------------: |
| http://example.com/api/v1/login.html | 是 | 只有路径不相同 |
| http://user:[email protected]/api/v1/other.html | 是 | 只有路径不相同 |
| https://example.com/api/v1/index.html | 否 | 不同协议(https) |
| http://example.com:81/api/v1/index.html | 否 | 不同域名 |
| http://test.example.com/api/v1/index.html | 否 | 不同端口 |

有一些标签是不受同源策略限制的,这些标签可以自由地加载和显示来自其他域的内容,而无需进行跨域请求。

  • script:\<script src="http://example.com/script.js">\</script>
  • img:\<img src="http://example.com/image.jpg" alt="Image">
  • iframe:\<iframe src="http://example.com">\</iframe>
  • link:\<link rel="stylesheet" href="http://example.com/styles.css">

有了同源策略可以较有效的防止CSRF和XSS等漏洞,但同时也带来了一个弊端:同协议、同域名、同端口使得跨域资源共享变得更为复杂困难。这时就需要引入CORS(跨域资源共享)来处理这个问题。

CORS

定义

CORS(跨域资源共享)是一种用于在Web浏览器中处理跨域请求的机制。当在浏览器上执行JavaScript代码时,由于同源策略的限制,脚本只能与同源(相同协议、域名和端口)的服务器进行通信。但在某些情况下,我们可能需要从一个域向另一个域请求数据或资源,这就涉及到跨域请求。

工作原理

CORS允许服务器定义哪些外部域有权限访问其资源。当浏览器发起跨域请求时,它会首先发送一个预检请求(OPTIONS请求),询问服务器是否允许实际请求。服务器通过返回特定的HTTP响应头来控制跨域访问,其中最重要的是"Access-Control-Allow-Origin"头,指定允许访问的域。如果服务器响应中包含了请求的源域,那么浏览器会允许实际的跨域请求并接收响应。

除"Access-Control-Allow-Origin"外,还有其他的CORS头可以用来进一步定义跨域请求的行为,例如:.

  • Access-Control-Allow-Credentials:是否允许浏览器读取response的内容
  • Access-Control-Allow-Methods:指定允许的HTTP方法(GET、POST等)。
  • Access-Control-Allow-Headers:指定允许的请求头。
  • Access-Control-Max-Age:指定预检请求的有效期。

CORS漏洞

漏洞原理

CORS跨域漏洞的本质是服务器配置不当,即Access-Control-Allow-Origin设置为*或是直接取自请求头Origin字段,Access-Control-Allow-Credentials设置为true等。

测试环境

firefox 59.0:Directory Listing: /pub/firefox/releases/59.0/ (mozilla.org)

tomcat 8.5

靶机:192.168.235.166

攻击机:192.168.43.136

漏洞测试

先设置一个登录框,和一个信息查询页面,模拟用户登录和获取个人信息

LoginServlet

```
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "login", value = "/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (req.getParameter("user") != null){
if (req.getParameter("user").equals("admin")){
Cookie cookie = new Cookie("user", "admin");
resp.addCookie(cookie);
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().print("Sentiment登陆成功! ");
}
}else {
resp.getWriter().print("登录失败");
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    super.doPost(req, resp);
}

}
```

PersonInfoServlet

```
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "personinfo", value = "/info")
public class PersonInfoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies = req.getCookies();
resp.setContentType("text/html;charset=UTF-8");

    String origin = req.getHeader("origin");
    if (origin != null){
        resp.setHeader("Access-Control-Allow-Origin",origin);
        resp.setHeader("Access-Control-Allow-Credentials","true");
    }

    if (cookies != null){
        for (Cookie cookie : cookies) {
            String name = cookie.getName();
            String value = cookie.getValue();
            if (name.equals("user") && value.equals("admin")){
                resp.getWriter().print("你好Sentiment,你的密码是123456");
            }
        }
    }else {
        resp.getWriter().print("未登录");
    }
}

}
```

第一种情况

可能导致漏洞的环境有多种方式,先看下这种:

Access-Control-Allow-Origin: all-host
Access-Control-Allow-Credentials: true
//对应配置
resp.setHeader("Access-Control-Allow-Origin",origin);
resp.setHeader("Access-Control-Allow-Credentials","true");

这两个返回头表示应用程序允许来自任何Origin的任何脚本向应用程序发出CORS请求。

先模拟用户登录

CORS跨域资源共享攻击

此时用户访问/info,便能看到自己的信息

CORS跨域资源共享攻击

这时我们构造恶意脚本,发送给该用户

attack.html

```
<!DOCTYPE html>


CORS POC Exploit

Extract SID





```

当用户点击后,便可跨域请求用户端的info信息,并且带上了用户的cookie

CORS跨域资源共享攻击

第二种情况

服务器返回如下消息头,这种情况下,利用起来稍有困难,这里的null必须小写。

Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
//对应配置
resp.setHeader("Access-Control-Allow-Origin","null");
resp.setHeader("Access-Control-Allow-Credentials","true");

这时再请求attack.html,发现被拦截

CORS跨域资源共享攻击

这是由于发送的请求origin并不为null

CORS跨域资源共享攻击

此时修改attack.html

```
<!DOCTYPE html>


CORS POC Exploit

Extract SID