Web Güvenliği Perpekstifinden Meltdown ve Spectre Zafiyetleri, phpMyAdmin'de CSRF Var Mıydı Yok Muydu?

Invicti Security Team - 08 Ocak 2018 -

Bu yazımızda CPU larımızınde derdi Spectre&Meltdown zafiyetlerinden ve CSRF diye başlayıp HTTP Verb Tampering ile sonlanan bir phpMyAdmin zafiyetinden bahsedeceğiz.

Web Güvenliği Perpekstifinden Meltdown ve Spectre Zafiyetleri, phpMyAdmin'de CSRF Var Mıydı Yok Muydu?

2018'e tüm kullanıcıları şoke eden bir gelişme ile girdik. Google 3 Ocak tarihinde yayınladığı blog postta Google Project Zero ekibinin haziran ayında CPU üreticileri ile paylaştığı ve neredeyse 1995 yılından bu yana üretilen tüm CPU'ları (ARM, AMD ve Intel) etkileyen iki zafiyeti duyurdu.

Spectre ve Meltdown zafiyetleri CPU'lar dışında bu CPU'lar üzerinde çalışan donanım ve işletim sistemlerini de etkiliyor.

Zafiyete sebep ise modern CPU'ların performans artışı için kullandıkları "Speculative Execution" adı verilen bir yöntem.

Google aslında açıklamayı 9 Ocak'ta yapmayı planlıyordu ancak artan spekülasyonlar nedeniyle 3 Ocak'ta, ayrıntıları daha sonra açıklayacağını belirterek kamuoyuna duyurdu.

Daha da kötüsü şu, Mozilla'nın resmi olarak doğruladığı şekilde Javascript yoluyla da kullanılabilecek bu saldırı vektörü sayesinde, web site ziyaretçilerinin bilgisayarındaki verilere ulaşabilmek mümkün.

Atak vektörü olarak Javascript'den bahsetmişken, web güvenliği perspektifinden olayı ele aldığımızda neler yapabiliriz? Web güvenliği, işletim sistemi hatta donanım seviyesindeki bir zafiyet için nasıl derde deva olur?

Şüphesiz böylesi bir atak vektörü XSS'in etkisini muazzam bir şekilde arttıracak. Sayfamızda XSS zafiyeti olduğunda, sayfamıza enjekte edilen kod sadece bizim sitemizde çalışıyor, bizim sitemizin DOM'una erişebiliyor, tabir-i caizse cürmü kadar yer yakıyor idi.

Fakat enjekte edilen kod Spectre ve Meltdown gibi bir zafiyetin istismarı için ise, yani sitemizde XSS zafiyeti dolayısıyla sayfamıza reflected ya da stored böyle bir kod mevcut ise, bu noktada artık hattı müdafaadan bahsedemeyeceğiz. Çünkü böyle bir enjeksiyon ziyaretçinin tüm browserında, tüm işletim sisteminde etkiye neden olacaktır.

Site sahipleri olarak, inline script çağrılarını ya da whitelist ettiğimiz kaynaklar dışındaki kaynaklardan script yüklenmesini Content-Security-Policy headerı ile engelleyebiliyoruz. Dolayısıyla, bir ekstra defans mekanizması olarak CSP'nin varlığı, XSS zafiyetine rağmen böylesi bir istismarı engelleyecekti. Fakat yine de unutmamak gerekiyor. CSP gibi defence-in-depth yani derinlemesine defans mekanizmaları elbette önemli olmasına rağmen zafiyetin ortaya çıktığı noktada, zafiyetin tabiatına uygun müdahale yapılmalı ve zafiyet derhal ortadan kaldırılmalıdır. XSS için söylersek, girdilerin kontrolü ve çıktıların kontekste uygun olarak encode edilmesi.

Zafiyetin ayrıntıları ve Mozilla'nın zafiyet hakkındaki açıklaması için lütfen tıklayınız.

HTTP Verb Tampering vs. CSRF: phpMyAdmin'de Ortaya Çıkan Zafiyet

phpMyAdmin, PHP tabanlı, MySQL veritabanları için web yönetim konsolu sunan bir script. 18 yıldır aktif olarak geliştirilen phpMyAdmin'de şüphesiz onlarca zafiyet tespit edildi. Ancak yazımıza konu olan zafiyet biraz daha ilginç. Öyle bir zafiyet ki uygulamanın 4.7.0 'dan önceki sürümlerinde ve fixlenen versiyon olan 4.7.7 ve sonraki sürümlerde yok. Neden mi? Hali hazırda CSRF zafiyetine karşı kodda olan "token" birden bire ortadan kaldırılıyor ve database'deki tüm kayıtları silmeye kadar varabilecek etkilere sebep olan CSRF zafiyeti ortaya çıkıyor. Üstelik token kaldırıldığı esnada geliştiricilerden birinin commit için yaptığı yorum ilginç ayrıntılar içeriyor.

