weird legacy

소스코드
index.js
- 소스코드는 크게
index.html, index.js파일로 구성됩니다. - 인덱스(/) 경로로 접근하면 index.html 자원이 반환되며 URL에 들어가는 값에 따라 API가 호출됩니다.
- ”/”, “/fetch” - 서버에 보낼 수 있는 요청은 이 2가지밖에 없습니다.

- ”/”, “/fetch” - 서버에 보낼 수 있는 요청은 이 2가지밖에 없습니다.
- /fetch 경로로 요청을 보내면 URL에 함께 전달된
url파라미터 값을url변수에 저장하고, URL 인스턴스를 하나 생성해서 호스트명을host변수에 저장하고 있습니다. 이 때, 호스트(host) 값은localhost이거나,localhost로 끝나는 임의의 값이어야 합니다.- 만약 그렇지 않으면 서버로부터 “rejected” 혹은 “Invalid Url” 응답이 반환됩니다.
- 만약
url파라미터에 전달받은 값이 검증을 통과하면 서버는 입력된 url 경로로 요청을 보내는데, 이 때 요청 헤더에 플래그 값이 함께 전달됩니다. 그러므로 요 헤더 값을 탈취하는게 궁극적인 목표라고 할 수 있겠네요.

- 백그라운드에서 대상 서버로 보내지는 요청 패킷 정보는 어떻게 확인할 수 있을까요? 공격자가 서버로 요청을 직접 보내는 게 아니라 중개 서버를 거쳐서 대상 서버로 요청이 보내지는 경우에는 외부에서 이를 확인하기가 어렵습니다. 이럴 때 유용하게 사용할 수 있는 게
RequestBin, RequestCatcher입니다. (물론 여기서는 중개 서버와 대상 서버가 동일합니다.)- blind-command, ShareProfile 에서도 리퀘스트빈을 사용하여 문제를 풀이한 전적이 있습니다.
EXPLOIT
- 먼저 정상적인 URL 정보를 입력해주면 “Hello!” 메시지가 반환됩니다.
/fetch?url=http://localhost:3000

url파라미터에RequestBinURL을 넣으면localhost관련 조건이 충족되지 않기 때문에 “rejected” 메시지가 출력되는데요.- 이를 우회하기 위해서는
url파라미터에 입력된 (1) URL의 호스트명이localhost이거나, (2) URL이localhost로 끝나야 합니다. 여기서 플래그를 확인하기 위해서는 반드시 리퀘스트빈으로 요청을 보내야 하기 때문에 (1) 을 우회할 수는 없습니다. - 그럼 (2)를 우회해야 하는데요. RFC 3986(URI 표준)에서는 호스트 부분에서 허용되는 문자들을 정의하고 있습니다.

- 아래와 같이
! $ * ,"등의 문자를 사용해서 값을 전달해주면,tkedeow.request.dreamhack.games!localhost문자열 전체를 호스트명으로 인식하게 되고, 호스트 맨 끝에localhost값이 오는 조건을 만족하게 됩니다. 응답 값을 살펴 봐도rejected가 아닌 임의의 IP 주소가 반환됩니다.

- 이제 리퀘스트빈으로 가보면 요청 패킷의 헤더(Cookie)에 플래그가 찍힌 걸 확인할 수 있습니다.

🐛.. 🐛.. 🐛..