[Write-Up] PortSwigger - Manipulating the WebSocket Handshake to Exploit Vulnerabilities

목차


문제 분석

난이도: PRACTITIONER
Lab: Manipulating the WebSocket handshake to exploit vulnerabilities

image.png

WebSocket으로 구현된 라이브 챗 기능이 있으며, 공격적이지만 결함이 있는 XSS 필터가 적용되어 있다. WebSocket 메시지를 이용해 지원 상담원의 브라우저에서 alert() 함수를 호출하면 문제가 해결된다.

XSS 진단

챗 입력창에 <p>xss</p>를 입력하면 앞선 랩과 마찬가지로 서버로 전송되기 전에 클라이언트에서 HTML 인코딩된다. 프록시에서 메시지를 직접 수정해 인코딩되지 않은 태그를 전송하면 태그로 해석되어 출력된다.

image.png

이어서 img 태그와 이벤트 핸들러로 구성한 공격 페이로드를 전송하면 다음 응답이 돌아오고, 챗 기능에 더 이상 접근할 수 없게 된다.

{"error":"Attack detected: Event handler"}

필터가 메시지에서 이벤트 핸들러를 탐지한 것이다. 문제는 차단이 해당 메시지에만 그치지 않고 연결 자체가 끊긴다는 점이다. 세션 쿠키를 지우고 다시 접근해도 계속 차단되므로, 세션이 아닌 IP를 기준으로 차단이 적용되었다고 볼 수 있다.

차단이 IP 기반이라면 핸드셰이크 단계에서 출처 IP를 다르게 인식시키면 된다. Burp Repeater의 핸드셰이크 편집 기능으로 다음 헤더를 추가해 재연결을 시도하면 정상적으로 연결이 수립된다.

X-Forwarded-For: 0.0.0.0

애플리케이션이 클라이언트 IP를 판단할 때 이 헤더를 그대로 신뢰하고 있으며, 그 판단이 핸드셰이크 시점에 이루어지기 때문에 가능한 우회다.


익스플로잇

차단 사유가 “Event handler"였으므로, 필터가 핸들러 이름을 어떤 방식으로 매칭하는지 확인한다. HTML 속성 이름은 대소문자를 구분하지 않으므로, 이름을 대문자로 바꿔 전송한다.

<img src=x ONERROR='alert`1`'>

필터에 차단되지 않고 메시지가 전달되며, 상담원의 브라우저에서 alert()가 실행되어 문제가 해결된다. 호출은 괄호 대신 태그 함수 형태(alert + 백틱)를 사용했는데, 괄호까지 함께 차단하는 필터에서도 동일한 페이로드를 재사용할 수 있다.

image.png

image.png


정리

이 랩은 WebSocket 통신에서 두 가지 층위의 문제를 함께 다룬다.

첫째, 블랙리스트 기반 필터의 한계다. 필터는 이벤트 핸들러라는 위험 요소를 정확히 식별했지만 대소문자를 구분해 매칭했기 때문에, HTML 속성 이름이 대소문자를 구분하지 않는다는 명세와 어긋나면서 우회가 가능해졌다. 차단 목록은 브라우저의 실제 파싱 규칙과 일치해야 방어로 기능한다.

둘째, 핸드셰이크가 독립적인 공격면이라는 점이다. WebSocket의 인증·세션·클라이언트 식별은 핸드셰이크 시점에 결정되고 이후 메시지는 그 컨텍스트에서 처리된다. 따라서 X-Forwarded-For처럼 클라이언트가 임의로 넣을 수 있는 헤더를 근거로 보안 결정을 내리면, 메시지 단위 방어가 아무리 촘촘해도 연결 단계에서 무력화된다. 진단할 때도 메시지만 보지 않고, 핸드셰이크를 다시 만들어 헤더를 조작해보는 접근이 필요하다.