Web Güvenliği Sadece Web Güvenliği Değildir: Web Temelli Saldırılar ile IoT Cihazların Keşfi ve Kontrolü

Ziyahan Albeniz - 13 Kasım 2018 -

DNS rebinding atakları günümüzde hala atak vektörleri değişerek karşımıza çıkıyor. IOT cihazlarda DNS rebinding ataklar ile yapılan araştırmayı paylaşıyoruz. Ayrıca Fragmented SQL Injection ile birden fazla parametre kullanılarak nasıl injection yapıldığını da sizler için yazdık..

Web Güvenliği Sadece Web Güvenliği Değildir: Web Temelli Saldırılar ile IoT Cihazların Keşfi ve Kontrolü

Neredeyse 20 yıldır DNS Rebinding atağı gündemimizde. Browser üreticileri fixlemek için ne yaptılarsa da istenen sonuç elde edilemedi. Fixlendiğini düşündükten tam sekiz yıl sonra yeniden gündeme geldi, başka bir kaynak için başka bir atak vektörü olarak.

Gökkubenin altında söylenmemiş yeni bir söz yok fikrinden hareketle güvenlik dünyasında bundan sonraki hareketliliğin varolan atakların kombinasyonu ile ortaya çıkacak yeni atak vektörleri olduğunu söyleyebiliriz.

Nitekim kripto para cüzdanlarının çalınmasına yol açan DNS Rebinding saldırısı bunlardan biriydi.

Bu yazımızın konusu ise Princeton Üniversitesi ve UC Berkley Üniversitesi'nden araştırmacıların ortak imzalarını taşıyan IoT cihazlarının web temelli saldırılar ile keşfi ve kontrolünü irdeleyen araştırma.

Araştırma Ağustos ayında kamuoyu ile paylaşıldı. Araştırmacılar, ilk olarak 15 adet IoT cihazı incelemek istedilerse de içerisinde built-in HTTP sunucu bulunan ancak 7 tanesi araştırma kapsamına alınabildi ve araştırmanın devamında sadece bu cihazlar kullanıldı.

Araştırmaya dahil edilen cihazlar, Google Chromecast, Google Home, Camera, Smart TV, Smart Switch vb cihazlardan oluşmaktadır.

Araştırma temel olarak saldırgan kontrolündeki bir siteye girmeye ikna edilen kurbanın yerel ağında bulunan IoT cihazların web temelli atakları kullanılarak keşfi ve kontrol edilmesine dayanıyor.

Aslında bu yeni bir vektör değil. Fakat saldırganların bu atak vektörlerini kullanarak sonuç elde etmesi ortalama bir dakikalık bir süreyi kapsıyordu.

Kullanıcıların yüzde 55'inin girdikleri sitelerde maksimum 15 saniye geçirdiği araştırmasını baz alacak olursak, kullanıcıların çoğunlunun bu zafiyetlerden etkilenmeyeceğini söyleyebiliriz.

Ancak…

Yazımıza konu olan araştırma sahipleri aynı zamanda saldırı için gerekli olan süreyi hatırı sayılır ölçüde kısalttıklarını iddia ediyorlar. Araştırmacılar kullandıkları yöntem ile lokal ağda bulunan cihazların yaklaşık 10 saniye içerisinde tespit edildiğini ve cihazlara ulaşıldığını belirtiyor.

Araştırmacılar, teste tabi tutulacak cihazları bir test ortamında analiz ederek, yani bir Raspberry Pi cihazına router olarak bağlanmalarını sağlayarak hem bu cihazlardan gönderilen ve alınan paketleri, hem de bu cihazlara eşlenik olarak çalışan mobil uygulamaların yine aynı ağa bağlı durumda gönderip aldıkları paketleri incelediler.

Araştırma sonucunda 35 GET, 8 POST isteğinde endpointler keşfettiler.

