CVE Takibi ve Linux Sistemlerde Yama Yönetimi

Bir gece yarısı telefon çalıyor ve ekibindeki birisi “hocam şu log’lara bir bak, garip bir şeyler var” diyor. Bakıyorsun, üç ay önce kapatılmış olması gereken bir CVE üzerinden sisteme sızılmış. Yama uygulanmamış, takip edilmemiş, kimse haberdar değil. Bu senaryo maalesef kurumsal dünyada çok yaygın. CVE takibi ve yama yönetimi, sysadmin’lerin en çok ertelediği ama en kritik konuların başında geliyor. Bu yazıda hem teorik altyapıyı hem de gerçek dünyada nasıl uygulayacağını adım adım anlatacağım.

CVE Nedir, Neden Önemli?

CVE (Common Vulnerabilities and Exposures), yazılım ve donanımlardaki güvenlik açıklarını standart bir formatta kataloglayan bir sistemdir. MITRE Corporation tarafından yönetilir ve her açığa CVE-YYYY-NNNNN formatında benzersiz bir kimlik atanır. Örneğin Log4Shell açığı CVE-2021-44228 olarak kayıtlıdır.

CVSS (Common Vulnerability Scoring System) puanı ise bir açığın ne kadar tehlikeli olduğunu 0-10 arasında skorlar:

  • 0.1-3.9: Düşük (Low)
  • 4.0-6.9: Orta (Medium)
  • 7.0-8.9: Yüksek (High)
  • 9.0-10.0: Kritik (Critical)

Bir sysadmin olarak CVSS puanı 7 ve üzeri olan her şeyi acil olarak ele alman gerekiyor. Kritik açıklar için ise saatler içinde aksiyon almak şart.

Linux Sistemlerde Açık Tespiti

Mevcut Paket Açıklarını Kontrol Etmek

Debian/Ubuntu tabanlı sistemlerde unattended-upgrades ve apt araçları temel güvenlik bilgisi sunar:

# Güvenlik güncellemelerini listele
apt list --upgradable 2>/dev/null | grep -i security

# Daha detaylı bilgi için
apt-get upgrade --dry-run | grep -i security

# Belirli bir paketin CVE bilgisini sorgula
apt-get changelog openssh-server | head -50

Red Hat/CentOS/Rocky Linux tarafında ise yum ve dnf çok daha güçlü güvenlik araçları sunar:

# Sadece güvenlik yamalarını listele
dnf check-update --security

# Kritik güncellemeleri filtrele
dnf updateinfo list --security --severity=Critical

# Belirli bir CVE için yama var mı kontrol et
dnf updateinfo list | grep CVE-2023-4911

# Yüklü paketlerin güvenlik geçmişini gör
dnf updateinfo info --security

OpenSCAP ile Uyumluluk Taraması

OpenSCAP, sistemini belirli güvenlik standartlarına göre tarayan güçlü bir araçtır. CIS Benchmark veya DISA STIG profilleriyle sisteminizi değerlendirebilirsiniz:

# OpenSCAP kurulumu (RHEL/Rocky)
dnf install openscap-scanner scap-security-guide -y

# Mevcut profilleri listele
oscap info /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml | grep "Profile"

# CIS L2 profiliyle tarama yap
oscap xccdf eval 
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 
  --report /tmp/scap-report.html 
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

# HTML raporu oluştur ve insan okunabilir formata getir
oscap xccdf generate report /tmp/scap-results.xml > /tmp/report.html

Trivy ile Konteyner ve Sistem Taraması

Eğer Docker veya Kubernetes kullanıyorsan Trivy vazgeçilmez bir araç:

# Trivy kurulumu
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin

# Sistem paketlerini tara
trivy fs --security-checks vuln /

# Belirli bir Docker imajını tara
trivy image nginx:latest

# Sadece kritik ve yüksek açıkları filtrele
trivy image --severity HIGH,CRITICAL ubuntu:22.04

# JSON formatında çıktı al (otomasyon için)
trivy image --format json --output /tmp/trivy-report.json myapp:latest

