Üstveri servisi, SSRF ve IMDSv2
- Bulut makinesi kimliğini 169.254.169.254 üstveri servisinden alır; IMDSv2 ve pod çıkış kuralı, SSRF'in bu adrese uzanan yolunu kapatır.
- Sunucu tarafı istek sahteciliği bu adrese ulaşırsa geçici anahtarlar dışarı çıkar.
- IMDSv2 jeton şartı, sıçrama sınırı ve pod çıkış kuralı bu zinciri kırar.
Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +60 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.
Bir bulut makinesi, rolünün anahtarlarını üstveri servisinden alır. Bu derste servisin neden var olduğunu, bir SSRF açığı bu servise ulaştığında neden ağır sonuç verdiğini ve bu riski kapatan ayarları görürsün. IMDSv2 jeton şartını, sıçrama sınırını, pod çıkış kuralını ve tespit ölçütlerini tek tek tanırsın.
Dersin sonunda aynı açığın bulutta neden ofis ağından çok daha ağır olduğunu ve bu farkı hangi ayarların kapattığını açıklayabilirsin. Komutları yalnız kendi lab makinende ya da yazılı iznin olan bir hesapta dene.
Üstveri servisi neden var
Bulut makinesi rolünün anahtarlarını nereden alır? Diskte bir dosyadan değil, bağlantı yerel bir adresten. 169.254.169.254 adresi yalnız o makinenin içinden erişilir ve makinenin kendi kimliğini döner. Bu tasarım kalıcı anahtar taşıma sorununu çözer: makineye uzun ömürlü bir anahtar gömmek yerine, makine kimliğini bu uçtan geçici olarak alır.
Anahtarlar kısa ömürlüdür ve kendiliğinden döner, bu yüzden diske yazılı sabit bir anahtardan daha güvenlidir. Yani servis aslında bir güvenlik iyileştirmesidir; sorun, bu kolaylığın yanlış ellerde nasıl kullanıldığından çıkar.
Adres tesadüf değildir. 169.254.169.254 bağlantı yerel (link-local) aralıktandır ve yönlendiriciler bu aralıktaki paketleri ağın dışına taşımaz. Bu yüzden servise gelen her istek o makinenin içinden gelir.
Servis ayrıca kimin sorduğunu sormaz; adrese ulaşan her yerel süreç aynı yanıtı alır. Azure belgesi bunu açıkça yazar: üstveri servisi hassas veri kanalı değildir, kimlik doğrulamasızdır ve makinedeki her sürece açıktır. Bu yüzden savunma adres düzeyinde değil, protokol düzeyinde kurulur ve oraya ulaşabilen her açık ciddiye alınır.
Bu tasarımın bir yan etkisi vardır. Makinenin içinden atılan her istek, makinenin kimliğiyle konuşur. Bir uygulama kullanıcının verdiği bir adrese istek atıyorsa, o adres üstveri servisi olabilir.
Sunucu tarafı istek sahteciliği, yani SSRF, tam burada devreye girer: saldırgan uygulamaya bir iç adres yazdırır, uygulama isteği kendi ağından, kendi kimliğiyle atar. Hedef bir iç yönetim paneli olabilir, ya da bu üstveri adresi olabilir. Fark şudur: iç panel bir bilgi sızdırır, üstveri adresi ise makinenin bulut anahtarlarını sızdırır.
IMDSv1'de bu istek düz bir GET çağrısıdır. Bu yüzden yalnız adres verebilen, başlık ekleyemeyen bir açık bile yanıtı okuyabilir. IMDSv2 tam da bu noktayı hedefler. Bu yüzden bir SSRF bulgusunun ciddiyetini ölçerken önce makinenin hangi sürüme izin verdiğine bakarsın.
Savunmanın hangi halkayı kırdığını anlamak için zinciri bilmek gerekir. Sonraki bölümde bu halkayı kıran ayarı kendi lab makinende uygularsın; IMDSv2 zorunlu olduğunda jetonsuz istek artık yanıt almaz.
Etkinlik 1 / 6
IMDSv1 açık bir makinede bu istek ne döner?
Önce kodu oku, sonra çıktıyı seç.
$ curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
IMDSv2: jeton şartı
İkinci sürüm, yani IMDSv2, erişimi iki adıma böler. Önce PUT yöntemiyle bir oturum jetonu alınır ve istekte jetonun ömrünü söyleyen bir başlık zorunludur. Sonra veri uçları bu jetonu bir başlıkta taşıyarak çağrılır.
IMDSv2 zorunluysa jetonsuz ya da süresi dolmuş jetonla gelen çağrı 401 Unauthorized yanıtı alır. Jetonun ömür tavanı altı saattir, yani 21600 saniye, ve jeton yalnız üretildiği makinede geçerlidir; başka makinede kullanılamaz. Bu iki adım küçük görünür ama basit SSRF zincirini kırmaya yeter, çünkü çoğu açık bu adımları atacak esnekliğe sahip değildir.
# 1) Jeton al (PUT + zorunlu ömür başlığı, en çok 21600 saniye) JETON=$(curl -sX PUT "http://169.254.169.254/latest/api/token" \ -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") # 2) Veriyi jetonla sor curl -s -H "X-aws-ec2-metadata-token: $JETON" \ http://169.254.169.254/latest/meta-data/iam/security-credentials/
Korumanın mantığı basit. SSRF açıklarının çoğu yalnız GET yollar ve özel başlık ekleyemez; birçoğu PUT bile gönderemez. IMDSv2'nin PUT artı başlık şartı bu basit zinciri kırar. Üstelik servis, X-Forwarded-For başlığı taşıyan PUT isteklerini reddeder; bu başlık isteğin bir ters vekil ya da yanlış yapılandırılmış bir güvenlik duvarı üstünden iletildiğini gösterir.
Üstveri servisi yalnız kimlik de dağıtmaz: makinenin kullanıcı verisi alanı da aynı adresten okunur ve çoğu zaman açılış betiklerini taşır. Betikte parola ya da özel depo adresi varsa aynı zincir onu da çıkarır, bu yüzden o alana sır yazmamak ayrı bir kuraldır.
Etkinlik 2 / 6
Kendi laboratuvar makinende izin verilen en uzun ömürlü, yani altı saatlik IMDSv2 oturum jetonunu iste. Ömür başlığına saniye cinsinden değeri yaz.
İsteği tamamla ve gönder.
Geçişin yazılım tarafı genelde sanıldığından kolaydır. Güncel AWS SDK'ları ve AWS CLI üstveriye varsayılan olarak IMDSv2 ile gider ve jeton adımını kendisi yapar. Kırılan çoğunlukla eski bir SDK sürümü ya da elle yazılmış bir curl betiğidir.
Jeton ömrünü uzun tutmak riski de uzatır, çünkü çalınan bir jeton tavan süresi boyunca geçerli kalır. Yine de asıl koruma ömürde değil, jetonun PUT ile alınması ve her istekte başlıkta taşınması şartındadır.
Etkinlik 3 / 6
IMDSv2'nin sunucu tarafı istek sahteciliğine karşı asıl koruması nedir?
Derinleş:Açık mı, zorunlu mu
IMDSv2'yi açmak ile zorunlu kılmak aynı şey değildir. Makinenin üstveri ayarında http-tokens değeri optional ise iki sürüm birlikte çalışır: jetonlu istek IMDSv2 gibi işlenir, jetonsuz GET ise eskisi gibi yanıt alır. Bu modda koruma yoktur, çünkü jetonsuz yol hâlâ açıktır.
Zinciri yalnız required değeri kapatır. Geçişi güvenle yapmak için önce CloudWatch'taki MetadataNoToken ölçütünü izlersin. Bu ölçüt jetonsuz çağrıları sayar ve sıfıra indiğinde hiçbir yazılımın birinci sürüme muhtaç olmadığını gösterir.
required moduna geçtikten sonra MetadataNoTokenRejected ölçütü reddedilen çağrıları sayar ve kırılan bir yazılımı hemen gösterir. Varsayılan ayar hesap düzeyinde de yapılabilir. Böylece yeni açılan her makine baştan IMDSv2 zorunlu gelir; zorlama açıksa IMDSv1 açık bir makine hiç başlatılamaz.
Katmanlı savunma
Jeton şartı ilk katmandır, ama tek başına bırakılmaz. İkinci ayar sıçrama sınırıdır. IMDSv2'de jeton yanıtının IP paket ömrü varsayılan olarak birdir. Konteyner ağı, makineye göre fazladan bir sıçrama sayılır; bu yüzden konteynerden gelen jeton isteğinin yanıtı yolda düşer ve konteyner jeton alamaz.
Ana makinedeki süreç ise jetonunu alır ve çalışmaya devam eder. Bazı kurulumlarda konteynerler kırılmasın diye bu değer ikiye çıkarılır, bu yüzden denetimde değeri ayrıca kontrol edersin. Bulut tarafında jeton şartı ve sıçrama sınırı tek komutla birlikte yazılır ve değişiklik makineyi yeniden başlatmadan geçerli olur.
# IMDSv2'yi zorunlu kıl ve konteyner erişimini kes (sıçrama = 1) aws ec2 modify-instance-metadata-options \ --instance-id i-0abc123 \ --http-tokens required \ --http-put-response-hop-limit 1
Üçüncü katman kümededir. Pod ağından 169.254.169.254 adresine çıkışı bir ağ politikasıyla kapatırsın ve her iş yüküne hizmet hesabı üstünden kendi bulut rolünü verirsin. Aksi halde her pod, düğüm rolünün yetkilerine erişir ve bir pod ele geçtiğinde o rol de ele geçer.
Savunmayı yalnız üstveri tarafına yaslamak da eksik kalır; asıl açık uygulamadadır. Dışarıya istek atan uçlarda hedef adresler bir izin listesiyle sınırlanır ve bağlantı yerel adres aralıkları reddedilir. Kara liste yerine beyaz liste kullanmak, açık yönlendirme ve ad çözümü hileleriyle atlatmayı zorlaştırır; çünkü beyaz listede olmayan her adres baştan reddedilir.
Uygulama tarafındaki kontrolü kurarken birkaç bilinen atlatmayı da hesaba katmak gerekir. Saldırgan bir adresi farklı yazımlarla gizleyebilir, kendi alanını bağlantı yerel bir IP'ye çözdürebilir ya da uygulamayı önce güvenli bir adrese, sonra bir yönlendirmeyle iç adrese gönderebilir. Bu yüzden kontrol yalnız ilk adresi değil, yönlendirme sonrası ulaşılan son adresi de denetler ve ad çözümünün sonucunu da bağlantı yerel aralığa karşı sınar. Bir uygulamanın dışarıya istek atan her ucu bu gözle gözden geçirilir; çünkü tek bir denetlenmemiş uç, bütün katmanlı savunmanın girişini açar.
Etkinlik 4 / 6
Yetkili bir testte üstveri servisi üstünden ilerleyen saldırı zincirinin adımlarını sıraya koy.
Bir öğeye odaklan, yukarı ve aşağı ok tuşlarıyla taşı. Home tuşu en üste, End tuşu en alta alır.
- 1Anahtarların yetkisi sts ve iam sorgularıyla çıkarılır
- 2Rolün geçici anahtarları alınır
- 3Bağlı rolün adı okunur
- 4Uygulamada dışarıya istek atan bir uç bulunur
- 5İstek bağlantı yerel üstveri adresine yönlendirilir
Zinciri gördükten sonra önlemleri iki gruba ayırırsın. Bir grup önlem isteği baştan engeller ve anahtara hiç ulaşılmasın diye kapıyı kapatır; jeton şartı bu grubun en bilinen örneğidir. Öteki grup, istek bir şekilde geçse bile zararı küçültür; bir rolün yetkisini kısmak bu türdendir.
İkisini birlikte kurarsın, çünkü hiçbir tek önlem her ortamda kusursuz değildir. Bir ortamda jeton şartı eski bir yazılım yüzünden ertelenmiş olabilir, bir başkasında rol gereğinden geniş kalmış olabilir.
Etkinlik 5 / 6
Her önlemi zinciri kırdığı noktaya göre ayır.
Önce bir seçeneğe, sonra aşağıdaki uygun kutuya bas. İstersen seçeneği kutuya sürükleyip bırak. Yerini değiştirmek için aynı işlemi tekrarla.
0/5 seçenek yerleşti.
Bulut farkları ve tespit
Aynı kavram öteki bulutlarda farklı başlıklarla kurulur. Azure üstveri servisi Metadata değeri true olan bir başlık ister ve X-Forwarded-For taşıyan isteği reddeder. Google Cloud ise Metadata-Flavor değeri Google olan bir başlık zorunlu kılar ve aynı biçimde ara sunucudan geçmiş istekleri reddeder.
Üçünde de mantık aynıdır: basit bir GET'in asla kendiliğinden eklemeyeceği özel bir başlık şart koşulur ve bu, kör SSRF zincirini kırar. Bu yüzden bir uygulamayı denetlerken hangi bulutta çalıştığını bilmen gerekir; savunmanın özü aynı olsa da başlık ve komut adları değişir.
Tespit katmanı da kurulur. Bir makine rolünün geçici anahtarlarının makine dışından kullanılması güçlü bir sinyaldir. Amazon GuardDuty bu kalıbı UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration bulgusuyla işaretler.
Bulgunun OutsideAWS türü anahtarın AWS dışındaki bir adresten, InsideAWS türü başka bir AWS hesabından kullanıldığını söyler. MITRE ATT&CK bu tekniği T1552.005, Cloud Instance Metadata API başlığıyla kaydeder. Son halka etki daraltmadır: makineye bağlı rolün yetkisi darsa, çalınan anahtarın değeri de düşük olur.
Bir uygulama açığını değerlendirirken bulut bağlamını da hesaba katarsın. Aynı SSRF, ofis ağındaki bir sunucuda orta dereceli kalırken bulut makinesinde hesap devralmaya çıkabilir. Derece, açığın kendisinden çok içinde bulunduğu ortamdan gelir.
Zincirin her halkasında bir önlem varsa, tek bir açık hesabın tamamını açmaz; işte katmanlı savunmanın değeri buradadır. Jeton şartı, sıçrama sınırı, pod çıkış kuralı, dar rol ve tespit; her biri ayrı bir halkayı kırar ve birlikte zinciri koparır. Bir denetimde bu halkaları tek tek sorgular, hangisinin eksik olduğunu bulur ve raporunu o eksik halka üzerinden kurarsın; çünkü en zayıf halka, zincirin gerçek direncini belirler.
Etkinlik 6 / 6
Doğru mu, yanlış mı?
Kubernetes'te hizmet hesabına IAM rolü bağlamak, düğüm rolüne yaslanmaktan daha dar bir yetki verir.
Okumayı istediğin sırayla sürdürebilirsin. Ders, bütün etkinlikleri cevapladığında tamamlanır.