phpMyAdmin'de CSRF Var Mıydı Yok Muydu -1

Resim: https://github.com/phpmyadmin/phpmyadmin/commit/dae3390a02ca6687fd31ca784474d56240c6c538

Önce zafiyete bir göz atalım.

Zafiyet hakkındaki detaylar, yine zafiyeti tespit eden Ashutosh Barot tarafından 20 Aralık 2017'de yayınlandı.

PoC konsept videosunda ayrıntılar pek anlaşılmıyor ama blog postun ayrıntılarında bunun yalınkat bir CSRF zafiyeti olmadığı, HTTP Verb Tampering 'in de bu zafiyette önemli bir rol oynadığını farkediyoruz.

HTTP Method Tampering Nedir?

Sanırım öncelikle HTTP Verb denilince ne anlamak gerekiyor ona değinmeliyiz. HTTP Verb'leri nam-ı diğer HTTP metotları, istek mesajının daha ilk satırında yer alan ve HTTP istekleriyle neyin murad edildiğini belirten kelimelerdir. Aslında hepimiz aşinayız: POST, HEAD, GET, OPTIONS, PUT, PATCH bunlar HTTP Verb'leridir. Yani HTTP mekanizmasının eylemleri.

HTTP'nin 0.9 versiyonunda sadece GET metodu vardı. 1999 yılında HTTP 1.1 spesifikasyonu ile protokole POST ve HEAD metodları dahil edildiler. PATCH'in spesifikasyonu girmesi ise biraz daha sonradır.

Güvenlik terminolojisine Verb Tampering adı ile giren hadise ise, İngilizce bir kelime olan Tamper'ın sözlük anlamından da anlaşılacağı üzere farklı metot varyasyonlarını deneyerek uygulama davranışındaki anomalileri tespit etmek. Hatta bu yöntemin spesifik olarak test edildiği ve araştırmalara konu edildiği alan olarak yetkilendirme sistemlerini gösterebiliriz. Nitekim Arshan Dabirsiaghi tarafından yayınlanan Bypassing Web Authentication and Authorization with HTTP Verb Tampering: How to inadvertently allow attackers full access to your web application. (Web Kimlik Doğrulama ve Yetkilendirme İşlemlerini HTTP Verb Tampering ile Atlatmak: Nasıl istemeden saldırganların web uygulamasına tam erişimine izin verirsiniz) başlıklı araştırma konunun ayrıntılarına ışık tutmaktadır.

<?php
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // Check if request is valid
        if($_POST["token"] != $_SESSION["csrf_token"]) {
            exit("Invalid token!");
        }
    }
 
 $username = $_REQUEST["username"];
 $password =  $_REQEST["password"];
 write_user_to_db($username, $password);
 ?>
 

Yukarıdaki kod bloguna bir göz atalım. Geliştricinin varsayımı bir POST isteği yapıldığında, token geçersiz ise bu isteği reddetmek yönünde. Fakat saldırgan istek metodunu yani POST olarak beklenen metodu GET olarak değiştiriyorsa? Açık ki CSRF için yapılan kontrolünün semtine bile uğramadan kod çalışmasına devam edecek, kullanıcı adı ve şifreyi veritabanına ekleyecektir.

Araştırmadan bir örnekle devam edelim. Aşağıda bir Java EE uygulamasına ait web.xml dosyasını görüyoruz:

 <security-constraint>
    <web-resource-collection>
        <url-pattern>/admin/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>admin</role-name>
    </auth-constraint>
</security-constraint>

/admin/ klasörü için erişim, sadece admin rolüne sahip kullanıcılar için kısıtlanmış durumda. Ama ayrıntıda gizli olan ise şu, yukarıdaki kontrol şayet bu klasöre yönelen istekler GET veya POST metodları ile yapılırsa geçerli. Peki ya spesifikasyonda GET ile aynı muameleye tutulması tavsiye edilen HEAD'ı kullanırsak? Ayrıntılar yazının devamında...

Maalesef geliştiriciler yukarıdaki gibi mekanizmaların implementasyonunda güvenli bir yol izlemiyorlar. Yani kısıtları tanımladıkları HTTP metotları dışında metot kullanan istekler için bir denetim ya da kontrol mekanizmaları yok. Oysa bu tarz kural dışı istekleri doğrudan reddetmeleri gerekiyor.

Bu tarz Verb ya da metot tampering işlemleriyle güvenlik mekanizmalarını bypass edebiliriz.