CVE Takip Sistemi Kurmak

Vuls ile Otomatik CVE Taraması

Vuls, agentless çalışan ve sistemlerdeki CVE’leri otomatik takip eden açık kaynaklı bir araçtır. Birden fazla sunucuyu merkezi olarak yönetmek için idealdir:

# Vuls kurulumu için Go ortamı hazırla
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

# Vuls'u derle ve kur
go install github.com/future-architect/vuls@latest

# NVD veritabanını indir (bu biraz zaman alır)
go install github.com/kotakanbe/go-cve-dictionary@latest
go-cve-dictionary fetch nvd

# OVAL veritabanını indir
go install github.com/kotakanbe/goval-dictionary@latest
goval-dictionary fetch ubuntu 20.04 22.04

# Temel Vuls yapılandırması
cat > /etc/vuls/config.toml << 'EOF'
[cveDict]
  type = "sqlite3"
  sqliteDBPath = "/var/lib/cve-dictionary/cve.sqlite3"

[ovalDict]
  type = "sqlite3"
  sqliteDBPath = "/var/lib/goval-dictionary/oval.sqlite3"

[servers]
  [servers.webserver01]
    host = "192.168.1.10"
    port = "22"
    user = "vuls"
    keyPath = "/root/.ssh/vuls_key"
    
  [servers.dbserver01]
    host = "192.168.1.20"
    port = "22"
    user = "vuls"
    keyPath = "/root/.ssh/vuls_key"
EOF

# Tarama başlat
vuls scan
vuls report -format-full-text

Otomatik CVE Bildirim Scripti

Kritik CVE’leri anında haber almak için basit ama etkili bir script yazalım:

#!/bin/bash
# /usr/local/bin/cve-check.sh
# Her gece çalışacak CVE takip scripti

SEVERITY_THRESHOLD=7
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
EMAIL="[email protected]"
LOG_FILE="/var/log/cve-check.log"
DATE=$(date '+%Y-%m-%d %H:%M')

echo "[$DATE] CVE kontrolü başladı" >> "$LOG_FILE"

# Debian/Ubuntu için güvenlik güncellemelerini topla
if command -v apt &>/dev/null; then
    UPDATES=$(apt-get upgrade --dry-run 2>/dev/null | grep -c "^Inst.*security")
    if [ "$UPDATES" -gt 0 ]; then
        DETAILS=$(apt-get upgrade --dry-run 2>/dev/null | grep "^Inst.*security" | head -20)
        
        MESSAGE="*[$HOSTNAME]* $UPDATES adet güvenlik güncellemesi bekliyor!n```n$DETAILSn```"
        
        # Slack bildirimi gönder
        curl -s -X POST -H 'Content-type: application/json' 
            --data "{"text":"$MESSAGE"}" 
            "$SLACK_WEBHOOK"
        
        # E-posta bildirimi gönder
        echo -e "Sunucu: $HOSTNAMEnTarih: $DATEnBekleyen güncellemeler:nn$DETAILS" | 
            mail -s "[$HOSTNAME] Güvenlik Güncellemesi Gerekli" "$EMAIL"
            
        echo "[$DATE] $UPDATES güvenlik güncellemesi tespit edildi ve bildirim gönderildi" >> "$LOG_FILE"
    fi
fi

# RHEL/Rocky için
if command -v dnf &>/dev/null; then
    CRITICAL=$(dnf check-update --security --severity=Critical -q 2>/dev/null | grep -v "^$" | wc -l)
    if [ "$CRITICAL" -gt 0 ]; then
        echo "[$DATE] KRİTİK: $CRITICAL kritik güvenlik güncellemesi!" >> "$LOG_FILE"
        # Slack ve mail bildirimi burada da eklenebilir
    fi
fi

echo "[$DATE] CVE kontrolü tamamlandı" >> "$LOG_FILE"
# Script'i çalıştırılabilir yap ve cron'a ekle
chmod +x /usr/local/bin/cve-check.sh

