Software-Asset-Management: Lizenzen, Versionen und End-of-Life im Blick behalten

Einleitung

Software-Asset-Management klingt nach Lizenz-Buchhaltung für Enterprise-Einkäufer. Für Security-Teams ist es etwas anderes: wer weiß, welche Softwareversionen im Netz laufen und welche davon End-of-Life sind, hat einen direkten Blick auf seine Angriffsfläche. Ein Apache 2.4.49 auf einem vergessenen Server, ein Java 8-Runtime das seit 2019 keine Patches mehr bekommt, ein Windows Server 2012 R2 ohne ESU – das sind nicht Lizenz-Probleme, das sind CVEs mit Name und Hausnummer. Dieser Artikel zeigt, wie du Software-Inventar aufbaust, EOL-Daten automatisch abfragst und beides in deinen Security-Workflow integrierst.


Warum das Thema wichtig ist

End-of-Life-Software ist eine der am meisten unterschätzten Angriffsflächen in KMU. Der Grund: EOL-Software bekommt keine Sicherheitspatches mehr, neue CVEs werden für sie veröffentlicht aber nie geschlossen. Ein Angreifer, der eine CVE für OpenSSL 1.0.2 (EOL seit 2020) ausnutzt, hat einen einfachen Job: der Patch existiert nicht, die Verteidigung ist blind.

NIS2 und der BSI IT-Grundschutz verlangen explizit, dass Software-Versionen und End-of-Life-Status bekannt sind. In Audit-Gesprächen ist „wir wissen nicht, was läuft“ kein akzeptables Ergebnis. Gleichzeitig hat SAM einen klaren ROI jenseits Security: Lizenz-Compliance vermeidet teure Software-Audit-Nachzahlungen – ein ungeplanter Microsoft-Audit kann ein KMU mehrere Zehntausend Euro kosten.


Software-Inventar aufbauen

Schicht 1: Windows-Endpoints und Server

PowerShell – installierte Software aus der Registry:

function Get-InstalledSoftware {
    param([string[]]$ComputerName = $env:COMPUTERNAME)
    $regPaths = @(
        'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
        'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
    foreach ($pc in $ComputerName) {
        try {
            $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $pc)
            foreach ($path in @('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
                                'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall')) {
                $key = $reg.OpenSubKey($path)
                if (-not $key) { continue }
                foreach ($subkey in $key.GetSubKeyNames()) {
                    $sub = $key.OpenSubKey($subkey)
                    $name    = $sub.GetValue('DisplayName')
                    $version = $sub.GetValue('DisplayVersion')
                    $install = $sub.GetValue('InstallDate')
                    if ($name) {
                        [PSCustomObject]@{
                            Computer  = $pc
                            Name      = $name
                            Version   = $version
                            Installed = $install
                        }
                    }
                }
            }
        } catch {
            Write-Warning "$pc: $($_.Exception.Message)"
        }
    }
}

$computers = Get-ADComputer -Filter * | Select -Expand Name
Get-InstalledSoftware -ComputerName $computers | Export-Csv software-inventory.csv -NoTypeInformation

Schicht 2: Linux-Server

#!/bin/bash
# Debian/Ubuntu
dpkg-query -W -f='${Package}\t${Version}\t${Status}\n' > /tmp/packages.tsv

# RHEL/CentOS/AlmaLinux
rpm -qa --queryformat '%{NAME}\t%{VERSION}-%{RELEASE}\t%{INSTALLTIME:date}\n' > /tmp/packages.tsv

# Hostname + Datum hinzufügen
awk -v host="$(hostname -f)" -v date="$(date -I)" \
    '{print host "\t" date "\t" $0}' /tmp/packages.tsv

Ausgabe per Ansible sammeln:

- name: Collect software inventory
  hosts: all
  tasks:
    - name: Gather dpkg list
      command: dpkg-query -W -f='${Package}\t${Version}\n'
      register: pkgs
      changed_when: false
    - name: Write to central share
      copy:
        content: "{{ pkgs.stdout }}"
        dest: "/inventory/{{ inventory_hostname }}_pkgs.tsv"
      delegate_to: inventory-server

Schicht 3: Web-Applikationen und Middleware

Viele Schwachstellen stecken nicht im OS, sondern in Middleware (Apache, nginx, Tomcat, Node.js) und Libraries. Für diese reicht dpkg nicht:

# Apache-Version
apache2 -v

# nginx
nginx -v

# Java (alle JVMs finden)
find / -name "java" -type f 2>/dev/null | xargs -I{} {} -version 2>&1

# Node.js-Pakete global
npm list -g --depth 0

# Python-Pakete
pip list --format=columns

EOL-Status automatisch prüfen: endoflife.date API

endoflife.date ist eine Community-betriebene Datenbank mit EOL-Daten für über 300 Produkte, mit kostenloser API.

import requests, csv, datetime

