Meltdown & Spectre Zafiyetlerinin Detaylı Analizi - Part I Meltdown
1.
Giriş
Şekil 1 - Sırasıyla Meltdown ve Spectre zafiyetlerinin logoları. |
3 Ocak 2018 günü Google’ın Project
Zero ekibinden Jann Horn bilgi güvenliğini derinden etkileyecek bir çalışma yayımladı. [1] Bu çalışmada işletim sisteminin en temel kurallarından olan kullanıcı ile
çekirdek alanlarının veya süreç alanlarının birbirinden izolasyonunu, modern
işlemci mimarisindeki optimizasyon yöntemlerinden biri olan spekülatif yürütmeyi
suistimal ederek aşması yer alıyor ve toplamda 3 atak varyasyonu anlatılıyor.
Bunlardan ikisine Spectre ve diğerine de Meltdown ismi verildi.
- Varyasyon 1: bounds check bypass (CVE-2017-5753) (Spectre)
- Varyasyon 2: branch target injection (CVE-2017-5715) (Spectre)
- Varyasyon 3: rogue data cache load (CVE-2017-5754) (Meltdown)
Geçen yıl Haziran ayında bahsi geçen
atak yöntemleri hakkında Intel, AMD, ve ARM firmaları bilgilendirildi. Kamu
aydınlatılma için geri sayım bitmeden önce ise bir araştırma ekibi de ilgili
zafiyetler ile alakalı makaleler yayımladı. [2][3]
Meltdown ve Spectre zafiyetlerini
derinlemesine anlatmaya çalışacağımız yazı dizisinin ilkinde, bizce
anlaşılırlığı arttırmak için hakim olunması gereken konseptler ile ilgili bilgi
vereceğiz. Bunlar modern işlemci ve spekülatif yürütme, ön bellek teknolojisi
ve yan kanal atakları (eğer ilgili konseptlere zaten hakim olduğunuzu
düşünüyorsanız, 4. başlıktan devam edebilirsiniz). Ardından Meltdown zafiyetinin
modern işlemci mimarisindeki suistimal ettiği durumu ve yetkisiz bir kullanıcı
olarak çekirdek alanından nasıl veri okunabileceğini göstereceğiz.
2.
Sözlük
Bu yazıda aşağıda belirtilen İngilizce terimler yerine Türkçe karşılıkları
kullanılacaktır:
- Cache: Ön bellek
- Cache hit: Ön bellek isabeti
- Cache miss: Ön bellek kaybı
- Process: Süreç
- Speculative execution: Spekülatif yürütme
- Out of order execution: Sırasız yürütme
- Side channel attack: Yan kanal atağı
- Kernel space: Çekirdek alanı
- User space: Kullanıcı alanı
- Process space: Süreç alanı
- Instruction: Komut
- Instruction queue: Komut sırası
- Architectural stage: Mimari durum
- Micro-architectural stage: Mikro mimari durum
- Scaler processor: Ölçekleyici işlemci
- Super scaler processor: Süper ölçekleyici işlemci
- Read only memory: Salt okunur bellek
3.
Gerekli
Konseptler
İlgili zafiyetler bilgisayar
sisteminin alt seviye teknolojilerini suistimal etmektedir. Mümkün olduğunca
siz okuyucuların akıllarında Meltdown ve Spectre ile alakalı soru işareti
bırakmamaktır bu yazının esas amacı. Amacımıza ulaşmak için de sırasıyla yan kanal
atakları, ön bellek teknolojisi, modern işlemci ve spekülatif yürütmeyi kısaca
anlatmaya çalışacağız.
3.1. Ön Bellek
İşlemci hızı ile bir verinin bellekten okunma hızının yaklaşık bir değer olduğu zamanlar, bir komutu çalıştırabilmek için gerekli verinin bellekten okunması bir performans sorunu değildi. Moore yasasının da öngördüğü gibi [4] yıllar geçtikçe aradaki fark daha da büyüdü. Bundan dolayı, artık bir komut için gerekli verinin bellekten okunması yüzlerce işlemci döngüsüne denk düşer hale geldi. Mümkün olduğunca bellekten okuma işlemlerinin seyrekleştirilmesi için, ön bellek adı verilen işlemciye yakın birimler geliştirilmiştir. Programın sıklıkla bellekte eriştiği, devam eden akışında da erişmesi muhtemel görünen veriler, komple blok halinde bellekten direk bu birime aktarılır. Böylece işlemcinin gerekli verilere çok daha hızlı bir şekilde ulaşması sağlanır.
Şekil 2 - Intel ön bellek hiyerarşisi. L1 ve L2 ön bellekleri işlemci çekirdeklerine özel iken, L3 ön belleği bütün çekirdekler arasında paylaşılır. |
Şekil 2’de görüldüğü gibi, modern Intel işlemcileri 3 seviye ön belleğe sahiptir: L1, L2 ve L3. L1 ön belleği en küçük, işlemciye en yakın olmasından dolayı da en hızlı ön bellektir. L2 orta seviye ön bellek olarak adlandırılır ve L1’den kat ve kat daha büyüktür. L3 ise en büyük ve en yavaş ön bellektir ve işlemci çekirdekleri tarafından paylaşılır [5]. İşlemcinin çalıştırdığı komutların veya ihtiyaç duyduğu verinin ön bellekte bulunması ön bellek isabeti olarak adlandırılır. Bulunmama durumuna ise ön bellek kaybı denir ve bellekten gerekli veri çekilir. Bahsedilen iki kavramın arasında ciddi zamansal farklılıklar gözlenmektedir.
3.2.
Yan
Kanal Atağı
Algoritmadaki zayıflıklar yerine
bilgisayar sisteminin fiziksel durumundaki farklılıklardan çıkarılan bilgilere
dayanan bir atak türüdür. Intel’in ocak ayında yayınladığı raporda da
belirtildiği gibi; bu atak türü mikro mimari özelliklerini ölçmek gibi, sistemi
gözlemleyerek çalışır [6]. Doğrudan programın akışına müdahale etmez. Asıl
amacı ise; mikro ölçekte gerçekleşen durum değişikliklerini mimari ölçeğe
taşımak ve böylece hedeflenen veriyi ele geçirmektir. Güç tüketimi, ses ve
zamana bağlı ölçümler sistemleri istismar etmek için kullanılabilir [7].
Ön bellek yan kanal atakları
saldırganın ön bellek kullanımını izleyebilmesine bağlıdır. Flush+Reload isimli
teknikte, L3 paylaşımlı ön bellek hedef alınır [8]. Paylaşımlı olduğu için,
hedef süreç ile aynı işlemci çekirdeğini kullanmak dahi gerekli değildir.
İki sürecin kullanacağı ortak programlar var ise, bu programlar belleğe 2.
kez yüklenmez ve aynı adresler ortaklaşa kullanılır. Ortak kodlar salt okunur
bellekte bulunduğu için, iki süreç de birbirini etkileyemez. İlgili teknik
ile saldırganın amacı ise, hedef sürecin hangi kod bloklarını
çalıştırdığını saptamaya çalışmak. Bu atak 3 adımdan oluşur:
- Saldırgan L3 ön belleğinde bulunan kontrol kod bloklarını yok eder,
- Ardından belli bir süre beklemeye geçer,
- Yeterince bekledikten sonra kontrol kod bloklarını çekmeye çalışır ve toplamda geçen süreyi esas alarak hedef sürecin bekleme zamanında bu bloğu kullanıp kullanmadığını tespit etmeye çalışır.
Eğer hedef süreç bekleme
zamanında bu kod bloklarını çalıştırdıysa, ön bellek kaybı durumu ortaya çıkar
ve bellekten çekmesi gerekir. İlgili kod bloğu paylaşılan ön bellek alanında
depolanır. Saldırganın ilgili kod bloğunu çekme süresi kısa sürerse, hedef
sürecin bekleme zamanında bu bloğu çalıştırdığı anlaşılır. Eğer uzun
sürerse, bu kodların ön bellekte bulunmadığı yani sürecin bunları
çalıştırmadığı anlaşılır.
3.3. Spekülatif Yürütme
Her bir işlemci döngüsünde 1 komut
çalıştıran işlemci türüne ölçekleyici işlemci denir [9]. Bu işlemci türü modern
işlemcilerin en basit halidir. Süper ölçekleyici isimli tür ise her bir işlemci
döngüsünde birden fazla komut çalıştırabilme yeteneğine sahiptir. Sıralı süper
ölçekleyici işlemciler, gelen komutların gerekliliklerine bağlı olarak analiz
edip bunları eş zamanlı yürütmeye çalışır. Böylece işlemci saat hızı artışı
belli bir oranda devam etse dahi, genel performans anlamında büyük bir artış sağlanmış
olur. Sırasız işlemciler gelen komutları gerekliliklerine bağlı olarak
sırasız olarak çalıştırabilir. Yani sıradaki komut için gerekli olan
hesaplamalar veya bellekten gelmesi gereken veriler beklenirken, sonradan
çalışması gereken komutları çalıştırabilir ve böylece maksimum paralelleşme sağlanır.
Bu tip işlemcilerde bir komut sırası yapısı vardır. Gelen komutlar çözümlenmelerinin
ardından komut sırasına girerler ve gereklilikleri sağlanana kadar beklerler.
Sağlandıktan sonra da ilgili işlem birimlerine geçerler. Peki sıradaki komut
hali hazırda belli olmayan bir değere bağlı olarak programın akışını
dallandıracaksa (‘if’ sorguları, döngüler), işlemci nasıl bir yol izlemeli?
Spekülatif yürütme optimizasyonu böyle durumların önüne geçmek ve gene
performans artışı sağlamak amacıyla geliştirilmiştir. Bu optimizasyonda işlemci
sofistike hesaplamalar yaparak programın muhtemelen devam edeceği dallanmayı
tahmin etmeye çalışır ve buna bağlı olarak ihtiyaç duyulacağı kesinleşmemiş komutları
çalıştırmaya başlar. Eğer yaptığı tahmin doğru çıkarsa hesapladığı sonuçları alarak
programın akışına devam eder. Ama dallanmayı yanlış tahmin etmişse hesaplanan
verileri yok sayar akışa doğru yoldan devam eder. İhtiyaç duyulmayan komutların
çalıştırılması elbette gereksiz bir enerji tüketimi manasına geliyor. Fakat
geneline vurduğumuzda kazanılan performans çok fazla olduğu için, bu kriter göz
ardı edilir.
Bir komutun emekli olması için
öncelikle gerekli tüm hesaplamalarının yapılması ve sonuçlarının elde edilmesi
gerekir. Ardından ilgili komut ile alakalı bir hata oluşup oluşmadığı kontrol
edilir. Hatanın olmadığı durumlarda komut emekli olur ve sonuçları da işlemcinin
mimari durumunu değiştirir [10]. Bir hata ile karşılaşılırsa eğer, hesaplanan
veriler ve o esnada komut sırasında bekleyen diğer komutlar yok sayılır ve hata
ile ilgili programın kendisinden veya yoksa işletim sisteminden o hatayla
alakalı bölüm çalıştırılır [11]. Böylece o komut emekli olamaz ve sonuçları
işlemcinin mimari durumunu etkilemez. Fakat mikro ölçekte bu sonuçlar
farklılıklar oluşturabilir. Bellekten çekilen verilerin ön bellekte depolanması
buna bir örnektir. Yetkisiz bir sürecin çekirdek alanından veri çekmesi program
akışında hatanın oluşmasına neden olur. İlk önce istenilen veri çekilir.
İşlemcinin mimari düzeyini değiştirmeden yani komut emekli olmadan hata olup
olmadığı kontrol edilir. Ve bu aşamada, çekirdek alanından yetkisiz bir şekilde
veri okunmaya çalışıldığı anlaşılır ve hata oluşur.
Hata kontrolünden önce çekirdek
alanından okunan veri, çalışabilmek için bu veriye ihtiyaç duyan komutlara
sağlanır. Bu komutların çalışmaya başlaması ile, yetkisiz çekirdek alanından
veri çekme kaynaklı program akışından hata oluşması arasındaki sürede, çekilen
veri kullanılarak mikro düzeyde durum değişikliklerine neden olunabilir. Böylece
yan kanal ataklarına ortam hazırlanmış olur.
4.
Meltdown
Meltdown, işlemci mimarisindeki
performans optimizasyon teknolojilerini suistimal ederek haritalandırılmış
çekirdek alanından veri okumaya imkan veren donanımsal bir zafiyettir. Yazılımdan bağımsız
bir zafiyet olduğu için hem Windows hem de Linux işletim sistemlerinde çalışır,
kişisel bilgisayarlar ve bulut sistemlerini de etkiler.
Meltdown toplamda
3 adımdan oluşur:
- Saldırganın yetkisi dahilinde olmayan bir alandan veri çekilir,
- Bu veri kullanılarak işlemcinin mikro mimari durumunda değişiklik meydana getirilir,
- Yan kanal atağı yöntemi kullanılarak mikro mimari durumdaki değişiklik mimari duruma taşınır, böylece gizli bilgi erişilebilir hale gelir.
Saldırganın saldırıyı gerçekleştirebilmesi
için hedef sistemde yetkisiz kod çalıştırabiliyor olması gerekmektedir. Sisteme
fiziksel olarak erişimi ise gerekli değildir.
Şekil 3 - Meltdown zafiyetinin detaylarını incelemek amacıyla örnek olarak kullandığımız assembly komutları. Meltdown makalesinden [2] alınarak düzenlenmiştir. |
Şekil 3’te mov komutu ile ilgili adreslerden verilerin
çekilmesi, shl komutu ile de ilgili değerde sola kaydırma amaçlanmıştır. Yetkisiz bir kullanıcı tarafından çalıştırıldığında
ilk olarak 4. satırdaki mov komutu işlemci tarafından çözümlenir ve komut
sırasına alınır. Gereklilikleri sağlandığında, ilgili adresten veri istenir. Ön
bellek isabeti veya kaybı durumlarına göre, istenilen veri ön bellekten veya
bellekten temin edilir. Veri işlemciye ulaştığında, herhangi bir hata oluşup
oluşmadığının kontrolünden önce (ki yetkisiz bir şekilde çekirdek alanından
veri okunduğu için hata oluşacaktır) bu veriye ihtiyaç duyan ve spekülatif
olarak çalışmayı bekleyen komutlara ulaştırılır. Hata kontrolünün yapılmasından
önce gerekli işlemler yapılırsa, çekirdek alanından çekilen veri işlemci mikro
mimari durumunu etkileyebilir ve yan kanal atağına uygun bir ortam oluşturur. O
aşamada Flush+Reload yöntemi kullanılarak, ön bellekte hangi verinin
depolandığını hassas ölçümler yaparak tespit edip, veriler ele geçirilmiş olur.
Flush+Reload atağının kullanılabilmesi
için, öncelikle kullanıcı alanından okunacak verinin ön bellekte bulunmaması
gerekir. Çalıştırılan komutlar sonrasında ön bellekte depolanan verinin izinden
giderek çekirdek alanındaki gizli veriyi ele geçirebiliriz. Gizli veri
kullanılarak kullanıcı alanından veri çekilmesi sırasında (9. satır) ön bellek
kaybı oluşacaktır ve veri bellekten istenecektir. Sonradan ihtiyaç duyulması halinde
daha hızlı erişebilmek adına işlemci bu veri bloğunu ön belleğe depolayacaktır.
Buradaki önemli nokta; gizli veri ile kullanıcı alanından adres hesabı yaparken
oluşacak adreslerin aynı sayfa içerisinde yer almalarını önlemek. Çünkü eğer
aynı sayfa içerisinde yer alırlarsa, Flush+Reload kullanarak ön bellekte hangi
verinin depolandığını tespit etmeye çalıştığımızda, veri blok halinde
depolandığı için, başarısız oluruz. Onun için 8. satırdaki komutu
çalıştırıyoruz. Eğer işlemcinin 4. satırdaki komut ile alakalı hata kontrolü
yapmasından önce bu işlemleri yapabilirsek, işlemciyi mikro düzeyde etkilemiş
oluruz (ön bellekte veri depolanması). Hata kontrolünün ardından bütün komut
sırası ve elde edilen veriler yok sayılıp hata ile ilgili kod bloğu
çalıştırılmaya başlanacaktır. Yani 8. ve 9. satırdaki komutların çalışmasına
ihtiyaç duyulmayacaktı. İşlemcide spekülatif yürütme optimizasyonu olmasaydı,
ihtiyaç duyulup duyulmayacağı belli olmayan komutlar çalıştırılmayacaktı,
dolayısıyla atağımız başarısız olacaktı.
Bu aşamada, ön bellekte gizli veriye
bağlı bir adresin verisi depolanmıştır. Ön bellekte depolanan veriyi tespit
ettiğimizde, gizli veriye bağlı olduğu için otomatik olarak gizli veriyi de tespit
etmiş oluyoruz. Böylece sistemin çekirdek alanından yetkisiz bir şekilde bilgi
okumuş oluyoruz. Bu işlem farklı adresler ile tekrarlandığında (4. satırdaki
adres), haritalandırılmış bütün çekirdek alanını yani dolayısıyla bütün parola bilgilerini, kredi kartı bilgilerini, şifreleme anahtarlarını ve diğer hassas
verileri ele geçirmiş oluyoruz.
Araştırma grubunun test maksatlı
yaptığı saldırıda maksimum 503 KB/s okuma hızına ulaştığı belirtilmiş. Ayrıca
yapılan testlerde, konteyner teknolojilerinde (Docker, LXC, OpenVZ vs.)
başarılı sonuçlar elde edilmiştir. Ortak çekirdeği paylaşan konteynerlerin
birinden yapılan saldırıda, sadece çekirdek alanı değil, diğer konteynerlerin
de verilerine ulaşılabilmiş.
5.
Meltdown’a
Karşı Önlemler
İşletim sistemi çekirdeğini hedef
alan ve yan kanal ataklarına karşı geliştirilmiş olan KAISER sistemi, çekirdek
ile kullanıcı alanlarının izolasyonunu kuvvetlendirir ve bu tip ataklara karşı
koruma sağlar. İşlemci kullanıcı modunda iken, donanımın çekirdek adresleri ile
ilgili herhangi bir bilgi tutmamasını sağlar [12]. Başka bir deyişle, kullanıcı
alanına x86 mimarisinin birkaç ihtiyacı harici, çekirdek alanının
haritalandırılmasını engeller. Araştırma ekibinin yayınladığı makalede, KAISER
sisteminin kazara Meltdown ataklarına karşı da güvenlik sağladığı belirtiliyor.
Bu güvenlik sisteminin, Linux’e “Kernel page-table isolation” adı ile
geleceğini ve Windows ve Mac OSX için de benzer güncellemelerin geleceğini
kaydediyor.
KAISER koruma sağlasa da x86
mimarisinin dizaynından dolayı, birçok çekirdek alanının kullanıcı alanından
erişilmesi gerekmektedir. Yani bu durum Meltdown’a atak yüzeyi kazandırmış
oluyor.
Intel yayınlamış olduğu dokümanda,
bu zafiyet için yazılımsal modifikasyonlar yapılmasını öneriyor. Spekülatif
yürütmenin durdurulması gereken yerlerde LFENCE komutunun kullanılması
gerektiğini belirtiyor. Linux çekirdeği üzerinde statik analizler yaptıklarını
ve spekülatif yürütme bariyerinin ihtiyaç duyulduğu birçok bölüm bulduklarını
da ayrıca ekliyorlar.
6.
Referanslar
[1].
https://googleprojectzero.blogspot.com.tr/2018/01/reading-privileged-memory-with-side.html?m=1
[2].
https://meltdownattack.com/meltdown.pdf
[3].
https://spectreattack.com/spectre.pdf
[4]. https://en.wikipedia.org/wiki/Moore%27s_law
[5]. https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/cache-allocation-technology-white-paper.pdf, Improving Real-Time Performance by Utilizing Cache Allocation Technology
[6].
https://newsroom.intel.com/wp-content/uploads/sites/11/2018/01/Intel-Analysis-of-Speculative-Execution-Side-Channels.pdf,
Intel Analysis of Speculative Execution Side Channels
[7].
https://en.wikipedia.org/wiki/Side-channel_attack
[8].
https://eprint.iacr.org/2013/448.pdf,
FLUSH+RELOAD: a High Resolution, Low Noise, L3 Cache Side-Channel Attack
[9].
https://www.raspberrypi.org/blog/why-raspberry-pi-isnt-vulnerable-to-spectre-or-meltdown/
[10].
https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf
[11].
https://cyber.wtf/2017/07/28/negative-result-reading-kernel-memory-from-user-mode/,
Negative Result: Reading Kernel Memory From User Mode
[12].
https://gruss.cc/files/kaiser.pdf,
KASLR is Dead: Long Live KASLR
Mert Değirmenci
Cyber Security Expert
CRYPTTECH - Cyber Security Intelligence
Cyber Security Expert
CRYPTTECH - Cyber Security Intelligence
Yorumlar
Yorum Gönder