# Her gece 02:00'da çalıştır
echo "0 2 * * * root /usr/local/bin/cve-check.sh" >> /etc/cron.d/cve-check

Yama Yönetimi Stratejisi

Test-Staging-Production Pipeline

Yamayı direkt production’a uygulamak ciddi riskler taşır. Doğru yaklaşım şu sırayla gitmektir:

  • Test ortamı: Yama önce burada uygulanır, fonksiyonel testler çalıştırılır
  • Staging ortamı: Production kopyasında doğrulama yapılır
  • Production: Onaylanan yama uygulanır, rollback planı hazırda olur

Ansible ile Otomatik Yama Yönetimi

Yüzlerce sunucuyu elle yamalamak hem zaman kaybı hem de hata riski demektir. Ansible bu işi güvenle otomatize eder:

# patch-management.yml
---
- name: Linux Sunucularına Güvenlik Yamalarını Uygula
  hosts: all
  become: yes
  vars:
    reboot_required: false
    patch_log: "/var/log/ansible-patches.log"
  
  tasks:
    - name: Mevcut tarihi kaydet
      command: date '+%Y-%m-%d %H:%M:%S'
      register: patch_date
      changed_when: false

    - name: Debian/Ubuntu - Güvenlik yamalarını uygula
      apt:
        upgrade: yes
        update_cache: yes
        only_upgrade: yes
        dpkg_options: 'force-confold,force-confdef'
      when: ansible_os_family == "Debian"
      register: apt_result
      
    - name: RHEL/Rocky - Güvenlik yamalarını uygula
      dnf:
        name: '*'
        state: latest
        security: yes
        update_only: yes
      when: ansible_os_family == "RedHat"
      register: dnf_result

    - name: Reboot gerekip gerekmediğini kontrol et (Debian)
      stat:
        path: /var/run/reboot-required
      register: reboot_file
      when: ansible_os_family == "Debian"

    - name: Gerekiyorsa sistemi yeniden başlat
      reboot:
        msg: "Güvenlik yamaları sonrası yeniden başlatılıyor"
        connect_timeout: 5
        reboot_timeout: 300
        pre_reboot_delay: 10
        post_reboot_delay: 30
      when: reboot_file.stat.exists is defined and reboot_file.stat.exists

    - name: Yama logunu kaydet
      lineinfile:
        path: "{{ patch_log }}"
        line: "{{ patch_date.stdout }} - Yama tamamlandı: {{ inventory_hostname }}"
        create: yes
# Sadece belirli sunucu grubuna uygula
ansible-playbook patch-management.yml -l webservers --check  # önce dry-run
ansible-playbook patch-management.yml -l webservers          # sonra gerçek uygulama

# Belirli bir CVE için yama uygula
ansible-playbook patch-management.yml -l dbservers 
  --extra-vars "target_cve=CVE-2023-4911"

Kernel Güncellemesi ve Canlı Yama

Kernel güncellemesi için genellikle yeniden başlatma gerekir. Ancak kritik üretim sistemleri için kpatch veya ticari çözümler (Ksplice, KernelCare) canlı yama imkanı sunar:

# kpatch kurulumu ve kullanımı (RHEL/Rocky)
dnf install kpatch kpatch-dnf -y

# Mevcut canlı yamaları listele
kpatch list

# Otomatik canlı yama (dnf ile entegre)
dnf kpatch upgrade

# Yama durumunu kontrol et
kpatch info

# Mevcut kernel sürümünü ve yüklü yamaları göster
uname -r
rpm -qa | grep kpatch

Gerçek Dünya Senaryosu: Log4Shell Müdahalesi

Aralık 2021’de Log4Shell açığı (CVE-2021-44228) patlak verdiğinde, CVSS skoru 10.0 olan bu açık tüm dünyada panik yarattı. Bu tür bir senaryoda nasıl hareket etmeli?

#!/bin/bash
# log4shell-check.sh
# Sistemde Log4j kullanımını tespit et