Araştırmacılar çalışmayı iki fazda ele alıyorlar: Discovery (Keşif) ve Access (Erişim) fazları.

Discovery keşif fazında HTML5 elemanları ile istek yaparak local ağda bulunan IoT cihazlarını tespit eden araştırmacılar, ikinci aşamada elde ettikleri cihaz IP adresleri ile DNS Rebind saldırısını kombine ederek cihazlardan bilgi elde ediyor ve state (durum) değişikliklerini tetikliyorlar.

Keşif adımları:

  1. WebRTC ile local IP adresi elde edilir.
  2. Sonrasında aralıktaki tüm IP'lere 81. Porttan istek yapılır. 81 numaralı port genelde kullanılmadığından aktif cihazlar anında TCP RST ile cevap vereceklerdir. Kurguya göre bir IP'ye ait canlı bir sistem olmayışı ise istek paketlerinin time-out oluşundan hareketle anlaşılmaktadır.
  3. Aktif IP adreslerine HTML5 element'i ile cihazlardan toplanan 35 adet GET isteği yapılır.

Dönen hata mesajlarından hareketle saldırı scripti bu aktif IP'lerin 7 adet cihazdan birine ait olup olmadığını tespit eder.

Araştırma başlangıçta üç farklı işletim sistemi (Ubuntu, Windows 10 ve macOS) ve dört farklı browser (Chrome, Firefox, Safari, Microsoft Edge) üzerinden başladı. Ancak sadece Chrome ve Firefox tarayıcıların davranışı testin devamına uygun olduğundan sadece bu iki tarayıcı ile teste devam edilebildi.

Safari ve Edge tarayıcıların teste katılamaması ise araştırmada şu satırlarla gerekçelendirildi:

"Safari'de tüm Fetch istekleri time out oluyordu, bu da saldırı scriptinin aralıktaki tüm IP adreslerini inaktif makineler olarak tespit etmesine sebep oldu. Edge ise tüm aktif IP adreslerini Fetch ile tespit edebilmesine rağmen, keşif aşamasının diğer bir kısmı olan HTML5 hata mesajlarının elde edilmesi mümkün değildi. Bu yüzden saldırı için hazırlanan script Edge browserlarda hiçbir IoT aygıtını tanımlayamadı."

Bu saldırı sonucunda cihazların anlık olarak bağlı olduğu kablosuz ağ SSID'si, kullandıkları yazılımın versiyon veya modeli, cihazların yakınında bulunan kablosuz ağlara ait SSID'ler ifşa olurken, Google Chromecast, Google Home, Smart TV ve Smart Switch gibi cihazlarda cihaz açıp kapama, video veya ses dosyası oynatma gibi işlemler de yapılabildi.

Araştırmacılara göre böylesi bir zafiyetin etkilerini hafifletmede kullanıcı, browser üreticileri, IoT üreticileri ve hatta DNS servis sağlayıcılarının her birine düşen görevler var. Önce bunları sıralayacak, sonra web güvenliği perspektifinden bizler de fikirlerimizi paylaşacağız.

  1. Tarayıcınızda WebRTC'yi disable edebilir, yani devredışı bırakabilirsiniz. Böylece private IP'nizin ifşa olmasına engelleyebilirsiniz. Ancak saldırgan *.*.*.1 adresinde router cihazınız olduğundan hareketle tüm private IP aralıklarına istek yapıp, private IP'nizin aralığını tespit edebilecektir.
  2. Saldırgan IoT cihazlarının sizin bilgisayarınızla aynı IP aralığında olduğundan hareketle, cihaz tarama işlemine */24 adres kümesinden başlıyordu. DHCP ayarlarınızı */16 ağ kümesinden IP dağıtacak şekilde ayarlayabilirsiniz.