Basit bir yöntem olarak HEAD metoduna bir göz atalım. Spesifikasyona göre HEAD metodu, GET metodu ile aynı prosedürleri işletmelidir. GET ile HEAD metodu arasındaki tek fark, HEAD metodu ile istek yapıldığında kullanıldığında çağrılan kaynak response body'sine konulmak yerine, dönen HTTP yanıt mesajının body yani gövde kısmı boş bırakılmalıdır. Daha çok cache mekanizmalarının içerik kontrollerinde, istenen kaynak değişmiş mi, değişmemiş mi anlamak için kullanılıyor. Yanı sıra bir indirme yöneticisi (download manager), önce HEAD isteği ile hedef dosyanın boyut bilgilerini alarak, sonrasında dosyayı peyder pey talep edebilir. Konu dışı olduğu için daha fazla ayrıntıya değinmiyoruz.

Eğer bir uygulama işleyişinde, aşağıdaki üç nokta mevcutsa HTTP Verb Tampering saldırısına maruz kalabilir:

  • Eğer güvenlik kontrolleri, belirli HTTP metotları ile sınırlandırıldı ise
  • Bu listelenen güvenlik metotları için, beklenen değer dışında bir değer gelmesi durumunda bir fail-safe kod tanımlı değilse, yani bu istisnayı yönetmek için bir case düşünülmedi ise,
  • GET bildiğiniz gibi güvenli işlemler, yani arka tarafta bir state deşikliğine neden olmayan resourcelar için kullanılmalı. Buna uygun olmayan bir kullanım var ise ve arbitrary yani gelişigüzel metot kullanımları ile çalıştırılabiliyorsa. Üstelik bu gelişigüzel HTTP metotları örneğin ZYHN diye bir HTTP metodu kullandığımda, spesifikasyonda yer almayan bu metot GET metodu ile fallback ediliyorsa uygulama HTTP Verb Tampering saldırısına açık demektir.

Devam edelim…

phpMyAdmin arayüzünde, veritabanından bir tabloyu, ya da DBMS'dan bir veritabanını silmek istediğinizde, başka bir deyişle arayüzden Drop ya da Delete butonlarına basarak ilgili öğe ya da kaydın silinmesini istediğinizde aşağıdaki gibi bir istek gerçekleşiyor:

http://192.168.1.25/pma/sql.php?ajax_request=true&token=b6a6527a5805591d544fb66c84f30faf&server=1&get_default_fk_check_value=true&_nocache=1515335432843146723

phpMyAdmin'de CSRF Var Mıydı Yok Muydu -2

Yukarıdaki URL'de tokenlar var, hani CSRF'ten söz ediyorduk dediğinizi duyar gibiyim. Haklısınız, devam edelim.

Bir tabloyu silmek üzere olduğumuz ve gerçekten aklımızın başında olup olmadığı sorusunu OK diyerek onayladıktan sonra sunucu başka bir istekte bulunuyor. Bu defa bir POST isteği yapıyor:

phpMyAdmin'de CSRF Var Mıydı Yok Muydu -3

Dikkatinizi çekmiş olmalı istek bir POST isteği. Üstelik CSRF 'e karşı token değeri de içeriyor. Üstelik POST isteğinde bu token beklendiği gibi de çalışıyor. Nitekim token değerini yanlış göndermeye kalktığımızda alacağımız yanıt:

phpMyAdmin'de CSRF Var Mıydı Yok Muydu -4

Fakat burada bir şey daha dikkatinizi çekmiş olmalı. İstek bir POST isteği olmasına rağmen istek URL'i:

http://192.168.1.25/pma/sql.php?db=one&goto=db_structure.php&table=test&reload=1&purge=1&sql_query=DROP+TABLE+%60test%60&message_to_show=Table+test+has+been+dropped

Yani istekle beraber yapılacak işlem için gerekli olan tüm data Querystring olarak taşınıyor. Elbette ki bu durumda researcher'ın aklına HTTP Verb Tampering geliyor.

Kendi kontrolündeki bir siteye aşağıdaki kodu eklediğinde ve phpMyAdmin 'de oturum açmış bir kullanıcıyı da bu siteye girmeye ikna ettiğinde, database'de hedeflenen işlem gerçekleşiyor. Örneğimizde "test" tablosu veritabanından kaldırılıyor:

<img src="http://192.168.1.25/pma/sql.php?db=one&goto=db_structure.php&table=test&reload=1&purge=1&sql_query=DROP+TABLE+%60test%60&message_to_show=%3Cscript%3Ealert(1)%3B%3C%2Fscript%3E"/>

Buradaki zafiyet tam da sözünü ettiğimiz gibi bir HTTP Verb Tampering zafiyeti. phpMyAdmin geliştiricileri anti-CSRF mekanizmasını POST isteği üzerine kurmuşlar ve bir failsafe tanımlamamışlar. Yani CSRF token kontrolü şayet istek metodu POST ise yapılıyordu. Bekledikleri dışında bir metot ile aynı işlem tetikleneceği zaman bu operasyonu güvenli bir şekilde yönetememişler.

Şayet phpMyAdmin kullanıyorsanız zafiyetin fixlendiği 4.7.7 sürümüne geçmenizi öneririz.

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