Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

뭉크테크

Web cache poisening attack(Using multiple headers) 본문

CERT

Web cache poisening attack(Using multiple headers)

뭉크테크 2025. 4. 5. 21:06

웹 캐시 포이즈닝이란?

웹 캐시는 웹사이트가 자주 사용하는 데이터를 저장해서 같은 요청이 들어오면 빠르게 응답할 수 있게 해준다. 예를 들어, innocent-site.com이라는 사이트에 접속하면 그 페이지 내용이 캐시에 저장돼서 다음에 접속할 때 로딩이 빨라지는 식이다.
하지만 공격자가 이 캐시를 조작하면, 사용자가 정상적인 사이트에 접속했는데도 악의적인 내용(예: 가짜 로그인 페이지나 악성 코드)이 담긴 응답을 받게 될 수 있다.


기본적인 공격: 한 가지 헤더 조작

먼저 간단한 경우를 보죠. 웹사이트가 HTTPS(보안 프로토콜)를 강제로 사용하게 설정되어 있다고 해볼게요. 사용자가 실수로 http://innocent-site.com/random에 접속하면, 사이트는 "여긴 보안이 안 되니까 HTTPS로 이동해!"라며 아래처럼 응답한다.

 
HTTP/1.1 301 Moved Permanently Location: https://innocent-site.com/random

이제 공격자가 X-Forwarded-Proto라는 헤더를 조작해서 요청을 보내면, 사이트는 이 요청을 보고 "아, HTTP로 온 요청이네. HTTPS로 리디렉션해야지!"라고 판단한다.

 

예를 들어:

 
  • GET /random HTTP/1.1 Host: innocent-site.com X-Forwarded-Proto: http

 

응답은 똑같이:

 

 

이 응답이 캐시에 저장되면, 이후 다른 사용자가 http://innocent-site.com/random에 접속할 때 캐시된 이 리디렉션 응답을 받게 된다. 여기까진 문제가 없어 보인다. 하지만 이 기본 동작에 다른 취약점이 결합되면 이야기가 달라진다.


여러 헤더를 조작한 정교한 공격

공격자가 더 악랄해져서 두 개 이상의 헤더를 조작하면, 캐시된 응답을 악의적인 URL로 바꿀 수 있다. 예를 들어, X-Forwarded-HostX-Forwarded-Proto를 함께 조작하는 경우를 보도록 하자.

공격자가 이런 요청을 보낸다고 가정하자:

 
GET /random HTTP/1.1 Host: innocent-site.com X-Forwarded-Proto: http X-Forwarded-Host: malicious-site.com
  • X-Forwarded-Proto: http: "이 요청은 HTTP로 왔어요"라고 속이는 헤더예요. 사이트는 HTTPS로 리디렉션하려고 준비하죠.
  • X-Forwarded-Host: malicious-site.com: "이 요청은 malicious-site.com을 대상으로 한 거예요"라고 속이는 헤더예요. 사이트가 이 값을 믿고 리디렉션 URL을 만들 때 사용하면 큰일 나죠.

웹사이트가 이 헤더들을 제대로 검증하지 않고 응답을 만들면:

 
HTTP/1.1 301 Moved Permanently Location: https://malicious-site.com/random

이 응답이 캐시에 저장된다. 그러면 이후 사용자가 http://innocent-site.com/random에 접속할 때, 캐시에서 이 응답을 받아 https://malicious-site.com/random으로 리디렉션된다. 이 악성 사이트는 가짜 로그인 페이지나 악성 코드를 실행시킬 있게된다.

 

  • 그러나 비단, http 통신 요청에만 국한되는게 아니다. 이번 글의 주제가 뭔지 아는가? Web cache poisening attack(Using multiple headers)이다. 즉, 복합적인 헤더를 이용하여 웹 캐싱을 오염시키는 것이다. 즉, 이 복합적인 헤더라 함은 이번에 쓰이는 X-Forwarded-Proto와 X-Forwarded-Host를 이용한다는 것이다. 이 두 헤더를 이용하여 리다이렉팅 되는 경로를 오염시키는 것이다. 그런데 그 리다이렉팅되는 곳 그곳은 원래 사용자가 정상적인 요청을 하면 도달하는 캐시 자원의 위치이다. 그런데 공격자 그곳을 오염시키지 않았는가? 그러닌까 사용자가 http 요청이 아닌, https 요청을 해도 결국 도착한 그 캐시 자원의 위치가 오염이 되었다는 것이다. 그래서 이번 시간은 이 복합적인 헤더를 이용한 리다이렉팅 기술을 이용해 웹 캐시 포이즈닝을 하고자 한다.

