İlk SSH bağlantısında, herhangi bir VPS veya bulut sağlayıcısında MITM saldırısını engellemek
(joachimschipper.nl)- ssh-init-vm, yeni bir VM’ye ilk SSH bağlantısında ortadaki adam saldırısını engellemek için cloud-init ile geçici bir SSH ana makine özel anahtarı enjekte eder ve uzun ömürlü ana makine anahtarı oluşturulup alınana kadar yalnızca buna güvenilmesini sağlar
- Hetzner Cloud gibi özel bağlantı koruma özelliği olmayan VPS veya bulutlarda da çalışır; gereken tek şey yaygın biçimde desteklenen cloud-inittir
- Yaygın Trust On First Use yaklaşımında
sshiçindeki “The authenticity of host [...] can't be established” sorusunayesyazılırsa, bir saldırgan trafiği proxy'leyebilir veya kullanıcıya kendi VM’siymiş gibi görünen bir makine sunabilir - Uzun ömürlü SSH ana makine özel anahtarını doğrudan cloud-init userdata içine koymak, ilk bağlantının doğrulanmasına yardımcı olur; ancak hassas anahtar materyali metadata servisi, SSRF, bulut sağlayıcısının sistemleri veya yönetici iş istasyonu üzerinden açığa çıkabilir
- ssh-init-vm, geçici anahtarı geçici bir dizinde tutar ve
~/.ssh/known_hostsiçine koymaz; ayrıca VM çıktısını olduğu gibi kaydetmez, uzun ömürlü anahtarı yazmak için OpenSSH’nin host key rotation mekanizmasına dayanır
cloud-init userdata ifşası sorunu
- cloud-init ile uzun ömürlü SSH ana makine özel anahtarı enjekte edilirse, açık anahtar
~/.ssh/known_hostsiçine konarak ilk bağlantı doğrulanabilir; ancak özel anahtar birden fazla yoldan sızabilir - VM içindeki rastgele bir süreç, genellikle okunabilir olan metadata servisi üzerinden userdata’yı alabilir; Hetzner VM’lerinde
http://169.254.169.254/hetzner/v1/userdataadresinde cloud-init içeriği görülebilir - Saldırgan, SSRF yoluyla bir sürecin metadata’yı sızdırmasını sağlayabilir; bu tür engellemeler, özel koruma özelliği olan ortamlarda bile her zaman uygulanmış olmaz
- cloud-init userdata, bulut sağlayıcısının diğer sistemlerinde de açığa çıkabilir; Hetzner, sunucu oluşturma API belgelerinde “passwords or other sensitive information” saklamamayı açıkça belirtir
- Yönetici iş istasyonu da cloud-init userdata’nın kaldığı veya içinden geçtiği bir yer olabilir; bu nedenle uzun ömürlü özel anahtar koyma yaklaşımı, anahtar geçerli olduğu sürece ifşa riski yaratır
Güvenlik analizi ve tehdit modeli
- Varsayım, OpenSSH protokolüne ve uygulamasına güvenildiği ve yöneticinin saldırıyı tespit etme becerisine dayanılmadığıdır
-
Ağ saldırganına karşı koruma
- Korunan varlıklar, yönetici iş istasyonunun bütünlüğü ve VM’dir
- Saldırgan, ağı tamamen kontrol eden bir ortadaki adamdır ve script başarıyla ya da başarısızlıkla sonlandıktan sonra herhangi bir anda cloud-init userdata’yı öğrenebilir
- Koruma, saldırgan anahtar materyalini hâlâ değerliyken öğrenemediği için geçerlidir
- Script, geçici SSH ana makine anahtarının yanlışlıkla kullanılmasını önlemek için onu geçici bir dizinde tutar ve geçici SSH ana makine anahtarını
~/.ssh/known_hostsiçine koymaz
-
Yönetici iş istasyonu ele geçirilmişse
- Koruma, VM ve VM’nin uzun ömürlü SSH ana makine özel anahtarıyla sınırlıdır
- Saldırganın ağı ve yönetici iş istasyonunu tamamen kontrol ettiği, ancak gerçek VM’ye erişmediği varsayılır
- Uzun ömürlü SSH ana makine özel anahtarı hiçbir zaman yönetici iş istasyonunda bulunmamıştır; saldırgan da gerçek VM’ye erişmediği için VM’nin uzun ömürlü ana makine anahtarını elde edemez
- Saldırgan gerçek VM’ye erişirse,
ssh root@<VM> cat /etc/ssh/ssh_host_*gibi bir yöntemle SSH ana makine anahtarlarını öğrenebilmesi büyük olasılıktır
-
VM veya sağlayıcı ele geçirilmişse
- Koruma yalnızca yönetici iş istasyonunun bütünlüğüyle sınırlıdır
- Saldırgan ağı tamamen kontrol eder ve ayrıca VM’yi veya sağlayıcıyı da tamamen kontrol edebilir
- Bu durumda da OpenSSH’nin güvenli olduğu varsayımı sayesinde yönetici iş istasyonunun bütünlüğü korunur
- Ek savunma olarak script, VM çıktısını doğrudan
~/.ssh/known_hostsiçine yazmaz; bunun yerine OpenSSH anahtar rotasyonuna dayanarak uzun ömürlü SSH ana makine anahtarını ekler - Bu yaklaşım, ele geçirilmiş bir hostun
known_hostsayrıştırıcısına kötü amaçlı veri yedirmesini engeller ve yalnızca VM’nin gerçekten kontrol ettiği anahtarların~/.ssh/known_hostsiçine yazılmasını sağlar HashKnownHostsgibi OpenSSH seçenekleri ve gelecekteki ilgili seçenekler de doğru şekilde işlenebilir
Gerçek bir ortadaki adam saldırısının başarılı olması için gereken koşullar
- Ortadaki adam saldırısının başarılı olup olmayacağı; kullanıcının tüm bağlantıların en baştan yanlış makineye gittiğini gerçekten fark edip etmemesine, parola girmeyi reddedip etmemesine ve
sshagent ya da X11 forwarding ayarlayıp ayarlamamasına bağlıdır - ssh-mitm temel alınarak basitleştirilmiş koşullarda, saldırgan gerçek hedef host yerine saldırganın kontrol ettiği bir makineye erişim verip kullanıcıyı kandırabiliyorsa başarı olasılığı yüksektir
- Saldırgan, kullanıcıyı kandırarak gerçek hosta giriş yapmaya yarayan bilgileri elde ederse de başarılı olur
- Kullanıcı saldırganın makinesine parola ile giriş yaparsa saldırgan başarılı olabilir
- Kullanıcı herhangi bir kimlik doğrulama yöntemiyle giriş yaptıktan sonra istemde parola girerse saldırgan başarılı olabilir
- Kullanıcı herhangi bir kimlik doğrulama yöntemiyle giriş yapıp ssh-agent bağlantısını iletirse saldırgan başarılı olabilir
- Bu koşullar yoksa saldırganın kullanıcıyı kandırmak için gerçek host erişimine ihtiyacı vardır; ancak kullanıcının girdileri tek başına gerçek hosta giriş yapmaya yetmeyeceğinden saldırının başarısız olma ihtimali yüksektir
- Kullanıcı X11 bağlantısını iletirse, saldırgan kimlik doğrulama yönteminden bağımsız olarak yönetici iş istasyonuna saldırmada da başarılı olabilir
1 yorum
Lobste.rs yorumları
Otomatikleştirilebildiği için harika. Elle yapılan yöntemde, sunucunun SSH parmak izini bulut sağlayıcısının konsolundan ayrı bir kanal üzerinden doğruluyordum
Yönettiğim bulut instance sayısı çok olmadığı için, provizyonlamada birkaç manuel adım olmasının sakıncası yok
DNS bölgesini otomatikleştirdiyseniz başka bir yaklaşım da mümkün: kapsamı çok dar olan tek kullanımlık bir token oluşturup, örneğin yalnızca
my-server-hostname.example.netiçin tek bir kayıt oluşturmaya izin vermekBu token'ı
cloud-initile sunucuya verip, sunucunun açık SSH anahtarını DNS'teki SSHFP kaydı olarak yayımlamasını sağlayabilirsiniz. Ardından SSH istemcisi SSHFP kaydını otomatik doğrulayabilir; bunun için DNS bölgesinin DNSSEC ile imzalanmış olması gerekirBu akış, sunucunun özel SSH host anahtarını elinde tutmasını sağlarken anahtar rotasyonunu da önler. Çoğu DNS sağlayıcısı bu kadar ayrıntılı tek kullanımlık erişim token'larını desteklemez, ancak token'ı doğruladıktan sonra kalıcı ve kapsamı sınırlandırılmamış token'la onun yerine API çağrısı yapan basit bir iç web servisi kurulabilir. SSH sunucusu bu kalıcı token'a erişemez
Yine de DNSSEC alanına yazmaktansa SSH sertifikaları üretmeyi tercih ederdim; o noktadan sonra da mesele hangi çözümün hangi ortama daha uygun olduğu haline geliyor
Bu kadar esnek token'lar üretebilen bir yazılım ya da sağlayıcı biliyor musunuz, yoksa bunun bir kısmını kendiniz mi geliştirmeniz gerekir merak ediyorum
Oldukça temiz görünüyor. Ancak yazının tarihindeki ay ve gün yer değiştirmiş gibi
Geçmişte aynı SSH tavuk-yumurta problemini incelemek için deneysel bir servis yapmıştım
İstek üzerine SSHFP DNS kaydı oluşturuyor; ilgilenirseniz https://github.com/tedb/sshfp adresine bakabilirsiniz
VM sağlayıcıları arasında az çok tutarlı olan 169.254.169.254 metadata servisini ele almanız hoşuma gitti.
cloud-initkaynağındaki çeşitlicloudinit/source/DataSource*.pygirdilerine bakınca bunu görebilirsinizBen şahsen
cloud-init'in tasarımı ve sınırları yüzünden ona karşı giderek daha fazla bıkkınlık hissediyorum. Yerel QEMU sanal makineleri, uzak makineler, container'lar ve fiziksel donanım genelinde sistem yapılandırmasını birleştirmekle ilgileniyorumarch-boxes project, ArchLinux cloud-init image'ının nasıl üretildiğini gösteriyor ve son derece basit bir shell script koleksiyonu. Bu yöntemi
guestfishveya µvm ile uygularsanız, OCI uyumlu image'lar, QEMU veya bulut sağlayıcıları için disk image'ları ve yeni fiziksel makine provizyonlaması için tam olarak aynı script'leri kullanabilirsinizBirkaç QEMU bayrağıyla birlikte,
cloud-initbağımlılığı olmadan aynı yaklaşımı yeniden üretebilirsiniz. Bildiğim kadarıylasystemd.system-credentialsile geçici host anahtarları aktarılamıyor; yalnızcassh.authorized_keys.rootgibi~/.ssh/authorized_keysiçin kimlik bilgileri varBunun yerine initrd aşamasında ya da
systemd-firstboot.serviceile birlikte çalışan bir unit dosyası yazabilirsiniz. Bu unit dosyası image içine önceden konabilir veyasystemd.extra-unit.*kimlik bilgileriyle geçici olarak enjekte edilipsystemd.wants=…kernel komut satırı seçeneğiyle etkinleştirilebilir. QEMU'da metadata servisinin varlığını-netdev user,id=metadata,net=169.254.0.0/16,dhcpstart=169.254.0.15,guestfwd=tcp:169.254.169.254:80-cmd:…girdisiyle taklit edebilirsiniz. Ancak oluşturulan arayüzü etkinleştirmeniz gerekebilir; bunu da yine geçici bir unit dosyasıyla yapmak daha iyi olabilirBu şekilde, farklı türde “makinelerde” tutarlı sistem yapılandırması yaparken, görece düşük karmaşıklıkla oldukça fazla esneklik elde edersiniz. Aslında yalnızca bu iş açısından bakarsak, image oluşturma aracının sabit host anahtarları içeren makine image'ları üretmesi ve ilk yeniden başlatma ya da kapanışta çalışan özel bir host anahtarı rotasyon betiğini bir SystemD servisi olarak kurması en iyi yaklaşım gibi görünüyor
/etc/mkinitcpio.confiçindesystemdHOOKunu etkinleştirirseniz, initrd'de yapılacak işler için SystemD unit dosyaları yazabilirsiniz; hatta fiilen yazmanız gerekirGerçekte kullanınca,
{/etc,/usr/lib}/initcpio/hooksyazmaktan sadece çok az daha zahmetli oluyorAma initrd içinde
systemd-networkingvesystemd-resolved'ı açmak oldukça kolay olduğu için, initrd sistem başlatma sorumluluğunu alabilir ve kök dosya sistemine geçmeden önce işleri planlayabilirElbette dizüstü gibi fiziksel donanımlarda Wi-Fi bağlantısı için
NetworkManagerbenzeri bir şeye ihtiyaç duyulacağından çok uygun olmayabilir; ama QEMU VM'ler ve barındırılan VM'ler için gayet uygun ve sistem başlangıç görevlerinin çoğu doğal olarak bu alana uyuyorAmaç,
cloud-init'e bağımlı olmadan, tek bir bulut sağlayıcısına kilitlenmeden, fiziksel makineler, container'lar, yerel VM'ler ve barındırılan VM'ler arasında tutarlılık sağlamak ve bağımlılıkları fiilen SystemD seviyesine kadar azaltmak