Keşif için sıralanan bu önerilerden sonra, saldırının ikinci aşamasında yer alan DNS Rebinding saldırısına karşı öneriler şu şekilde:

  1. Local bir DNS yönlendiricisi olan dnsmasq programı ile DNS yanıtlarında RFC 1918 kapsamında yer alan private IP'lerin bulunmasını engelleyebilirsiniz
  2. OpenWRT gibi bir routera doğrudan dnsmasq'ı yükleyebilir, tüm bağlı kullanıcılar için bu işlemi yapabilirsiniz.
  3. IoT üreticileri web arayüzlerine yapılan istekte bulunan Host headerını kontrol edebilir. Burada RFC 1918'e uygun bir private IP yoksa erişimi engelleyebilirler.
  4. DNS servis sağlayıcıları dnswall vb bir mekanizmayla private IP'lerin DNS kayıtlarında dönmesinin önüne geçebilirler.

Takdir edersiniz ki bu tür araştırmalar her zaman deneysel amaçlarla yapılmakta, ne de saldırganlar her zaman bu tarz zafiyetlerin istismarı için sizin kendi sitelerine girmenizi beklemektedir. Yukarıda saydığımız türden zararlı bir script kodu siteniz üzerinde bir XSS zafiyeti dolayısıyla çalışıyor olabilir. Dolayısıyla öncelikle XSS'e karşı kullanıcıdan ya da etkileşimde bulunduğunuz servislerden aldığınız datayı doğrudan sayfanıza eklemek yerine, girdinin eklendiği contexte uygun olarak encode etmenizi; ayrıca siteniz üzerinden istek yapılacak kaynakları whitelist etmek için tarayıcıların tüm güncel versiyonlarında desteklenen Content-Security-Policy mekanizmasını kullanmanızı öneriyoruz.  

Araştırmanın ayrıntıları için lütfen tıklayınız.

Fragmented SQL Injection

Bir web uygulamasında SQL Injection var mı sorusuna pek çoğu "tek tırnak payloadu kullanır ve sonucu gözlemlerim" yanıtını verecektir. Hatta bazı kaynaklarda SQL injection için Quote Injection dendiğini görürseniz şaşırmayın! Benden söylemesi.

Öncelikle neden diye cevaplayalım. Neden tek ya da çift tırnak bir sorguya dahil edildiğinde sorgu bozulur ve sistem hata üretir?

Bir sistemde gündelik anlamı (literal) dışında özel bir anlamı ve fonksiyonu olan karakterler "meta karakter" olarak anılmaktadır.

SQL contextinde de çift ya da tek tırnak işareti string tipindeki verilerin başlangıcı ve bitişini temsil etmektedir.

select * from users where user_name='GIRDI NOKTASI'