이게 어떻게 가능한가?

이 공격이 성공하려면 몇 가지 조건이 맞아야 한다:

  1. 캐시가 응답을 저장함: 웹사이트나 중간 프록시가 이 리디렉션 응답을 캐시에 저장해야 한다.
  2. 헤더 검증 부족: 사이트가 X-Forwarded-ProtoX-Forwarded-Host 같은 헤더를 맹신하고, 이 값으로 동적으로 URL을 만들면 취약해진다.
  3. HTTPS 강제 설정: HTTPS로 리디렉션하는 동작이 공격자가 조작한 헤더에 영향을 받을 때 문제가 커진다.

 

 

실습 시나리오(모의해킹)

 

이번 실습 시나리오

  • 공격 사이트의 자바스립트 요청 주소를 http로 요청할 때 https로 리다이렉트 하는 장소를 내 악성 스크립트가 있는 자원의 우치로 오염시키고자 하는 테스트를 캐시 버스터를 이용한다.
  • 해당 캐시버스트 테스트가 끝나면 본 사이트에 http 요청할 때 https로 리다이렉트 되는 자원의 위치를 내 악성스크립트가 있는 자원의 위치로 오염시킨다.
  • 그 결과, 리다이렉트되는 그 장소가 오염돼므로 https 요청을 하든, http 요청을 하든 결국 사용자는 내 악성스크립트가 있는 자원을 요청하게 될 것이고, 자연스럽게 해당 악성스크립트가 실행하게 된다. 

 

 

 

이번에는 직접적으로 자바스크립트 파일을 요청하는 get 요청 캐시를 조작해볼 것이다. 저번에는  https://0a6d0059049e5bbc803b0392003f00d9.web-security-academy.net/  에 웹 캐시 포이즈닝을 수행하지 않았나 이번에는 https://0a6d0059049e5bbc803b0392003f00d9.web-security-academy.net/resources/js/tracking.js 이라는 해당 사이트의 자바스크립트 경로에 관한 캐시 포이즈닝을 하고자한다.

 

먼저 반환할 악성스크립트 제공 페이지를 만들어둔다. 그리고 해당 페이지쪽으로 요청하도록 캐시 포이즈닝을 할텐데, 이때 이번에 사용하는 방법은 http 요청에 관한 https로 리다이렉트할 때 반환하는 페이지를 저 페이지로 가게끔 캐시 포이즈닝을 한다는 것이다.

사용자가 만약  http://0a6d0059049e5bbc803b0392003f00d9.web-security-academy.net/resources/js/tracking.js 에 요청을 하면, https://exploit-0a62001404ba5bdc80dd251a016200b6.exploit-server.net/resources/js/tracking.js 로 안내 받게 되고, 그로인해 사용자는 해당 페이지의 악성 스크립트인 alert(document.cookie) 를 실행하게 되는 것이다.

 

?cb=1234 라는 캐시버스터를 이용하여 실제 공격을 하기 전 테스트 용도로 해당 파라미터를 URL 옆에 붙여주었고,

X-Forwarded-Proto 헤더와 X-Forwarded-Host 헤더를 이용하여 X-Forwarded-Proto를 이용하여 현재 요청할 때 쓰인 프로토콜은 http임을 명시하였고, X-Forwarded-Host 헤더를 이용하여 해당 요청은 exploit-0a62001404ba5bdc80dd251a016200b6.exploit-server.net 쪽으로 보낼려고 한거다라는 것까지 명시해주었다. 그 결과, 이렇게 하기 전과 별반 다르지 않는 응답 값을 받았다. 

 

그래서 이번에는 X-Forwarded-Proto 헤더 대신 X-Forwarded-Scheme 헤더를 이용하였다. 그 결과, response 보면 알 수 있듯이, 302 응답을 받은 것을 볼 수 있고, 리다이렉팅 된 곳을 보면, 방금 위에서 본 https://exploit-0a62001404ba5bdc80dd251a016200b6.exploit-server.net/resources/js/tracking.js 라는 경로임을 알 수 있다. 즉, 제대로 리다이렉팅에 성공 했음을 알 수있다. 나아가, age: 9 라는 값을 통해 캐싱된지 9초가 지났다는 것과 X-Cache: hit 라는 값을 통해 캐싱되었다는 것을 알 수 있다. 갑자기 저 헤더로 바꾼 이유는 아래와 같다.  

헤더의 역할

