Portswigger-Targeted web cache poisoning using an unknown header
풀이
쿠키를 캐시 키에 포함하지 않아 웹 캐시 포이즈닝 취약점이 있다. 유저가 약 1 분에 한 번씩 홈페이지를 방문하고, 게시글에 작성한 댓글을 열람한다. 방문자의 브라우저에 alert(document.cookie)를 실행시켜라. 참고로 의도한 피해자가 속한 특정 사용자 하위 집합을 대상으로 response가 가도록 해야 한다.

먼저 조작 가능한 unkeyed input을 찾아보았다. Param Miner를 이용해 숨겨진 헤더를 찾아보았다. x-host 라는 헤더를 찾아내었으며 이 헤더가 캐시 포이즈닝 공격에 취약하다는 것을 알아내었다.

이 헤더를 이용하여 어떤 공격이 가능할지 이전 Response와 비교해보았다. x-host 헤더의 값을 이용하여 자바스크립트 경로를 생성한다는 것을 알아내었다. 도메인을 공격자 서버로 두고, 동일 경로에 악의적인 자바스크립트를 두면 XSS가 가능해보인다.

이와 같이 페이로드를 주입하여 보냈다. 하지만 캐시 페이지에 접근하지 못했다. 이는 Param Miner의 Request를 Repeater에 가져와 사용했는데, Param Miner가 다른 헤더에도 캐시 버스터를 넣었기 때문이다.

Response를 잡아보면 Vary 헤더의 값으로 User-Agent가 있다. Vary 헤더는 주로 unkeyed 헤더 중 key로 사용할 헤더를 지정하는 용도로 사용된다고 한다. 즉, Param Miner가 User-Agent에 포함한 캐시 버스터때문에 이 캐시에 hit되지 않은 것이다.
기타 캐시 관련 헤더 역시 확인할 수 있다. X-Cache를 통해 캐시를 사용하며 캐시 miss 생태였다는 것을 알 수 있다. Cache-Control 헤더를 통해 캐시가 갱신되는 주기가 30초라는 것을 알 수 있다.
User-Agent를 동일하게 맞춘 뒤 캐시 페이지에 접근하면 XSS가 트리거된다. 이 XSS 공격을 타겟이 트리거하게 하려면 타겟의 User Agent를 알아야 한다.

게시물 코멘트에는 HTML is allowed 라는 메시지가 있다. 몇 가지 간단한 XSS 페이로드를 넣어보았는데 필터링이 되었다.

img 태그를 이용하여 외부 공격자 서버에 이미지를 요청하도록 했다. 이렇게 하면 사용자의 User-Agent를 알아낼 수 있다.

공격자 서버의 로그를 통해 타겟의 IP 주소와 User-Agent 헤더를 알아내었다. “Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36” 이다.

마지막으로 캐시 버스터를 전부 제거하고, User-Agent를 타겟에게 맞춰 캐시 포이즈닝을 한다.

타겟이 캐시에 접근하여 XSS를 트리거하면 성공이다.
이 취약점은 사용자가 조작할 수 있는 헤더를 그대로 믿고 사용해서 발생했다. 숨겨진 헤더지만 헤더 인젝션으로 찾아낼 수 있다는 점을 간과했다. 헤더에서 정보를 노출해 캐시 키로 이용되는 헤더에 대한 정보를 얻어 특정 타겟에 대한 공격이 가능했다.
tags: writeup, web-cache-poisoning, xss, reflected xss, wstg-inpv-01, business-logic-vul, wstg-busl-02, host-header-injection, wstg-inpv-17, web hacking