Dolayısıyla yukarıdaki gibi bir girdi noktasına tek tırnak enjekte edildiğinde SQL string başlangıç ve bitişi konusunda kararsız kalacak, tek başına kalan sondaki tek tırnak işaretinin (') sonlandırılmadığı konusunda hata verecektir.

Tabii ki sözünü ettiğimiz kontekst string konteksti, yoksa aşağıdaki gibi bir kontekst için tek ya da çift tırnak enjekte etmeye gerek yoktur:

select * from users where id=GIRDI NOKTASI

Sayısal bir veriden sonra yukarıdaki GIRDI NOKTASI'na verilecek input SQL komut kontextine eklenecektir.

Tek tırnak enjekte edildiğinde alınan hata yukarıdaki bilgilerden hareketle kullanıcıdan alınan girdinin herhangi bir denetime tabi tutulmadan SQL sorgusuna eklendiğine ve bu girdi de şayet SQL kontextinde anlamlı bir karakter içeriyorsa DB sistemi tarafından alelade bir karakter değil, kendisi için özel anlama sahip bir karakter olarak yorumlandığına işaret etmektedir.

Sonrasında gelsin exploitler, gitsin PoC'ler.

Peki tek tırnak işareti kara listeye alındı ise ya da bir şekilde SQL sorgusunda escape ediliyorsa?

$username ="' or 1=1 --";
$password ="qwerty123456";
$query = select * from users where username='".$username."' and password='".$password."'";
select * from users where username='\' or 1=1 -- ' or password='qwerty123456'; 

Gördüğünüz üzere tek tırnak (') işareti escape edildiği için saldırganın enjekte ettiği SQL komutları komut olarak algılanmadı.

Şimdi Fragmented SQL Injection'dan söz etme zamanı.

Aslında bu trick araştırmanın sahibi Rodolfo (kendini bu şekilde tanıtıyor.) bu şekilde isimlendirilmiyor.

Saldırganlar birden fazla noktayı kontrol edebildiği ve bu noktalardan alınan girdinin aynı kontexte dahil edildiği şartlar altında Fragmented yani bölünmüş payloadlar kullanıyorlar. Bu yolla karakter sayısı ve karakter limitleri gibi blacklistleri atlatmaları mümkün olabiliyor.

Yukarıdaki SQL komutunda enjekte ettiğimiz payloaddaki tek tırnak karakterinin escape edildiğini gördük:

select * from users where username='\' or 1=1 --' or password='qwerty123456';

Peki şöyle bir payload'a ne dersiniz?

username: \
password: or 1 #

$query = select * from users where username='".$username."' and password='".$password."'";
select * from users where username='\' or password=or 1 #';

"\" karakteri kendisinden sonra gelen tırnak işaretini etkisizleştirecektir. Dolayısıyla username kolonu için string başlangıcı password=' alanındaki tırnak işareti ile sonlanacaktır (Mavi renkli alan). Devamındaki or 1 komutu SQL sorgusundan mutlak bir true dönmesini sağlayacak, # (pound) işareti kendisinden sonraki tırnak işareti ve varsa diğer SQL komutlarının yorum olarak değerlendirilmesini yani DB Sistemi tarafından çalıştırılmamasını sağlayacaktır.

Fakat referans verdiğimiz araştırmada bir noktaya şerh düşmeden edemeyeceğimiz. İlgili araştırma çözüm olarak htmlentities fonksiyonu ile birlikte HTML encoding uygulanmasını öneriyor.

Evet HTML encoding tek tırnak, çift tırnak, tag açma ve kapama (< ve >) karakterlerini HTML entitylere dönüştürür. Fakat SQL Injection için çözüm bu olmamalı. Zira tek tırnak, çift tırnak karakterlerine (contexte göre) ihtiyaç duymadan payload enjekte edilebilir, dahası GBK karakter encoding gibi bir yöntemle, karakterleri farklı bir dil kodlamasında encode ederek bu korumayı bypass edebilirler.

Peki biz ne öneriyoruz?

Netsparker olarak SQL Injection zafiyetinde kesinkes çözümün Prepared Statement ya da Parameterized Query olarak bilinen yöntemle gerçekleştirilmesini öneriyoruz.

Ancak bu yöntemle kullanıcının parametre olarak verdiği datanın komut olarak işlenmesinin yüzde 100 önüne geçebilirsiniz. Diğer yöntemler bugün olmasa bile yarın yaratıcı başka bir teknikle bypass edilebilir.

PHP'de Parameterized Query işlemini aşağıdaki yol ile gerçekleştirebilirsiniz:

$stmt = $dbh->prepare("update users set email=:new_email where id=:user_id");
$stmt->bindParam(':new_email', $email);
$stmt->bindParam(':user_id', $id);

.NET uygulamalarında ise aşağıdaki yöntemi kullanabilirsiniz:

string sql = "SELECT * FROM Customers WHERE CustomerId = @CustomerId";
SqlCommand command = new SqlCommand(sql);
command.Parameters.Add(new SqlParameter("@CustomerId", System.Data.SqlDbType.Int));
command.Parameters["@CustomerId"].Value = 1;

Makalenin ayrıntıları için lütfen tıklayınız.