일단, 두 헤더가 무엇인지부터 알아보자:

  • X-Forwarded-Proto: 클라이언트가 요청을 보낸 원래 프로토콜(HTTP 또는 HTTPS)을 서버에 전달한다.
  • X-Forwarded-Scheme: 마찬가지로 클라이언트 요청의 원래 스키마(HTTP 또는 HTTPS)를 서버에 알려준다.

쉽게 말해, 둘 다 "이 요청이 원래 HTTP로 왔는지 HTTPS로 왔는지"를 서버에 전달하는 역할을 한다. 프록시나 로드 밸런서를 거치면서 프로토콜 정보가 바뀔 수 있기 때문에 이런 헤더가 필요하다고 한다. 다만, 전자는 통신프로토콜에 초점을 두었고, 후자는 URl 스키마인 http:// or https:// 에 초점을 두었다는 것이다.


사이트마다 다른 이유

그렇다면 왜 어떤 사이트는 X-Forwarded-Proto를 쓰고, 어떤 사이트는 X-Forwarded-Scheme를 사용할까? 그 이유는 몇 가지 요인 때문이다:

  1. 서버 설정
    • 웹 서버(Nginx, Apache 등)나 애플리케이션 프레임워크가 어떤 헤더를 지원하거나 선호하느냐에 따라 다르다.
    • 예를 들어, Nginx는 기본적으로 X-Forwarded-Proto를 사용한다.
  2. 프록시 설정
    • 프록시나 로드 밸런서(AWS ELB, Cloudflare 등)가 어떤 헤더를 전달하느냐에 따라 달라진다.
    • 예: AWS ELB(Elastic Load Balancer)는 X-Forwarded-Proto를 전달한다.
  3. 호환성
    • 오래된 시스템에서는 X-Forwarded-Proto를 주로 사용하고, 최신 시스템에서는 X-Forwarded-Scheme를 지원하는 경우가 많다.
  4. 개발자 선호
    • 개발자가 특정 헤더를 사용하도록 직접 설정했을 수도 있다.

언제 어떤 헤더를 사용하는지

  • X-Forwarded-Proto:
    • 주로 웹 서버나 프록시에서 사용된다.
    • 예: Nginx에서 SSL 오프로딩(HTTPS를 HTTP로 변환)을 할 때 X-Forwarded-Proto를 설정한다.
  • X-Forwarded-Scheme:
    • 애플리케이션 프레임워크에서 더 자주 사용된다.
    • 예: Ruby on Rails 같은 프레임워크는 X-Forwarded-Scheme를 지원한다.

결론

사이트마다 X-Forwarded-ProtoX-Forwarded-Scheme 중 다른 헤더를 사용하는 이유는 서버 설정, 프록시 설정, 시스템 호환성, 개발자 선호 등 다양한 요인 때문이다. 실제로 사용할 때는 해당 사이트의 서버나 프록시가 어떤 헤더를 처리하는지 확인하고, 그에 맞춰 설정하면 된다.

 

따라서 X-Forwarded-Proto가 안되서 X-Forwarded-Scheme을 사용해보았다. 물론 이 2개 말고도 이와 비슷한 기능을 가진 헤더들도 있다. 그러나 비표준헤더라서 특별한 경우가 아니라면, 거의 사용하지 않는다고 한다. 그래도 아래에 명시해두기는 하겠다.

추가적인 헤더들

  1. Forwarded
    • 설명: 이 헤더는 RFC 7239에 정의된 표준 헤더로, 원래 요청의 프로토콜 정보를 전달할 수 있음.
    • 사용 예시: Forwarded: proto=https (HTTPS로 온 요청임을 나타냄)
    • 특징: X-Forwarded-* 계열 헤더의 기능을 통합하며, 프로토콜뿐만 아니라 클라이언트 IP나 프록시 정보도 함께 전달 가능.
  2. X-Original-Proto
    • 설명: 일부 시스템에서 원래 요청의 프로토콜을 전달하기 위해 사용되는 비표준 헤더.
    • 사용 예시: X-Original-Proto: https
    • 특징: 특정 프레임워크나 서버 환경에서만 사용되며, 널리 채택되지는 않았다.
  3. X-Url-Scheme
    • 설명: 주로 레거시 시스템에서 원래 요청의 프로토콜(스키마)을 전달하는 데 사용되는 비표준 헤더.
    • 사용 예시: X-Url-Scheme: https
    • 특징: 오래된 애플리케이션이나 특정 환경에서 간혹 사용되지만, 표준화되지 않았다.

 

암튼 리다이렉팅된 주소에 접속한 결과, 정상적으로 스크립트를 반환해주는 것을 볼 수 있다.

 

