Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 24 additions & 14 deletions src/pentesting-web/csrf-cross-site-request-forgery.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,28 +323,35 @@ The first part of [**this CTF writeup**](https://github.com/google/google-ctf/tr

Therefore, if a GET request is being limited, you could just **send a HEAD request that will be processed as a GET request**.<sup>[[9]](#references)</sup>

### Browser-to-localhost / local service CSRF
### Browser-to-localhost / internal service CSRF

Don't limit CSRF hunting to the target origin. Desktop agents, update daemons, browser helpers, wallet software, IDE/dev servers, and admin panels often expose HTTP APIs on `127.0.0.1`, `localhost`, `0.0.0.0`, or RFC1918 addresses and trust that **only the local user** can reach them.

Common weak points:
Classic CSRF normally abuses ambient credentials, but an **unauthenticated** loopback or internal API is still exploitable: the victim browser contributes its **network position** instead of a cookie. The Same-Origin Policy may prevent the attacker from reading the response, but it does not stop a CORS-safelisted request from reaching the service and triggering a side effect.<sup>[[16]](#references)[[17]](#references)[[18]](#references)</sup>

- permissive or substring-based `Origin` checks
- no CSRF token because loopback is assumed to be trusted
- JSON endpoints that also accept `text/plain` or other relaxed content types
- browser quirks or alternative loopback aliases that bypass local-network assumptions
During source review, correlate the following patterns across routes and server initialization rather than checking handlers in isolation:<sup>[[17]](#references)[[18]](#references)</sup>

Minimal probe:
- State-changing command, script, sequence, device-control, or administrative routes with no authentication, authorization, CSRF token, or strict `Origin` validation.
- Handlers accepting `application/x-www-form-urlencoded`, `multipart/form-data`, or `text/plain`; browsers can submit these CORS-safelisted content types without an `OPTIONS` preflight when the other simple-request constraints are met.
- Request fields flowing directly into command buses, interpreters, script runners, or subprocess arguments. Distinguish an application command dispatcher from arbitrary shell execution and report only the operations its configured command set exposes.
- Listener configuration that is read but never reaches the final server/socket constructor. Confirm the effective exposure at runtime (for example, with `ss -lntp`) because a hardcoded `0.0.0.0` bind defeats an intended loopback-only setting.

```javascript
fetch("http://127.0.0.1:53000/asus/v1.0/Reboot", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ Event: [{ Cmd: "Reboot" }] })
})
Use an auto-submitting form for a **blind**, preflight-free probe and choose a harmless action whose side effect can be confirmed in service or audit logs:<sup>[[16]](#references)[[17]](#references)</sup>

```html
<iframe name="sink" hidden></iframe>
<form id="f" action="http://127.0.0.1:PORT/SENSITIVE_ROUTE"
method="POST" target="sink">
<input type="hidden" name="PARAMETER" value="HARMLESS_ACTION">
</form>
<script>document.getElementById("f").submit()</script>
```

For a real-world case study, check [this other page about browser-to-localhost abuse](../windows-hardening/windows-local-privilege-escalation/abusing-auto-updaters-and-ipc.md).
Do not assume that preflight-free means universally deliverable. Supporting browsers can gate public-to-local and public-to-loopback requests behind **Local Network Access** permissions (including form submissions and subframe navigation), and enterprise policy or an earlier permission decision can change the result. Test the exact victim browser and policy state.<sup>[[19]](#references)</sup>

Validate the primitive with a real or headless browser: record requests to the target origin, assert that the `POST` arrives, count any `OPTIONS` requests, and verify the harmless server-side effect independently. A successful action does not require response access, and direct network isolation is insufficient when an operator's browser can route to the service.<sup>[[17]](#references)[[18]](#references)</sup>

For another real-world case study, check [this page about browser-to-localhost abuse](../windows-hardening/windows-local-privilege-escalation/abusing-auto-updaters-and-ipc.md).

## **Exploit Examples**

Expand Down Expand Up @@ -885,5 +892,8 @@ Use purpose-built tooling and hands-on labs to validate PoCs without losing brow
- [14] [brycec - corCTF 2021 challenges writeup](https://brycec.me/posts/corctf_2021_challenges)
- [15] [anonymousyogi - JSON CSRF: CSRF that none talks about](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937)
- [16] [MDN - HTTP - CORS: Simple Requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests)
- [17] [NASA-AMMOS AIT-GUI security advisory GHSA-p9r8-2q67-fp86](https://github.com/NASA-AMMOS/AIT-GUI/security/advisories/GHSA-p9r8-2q67-fp86)
- [18] [Cycode - Unauthenticated command execution in AIT-GUI](https://cycode.com/blog/ait-gui-unauthenticated-command-execution/)
- [19] [Chrome for Developers - New permission prompt for Local Network Access](https://developer.chrome.com/blog/local-network-access)

{{#include ../banners/hacktricks-training.md}}