def check_eol(product: str, version: str) -> dict:
    """Prüft ob eine Version EOL ist via endoflife.date API"""
    # Extrahiere Major.Minor (z.B. "2.4.51" → "2.4")
    short = '.'.join(version.split('.')[:2])
    url = f"https://endoflife.date/api/{product}/{short}.json"
    try:
        r = requests.get(url, timeout=5)
        if r.status_code == 404:
            return {'eol': 'unknown', 'eol_date': None}
        data = r.json()
        eol = data.get('eol', False)
        eol_date = data.get('eol') if isinstance(data.get('eol'), str) else None
        is_eol = eol is True or (
            eol_date and datetime.date.fromisoformat(eol_date) < datetime.date.today()
        )
        return {
            'eol': is_eol,
            'eol_date': eol_date,
            'latest': data.get('latest'),
            'lts': data.get('lts', False),
        }
    except Exception as e:
        return {'eol': 'error', 'error': str(e)}

# Beispiel-Batch
products = [
    ('apache', '2.4.51'),
    ('nodejs', '14.21.0'),
    ('java', '8.0.322'),
    ('windows-server', '2012'),
]

for product, version in products:
    result = check_eol(product, version)
    status = "EOL" if result.get('eol') is True else "OK"
    print(f"{product} {version}: {status} (EOL-Datum: {result.get('eol_date')}, Latest: {result.get('latest')})")

EOL-Dashboard: die kritische Übersicht

Eine einfache HTML-Tabelle, wöchentlich generiert:

Produkt Version Host EOL-Datum Status Aktion
Java 8 8.0.322 appserver02 2030-12-31 EOL (kein kostenloser Support) Migration auf 21 LTS
Windows Server 2012 R2 6.3 fileserver01 2023-10-10 EOL (ESU verfügbar) Upgrade oder ESU
Apache 2.4.49 2.4.49 webserver03 2021-09-17 EOL Sofort-Update
OpenSSL 1.0.2 1.0.2u legacy01 2020-01-01 EOL Decommission oder Isolierung

Produkte mit Status = EOL landen automatisch als P3-Tickets im Vulnerability-Workflow.


Lizenz-Compliance als Security-Nebeneffekt

SAM ist nicht nur Security – Lizenz-Compliance schützt vor Audit-Nachzahlungen:

Lizenz-Risiko Auswirkung Check
Mehr Installationen als Lizenzen Nachzahlung + Bußgeld Installations-Count vs. Lizenz-Count
EOL-Software mit aktivem Support-Vertrag Zahlst für nichts Support-Verträge vs. EOL-Datum
Open-Source-Lizenzen in kommerziellen Produkten GPL-Compliance-Pflichten SPDX-Scan der Entwicklungs-Repos

Für Security-Teams ist der wichtigste Aspekt: EOL-Software ohne Support-Vertrag = keine Patches = offene Angriffsfläche.


Offene Tools für SAM in KMU

Tool Stärken Schwächen
OCS Inventory Agent-basiert, Windows+Linux, kostenlos UI veraltet
Spiceworks Inventory Einfach, kostenlos Cloud-basiert, Datenschutz prüfen
Lansweeper Free Gutes Reporting, Auto-Discovery Limitierungen in Free-Tier
OpenAudit Open Source, Web-UI Weniger aktiv gepflegt
Ansible + Custom Script Flexibel, in CI/CD integrierbar Mehr Eigenaufwand

Für die meisten KMU unter 200 Hosts: OCS Inventory + eigene EOL-Prüfung via endoflife.date API als pragmatischste Kombination.


Integration in den Security-Workflow

SAM-Daten sind nur nützlich, wenn sie mit anderen Security-Daten verknüpft sind:

Software-Inventar
      ↓
  EOL-Check (endoflife.date)
      ↓
  Vulnerability-Scanner (CVE-Abgleich)
      ↓
  Ticketing (P1/P2/P3)
      ↓
  CMDB-Update

Praktisch: wöchentlicher Cron-Job, der Inventar exportiert, EOL prüft, neue EOL-Findings als Tickets anlegt.


Stolperfallen


Praxis-Checkliste


Fazit

Software-Asset-Management ist Security-Hygiene, die sich doppelt auszahlt: du kennst deine Angriffsfläche und vermeidest Lizenz-Compliance-Fallen. EOL-Software ist eine der einfachsten Attack-Vektoren – und eine der am häufigsten übersehenen. Mit einem automatisierten Inventar, einer wöchentlichen EOL-Prüfung via endoflife.date und einem direkten Weg ins Ticketing-System schließt du diese Lücke ohne großen Aufwand. Der Aufbau dauert einen Tag. Die Alternative – ein Ransomware-Angriff über ein vergessenes Java 8 auf dem App-Server – dauert deutlich länger.


Wenn du tiefer einsteigen willst: Im Newsletter zeige ich jeden Monat konkrete SAM-Skripte, EOL-Dashboard-Vorlagen und Integration-Patterns für KMU. Trag dich ein.

← Zurück zur Übersicht