테스트가 통과됐으니 캐시버스터를 제거하고, 실제로 웹 캐싱 포이즈닝 어택을 하고자 위 그림의 리퀘스트와 같이 요청 헤더를 수정후 전송하였고, 이 또한 캐싱에 성공하였다.

 

실제로 공격이 들어갔는지 테스트를 위해 리로딩을 해보니, 악성스크립트인 alert(document.cookie) 가 실행됨을 위 그림을 통해 확인할 수 있다. 즉, 멀티 헤더를 이용한 리다이렉팅 방법을 통해 웹 캐시 포이즈닝 어택이 성공하였다.

 

 

대응 방안

1. 헤더 검증 강화

공격의 핵심은 서버가 X-Forwarded-* 헤더를 맹신하여 잘못된 리다이렉션 URL을 생성하는 데 있다. 이를 방지하려면 헤더를 신뢰하지 않고 검증해야한다.

  • 신뢰할 수 있는 헤더만 사용:
    • X-Forwarded-Proto, X-Forwarded-Scheme, X-Forwarded-Host 같은 헤더는 프록시나 로드 밸런서에서 설정된 경우에만 신뢰
    • 클라이언트가 직접 보낸 요청에서 이러한 헤더를 무조건 신뢰하지 말고, 신뢰할 수 있는 프록시에서만 해당 헤더를 허용하도록 설정.
    • 예: 프록시가 설정한 헤더를 확인하기 위해 IP 화이트리스트를 사용하거나, 프록시가 추가한 특정 헤더(예: Via)를 확인
  • 기본값 사용:
    • X-Forwarded-ProtoX-Forwarded-Scheme이 없거나 신뢰할 수 없는 경우, 서버가 직접 요청의 프로토콜(HTTP/HTTPS)을 확인하거나 기본값(예: HTTPS)을 사용하도록 설정.
    • 예: 서버가 HTTPS로만 동작하도록 설정되어 있다면, X-Forwarded-Proto: http를 무시하고 항상 HTTPS로 처리.
  • 헤더 필터링:
    • 프록시나 웹 서버(Nginx, Apache 등)에서 클라이언트 요청에서 X-Forwarded-* 헤더를 제거하거나 덮어쓰는 규칙을 설정.
    • 예: Nginx 설정에서 proxy_set_header X-Forwarded-Proto $scheme;를 사용하여 프록시가 직접 프로토콜을 설정하도록 보장.

2. 리다이렉션 로직 개선

리다이렉션 URL을 동적으로 생성할 때 조작된 헤더 값을 반영하지 않도록 해야 한다.

  • 고정된 도메인 사용:
    • 리다이렉션 URL을 생성할 때 X-Forwarded-Host 같은 헤더 값을 사용하지 말고, 서버에 하드코딩된 도메인(예: example.com)을 사용.
    • 예: Location: https://example.com/resources/js/tracking.js처럼 고정된 도메인을 사용하면, X-Forwarded-Host: malicious.com이 반영되지 않는다.
  • HTTPS 강제 로직 점검:
    • HTTPS로 리다이렉션할 때, 요청의 실제 프로토콜(서버가 수신한 연결이 HTTPS인지)을 확인하고, X-Forwarded-ProtoX-Forwarded-Scheme에 의존하지 않도록 설정.
    • 예: 서버가 HTTPS로 동작 중이라면, 리다이렉션 없이 바로 요청을 처리하도록 설정.

3. 캐시 관리 강화

캐시 포이즈닝은 캐시가 오염된 응답을 저장하고 반환하는 데서 발생한다. 이를 방지하려면 캐시 동작을 세밀하게 제어해야함.

  • 캐시 키에 프로토콜 포함:
  • 조작 가능한 헤더를 캐시 키에서 제외:
    • X-Forwarded-Proto, X-Forwarded-Scheme, X-Forwarded-Host 같은 헤더를 캐시 키에 포함시키지 않도록 설정.
    • 예: 캐시 키가 경로와 Host 헤더만 포함하도록 설정하면, X-Forwarded-Host로 조작된 응답이 다른 사용자에게 영향을 미치지 않는다.
  • 리다이렉션 응답 캐싱 비활성화:
    • 302 Found 같은 리다이렉션 응답을 캐시에 저장하지 않도록 설정하기.
    • 예: Cache-Control: no-store 헤더를 리다이렉션 응답에 추가하여 캐싱을 방지.
    • 설정 예: Nginx에서 proxy_cache_bypass를 사용하여 특정 응답이 캐시되지 않도록 설정.