echo "=== Log4Shell (CVE-2021-44228) Tespit Taraması ==="
echo "Tarih: $(date)"
echo ""

# JAR dosyalarını tara
echo "[+] JAR dosyaları aranıyor..."
find / -name "*.jar" -type f 2>/dev/null | while read jar; do
    if unzip -l "$jar" 2>/dev/null | grep -q "JndiLookup.class"; then
        echo "UYARI: Etkilenmiş sınıf bulundu: $jar"
        # JAR içindeki log4j sürümünü tespit et
        VERSION=$(unzip -p "$jar" META-INF/MANIFEST.MF 2>/dev/null | grep -i "implementation-version" | cut -d' ' -f2)
        echo "  Sürüm: $VERSION"
    fi
done

# Maven/Gradle bağımlılıklarını kontrol et
echo ""
echo "[+] Maven pom.xml dosyaları aranıyor..."
find / -name "pom.xml" 2>/dev/null | xargs grep -l "log4j" 2>/dev/null | head -20

# Çalışan processlerde log4j kullanımı
echo ""
echo "[+] Çalışan processlerde log4j kontrolü..."
for pid in $(ls /proc | grep -E '^[0-9]+$'); do
    if ls -la /proc/$pid/fd 2>/dev/null | grep -q "log4j"; then
        echo "PID $pid log4j kullanıyor:"
        cat /proc/$pid/cmdline 2>/dev/null | tr '' ' '
        echo ""
    fi
done

echo ""
echo "=== Tarama tamamlandı ==="

Yama Takip ve Raporlama

Merkezi Yama Veritabanı

Küçük bir SQLite veritabanıyla tüm yama geçmişini takip edebilirsiniz:

#!/bin/bash
# patch-tracker.sh - Yama kayıt sistemi

DB="/var/lib/patch-tracker/patches.db"
mkdir -p /var/lib/patch-tracker

# Veritabanını oluştur
sqlite3 "$DB" << 'EOF'
CREATE TABLE IF NOT EXISTS patches (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    hostname TEXT NOT NULL,
    cve_id TEXT,
    package_name TEXT NOT NULL,
    old_version TEXT,
    new_version TEXT,
    applied_date TEXT NOT NULL,
    applied_by TEXT,
    status TEXT DEFAULT 'applied',
    notes TEXT
);
CREATE TABLE IF NOT EXISTS pending_patches (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    hostname TEXT NOT NULL,
    cve_id TEXT,
    package_name TEXT NOT NULL,
    severity TEXT,
    detected_date TEXT NOT NULL,
    deadline TEXT
);
EOF

# Yama kaydı ekle
add_patch() {
    local cve=$1
    local package=$2
    local old_ver=$3
    local new_ver=$4
    
    sqlite3 "$DB" "INSERT INTO patches (hostname, cve_id, package_name, old_version, new_version, applied_date, applied_by) 
        VALUES ('$(hostname)', '$cve', '$package', '$old_ver', '$new_ver', '$(date +%Y-%m-%d)', '$(whoami)');"
    echo "Yama kaydedildi: $package ($old_ver -> $new_ver)"
}

# Son 30 günün yama raporunu göster
show_report() {
    echo "=== Son 30 Günün Yama Raporu ==="
    sqlite3 -column -header "$DB" 
        "SELECT hostname, cve_id, package_name, old_version, new_version, applied_date 
         FROM patches 
         WHERE applied_date >= date('now', '-30 days') 
         ORDER BY applied_date DESC;"
}

case "$1" in
    add)    add_patch "$2" "$3" "$4" "$5" ;;
    report) show_report ;;
    *)      echo "Kullanim: $0 {add|report}" ;;
esac

İzleme ve Alarm Mekanizmaları

Prometheus ve Alertmanager kullanıyorsan, bekleyen güvenlik güncellemelerini metrik olarak export edebilirsin:

#!/bin/bash
# security-metrics.sh
# Node Exporter textfile collector için güvenlik metrikleri

METRICS_FILE="/var/lib/node_exporter/textfile_collector/security.prom"

# Bekleyen güvenlik güncellemesi sayısı
if command -v apt &>/dev/null; then
    PENDING=$(apt-get upgrade --dry-run 2>/dev/null | grep -c "^Inst.*security" || echo 0)
    CRITICAL=$(apt-get upgrade --dry-run 2>/dev/null | grep -c "^Inst.*critical" || echo 0)
fi

if command -v dnf &>/dev/null; then
    PENDING=$(dnf check-update --security -q 2>/dev/null | grep -v "^$" | wc -l || echo 0)
    CRITICAL=$(dnf check-update --security --severity=Critical -q 2>/dev/null | grep -v "^$" | wc -l || echo 0)
fi

# Son yeniden başlatmadan bu yana geçen gün
UPTIME_DAYS=$(awk '{print int($1/86400)}' /proc/uptime)

# Metrikleri yaz
cat > "$METRICS_FILE" << EOF
# HELP security_pending_updates Bekleyen güvenlik güncellemesi sayısı
# TYPE security_pending_updates gauge
security_pending_updates{hostname="$(hostname)"} ${PENDING:-0}

# HELP security_critical_updates Kritik güvenlik güncellemesi sayısı
# TYPE security_critical_updates gauge
security_critical_updates{hostname="$(hostname)"} ${CRITICAL:-0}

# HELP system_uptime_days Son yeniden başlatmadan bu yana geçen gün
# TYPE system_uptime_days gauge
system_uptime_days{hostname="$(hostname)"} $UPTIME_DAYS
EOF

echo "Metrikler güncellendi: $METRICS_FILE"

En İyi Pratikler

Yıllar içinde öğrendiğim ve gerçekten işe yarayan pratikler şunlar:

  • SLA tanımla: Kritik CVE’ler için 48 saat, yüksek için 7 gün, orta için 30 gün gibi net süreler belirle ve buna uy
  • Değişiklik penceresi kullan: Yamaları rastgele değil, belirlenmiş maintenance window’larda uygula
  • Rollback planın her zaman hazır olsun: Snapshot al, yedeği kontrol et, sonra yamala
  • Bağımlılıkları izle: Bir paketi güncellemek başka bir şeyi bozabilir, bağımlılık grafiğini anla
  • Kernel güncellemesini erteleme: Kernel yamaları en çok ertelenen ama en kritik olanlar, reboot korkusunu yenmek gerekiyor
  • CVE kaynaklarını takip et: NVD (nvd.nist.gov), CERT/CC, vendor security bulletinleri ve distro security mailing listleri
  • Önceliklendirme yap: Her açığı aynı aciliyetle ele almanın anlamı yok, risk değerlendirmesi yaparak önceliklendir
  • Dokümante et: Hangi yamayı ne zaman neden uyguladığını kayıt altına al, audit süreçlerinde hayat kurtarır

Sonuç

CVE takibi ve yama yönetimi, “yapılacaklar listesinin en altında kalan” bir konu olmaktan çıkıp güvenlik stratejisinin merkezine alınması gereken bir süreç. Tek bir yamayı atlaman, sistemine aylar sonra sızmaya yetebilir ve bu tür olayların ortalama tespit süresi hala 200 günün üzerinde.

Bu yazıda anlattığım araçları ve script’leri kullanarak başlangıç düzeyinde bir CVE takip altyapısı kurabilirsin. Küçük ortamlar için Vuls + Ansible + Slack bildirimleri yeterli bir çözüm sunar. Daha büyük ortamlarda Tenable, Qualys veya Rapid7 gibi ticari araçları değerlendirebilirsin.

En önemli şey ise şu: Otomatize edemediğin şeyi tutarlı şekilde yapamazsın. Yama yönetimini elle takip etmeye çalışmak kaçınılmaz olarak açıklar bırakır. Sistematik, otomatize ve belgelenmiş bir süreç kur, düzenli olarak test et ve ekibinle paylaş. Gece saat 03:00’da telefon almak istemiyorsan, bu işi ciddiye almanın tam zamanı.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir