Linux Server Sicherheit Kursnotizen Mai 2025

1 Tag 1

1.1 Crypto Wettbewerbe

1.2 Links zum Thema Krypto-Algorithmen

TL;DR

Ed25519 is great. NIST P-256 and P-384 are okay (with caveats). Anything else is questionable, and their parameter selection should come with a clear justification.

1.3 Aufgabe: Hash und HMAC

  • Lade die Datei https://server-sicherheit.lxht.de/LinuxSecurityEinfuehrung.pdf
  • Welcher SHA256 Hash-Wert ist korrekt?
    1. 0245bcddf700ddfb4fd37c58bbfc67e19b9aa8827d0242fc9beb40078925f191
    2. f8eee6980c49d8020b10449a0fec6544e266af09
    3. 22833704a424725d5725d977cc733244afe0e38a6e2a987a560c95aa39da2d01
    4. AEGHHA91288ABCCVA005612991ZZ612566189811
openssl dgst -sha256 < LinuxSecurityEinfuehrung.pdf
  • Der folgende Wert sind die HMACs für die PDF-Datei. Welcher PSK (pre-shared-secret) wurde verwendet:
   HMAC-SHA256 =
    3989780c03e83f553dca485c38a4d6239de58affbe27f0d7b572be00a5e512ee
  • Auswahl der PSKs:
    1. ’LinuxHotel’
    2. ’EssenHorst’
    3. ’vogelsang’
openssl sha256 -hmac "<psk>" < LinuxSecurityEinfuehrung.pdf

1.4 Symmetrische Verschlüsselung mit OpenSSL

# AES
% echo "mein geheimer text" | openssl enc -e -aes256 -a
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
<verschlüsselter text>

echo "<verschlüsselter text>" |  openssl enc -d -aes256 -a

1.5 Asymmetrische Verschlüsselung mit OpenSSL

# einen neuen privaten RSA Schlüssel erstellen
openssl genpkey -algorithm RSA -out key.pem

# den privaten Schlüssel mit AES 256bit verschlüsseln
openssl pkey -in key.pem -aes256 -out keyaes.pem
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

# Unverschlüsselten privaten Schlüssel löschen
rm key.pem

# den öffentlichen Schlüssel erzeugen (kann bei RSA aus dem privaten
# Schlüssel erzeugt werden)
openssl pkey -in keyaes.pem -pubout -out pubkey.pem

# Daten mit dem öffentlichen Schlüssel verschlüsseln
echo "Hallo LinuxHotel" > plain.txt
openssl pkeyutl -in plain.txt -out cipher.txt -encrypt -pubin -inkey pubkey.pem

# Verschlüsselten Text als Hex und ASCII anzeigen
od -xa cipher.txt

# Daten mit dem privaten Schlüssel entschlüsseln
openssl pkeyutl -in cipher.txt -out plain2.txt -decrypt -inkey keyaes.pem
Enter pass phrase for keyaes.pem:

# entschlüsselten Text wieder anzeigen
cat plain2.txt
Hallo LinuxHotel

1.6 Zufallszahlen und Linux (heutzutage meistens obsolet)

1.6.1 Moderne Kernel (ab Version?)

  • benutzen einen internen HAVE-Algorithmus, d.h. dort sind weder haveged noch die rng-tools sinnvoll!

1.6.2 Für ältere Systeme und/oder spezielle Systeme (ohne hwrng)

  • Starte top in einem anderen Terminal-Fenster, beobachte dort die CPU Benutzung des ssh-keygen Prozesses
  • Erstelle einen 10000 bit ssh RSA Schlüssel (hier nur zur Demo von Zufallszahlen und haveged oder rngd)
cat /dev/random # Abbrechen
ssh-keygen -b 10000 -t rsa -f /tmp/test
  • Die Erstellung des Schlüssels dauert extrem lange, da /dev/random benutzt wird.
  • Rngd als Hardware-Zufallszahlengenerator installieren
  • Haveged erzeugt Zufallswerte aus der verteilung von Prozessen auf Prozessorkerne. Homepage http://www.issihosts.com/haveged/ Auch geeignet für virtuelle Umgebungen
  • Haveged installieren
apt install haveged
systemctl status haveged
  • Der Schlüssel sollte nach dem Start von haveged in ein paar Sekunden erstellt sein!
  1. Durchsatz des Zufallszahlengenerators messen
    • rngd installieren
    apt install rng-tools5
    systemctl status rngd
    
    • aus /dev/random lesen und der Durchsatz per pv anzeigen lassen
    apt install pv
    dd if=/dev/random | pv > /dev/null
    
    • haveged an-/ausschalten (in einem anderen Terminal, die Datenrate im pv betrachten)
    • Dasselbe mit rngd
    • Beide zusammen und keines von Beiden
    systemctl stop haveged rngd
    systemctl start rngd
    systemctl stop rngd
    systemctl start haveged
    systemctl start rngd
    

1.6.3 Weitere Informationen zu Linux Zufallszahlen

1.7 Verschlüsselungssysteme

1.7.1 GnuPG/GPG - GNU Privacy Guard

  • GnuPG is a complete and free implementation of the OpenPGP standard as defined by RFC4880 (also known as PGP). GnuPG allows you to encrypt and sign your data and communications; it features a versatile key management system, along with access modules for all kinds of public key directories. GnuPG, also known as GPG, is a command line tool with features for easy integration with other applications. A wealth of frontend applications and libraries are available. GnuPG also provides support for S/MIME and Secure Shell (ssh): https://gnupg.org

1.7.2 AGE - Actually Good Encryption

  • A simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability: https://age-encryption.org

1.7.3 XCA - X Certificate and Key Management

  • X.509 graphisch und nachvollziehbar ;-)

1.8 su

  • mit dem Programm su (Switch User eigentlich Substitute User) kann ein Benutzer ein einen anderen Benutzerkontext wechseln
  • Unterschiede bei den Umgebungsvariablen zwischen su und su - oder su -l
    • bei su werden die Umgebung des aufrufenden Benutzer übernommen (kann Sicherheitsprobleme erzeugen)
    • die Variablen $IFS, $HOME, $SHELL, $USER, $LOGNAME, $PATH werden bei su - oder su -l zurückgesetzt
  • Such-Pfade für Benutzer und root werden in /etc/login.defs über die Optionen ENV_PATH und ENV_SUPATH konfiguriert

1.9 Sicherheit bei der Unix-Benutzeranmeldung

  • Die Sicherheit der Unix-Benutzeranmeldung hängt u.a. an der Sicherheit der gespeicherten Passwörter. Passwörter werden in einem Linux-System als SHA512-Hash gespeichert. Dabei wird das Passwort 5.000 mal mit dem SHA512 Algorithmus gehashed bevor es in der Datei /etc/shadow gespeichert wird oder gegen den Hash in dieser Datei geprüft wird.
  • 5.000 Runden SHA512 lassen sich heute mit grossen Rechnern “brute-force” berechnen. Die Default-Einstellung von Linux istso gewählt, das es auch auf sehr schwachen Rechnern (z.B. Heim-Routern) noch funktioniert. Moderne Systeme können eine grössere Anzahl SHA512 Runden für die Passwort-Sicherheit verwenden. Nachfolgend stellen wir die SHA512-Runden auf 1.000.000 (1 Million) ein.

1.9.1 Links zur Passwort Sicherheit

1.9.2 Sicherheit der Benutzerpasswörter

  • In der Datei /etc/pam.d/common-password wird die Stärke der Benutzer-Passwörter angepasst. Eine Änderung in dieser Datei wirkt sich nur auf alle neu gesetzten Passwörter aus, alle schon vorher vergebenen Passwörter bleiben mit der vorherigen Einstellung bestehen. D.h. nach einer Änderung dieses Parameters sollten wichtige Passwörter neu vergeben werden.
[...]
password    [success=1 default=ignore]    pam_unix.so obscure sha512 rounds=1000000
[...]

1.9.3 Yesycrypt ab Debian 11

  • Yescrypt ist eine neue Schlüsselableitungsfunktion für Passwörter vom OpenWall Projekt. Es basiert auf scrypt (RFC 7914) von Colin Percival (früherer Sicherheitleiter des FreeBSD Projektes). Es schützt besser vor Brute-Force Angriffen als SHA512 und andere Schlüsselableitungsfunktionen.
    • Debian 11 setzt Yescrypt als Standard-Algorithmus für die Benutzerpasswörter ein
    • Bei einem Update von Debian 10 auf Debian 11 bleiben die Passwort-Hashes im SHA512 Format
      • erst bei einer Passwortänderung mittels passwd wir der neue Yescrypt-Hash erzeugt
    • Beispiel Debian 10 SHA512 Hash in der /etc/shadow
       nutzer:$6$NtILOHbh$SZ1pFZKkJj/xqtrxqtSBrkOgRWQmXfv4tJhwlCfNkL7V4ft8G6eyLkVhxmvAs6DQsPuAmRqB7WVfJHMB5w0340:16442:0:99999:7:::
    
    • Beispiel Debian 11 Yescrypt Hash in der /etc/shadow
       nutzer:$y$j9T$YhVeKuFhMSSA91rR4FhwT/$9YTuWLhjyf1oqcPMoEkJFqSL.6YMRMQVMGaIgWIJyq9:18868:0:99999:7:::
    
  • yescrypt benutzt einen cost factor [1..11] anstelle der rounds
[...]
password    [success=1 default=ignore]    pam_unix.so obscure yescrypt rounds=10
[...]

Man erkennt es am Parameterteil im gehashten passwort (shadow) $jDT statt $j9T Standard sind 5 “Runden”

1.9.4 Gruppenpasswörter

  • Die Sicherheit der Gruppenpasswörter werden in der Datei /etc/login.defs festgelegt. Wenn Gruppenpasswörter benutzt werden, wird empfolen diese Werte mit der PAM-Konfiguration gleich zu halten.
ENCRYPT_METHOD SHA512
SHA_CRYPT_MIN_ROUNDS 1000000
SHA_CRYPT_MAX_ROUNDS 1000000

1.9.5 Benutzerdatenbank

  • Die Benutzerinformationen für die Passwortanmeldung unter Unix/Linux werden in der Datei /etc/shadow gespeichert
  1. Felder der Datei /etc/shadow:
    • Benutzername
    • Password-Hash
    • Datum des letzen Passwort-Wechsel
    • Mindestlebensdauer des Passworts
    • Max-Lebensdauer des Passwort
    • Passwort-Ablauf Warn-Zeitraum
    • Zeitdauer der Passwort-Inaktivität (Benutzer kann sich nach Ablauf des Passworts noch einloggen)
    • Ablaufdatum des Passworts
    • Reserviertes Feld
  2. Passwort-Hash-Methoden
    ID Methode
    1 MD5
    2a Blowfish (nicht in der Standard glibc; wurde einigen Distributionen hinzugefügt)
    5 SHA-256 (seit glibc 2.7)
    6 SHA-512 (seit glibc 2.7)
    y yescrypt

1.10 chage

useradd -m -N fritz
passwd fritz
chage -l fritz
  • Account abgelaufen
chage -E 0 fritz
  • Account ist ab einem bestimmten Datum nicht mehr gültig
chage -E 2019-03-01 fritz
  • Ablaufzeit zurücksetzen
chage -E -1 fritz
  • Passwort darf frühstens nach 3 und muss spätestens nach 9 Tagen geändert werden
chage -m 3 -M 9 -d "1 day ago" fritz
passwd fritz
  • Login innerhalb der Warn-Periode
chage -d "8 days ago" -W 3 fritz
su - fritz
  • Login außerhalb der Warn-Periode aber innerhalb der Gültigkeit
chage -d "12 days ago" -I 10 fritz
su - fritz
  • Login außerhalb der Gültigkeit
chage -d "21 days ago" -I 10 fritz
su - fritz
  • Benutzer muss sein Passwort einmalig beim ersten Login ändern
chage -E -1 -I -1 -m 0 -M 99999 fritz # alles zurücksetzen
passwd fritz                          # Ein Standardpasswort setzen
  • Passwortänderung nach der initialen Anmeldung erzwingen
chage -d 0 fritz

1.11 sudo

  • sudo ist ein moderner Ersatz für su. Gegenüber su hat sudo mehrere Vorteile:
    • es wird das eigene Benutzerpasswort abgefragt, nicht das Passwort dies Ziel-Benutzers
    • Das Ergebniss der Passwort-Prüfung des Benutzers kann für eine gewisse Zeit gespeichert werden, so das der Benutzer nicht für jeden Befehl das Passwort eingeben muss
    • Bessere Protokollierung
    • Umfangreiche Konfigurationsmöglichkeiten
  • sudo Installation
apt install sudo
sudo -V
  • sudo Basis-Konfiguration ausgeben
  • sudo Konfigurationsdatei sicher editieren (ggf. Variable $EDITOR setzen, sonst wird vi verwendet)
EDITOR=emacs visudo
  • aliase (host, user, command)
  • sudo und das Environment
  • sudo -i vs. sudo su -

1.11.1 Beispiel:

  • Befehl cat auf die Datei /var/log/apt/term.log für Benutzer nutzer02
  visudo -f /etc/sudoers.d/apt-term-cat
  ----
  nutzer02 ALL=(root) /bin/cat /var/log/apt/term.log
  ----
  nutzerXX$ sudo -l
  • sudo -l Zeigt die sudo-Konfiguration und die erlaubten Befehle eines sudo-Benutzers an.

1.11.2 Aufgabe:

  • Erstelle eine sudo Konfiguration, um es dem Benutzer nutzerXX zu erlauben, die Logdatei /var/log/boot.log und unter den Benutzerberechtigungen des Benutzers root mit den Programm less anzuschauen

1.11.3 Lösung

  visudo -f /etc/sudoers.d/log-message-view
  ------
  ...
  nutzerXX  ALL=(root) /usr/bin/less /var/log/boot.log
  ...
  • in einem anderen Terminal/Tmux-Fenster, teste sudo als nutzerXX
  nutzerXX$ sudo less /var/log/boot.log
  nutzerXX$ sudo less /etc/shadow       # <--- darf nicht gehen

1.11.4 Frage:

  • gibt es mit dieser Konfiguration ein Sicherheitsproblem?

1.11.5 Antwort:

  • Ja - less und viele andere Programme können Unterprogramme aufrufen (z.B. eine Shell), welche dann mit root-Rechten läuft
  • Lösung: NOEXEC:
  nutzerXX  ALL=(root) NOEXEC: /usr/bin/more /var/log/messages
  nutzerXX  ALL=(root) NOEXEC: /usr/bin/more /var/log/boot.log

1.11.6 sudoedit

  • Benutzer nutzerXX soll die Datei /etc/rsyslog.conf editieren dürfen
  • in der Datei /etc/sudoers
  visudo
  ----
  nutzerXX ALL= sudoedit /etc/rsyslog.conf
  ----
  sudoedit /etc/rsyslog.conf
  • Gruppe berechtigen
visudo -f /etc/sudoers.d/admins
%sudo  ALL=(ALL) NOPASSWD: ALL
  • Shells
sudo -s # entspricht su
sudo -i # entspricht su -

1.11.7 sudo Aliases

     # User alias specification
     User_Alias      FULLTIMERS = millert, mikef, dowdy
     User_Alias      PARTTIMERS = bostley, jwfox, crawl
     User_Alias      WEBMASTERS = will, wendy, wim

     # Runas alias specification
     Runas_Alias     OP = root, operator
     Runas_Alias     DB = oracle, sybase
     Runas_Alias     ADMINGRP = adm, oper

     # Host alias specification
     Host_Alias      SPARC = bigtime, eclipse, moet, anchor :\
                     LINUX = grolsch, dandelion, black :\
                     LINUX_ARM = widget, thalamus, foobar :\
                     LINUX_PPC64 = boa, nag, python
     Host_Alias      CUNETS = 128.138.0.0/255.255.0.0
     Host_Alias      CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0
     Host_Alias      SERVERS = master, mail, www, ns
     Host_Alias      CDROM = orion, perseus, hercules

     # Cmnd alias specification
     Cmnd_Alias      KILL = /usr/bin/kill, /usr/bin/pkill
     Cmnd_Alias      PRINTING = /usr/sbin/lpc, /usr/bin/lprm
     Cmnd_Alias      SHUTDOWN = /usr/sbin/shutdown
     Cmnd_Alias      HALT = /usr/sbin/halt
     Cmnd_Alias      REBOOT = /usr/sbin/reboot
     Cmnd_Alias      SHELLS = /usr/bin/sh, /usr/bin/zsh, /bin/bash

FULLTIMERS  SPARC=(OP) KILL
WEBMASTERS  LINUX=(:ADMINGRP) SHELLS

1.11.8 sudo replay

  • Füge die folgenden Konfigurationszeilen in die /etc/sudoers Datei ein
 Defaults log_output
 Defaults!/usr/bin/sudoreplay !log_output
 Defaults!/sbin/reboot !log_output
  • nutzerXX darf root werden
 nutzerXX ALL=(root) ALL
  • Benutze sudo als nutzerXX um eine interaktive Shell zu bekommen
 nutzerXX$ sudo -i
  • ein paar Befehle ausführen, die Ausgaben produzieren
  • die sudo Root-Shell wieder verlassen
  • (im Terminal als Benutzer root) Aufgezeichnete Sitzungen auflisten
 sudoreplay -l
  • aufgezeichnete sudo Sitzung abspielen
 sudoreplay <TSID>
  • Verzeichnis der sudo Aufzeichnungen:
 ls -l /var/log/sudo-io/

1.11.9 einfaches Intrusion Detection mit sudo (ab sudo 1.8.7) (nur Theorie)

 openssl dgst -sha256 /usr/bin/passwd
 SHA256(/usr/bin/passwd)= a92b1b6fb52549ed23b12b32356c6a424d77bcf21bfcfbd32d48e12615785270
 visudo
 ----
 nutzerXX ALL= sha256:a92b1b6fb52... /usr/bin/passwd
 ----

1.11.10 sudo Konfiguration (Passwort Cache Beispiele)

 Defaults passwd_tries=5, passwd_timeout=2
 Defaults timestamp_timeout=0 # Disable password caching
 Defaults timestamp_timeout=5 # 5 Minuten password caching (default)

1.11.11 Befehle ohne Passwort

 nutzer ALL=(dba) NOPASSWD: /opt/oracle/bin/befehl

1.11.12 Passwort des Zielaccount angeben (SUSE Linux Default)

Defaults targetpw

1.11.13 Links zu “sudo”

1.12 PAM -Pluggable Authentication Modules

cat /etc/pam.d/common-auth | grep -v "#"

auth    [success=1 default=ignore]      pam_unix.so nullok_secure
auth    requisite                       pam_deny.so
auth    required                        pam_permit.so
auth    optional                        pam_cap.so
  • PAM Dienst-Typen
    • account: Prüfung Berechtigung
    • auth: Authentifizierung
    • password: Passwort-Änderung
    • session: Sitzungsverwaltung
  • PAM Control
    • requisite = muss erfolgreich sein, sonst Kette beenden (notwendige Vorbedingung)
    • required = muss am Ende erfolgreich sein (notwendige Bedingung)
    • sufficient = bei Erfolg wird die Kette beendet (hinreichende Bedingung)
    • optional = Returncode wird nicht verwendet
  • Linux-PAM erweiterte Controls
    • Syntax: [return-value=action …]
    • Return-Values
      • vgl. z.B. /usr/include//security/_pam_types.h
    • Actions:
      • OK = Zugriff erlauben
      • ignore = Ignorieren
      • bad = Zugriff verweigern
      • die = Zugriff verweigern und Kette abschliessen
      • done = Zugriff erlauben und Kette abschliessen
      • reset = PAM Variablen zurücksetzen/löschen und weitermachen
      • <n> = die folgenden <n> PAM-Regeln überspringen

1.12.1 Aufgabe: pam_warn.so für Login installieren

  • Installiere das Modul pam_warn.so fuer die Facility auth (zusätzlich session) in PAM-Dienst login
  • Schalte auf einen der Konsolen-Bildschirme des Laptops um “STRG+ALT+F2 … F8”
  • Melde dort den Benutzer nutzerXX an
  • Prüfe die Syslog/Journal Ausgabe

1.13 Lösung

  • in Datei /etc/pam.d/login (ans Ende hinter alle @include)
auth       required   pam_warn.so
session    required   pam_warn.so
  • per STRG+ALT+F2 auf eine Text-Konsole wechseln
  • die neuen Log-Einträgen mit journalctl -f --grep pam_warn oder journalctl -f --facility=authpriv prüfen
  • als nutzerXX einloggen

1.13.1 Aufgabe: ein einfaches PAM-Modul aktivieren

  • Es gibt ein PAM-Modul, welches allen normalen Benutzern die Anmeldung am System verweigert. Nur der root Benutzer darf sich dann anmelden.
  • Dieses PAM-Modul ist schon für den Dienst login konfiguriert, wirkt sich aber nicht aus (Datei /etc/pam.d/login)
  • Lese die Man-Pages der PAM-Module für den Dienst login der auth-Funktionen, finde heraus, welches Modul das Login aller Nicht-Root-Benutzer verweigern kann, und wann es sich auswirkt.
  • Aktiviere diese Funktion und teste diese aus. Wechsle mit STRG+ALT+F2 auf die Text-Konsole und versuche Dich dort mit dem normalen Benutzer anzumelden. Alternativ: Anmeldung per SSH über das Loopback-Interface:
ssh nutzerXX@localhost
  • Wie kann einem normalen Benutzer der Grund für den Fehlschlag des Anmeldeversuches mitgeteilt werden?

1.13.2 Lösung:

  • Modul pam_nologin.so, aktiviert durch die Datei /etc/nologin:
echo 'Heute kein Login möglich! Wartungsarbeiten bis Dienstag!' > /etc/nologin

1.13.3 Aufgabe: 2-Faktor Authentisierung - OATH Open Authentication Event Token (HOTP)

  • RFC 4226 HOTP: An HMAC-Based One-Time Password Algorithm (https://tools.ietf.org/html/rfc4226)
  • Alternative: RFC 6238 “TOTP: Time-Based One-Time Password Algorithm”
  • Token-Software als App für viele Mobiltelefone verfügbar
  • Pakete installieren
apt install libpam-oath oathtool
  • pam_oath in die PAM Konfiguration aufnehmen (hier für den su Befehl). window=5 gibt ein Fenster von 5 Passwörtern aus der Liste an, welche akzeptiert werden.
$EDITOR /etc/pam.d/su
-----
#%PAM-1.0
auth            sufficient      pam_rootok.so
auth            requisite       pam_oath.so usersfile=/etc/oath/users.oath window=5
-----
  • OATH Benutzerdatei anlegen
mkdir /etc/oath
$EDITOR /etc/oath/users.oath
-----
HOTP nutzerXX - <hex-secret>
HOTP nutzerYY - 0102030405
  • Beispiel: Passwort in HEX-Zahl umrechnen:
echo "secrt" | od -x
0000000 6573 7263 0a74
0000006
  • Benutzerrechte setzen
chmod 000 /etc/oath/users.oath
chown root: /etc/oath/users.oath
  • Eine Reihe (5 Stück) von Passwörter zum Test erstellen
oathtool -w 5 <hex-secret>
  • Anmeldung ausprobieren als “nutzerXX”, eines der Passwörter aus der Liste probieren
su - nutzerXX
  • Wer ein Smart-Phone hat, mal im App-Store nach “OATH” suchen, eines OATH-Token Programm installieren und konfigurieren

1.13.4 Aufgabe: Einmal Passwörter mit OTPW

  • OTPW = One-Time-Password – ähnlich einer TAN-Liste
  • OTPW Pakete installieren
apt install libpam-otpw otpw-bin
  • das Modul pam_otpw in die PAM-Konfiguration vom su aufnehmen, die Konfiguration von OATH und common-auth auskommentieren
...
auth            required        pam_otpw.so
...
session         optional        pam_otpw.so
#@include common-auth
...
  • Auf alten Systemen benutzt otpw-gen zur Initialisierung des Zufallszahlengenerators netstat (ist das sicher?). Auf debian 12 (bookworm) ist das nicht mehr erforderlich.
apt install net-tools
  • Als Benutzer nutzerXX eine Passwortliste erstellen (dabei das Prefix-Passwort angeben) und ggf. ausdrucken. Ausdrucke finden sich im Kyocera-Drucker in der Vorhalle
su - nutzerXX
otpw-gen > otpwlist.txt
less otpwlist.txt
lp otpwlist.txt
  • OTPW legt Hashes der Einmalpasswörter in der Datei ~/.otpw ab
less ~/.otpw
  • OTPW ausprobieren (als NutzerXX nochmals per su anmelden). Das bei der Erstellung der Passwort-Liste angegebene Passwort muss vor dem Einmal-Passwort eingegeben werden
su - nutzerXX
  • das Passwort ist nun verbraucht und aus der Liste gestrichen
less ~/.otpw

1.13.5 Weitere Links zu PAM

1.13.6 PAM Duress

  • PAM Duress (https://github.com/nuvious/pam-duress) ist ein interessantes PM-Modul welches es dem Benutzer erlaubt, alternative Passwörter im PAM zu hinterlegen. Diese Passwörter sind jeweils mit einen Shell-Skript verbunden. Wird eines der “Duress” Passwörter statt dem “normalen” Benutzerpasswort eingegeben, so wird das dazugehörige Script ausgeführt.
  • Beschreibung der Einsatzszenatrien von der Projekt-Webseite

    Diese Funktion könnte genutzt werden, um jemandem, der unter [Zwang] zur Eingabe eines Kennworts gezwungen wird, die Möglichkeit zu geben, ein Kennwort einzugeben, das den Zugang gewährt, aber im Hintergrund Skripte ausführt, um sensible Daten zu bereinigen, Verbindungen zu anderen Netzwerken zu schließen, um lateral movement einzuschränken, und/oder eine Benachrichtigung oder einen Alarm zu senden (möglicherweise mit detaillierten Informationen wie Standort, sichtbaren WLAN-Hotspots, einem Bild von der Kamera, einem Link zu einem Stream vom Mikrofon usw.). Es kann sogar einen Prozess starten, um das Modul pam_duress zu entfernen, damit der Bedrohungsakteur nicht sehen kann, ob das PAM-Duress verfügbar war.

  • Weitere Einsatzgeniete:
    • Wegwerfbare Gast-Zugänge einrichten
    • Automatisches mit-protokollieren einer Sitzung per “sudo” beim Login einschalten
    • MacOS “Find-my-Mac” nachbauen (gestohlene Rechner orten)

1.14 TMUX - terminal multiplexer

apt install tmux
tmux
Aktion Tastaturkombination
Neues Terminal CTRL+B c
nächstes Terminal CTRL+B n
voheriges Terminal CTRL+B p
Screen Nr. x [0…9] CTRL+B 4
Terminal horizontal teilen CTRL+B “
Terminal vertikal teilen CTRL+B %
zwischen geteilten Terminals wechseln CTRL+B <cursor>
  CTRL+B O
Größe ändern CTRL+B CTRL+<cursor>
  CTRL+B <ESC> <cursor>
Zoomen CTRL+B z
Layout ändern CTRL+B <space>
Terminal schliessen CTRL+B x
Tmux abhängen (detach) CTRL+B d
Grafisch Fenster wechseln CTRL+B w
Grafisch Sitzung wechseln CTRL+B s
Tmux anhängen tmux attach
Tmux Kommandozeile CTRL+B :
Tastenkommandos in alle Fenster (Kommandozeile) set synchronize-panes

2 Tag 2

2.1 Zugriff auf Ressourcen beschränken

2.1.1 Resourcenbeschränkungen über PAM (Modul pam_limits)

  • Konfigurationsdatei der PAM-Limits ist /etc/security/limits.conf. Liste der Resourcen die kontrolliert werden können:
    core Grösse einer Core-Dump Datei (KB)
    data maximale Grösse des zu ladenen Programms (KB)
    fsize maximale Dateigrösse (KB)
    memlock maximale Grösse des Prozesspeichers, welcher nicht ausgelagert werden darf (KB)
    nofile maximale Anzahl der offenen Dateien
    rss maximale Grösse des “resident set size” (Speicherverbrauch eines Prozesses im Hauptspeicher) (KB)
    stack maximale Grösse des Stacks eines Prozesses (KB)
    cpu maximale CPU Zeit (MIN)
    nproc maximale Anzahl von Prozessen
    as Limit des Addressbereiches (KB)
    maxlogins maximale Anzahl der Logins pro Benutzername
    maxsyslogins maximale Anzahl der Logins am System (aller Benutzer)
    priority Priorität von Benutzerprozessen
    locks maximale Anzahl von Datei-Locks
    sigpending maximale Anzahl von wartenden Signalen für Prozesse
    msgqueue maximaler Speicherverbrauch von POSIX message queues (bytes)
    nice maximaler “nice” Wert: [-20, 19]
    rtprio maximale Echtzeit Priorität von Prozessen
    chroot Benutzer darf den “chroot” Syscall ausführen (Debian spezifisch)
  1. Format der limits.conf Datei
         # Benutzer/Gruppe  Type    Ressource       Wert
         *                  soft    core            0
         root               hard    core            100000
         *                  hard    rss             10000
         @student           hard    nproc           20
         @faculty           soft    nproc           20
         @faculty           hard    nproc           50
         ftp                hard    nproc           0
         ftp                -       chroot          /ftp
         @student           -       maxlogins       4
    
  2. Aktuelle Limits der aktuellen Session anzeigen
         ulimit -a
    
  3. limit setzen und testen
         ulimit -S -t 2
         dd if=/dev/urandom | gzip > /dev/null
    
         apt install stress
         ulimit -S -t 2
         prlimit --cpu=10:20 stress -c 1
    
  4. Anzahl Logins beschränken

    wir passen die Anzahl der erlaubten Logins pro Benutzer an

       nutzerXX             -       maxlogins       2
    
  5. testen der neuen Konfiguration
       ssh nutzerXX@localhost
    

    3 x wiederholen oder auf mehr als 3 Konsolen anmelden

  6. CPU Zeit, RAM und offene Dateien beschränken

    durch eine Forkbombe (oder durch einen Sicherheitsfehler in einem Programm) kann ein Benutzer ein Linux/Unix System zum erliegen bringen. Eine Forkbombe erzeugt exponential viele Prozesse. Wenn die Erzeugung von Prozessen nicht beschränkt wurde, kommt das System in einen Zustand in dem es nicht mehr produktiv benutzt werden kann:

      forkbomb(){ forkbomb | forkbomb & }; forkbomb
    
    • oder Kurzversion einer Forkbombe
      :(){ :|:& };:
    
    nutzerXX             -       cpu             1
    nutzerXX             soft    nproc           800
    nutzerXX             hard    nproc           1000
    nutzerXX             -       priority        5
    
  7. testen
      ps -p $$ -o pid,user,nice,cmd
      ulimit -a
      forkbomb(){ forkbomb | forkbomb & }; forkbomb
    

2.1.2 nice, renice und cpulimit

apt install cpulimit
stress-ng -c 8 # CPU Kerne * 2
renice -n <nice-wert> <pid>
cpulimit -l 50 -p <pid> # nicht mehr empfohlen

2.1.3 ionice

  1. Disk IO per ionice beschränken
    • per ionice kann die IO-Priorität eines Prozesses kontrolliert werden ( ab Kernel 2.6.13 mit CFQ I/O-Scheduler ). Dokumentation zu ionice findet sich in der Linux-Kernel Dokumentation /usr/src/linux/Documentation/block/ioprio.txt.
  2. iotop

    iotop zeigt die IO-Auslastung des Systems nach Prozessen an. In der Spalte “PRIO” wird die ionice Klasse und die Priorität angezeigt. Shortcuts beachten: Eventuell sortierung und accup anpassen

    apt install iotop
    stress -d 2
    iotop
    

2.2 Linux cgroups (Controll-Groups)

  • CGroups Informationen anzeigen
cat /proc/cgroups
ps xawf -eo pid,user,cgroup,args
systemd-cgls
systemd-cgtop

2.2.1 CGroups manuell

  • Stress erzeugen
stress-ng --cpu $(($(nproc)*2)) &
pgrep -alf stress-ng
  • CGroup manuell anlegen und kontrollieren
cd /sys/fs/cgroup
mkdir stressgroup
cd stressgroup
cat cgroup.controllers
cat cgroup.type
cat cgroup.subtree_control
  • Neue Untergruppen anlegen und kontrollieren
mkdir stress1 stress2
ls -l stress1
cat stress1/cgroup.type
cat stress1/cgroup.controllers
  • Controller vererben
echo +io +cpu > cgroup.subtree_control
ls -l stress1
  • Alle Prozesse in die Gruppe stress1 legen.
cd stress1
pgrep stress-ng | while read pid; do echo $pid > cgroup.procs; done
  • Schrittweise Last auf die Gruppe stress2 verteilen. Top beobachten. Weiter bis ca. Gleichstand erreicht ist.
cd ../stress2
echo <pid> > cgroup.procs
  • Kontrolle mit weight. Top beobachten
echo 10 > cpu.weight
  • In der anderen Gruppe mit harten Limits (CPU=100%) begrenzen
cd ../stress1
cat cpu.max
echo 100000 100000 > cpu.max
  • Alle Prozesse beenden
pkill stress-ng
rmdir stress1 stress2
cd ..
rmdir stressgroup

2.2.2 systemd

    systemctl set-property --runtime cups.service CPUQuota=10%
    systemctl cat cups.service

2.2.3 Systemresourcen beschränken mit systemd-run

systemd-run stress -c 3
systemd-run stress -c 3
systemctl show run-r<UUID>.service
systemctl set-property run-r<UUID>.service CPUWeight=33
systemctl set-property run-r<UUID>.service CPUQuota=100
systemd-run --on-active=20 -p CPUQuota=50% stress-ng --cpu 4

2.2.4 systemctl accounting anschalten

    $EDITOR /etc/systemd/system.conf.d/accounting.conf
    -----
    DefaultCPUAccounting=yes
    DefaultIOAccounting=yes
    DefaultBlockIOAccounting=yes
    DefaultMemoryAccounting=yes
    DefaultTasksAccounting=yes
  • BlockIO… gilt als deprecated. Deshalb fehlt die Directive.
    systemd-analyze cat-config /etc/systemd/system.conf   # pruefen

2.3 Dateisystemberechtigungen

2.3.1 normale Unix-Rechte

  1. die klassischen Unix-Dateisystemberechtigungen (RWX)
  2. das sgid-bit
         chmod g+s <verzeichnis>
    

    neue Dateien bekommen die Gruppe des Verzeichnisses anstatt der (primäre) Gruppe des Benutzers. Beim anlegen von Unterverzeichnissen bekommen diese auch ein sgid bit gesetzt

  3. Unerwartet: Schreibrechte auf Verzeichnis vs. Schreibrechte auf Datei
    useradd nutzer1
    useradd nutzer2
    groupadd projekt
    usermod -a -G projekt nutzer1
    usermod -a -G projekt nutzer2
    mkdir /home/projekt
    chown :projekt /home/projekt
    chmod g+w /home/projekt
    ls -ld /home/projekt/
    su - nutzer1
    cd /home/projekt/
    cat > unveraenderbarer.txt
    Dies ist ein unveraenderbarer text
    CTRL+D
    chmod u=rw,g=r,o=r unveraenderbarer.txt
    chgrp projekt unveraenderbarer.txt
    ls -l unveraenderbarer.txt
    -rw-r--r--. 1 cas projekt 35 Nov 23 21:57 unveraenderbarer.txt
    logout
    su - nutzer2
    cd /home/projekt
    ls -l unveraenderbarer.txt
    vi unveraenderbarer.txt
    
  4. Frage:
    • kann nutzer2 mit diesen Berechtigungen die Datei verändern?
  5. Antwort:
    • ja, indirekt. Der Benutzer hat Schreibrechte auf dem Verzeichnis. Daher kann er neue Dateien anlegen und bestehende Löschen. Er kann auch Dateien löschen, auf denen er keine Schreibrechte besitzt! Der vi Editor legt bei Bearbeiten einer Datei eine lokale Kopie an, diese Kopie wird editiert und beim Speichern wird die Ausgangsdatei gelöscht und durch die temporäre Datei ersetzt.
  6. Sticky-Bit auf Verzeichnis - Nur der Besitzer der Datei darf die Datei löschen
        chmod o+t <verzeichnis>
    

2.3.2 Erweiterte Attribute

  • Nicht alle Dateisysteme unterstützen alle erweiterten Attribute (EA). Unter Linux unterstützen die ext2/ext3/ext4-Dateisysteme und das XFS-Dateisystem einige der EAs. Die Man-Page zum Dateisystemformat gibt Auskunft über die EA Unterstützung (z.B. man ext4).
  • Anzeigen der erweiterten Attribute: lsattr
  • Ändern der erweiterten Attribute: chattr
  • Sicherheit von erweiterten Attribute (EA) unter Linux im Vergleich zu BSD: unter BSD können die Sicherheitsrelevanten EA (append, immutable) vom Benutzer root nur im Single-User Module (ohne Netzwerk) gelöscht werden. Unter Linux kann root die EA zu jedem Zeitpunkt entfernen!
  1. erweiterte Attribute vom Benutzer verwaltbar
    • d – Datei nicht bei “dump” mitsichern
    • s – Datei wird beim Loeschen mit Nullen ueberschrieben
    • A – bei der Datei wird atime nicht aktualisiert
  2. erweiterte Attribute welche nur vom Benutzer root verwaltet werden
    • a – append - Datei kann nur erweitert werden
    • i – immutable - Datei ist unveraenderbar
    • C – no copy-on-write - für COW-Filesysteme (btrfs)
  3. Beispiele
    # Erweiterte Attribute Auslesen
    lsattr /pfad/zur/datei
    # Erweiterte Attribute setzen
    chattr +d /pfad/zur/datei
    # Erweiterte Attribute löschen
    chattr -d /pfad/zur/datei
    

2.3.3 Posix ACLs

  1. ACLs setzen (modify)
         setfacl -m u:<nutzer>:rwx file/dir          # ACL setzen
         setfacl -x u:<nutzer>                       # ACL löschen
         setfacl -d -m "u::rwx,g::rwx,o::-" <dir>    # Default ACL auf Verzeichnisse setzen
         setfacl -m "d:u::rwx,d::g:rwx,d:o::-" <dir> # alternative Syntax. Generic default mask
    
         setfacl -d -m u:<uidName>:rwx <file/dir>    # Benamte Default ACL macht sie "vererbbar"
    
  2. ACLs auslesen
         getfacl <datei/verzeichnis>
    
  3. ACL mask
    • chmod gruppe ändert nur noch die Maske
    • die Maske filtert die ACLs
    • Berechtigungs-Änderungen können nur mit setfacl durchgeführt werden
    • setfacl -k – default ACLs löschen
    • setfacl -b – ACLs löschen

2.4 Linux Capabilities

  • Linux Capabilities erlaubes es, Teile der Rechte des root Benutzers an Prozesse und Dateien zu binden
  • die verfügbaren Capabilities sind unter man capabilities nachlesbar
  • Installiere ein paar Zusatztools für Linux-Capabilities
apt install libcap-ng-utils libpam-cap

2.4.1 Beispiel: Als Ersatz für SUID

Als User

cat /usr/bin/ping > PING
chmod a+x PING
./PING 9.9.9.9
sudo -i
setcap cap_net_raw+p .../PING
^d
PING 9.9.9.9

Mit pstree und unter dem proc Dateisystem CapPrm prüfen

2.4.2 Beispiel: root CAP_CHOWN entziehen

capsh --drop=cap_chown --
chown fritz /home/prj

2.4.3 strace

Einfache Prozessverfolgung

strace -e file ls -l

z.B. Verfolgen einer Shell mit ping

strace -e %creds -ff -p <pid>

2.5 systemd Sicherheit

2.5.1 Einfache Direktiven

  • Units unter anderer uid/gid laufen lassen
  • Zugriff auf Verzeichnisse beschränken
  • Prozesslimits setzen
systemctl edit --full --force simplehttp.service

[Unit]
Description=Python HTTP Server (do not use)

[Service]
Type=simple
Restart=on-failure
EnvironmentFile=-/etc/default/%n
ExecStart=/usr/bin/python3 -m http.server $HTTP_PORT

# Namespace Spielereien
#WorkingDirectory=/usr/share/doc
ReadOnlyDirectories=/proc /sys
InaccessibleDirectories=/var/log
PrivateTmp=yes

ProtectSystem=strict
ProtectHome=read-only

# Limits
# darf nicht forken
#LimitNPROC=1
# darf nicht ins fs schreiben
#LimitFSIZE=0

# laeuft als root. Capabilities
# entziehen
#CapabilityBoundingSet=~cap_chown,cap_net_raw
# setzen
#CapabilityBoundingSet=cap_net_raw
CapabilityBoundingSet=cap_net_bind_service

# laeuft als user. Capabilities
#User=gabi
#Group=users
DynamicUser=yes
AmbientCapabilities=cap_net_bind_service

2.5.2 weitere Directiven und Isolationstechniken

  • PrivateNetwork=yes
  • CapabilityBoundingSet=CAP_CHOWN CAP_KILL
  • CapabilityBoundingSet=~CAP_SYS_PTRACE
  • DeviceAllow=/dev/null rw
  • ProtectSystem={ full | strict }
  • ProtectHome=
  1. Tipp: alles studieren, was Private… Protect… oder …Capabilit… im Namen hat

2.5.3 Selbstanalyse

  • systemd-analyze security
  • systemd-analyze security <unit.service>

3 Tag 3

3.1 SSH

3.1.1 SSH Fingerprint eines Servers prüfen

  • SSH Fingerprint eines Schlüssels auf einem Server anzeigen (zur Prüfung eines ersten Logins)
ssh-keygen -l -f /etc/ssh/ssh_host_<algorithm>_key.pub

3.1.2 SSH Known Hosts hashen

ssh-keygen -H -f .ssh/known_hosts
$EDITOR .ssh/config
----------
HashKnownHosts yes
----------
chmod -Rc go= .ssh

3.1.3 Übung: SSH mit Schlüsseln statt mit Passwort (ca. 20 Minuten)

  • in dieser Übung arbeiten wir als Benutzer und als Administrator. Lege mit dem Übungs-Partner die Rolle fest (Benutzer oder Administrator) und führe die Übung durch. Danach wechselt die Rolle.
  • Administrator: lege einen Benutzeraccount für den Kollegen/Kollegin vor/hinter Dir im Kurs an (Passwort und Benutzername absprechen)
  • Administrator: OpenSSH Server installieren (wenn nicht schon geschehen)
sudo apt install openssh-server
  • Benutzer: Teste aus, dass Du Dich auf dem System des Übungs-Partners einloggen kannst. Bei der ersten Kontaktaufnahme wird der Fingerprint des Servers angezeigt. Dieser Fingerprint kann über den Administrator des Servers angefragt werden.
nutzerXX: ssh nutzerXX@notebookYY
  • Benutzer: nach dem Test wieder aus dem fernen Rechner ausloggen
  • Benutzer: als normaler Benutzer (nutzerXX, nicht root) einen neuen SSH-Schlüssel erstellen (4096 RSA). Eine Passphrase vergeben.
nutzerXX$ ssh-keygen -b 4096
  • Benutzer: den öffentlichen Schlüssel per SSH auf den fernen Rechner übertragen:
nutzerXX$ ssh-copy-id nutzerXX@notebookYY
  • Es empfiehlt sich, die Schlüssel mit ssh-copy-id -i .ssh/... zu begrenzen
  • Benutzer: Alternativ die Datei ~/.ssh/id_rsa.pub vom eigenen Rechner auf den fernen Rechner übertragen (z.B. per E-Mail senden) und den Administrator bitten, den eigenen Schlüssel in die Datei .ssh/authorized_keys einzutragen.
  • Administrator: Nun sind die Schlüssel ausgetauscht, und wir können Anmeldung per Passwort auf dem Server-System abschalten. Als root Benutzer:
  1. Passwort-Authentisierung abschalten

    Die Benutzung von Passwörter für die SSH-Authentisierung ist einfach aber liefert nur eine minimale Sicherheit. Passwörter sind oft zu erraten oder per Brute-Force-Angriff ermittelbar. Besser sind kryptografische Schlüssel. SSH bietet die Authentisierung per Schlüssel, jedoch wird die Passwort-Anmeldung als Rückfall-Mechanismus benutzt. Um SSH richtig abzusichern sollte daher die Passwort-Anmeldung in der Konfiguration des SSH-Servers abgeschaltet werden.

    $EDITOR /etc/ssh/sshd_config
    ------
    PermitRootLogin no
    PubkeyAuthentication yes
    PasswordAuthentication no
    ------
    
    • Administrator: SSH-Dienst neu starten
    systemctl restart sshd
    
    • Benutzer: Anmeldung am fernen Rechner testen, dies sollte nun nach Eingabe der Passphrase funktionieren
    nutzerXX$ ssh nutzerXX@notebookYY
    
    • Benutzer: Wenn ein Benutzer ohne Schlüssel versucht, sich am fernen Rechner anzumelden, wird er gleich abgewiesen
    ssh root@notebookYY
    
    • Info Benutzer: die Fingerprints der Server werden beim Client unter ~/.ssh/known_hosts gespeichert
    • Info Administrator: die öffentlichen Schlüssel werden auf dem fernen Rechner in der Datei ~/.ssh/authorized_keys gespeichert

3.1.4 SSH Passphrase ändern

ssh-keygen -p -f .ssh/id_ed25519

3.1.5 SSH-Agent

  • SSH-Agent starten (wird normalerweise in der Benutzer-Sitzung gestartet, z.B. über “.profile”)
#entweder in der aktiven Shell
eval $(ssh-agent)
#oder als prefix-Befehl
ssh-agent tmux #oder bash
  • die privaten SSH-Schlüssel dem SSH-Agent hinzufügen
ssh-add
ssh-add <schlüssel>
  • Fingerprints aller Schlüssel im Agent anzeigen
ssh-add -l
  • alle Schlüssel im Agent anzeigen
ssh-add -L
  • Agent sperren/entsperren
ssh-add -x
ssh-add -X
  • Schlüssel im SSH-Agent löschen
ssh-agent -D

3.1.6 Agent-Forwarding

  • Agent-Funktion an einem Jumphost weitergeben. Nun kann sich der Benutzer vom Jumphost mit Schlüssel an weiteren SSH-Servern anmelden
ssh -A <jumphost>
  1. Übung: SSH-Forwarding
    • der Nachbar sollte uns einen Benutzer auf seinem System mit Deinem Benutzernamen erstellen
    • Für diese Übung müssen wir unseren öffentlichen Schlüssel auf den Laptop eines Nachbarn installieren (dies wurde ggf. schon am Tag 2 gemacht: Übung Anmeldung am SSH mit Schlüssel
    ssh-copy-id nutzerXX@notebookYY
    
    • nachdem die Schlüssel kopiert wurden kann die Passwort-Authentisierung in der Datei /etc/ssh/sshd_config ausgeschaltet werden
    [...]
    PasswordAuthentication no
    [...]
    
    • und den SSH-Dienst neu starten
    systemctl restart sshd
    
    • nun sollte auf dem Laptop nur noch eine Anmeldung per Schlüssel möglich sein
    • stelle sicher, das der SSH-Agent für die aktuelle Shell-Sitzung aktiv ist und lade die eigenen Schlüssel in den SSH-Agent
    ssh-add -l
    
    • Teste die Anmeldung an den Trainer-Laptop (hier Anmeldung per Passwort villa)
    ssh trainer
    
    • Teste, das eine Anmeldung mit dem eigenen Benutzer (nutzerXX) von Laptop des Trainers auf den Laptop des Übungs-Partners (notebookYY) nicht möglich ist
    trainer-laptop$ ssh nutzerXX@notebookYY
    
    • den Laptop des Trainers wieder verlassen
    trainer-laptop$ exit
    
    • wir nehmen an, dass eine direkte Netzwerkverbindung zwischen dem eigenen Laptop und dem Laptop des benachbarten Teilnehmers nicht möglich ist, ein Login auf diesem Laptop muss über den Umweg des Trainer-Laptops geschehen (Jump-Host)
    • Teste die SSH-Agent-Forwarding Funktion mit einer Anmeldung an den Jump-Host (Trainer-Laptop per Passwort villa) und von dort aus einer Anmeldung an den Laptop des benachbarten Teilnehmers. Die zweite Anmeldung solle bei aktiven SSH-Agent ohne Passwortabfrage funktionieren
    notebookXX$ ssh -A trainer
    trainer-laptop$ ssh nutzerXX@notebookYY
    

3.1.7 SSH Agent-Forwarding vs. ProxyCommand

  1. AgentForwarding Alternative ProxyCommand
    • vor OpenSSH 7.3
    Host jumphost
     	User nutzer
     	Hostname 192.168.1.241 # Trainer Laptop
    	Port 8422
    
    Host internalserver
     	User nutzerXX
     	Hostname notebookYY # Laptop des anderen Teilnehmers
     	Port 22
     	ProxyCommand ssh -q -W %h:%p jumphost
    
    • seit OpenSSH 7.3
    Host jumphost
     	User nutzer
     	Hostname 192.168.1.241 # Trainer Laptop
    	Port 8422
    
    Host internalserver
     	User nutzerXX
     	Hostname notebookYY # Laptop des anderen Teilnehmers
     	Port 22
     	ProxyJump jumphost
    
    • ProxyJump auf der Kommandzeile (seit OpenSSH 7.3)
    ssh -J jumphost benutzer@internalserver
    
  2. Übung:
    • erstelle eine lokale Konfigurationsdatei ~/.ssh/config mit der ProxyCommand Konfiguration (siehe oben)
    • SSH-Verbindung durch den JumpHost (Trainer-Laptop) zum Laptop eines anderen Teilnehmers testen
    ssh internalserver
    

3.1.8 SSH Tunnel

  • Über SSH Tunnel können beliebige Ports über die SSH Verbindung geleitet werden
  • Praktische Illustration zu local und remote tunnels: https://iximiuz.com/ssh-tunnels/ssh-tunnels.png
  • Tunnel von Port 80 auf dem Server (notebookYY) zu Port 8080 auf dem Client über notebookXX
ssh -L 8080:notebookYY:80 nutzerXX@notebookXX
ssh -L 8080:datenbank:80 nutzerXX@notebookXX
  • Rückwärts-Tunnel: vom Ziel-System zurück auf den Client. Dieses Beispiel öffnet einen Tunnel von localhost:8000 auf dem Zielsystem auf Port 8000 des SSH-Clients
ssh -R 8000:notebookXX:8000 nutzerXX@notebookXX
  • Socks-Proxy Forwarding (Web-Browsen durch den Tunnel), im Browser die Socks-Proxy Konfiguration auf 127.0.0.1 Port 8080 setzen
ssh -CD 127.0.0.1:8080 nutzer@server
  1. Übung: SSH Tunnel
    • erstelle einen SSH-Tunnel von Port 8080 (lokal) auf die IPv4-Loopback-Adresse (127.0.0.XX; x=Teilnehmernummer, z.B. 42) des Trainer-Laptops, Port 8000:
    ssh -L 8080:127.0.0.XX:8000 nutzer31@192.168.1.83
    
    • auf dem Trainer-Laptop erstellen wir eine minimale HTML-Datei
    mkdir ~/webseiteXX
    cd ~/webseiteXX
    ~/webseiteXX% echo "dies ist der Webserver von NutzerXX" > index.html
    
    • auf dem Trainer-Laptop den Python3 Webserver auf der Loopback-Adresse, Port 8000, starten
    ~/webseiteXX% python3 -m http.server --bind 127.0.0.XX
    
    • Starte Firefox-Browser, verbinde Dich mit der eigenen Loopback-Adresse Port 8080 (URL http://127.0.0.1:8080/). Es sollte die minimale Webseite aus dem Heimverzeichnis auf dem Trainer-Laptop erscheinen

3.1.9 SSH RSA-SHA1 Schlüssel sind abgekündigt

  • OpenSSH hat in früherern Versionen standardmässig Schlüssel mit dem RSA-SHA1 Algorithmus erzeugt. Dieser Algorithmus gilt inzwischen als unsicher und werden bald mit einer neuen Version von OpenSSH nicht mehr unterstützt
    • Daher sollten Benutzer von OpenSSH testen, ob sie noch RSA-SHA1 Schlüssel benutzen und diese ggf. durch neue Schlüssel austauschen
    • Test mit RSA-SHA1 abgeschaltet. Klappt die Anmeldung, so wird ein anderer Schlüssel benutzt. Schlägt die Anmeldung fehlt, so sollte ein neuer Schlüssel für diesen Benutzer erstellt werden:
           ssh -oHostKeyAlgorithms=-ssh-rsa user@host
      
    • Gibt es die folgende Fehlermeldung, dann benutzt der Server noch alte RSA-SHA1 Schlüssel und diese Schlüssel sind in der lokalen known-hosts Datei eingetragen:
           @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
           @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
           @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
           IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
           Someone could be eavesdropping on you right now (man-in-the-middle attack)!
           It is also possible that a host key has just been changed.
           The fingerprint for the ECDSA key sent by the remote host is
           SHA256:/7MPZYXQhPQ0uwZaupxxUC0EDU7I2D+s8OQCLtN69rE.
           Please contact your system administrator.
           Add correct host key in /home/nutzer/.ssh/known_hosts to get rid of this message.
           Offending RSA key in /home/nutzer/.ssh/known_hosts:157
           ECDSA host key for ssh-host.example.com has changed and you have requested strict checking.
           Host key verification failed.
      
    • Der Server-Betreiber sollte den alten RSA-SHA1 Schlüssel vom Server entfernen
    • Der Benutzer sollte den Hash-Eintrag des RSA-SHA1 aus der Datei known-hosts entfernen und dann den Hash des neuen Schlüssels mit dem Betreiber des Servers (oder via DNS, siehe unten) abgleichen
  • Empfohlene SSH Schlüssel-Algorithmen
  • Informationen: OpenSSH 8.3 released (and ssh-rsa deprecation notice)

3.1.10 Lokale SSH-Konfigurationsdatei

  • Bei komplexen SSH-Konfigurationen ist es hilfreich, die SSH-Parameter pro Ziel-System in der lokalen SSH-Konfigurationsdatei für den Benutzer abzulegen. Fast alle Kommandozeilen-Optionen des SSH-Clients können in dieser Konfigurationsdatei festgelegt werden (siehe man ssh).
  • Beispiel einer lokalen SSH-Konfigurationsdatei für einen Benutzer. Datei ~/.ssh/config
Host zielhost                                          # symbolischer Name
        Hostname zielhost.example.com                  # echter DNS-Name
	User nutzerXX                                  # Standard Benutzer
	Compression yes                                # gzip Kompression an
	VerifyHostKeyDNS yes                           # Host-Key per DNS prüfen
	Port 65123                                     # SSH läuft auf diesem Port
	ProxyJump jumphost.example.com                 # Verbindung über Jumphost
  1. Übung: lokale SSH-Client-Konfigurationsdatei
    • Zeit: 15 Minuten
    • erstelle eine lokale SSH-Konfigurationsdatei ~/.ssh/config für die Verbindung auf die IP-Adresse des VM Servers für das SELinux Kapitel (später im Kurs)
    Benutzer Server Domainname
    Eva selinux001.dnslab.org
    Philip selinux002.dnslab.org
    Rafael selinux003.dnslab.org
    Mirko selinux004.dnslab.org
    Stefan selinux005.dnslab.org
    Michi selinux006.dnslab.org
    Rene selinux007.dnslab.org
    Carsten selinux008.dnslab.org
    • vergebe den symbolischen Namen selinux für den Server
    • SSH-Server läuft auf Port 22
    • Benutzername user, Passwort villa
    • benutze die IP-Adresse des Servers als Hostnamen in der Konfiguraionsdatei (find die IPv4-Adresse des Servers mit dig oder nslookup
           % dig selinuxNNN.dnslab.org a
      
    • die SSH Konfigurationsdatei sollte nur für den Benutzer lesbar sein (ggf. müssen die Dateiberechtigungen angepasst werden)
    • teste die Verbindung per symbolischen Namen
    ssh selinux
    
    • Beispiellösung
    Host selinux
      Hostname  159.223.128.127
      User user
      Port 22
    
  2. Weitere Informationen und Tipps: Simplify Your Life With an SSH Config File

3.1.11 VisualHostKey

  • der Konfigurationsparameter VisualHostKey in der Datei /.ssh/config zeigt eine visuelle Darstellung des Schlüssel-Hash jedes Ziel- und Jump-Host Servers an
VisualHostKey yes

3.1.12 SSH-PAM-Module

  • pam_ssh.so – per SSH Key Passphrase anmelden und Schlüssel in den Agent laden
  • pam_sshauth.so – lokale Anmeldung durch erfolgreiche SSH-Anmeldung an einen fernen SSH Server

3.1.13 TODO Übung: PAM-Anmeldung per SSH Passphrase

  • installiere pam_ssh
apt install libpam-ssh
  • prüfe, ob sich schon SSH-Schlüssel unter /home/nutzerXX/.ssh/ befinden. Wenn nicht, einen SSH-Schlüssel erstellen per ssh-keygen und für den Schlüssel eine Passphrase vergeben. Diese Passphrase sollte nicht das normale Benutzerpasswort sein.
  • Konfiguriere pam_ssh als sufficient PAM-Modul für das grafische Login (Datei /etc/pam.d/gdm-password =, Facility =auth)
  • Konfiguriere pam_ssh als optional PAM-Modul in /etc/pam.d/common-session (Facility session)
  • Die grafische GUI verlassen und an der GUI eine Anmeldung per SSH-Passphrase versuchen
  • Prüfen das der SSH-Agent gestartet ist und den/die Schlüssel geladen hat
ssh-add -l

3.1.14 Socks-SSH-Proxy

  • Socks-Proxy Forwarding (Web-Browsen durch den Tunnel), im Browser die Socks-Proxy Konfiguration auf 127.0.0.1 Port 8080 setzen
    • Option -C schaltet Kompression der Daten im Tunnel ein
    • Option -D schaltet den Socks-Proxy für den SSH-Tunnel ein
ssh -C -D 127.0.0.1:8080 nutzer@server

3.1.15 SSH-Escape

  • A tilde (~) after an Enter is the escape sequence of SSH
  • ~~ Tilde senden
  • ~. SSH-Verbindung sofort stoppen
  • ~<Ctrl-Z> SSH Sitzung in den Hintergrund senden (mit fg wieder in den Vordergrund holen)
  • ~& SSH als ’daemon’ in den Hintergrund senden und vom Terminal ablösen
  • ~? Hilfe anzeigen.
  • ~R neuen Sitzungschlüssel aushandeln
  • ~C SSH Komandozeile anzeigen (kann benutzt werden um neue Tunnel in schon bestehende Verbindungen einzubauen)
  • ~# bestehende SSH-Tunnel anzeigen

3.1.16 Ausführbare Befehle über die authorized_keys beschränken

command="foobar" ssh-rsa AAAAB3Nza… calls "foobar" and only "foobar" upon every login with this key
from="computer" ssh-rsa AAAAB3Nza… allows access with this key only from the host "computer".

3.1.17 SSH-Schlüssel Fingerprints in DNS

  • SSH Fingerprint im DNS hinterlegen (DNSSEC Absicherung empohlen!). SSHFP Records erstellen (auf dem Server, je ein Aufruf pro Schlüssel-Type (RSA, ECDSA, ED25519 …):
ssh-keygen -r <hostname> -f /etc/ssh/ssh_host_<algorithm>_key.pub
  • SSH mit Prüfung des SSH-Fingerabdrucks in DNS
ssh -o "VerifyHostKeyDNS ask" <hostname>
  • in SSH-Config Datei übernehmen
$EDITOR ~/.ssh/config
----
HOST *
  VerifyHostKeyDNS ask
  • Test
ssh host.example.com
The authenticity of host 'host.example.com (2001:db8:2b6:0:ba27:ebff:fe12:30db)' can't be established.
ECDSA key fingerprint is SHA256:ue1FlRUMmkPNhgFE55yqnnFl58FOlMnDGheCxQn2tWg.
Matching host key fingerprint found in DNS.
ECDSA key fingerprint is MD5:2e:a1:3c:94:d0:cb:ed:85:67:2e:7a:85:1c:bc:f3:70.
Matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)?
  • mit VerifyHostKeyDNS yes
ssh -v <host>
[...]
debug1: found 4 secure fingerprints in DNS
debug1: matching host key fingerprint found in DNS
[...]
  • Wenn OpenSSH Probleme hat, die DNSSEC Authentizität der SSHFP zu prüfen, muss ggf. EDNS in der Resolver-Konfiguration des Linux eingeschaltet werden
$EDITOR /etc/resolv.conf
----
[...]
options edns0

3.1.18 Verwaltung von SSH authorized_keys auf dem Server

3.1.19 Ein CHROOT für SSH

  • eine Gruppe für die CHROOT SSH Benutzer erstellen
 groupadd sshusers
 useradd -m -s /bin/bash -g sshusers sshguy
 passwd sshguy
  • wir erzeugen ein neues root Verzeichnis, das chroot-Verzeichnis
 mkdir -p /var/ssh-chroot/{dev,etc,lib,lib64,usr,bin,home}
 mkdir -p /var/ssh-chroot/usr/bin
 chown root: /var/ssh-chroot
  • die Gerätedatei /dev/null anlegen
 mknod -m 666 /var/ssh-chroot/dev/null c 1 3
  • das Heimverzeichnis des Benutzers in das chroot kopieren
 cp -R /home/sshguy /var/ssh-chroot/home/
 chown -R sshguy /var/ssh-chroot/home/
  • wir kopieren einige Dateien aus /etc in das Verzeichnis etc innerhalb des chroot
 cd /var/ssh-chroot/etc
 cp /etc/ld.so.cache /etc/ld.so.conf /etc/nsswitch.conf /etc/resolv.conf .
  • der Benutzer soll bash und ls ausführen können, also kommen diese Dateien in die chroot
 cd ../bin
 cp /bin/ls /bin/bash .
  • für jedes Programm im chroot müssen wir nun die dynamischen Bibliotheken in das chroot Verzeichnis kopieren. Der ldd Befehl listet alle Bibliotheken
 ldd /bin/ls
 ldd /bin/bash
  • Wir haben ein Skript, welches die Bibliotheken für ein Programm in das chroot kopiert:
 mkdir ~/bin
 $EDITOR ~/bin/l2chroot
 ----
 #!/bin/bash
 # Use this script to copy shared (libs) files to Apache/Lighttpd chrooted
 # jail server.
 # ----------------------------------------------------------------------------
 # Written by nixCraft <http://www.cyberciti.biz/tips/>
 # (c) 2006 nixCraft under GNU GPL v2.0+
 # + Added ld-linux support
 # + Added error checking support
 # ------------------------------------------------------------------------------
 # See url for usage:
 # http://www.cyberciti.biz/tips/howto-setup-lighttpd-php-mysql-chrooted-jail.html
 # -------------------------------------------------------------------------------
 # Set CHROOT directory name
 BASE="/var/ssh-chroot"

 [ ! -d $BASE ] && mkdir -p $BASE || :

 # iggy ld-linux* file as it is not shared one
 FILES="$(ldd $1 | awk '{ print $3 }' |egrep -v ^'\(')"

 echo "Copying shared files/libs to $BASE..."
 for i in $FILES
 do
   d="$(dirname $i)"
   [ ! -d $BASE$d ] && mkdir -p $BASE$d || :
   /bin/cp $i $BASE$d
 done

 # copy /lib/ld-linux* or /lib64/ld-linux* to $BASE/$sldlsubdir
 # get ld-linux full file location
 sldl="$(ldd $1 | grep 'ld-linux' | awk '{ print $1}')"
 # now get sub-dir
 sldlsubdir="$(dirname $sldl)"

 if [ ! -f $BASE$sldl ];
 then
   echo "Copying $sldl $BASE$sldlsubdir..."
   /bin/cp $sldl $BASE$sldlsubdir
 else
   :
 fi
  • Script ausführbar machen
 chmod +x ~/bin/l2chroot
  • das Script benutzen, um die Bibliotheken in das chroot zu kopieren
 l2chroot /var/ssh-chroot/bin/ls
 l2chroot /var/ssh-chroot/bin/bash
  • prüfen, das Bibliotheks-Dateien kopiert wurden
 ls -l /var/ssh-chroot/lib64
 ls -l /var/ssh-chroot/lib/x86_64-linux-gnu/
  • einen Hardlink für BASH in /usr/bin im chroot erstellen
ln bin/bash usr/bin/
  • Manueller Test der chroot Umgebung:
 chroot /var/ssh-chroot/ /bin/bash
  • Chroot für die Gruppe sshusers in der SSH-Konfiguration einrichten (Konfiguration am Ende der Datei anfügen)
 $EDITOR /etc/ssh/sshd_config
 ----
 Match group sshusers
           ChrootDirectory /var/ssh-chroot/
           X11Forwarding no
           AllowTcpForwarding no
	   PasswordAuthentication yes
 ----
  • SSH-Daemon neu starten
 systemctl restart sshd
  • Ausprobieren:
 ssh sshguy@localhost
  • Fertig!

3.1.20 Daten mit SSH-Schlüsseln signieren

  1. SSHIGN

3.1.21 Daten mit SSH-Schlüsseln verschlüsseln

  1. SSH-vault
  2. JASS

3.1.23 Alerting or notifying on SSH logins / PAM

  • Original von Jan-Piet Mens mit Benachrichtigung via MQTT: https://jpmens.net/2018/03/25/alerting-on-ssh-logins/
  • zentralisierte Benachrichtigung bei SSH-Logins auf einem Rechner der eigenen IT-Infrastruktur. Kommunikation zwischen SSH-Server und zentraler Monitoring-Instatnz über leichtgewichtiges UDP, E-Mail Kommunikationsparameter werden zentral verwaltet.
  • Quellcode des hare Programms (PAM-Modul für die SSH-Server)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <memory.h>
#include <sys/socket.h>

/*
 * hare.c (C)2018 by Jan-Piet Mens <jp@mens.de>
 */

#define PORTNO  8035

#define env(K)  ( getenv(K) ? getenv(K) : "<unknown>" )

int main(int argc, char **argv)
{
        struct sockaddr_in servaddr;
        unsigned long addr;
        int sockfd;
        char *host = argv[1], buf[BUFSIZ], myhostname[BUFSIZ];
        char *pamtype = env("PAM_TYPE");        /* Linux */
        char *pamsm = env("PAM_SM_FUNC");       /* FreeBSD https://www.freebsd.org/cgi/man.cgi?query=pam_exec */

        if (strcmp(pamtype, "open_session") != 0 && strcmp(pamsm, "pam_sm_open_session") != 0) {
                fprintf(stderr, "Neither PAM open_session nor pam_sm_open_session detected\n");
                return 0;
        }

        if (argc != 2) {
                fprintf(stderr, "Usage: %s address\n", *argv);
                exit(2);
        }

        if (gethostname(myhostname, sizeof(myhostname)) != 0)
                strcpy(myhostname, "?");

        snprintf(buf, sizeof(buf), "%s login to %s from %s via %s",
                env("PAM_USER"),
                myhostname,
                env("PAM_RHOST"),
                env("PAM_SERVICE"));

        addr = inet_addr(host);

        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(PORTNO);
        memcpy((void *)&servaddr.sin_addr, (void *)&addr, sizeof(addr));

        sockfd = socket(AF_INET, SOCK_DGRAM, 0);

        if (sendto(sockfd, (void *)buf, strlen(buf), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
                perror("sendto");
        }
        return (0);
}
  • Übersetzen und Installieren des hare Programms (ggf. das Paket gcc und build-essential installieren)
gcc -O2 -o hare hare.c
sudo cp hare /usr/local/sbin
  • das hare Programm in die PAM-Konfiguration /etc/pam.d/sshd eintragen. Ziel-IP ist der Laptop des Trainers (192.168.1.241)
[...]
session    optional     pam_exec.so /usr/local/sbin/hare <ip-des-hare-servers>
[...]
  • der zentrale Python-Server /usr/local/bin/hared.py, mit der Funktion pro SSH-Login eine Benachrichtigungs-Mail zu versenden (läuft auf dem Laptop des Trainers)
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket
import json
import smtplib, ssl
import random
import string
import datetime

__author__    = 'Jan-Piet Mens <jp()mens.de> / Carsten Strotmann <carsten()strotmann.de>'

myhostname     = "debian.example.com" # Domain-Name des E-Mail Senders (diese Maschine)
smtp_server    = "mail.example.com" # Name of the Mail-Server
smtp_port      = "587"  # SMTP with STARTTLS
sender_email   = "servernotification@example.com"
receiver_email = "admin@example.com"
smtp_user      = "admin"
smtp_password  = "secret"

server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(('', 8035))

while True:
    message, address = server_socket.recvfrom(1024)
    host, port = address

    data = {
        'host' : host,
        'msg'  : message,
    }

    js = json.dumps(str(data))
    # print(js)


    message = "To: <{}>\n".format(receiver_email)
    message = message + "From: <{}>\n".format(sender_email)
    message = message + "Message-Id: <{}@example.com>\n".format(''.join(random.choices(string.ascii_uppercase + string.digits, k=10)))
    time = datetime.datetime.now()
    message = message + "Date: {} \n".format(time.strftime('%d %b %Y  %H:%M:%S %z'))
    message = message + "Subject: SSH Login to {}\n\n".format(data["host"])
    message = message + "SSH Login into {} detected, Message: {}".format(data["host"], data["msg"])

    # Create a secure SSL context
    context = ssl.create_default_context()
    # if the TLS certificate of the mail server does not match
    # the mail servers hostname or domain-name, disable hostname checking
    # context.check_hostname = False
    server = smtplib.SMTP()
    # Try to log in to server and send email
    try:
        server.connect(smtp_server,smtp_port)      # Connect to the server
        server.ehlo(myhostname)                    # Send EHLO
        server.starttls(context=context)           # TLS Secure the connection
        server.ehlo(myhostname)                    # Another EHLO, now TLS secured
        server.login(smtp_user, smtp_password)     # Login to the server

        server.sendmail(sender_email, receiver_email, message) # send the mail
    except Exception as e:
        # Print any error messages to stdout
        print("Error: ", e)
    finally:
        if (server):
            server.quit()

3.1.24 Vorschläge für eine sichere SSH-Server Konfiguration

$EDITOR /etc/ssh/sshd_config
  • Nur Protokoll Version 2 erlauben
Protocol 2
  • Sichere Schlüssel-Austausch-Verfahren
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
  • neue DH Moduli für “diffie-hellman-group-exchange-sha256” (Achtung, dauert lange!) Hintergründe unter http://weakdh.org
ssh-keygen -G /etc/ssh/moduli.all -b 4096
ssh-keygen -T /etc/ssh/moduli.safe -f /etc/ssh/moduli.all
mv /etc/ssh/moduli.safe /etc/ssh/moduli
rm /etc/ssh/moduli.all
# Bei SELinux Systemen
chcon -v --type=etc_t /etc/ssh/moduli
  • EC-ED25519-Kurve Schlüssel bevorzugen
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
  • Sichere symmetrische Verschlüsselungs-Algorithmen
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
  • Sichere Message-Authenication-Codes (MAC)
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
  • Host-Keys neu erzeugen (Achtung: Clients werden Warnungen bekommen, Kunden und Kollegen informieren!)
cd /etc/ssh
rm ssh_host_*key*
ssh-keygen -t ed25519 -f ssh_host_ed25519_key < /dev/null
# rsa-sha2-512
ssh-keygen -t rsa -b 4096 -f ssh_host_rsa_key < /dev/null
  • Nach dem Erstellen neuer Schlüssel den SSH Server neu starten
systemctl restart sshd
  • SSH Client Parameter testen
ssh -Q cipher
ssh -Q cipher-auth
ssh -Q mac
ssh -Q kex
ssh -Q key
  • Jetzt nochmal per SSH auf dem fernen Rechner einloggen, -v Zeigt die Kommunikationsparameter an
nutzerXX$ ssh -v nutzer@notebookYY
  • Hier sollte jetzt eine Warnung ausgegeben worden sein, da die Host-Schlüssel nicht mehr mit den Fingerprints in der known_hosts Datei übereinstimmen. Den Admin des fernen Servers fragen, ob er die Schlüssel auf dem Rechner neu erstellt hat. Wenn der Admin dies bestätigt, dann er Texteditor den alten Fingerprint aus der ~/.ssh/known_hosts Datei löschen.
  • SSH Client ~/.ssh/config
VerifyHostKeyDNS yes
VisualHostKey yes

3.1.25 Links zum Thema SSH

3.2 Linux-Distributionen (Sicherheitsbewertung)

3.3 Software-Sicherheitsfunktionen unter Linux

3.3.1 Kernel-Konfigurationsoptionen

Der Linux-Kernel bietet einige Sicherheitfunktionen, welche zur Zeit der Übersetzung des Kernels aus den Quellen angeschaltet werden können. Einige dieser Funktionen haben negative Auswirkungen auf die Ausführungsgeschwindigkeit des Systems, so das diese Funktionen nicht in allen Distributionen gesetzt sind. In den Klammern sind die jeweiligen Konfigurationsnamen aufgeführt. In einem Linux-System können diese Namen in der Kernel-Konfigurationsdatei geprüft werden. Beispiel:

zcat /proc/config.gz | grep CONFIG_SECURITY_DMESG_RESTRICT

oder, wenn /proc/config.gz nicht vorhanden.

cat  /boot/config-$(uname -r) | grep CONFIG_SECURITY_DMESG_RESTRICT
  1. Die Funktionen (Kernel 4.15+):
    • Zugriff auf Kernel-Syslogmeldungen via dmesg unterbinden (CONFIG_SECURITY_DMESG_RESTRICT)
    • Speicher-Kopierroutinen zwischen Kernel- und Userspace härten (CONFIG_HARDENED_USERCOPY)
    • String- und Speicher-Funktionen gegen Buffer-Overflows härten (CONFIG_FORTIFY_SOURCE)
    • Lade alle Kernel-Dateien aus einem (nur-lese) Dateisystem (Module, Firmware, LSM-Dateien) (CONFIG_SECURITY_LOADPIN)
  2. Kernel-Schnittstelle für Hardware- und CPU Sicherheitsprobleme
    • Seit Kernel 4.15 besitzt der Linux-Kernel eine Schnittstelle zum Abfragen von bekannten Hardware- und CPU-Sicherheitsproblemen, und Informationen ob der laufende Linux-Kernel gegen die Sicherheitsprobleme schützt.
    grep . /sys/devices/system/cpu/vulnerabilities/*
    

3.3.2 Userspace Software-Sicherheitsfunktionen unter Linux

  1. Programm zum Prüfen der Sicherheitsfunktionen
    apt install git binutils
    git clone https://github.com/slimm609/checksec.sh
    cd checksec.sh/
    bash ./checksec --proc-all
    bash ./checksec --kernel
    bash ./checksec --dir=/usr/sbin --verbose
    

3.4 Linux Sicherheitsmeldungen

Quelle Link
Linux Weekly News Sicherheitsmeldungen https://lwn.net/Security/
Red Hat Sicherheitsmeldungen https://access.redhat.com/security/security-updates/#/security-advisories
Debian Security Tracker https://security-tracker.debian.org/tracker/
Debian “stable” Sicherheitsmeldungen https://security-tracker.debian.org/tracker/status/release/stable
SUSE Sicherheitsmeldungen https://www.suse.com/de-de/support/update/
Ubuntu Sicherheitsmeldungen https://www.ubuntu.com/usn/
Gentoo Sicherheitsmeldungen https://security.gentoo.org/glsa

3.5 Lynis

  • Lynis ist ein Sicherheitsscanner welcher veraltete Software-Versionen und bekannt unsichere Konfigurationen in Linux-Installationen aufspürt
  • Homepage: https://cisofy.com/lynis/
  • Lynis installieren (die lynis Version in den Debian Paket-Repositories ist veraltet)
 sudo apt install dirmngr
 sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 9DE922F1C2FDE6C4
 sudo apt install apt-transport-https
 echo "deb https://packages.cisofy.com/community/lynis/deb/ stable main" | sudo tee /etc/apt/sources.list.d/cisofy-lynis.list
 apt update
 apt install lynis
  • Lynis Version Information abfragen
 lynis update info
  • Lynis starten
 lynis audit system
  • Lynis Informationen anzeigen
lynis show help
lynis show commands
lynis show settings
lynis show profiles
lynis --man-page
  • In der Produktion: Lynis als Cron-Job (oder Systemd-Timer-Unit) eingerichten und periodisch ausführen, Ausgaben/Reports per E-Mail versenden

**

3.6 Audit Subsystem

3.6.1 Installation

  • Audit-Subsystem Programme installieren
apt install auditd audispd-plugins
  • Audit-Subsystem Trace eines Prozesses (hier 4 x ICMP Echo per ping)
autrace /bin/ping -c 4 8.8.8.8
  • Audit Log für einen speziellen autrace Aufruf anschauen
ausearch -i -p <audit-id>
  • Alle System-Calls des autrace Aufruf auflisten und nach Häufigkeit sortiert ausgeben
ausearch -i -p <audit-id> | grep type=SYSCALL | cut -f 6 -d ' ' | sort | uniq -c | sort -n

3.6.2 Konfiguration

  • Audit-Daemon Konfiguration anpassen (Grössen-Werte in MB)
$EDITOR /etc/audit/auditd.conf
----
space_left=4000
admin_space_left=2000
num_logs=10
max_log_file=<max-groesse-der-log-datei>
max_log_file_action=rotate
  • Audit-Dämon anschalten (so dass er bei einem Restart neu gestartet wird) und prüfen das der Prozess läuft
systemctl enable --now auditd
systemctl status auditd
  • Eine Audit-Policy erstellen
$EDITOR /etc/audit/rules.d/audit.rules
  • Eine Beispiel-Policy:
## First rule - delete all
-D

## Increase the buffers to survive stress events.
## Make this bigger for busy systems
-b 8192

## This determine how long to wait in burst of events
--backlog_wait_time 0

## Set failure mode to syslog
-f 1

# audit_time_rules - Record attempts to alter time through adjtime
-a always,exit -F arch=b64 -S adjtimex -k audit_time_rules

# audit_time_rules - Record attempts to alter time through settimeofday
-a always,exit -F arch=b64 -S settimeofday -k audit_time_rules

# audit_time_rules - Record Attempts to Alter Time Through stime
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -S clock_settime -k audit_time_rules

# audit_time_rules - Record Attempts to Alter Time Through clock_settime
-a always,exit -F arch=b64 -S clock_settime -k audit_time_rules

# Record Attempts to Alter the localtime File
-w /etc/localtime -p wa -k audit_time_rules

# Record Events that Modify User/Group Information
# audit_account_changes
-w /etc/group -p wa -k audit_account_changes
-w /etc/passwd -p wa -k audit_account_changes
-w /etc/gshadow -p wa -k audit_account_changes
-w /etc/shadow -p wa -k audit_account_changes
-w /etc/security/opasswd -p wa -k audit_account_changes

# Record Events that Modify the System's Network Environment
# audit_network_modifications
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k audit_network_modifications
-w /etc/issue -p wa -k audit_network_modifications
-w /etc/issue.net -p wa -k audit_network_modifications
-w /etc/hosts -p wa -k audit_network_modifications

#Record Events that Modify the System's Mandatory Access Controls
-w /etc/selinux/ -p wa -k MAC-policy

#Record Events that Modify the System's Discretionary Access Controls - chmod
-a always,exit -F arch=b32 -S chmod -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S chmod  -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - chown
-a always,exit -F arch=b32 -S chown -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S chown -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - fchmod
-a always,exit -F arch=b32 -S fchmod -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S fchmod -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - fchmodat
-a always,exit -F arch=b32 -S fchmodat -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S fchmodat -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - fchown
-a always,exit -F arch=b32 -S fchown -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S fchown -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - fchownat
-a always,exit -F arch=b32 -S fchownat -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S fchownat -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - fremovexattr
-a always,exit -F arch=b32 -S fremovexattr -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S fremovexattr -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - fsetxattr
-a always,exit -F arch=b32 -S fsetxattr -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S fsetxattr -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - lchown
-a always,exit -F arch=b32 -S lchown -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S lchown -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - lremovexattr
-a always,exit -F arch=b32 -S lremovexattr -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S lremovexattr -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - lsetxattr
-a always,exit -F arch=b32 -S lsetxattr -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S lsetxattr -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - removexattr
-a always,exit -F arch=b32 -S removexattr -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S removexattr -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Events that Modify the System's Discretionary Access Controls - setxattr
-a always,exit -F arch=b32 -S setxattr -F auid>=500 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S setxattr -F auid>=500 -F auid!=4294967295 -k perm_mod

#Record Attempts to Alter Logon and Logout Events
-w /var/log/faillog -p wa -k logins
-w /var/log/lastlog -p wa -k logins

#Record Attempts to Alter Process and Session Initiation Information
-w /var/run/utmp -p wa -k session
-w /var/log/btmp -p wa -k session
-w /var/log/wtmp -p wa -k session

#Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful)
-a always,exit -F arch=b32 -S creat -S open -S openat -S open_by_handle_at -S truncate -S ftruncate -F exit=-EACCES -F auid>=500 -F auid!=4294967295 -k access
-a always,exit -F arch=b32 -S creat -S open -S openat -S open_by_handle_at -S truncate -S ftruncate -F exit=-EPERM -F auid>=500 -F auid!=4294967295 -k access
-a always,exit -F arch=b64 -S creat -S open -S openat -S open_by_handle_at -S truncate -S ftruncate -F exit=-EACCES -F auid>=500 -F auid!=4294967295 -k access
-a always,exit -F arch=b64 -S creat -S open -S openat -S open_by_handle_at -S truncate -S ftruncate -F exit=-EPERM -F auid>=500 -F auid!=4294967295 -k access

#Ensure auditd Collects Information on the Use of Privileged Commands
#
#  Find setuid / setgid programs then modify and uncomment the line below.
#
##  sudo find / -xdev -type f -perm -4000 -o -perm -2000 2>/dev/null
#
# -a always,exit -F path=SETUID_PROG_PATH -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged

#Ensure auditd Collects Information on Exporting to Media (successful)
-a always,exit -F arch=b64 -S mount -F auid>=500 -F auid!=4294967295 -k export

#Ensure auditd Collects File Deletion Events by User
-a always,exit -F arch=b64 -S rmdir -S unlink -S unlinkat -S rename -S renameat -F auid>=500 -F auid!=4294967295 -k delete

#Ensure auditd Collects System Administrator Actions
-w /etc/sudoers -p wa -k actions

#Ensure auditd Collects Information on Kernel Module Loading and Unloading
-w /sbin/insmod -p x -k modules
-w /sbin/rmmod -p x -k modules
-w /sbin/modprobe -p x -k modules
-a always,exit -F arch=b64 -S init_module -S delete_module -k modules

#Make the auditd Configuration Immutable
-e 2
  • Die Policy kompilieren und prüfen
       augenrules --check
    
  • die neue Policydatei in den Kernel laden
       augenrules --load
    
  • aktive Regeln auflisten
       auditctl -l
    
  • Status des Audit-Subsystems anzeigen
    # auditctl -s
    enabled 2
    failure 1
    pid 12901
    rate_limit 0
    backlog_limit 8192
    lost 0
    backlog 0
    backlog_wait_time 0
    loginuid_immutable 0 unlocked
    

3.6.3 Beispiele für Audit-Abfragen

  • Alle Audit-Einträge zum Thema “sudo” zeigen
       ausearch -i -x sudo
    
  • Report über fehlgeschlagende Anmeldeversuche
       ausearch -m USER_AUTH,USER_ACCT --success no
    
  • Alle Audit-Meldungen für Benutzer UID 1000
       ausearch -ua 1000 -i
    
  • Fehlgeschlagende Syscalls seit gestern
       ausearch --start yesterday --end now -m SYSCALL -sv no -i
    
  1. Aufgabe:
    • Das Audit-Subsystem um neue Regel(n) zu Systemd erweitern:
      • Alle Systemd-Konfigurationsdateien mit der Endung *.conf, welche direkt unter /etc/systemd (nicht in den Unterverzeichnissen) gespeichert sind, sollen auf Schreibzugriffe überwacht werden
      • Die Audit-Events sollen mit dem Key systemd markiert werden
      • Die neue Richtlinie kompilieren und aktivieren (ggf. Reboot notwendig)
      • Die neue Richtlinie testen, in dem manuell an einer der überwachten Dateien eine Änderung vorgenommen wird
      • Die Audit-Meldungen per ausearch anzeigen und analysieren (suchen nach Events mit dem Key systemd)
  2. Beispiel-Lösung
    • Erweiterung der Audit-Regeln
    [...]
    # Systemd Konfiguration
    -w /etc/systemd/journald.conf -p wa -k systemd
    -w /etc/systemd/logind.conf -p wa -k systemd
    -w /etc/systemd/networkd.conf -p wa -k systemd
    -w /etc/systemd/resolved.conf -p wa -k systemd
    -w /etc/systemd/sleep.conf -p wa -k systemd
    -w /etc/systemd/system.conf -p wa -k systemd
    -w /etc/systemd/timesyncd.conf -p wa -k systemd
    -w /etc/systemd/user.conf -p wa -k systemd
    [...]
    
    • Suche nach Audit-Events mit dem Schlüssel systemd
    ausearch -i -k systemd
    

3.6.4 Audit-Hilfsprogramme

  • Die letzten Logins auf dem System anzeigen
aulast
  • Wann haben sich Benutzer zum letzten Mal eingelogged?
aulastlog
  • Zusammenfassung des Audit-Log
aureport
  • Grafische Auswertung von Audit-Logs
$ sudo apt install graphviz gnuplot git
$ git clone https://github.com/cstrotm/audit-visualize
$ cd audit-visualize
$ chmod +x ./mkgraph
$ chmod +x ./mkbar
  • Grafische Reports erstellen
$ sudo aureport -s -i --summary  | bash ./mkbar syscall
$ sudo aureport -f -i --summary --failed | bash ./mkbar failed-access
$ sudo aureport -e -i --summary | egrep -vi '(syscall|change)'
$ sudo aureport -e -i --summary | egrep -vi '(syscall|change)' | bash ./mkbar events2
  • Syscall Benutzung von Programmen
$ sudo aureport -s -i | awk '/^[0-9]/ { printf "%s %s\n", $6, $4 }' | sort | uniq | bash ./mkgraph
Gzipping graph...
Graph was written to gr.png
  • Welcher Benutzer führt welche Programme aus?
sudo aureport -u -i | awk '/^[0-9]/ { printf "%s %s\n", $4, $7 }' | sort | uniq | bash ./mkgraph
  • Wer greift auf welche Dateien zu?
sudo aureport -f -i | awk '/^[0-9]/ { printf "%s %s\n", $8, $4 }' | sort | uniq | bash ./mkgraph

3.6.5 CIS Benchmarks mit Vorlagen für Audit-Regeln

3.7 Secomp

3.8 eBPF/BCC

  • eBPF ist die extended Berkeley Packet Filter Infrastruktur im Linux Kernel
  • eBPF ist eine Weiterentwicklung der Berkeley Packet Filter Technologie (classic BPF = cBPF) https://en.wikipedia.org/wiki/Berkeley_Packet_Filter
  • eBPF ist eine Technologie im Linux-Kernel, welche Sandbox-Programme in einem Betriebssystem-Kernel ausführen kann.
    • eBPF wird verwendet, um die Fähigkeiten des Kernels sicher und effizient zu erweitern, ohne dass der Kernel-Quellcode geändert oder Kernel-Module geladen werden müssen.
    • eBPF kann neben Netzwerk-Paketen auch andere Daten aus dem Linux-Kernel überwachen und manipulieren

ebpf.png

3.8.1 BCC Übersicht

  • BCC ist die BPF Compiler Collection, eine Sammlung von Tools und eBPF Programmen

    bcc_tracing_tools_2019.png

3.8.2 BCC Installieren (inkl. der Kernel-Header)

  • BCC Programme sind abhängig von der jeweiligen Kernel-Version und müssen daher auf der Maschine mit Hilfe der aktuellen Kernel-Header kompiliert werden. Das Kompilieren geschied im Hintergrund beim Aufruf des Wrapper-Scripts.
# apt install bpfcc-tools bpfcc-lua bpftrace python3-bpfcc
# apt install linux-headers-$(uname -r)

3.8.3 BCC Tools für Linux-Server

  • Unter Debian enden alle BCC Programme auf -bpfcc:
       # ls -l /usr/sbin/*bpfcc
       -rwxr-xr-x 1 root root 34536 Feb  4  2019 /usr/sbin/argdist-bpfcc
       -rwxr-xr-x 1 root root  1648 Feb  4  2019 /usr/sbin/bashreadline-bpfcc
       -rwxr-xr-x 1 root root  4231 Feb  4  2019 /usr/sbin/biolatency-bpfcc
       -rwxr-xr-x 1 root root  5066 Feb  4  2019 /usr/sbin/biosnoop-bpfcc
       -rwxr-xr-x 1 root root  6387 Feb  4  2019 /usr/sbin/biotop-bpfcc
       -rwxr-xr-x 1 root root  1721 Feb  4  2019 /usr/sbin/bitesize-bpfcc
       -rwxr-xr-x 1 root root  2453 Feb  4  2019 /usr/sbin/bpflist-bpfcc
       -rwxr-xr-x 1 root root  6339 Feb  4  2019 /usr/sbin/btrfsdist-bpfcc
       -rwxr-xr-x 1 root root 10101 Feb  4  2019 /usr/sbin/btrfsslower-bpfcc
       -rwxr-xr-x 1 root root  4674 Feb  4  2019 /usr/sbin/cachestat-bpfcc
       [...]
    
  • Im folgenden werden einige BCC Tools vorgestellt, welche für die Sicherheit von Linux-Servern interessant sind
  1. opensnoop
    • Das BCC-Programm opensnoop-bpfcc zeigt systemweit an, welche Prozesse auf Dateien zugreifen (lesend und schreibend):
      # opensnoop-bpfcc
      PID    COMM               FD ERR PATH
      16884  links               3   0 /lib/x86_64-linux-gnu/liblz.so.1
      16884  links               3   0 /lib/x86_64-linux-gnu/liblzma.so.5
      16884  links               3   0 /lib/x86_64-linux-gnu/libbz2.so.1.0
      16884  links               3   0 /lib/x86_64-linux-gnu/libbrotlidec.so.1
      16884  links               3   0 /lib/x86_64-linux-gnu/libz.so.1
      16884  links               3   0 /lib/x86_64-linux-gnu/libssl.so.1.1
      16884  links               3   0 /lib/x86_64-linux-gnu/libcrypto.so.1.1
      16884  links               3   0 /lib/x86_64-linux-gnu/libgpm.so.2
      16884  links               3   0 /lib/x86_64-linux-gnu/libc.so.6
      16884  links               3   0 /lib/x86_64-linux-gnu/libm.so.6
      16884  links               3   0 /lib/x86_64-linux-gnu/libbrotlicommon.so.1
      16884  links               3   0 /lib/x86_64-linux-gnu/libdl.so.2
      16884  links              -1   2 /etc/links.cfg
      16884  links              -1   2 /etc/.links.cfg
      16884  links              -1   2 /root/.links2/links.cfg
      16884  links              -1   2 /root/.links2/.links.cfg
      16884  links              -1   2 /root/.links2/html.cfg
      16884  links              -1   2 /root/.links2/.html.cfg
      16884  links              -1   2 /root/.links2/user.cfg
      16884  links              -1   2 /root/.links2/.user.cfg
      16884  links               8   0 /root/.links2/bookmarks.html
      16884  links               8   0 /root/.links2/links.his
      16884  links               8   0 /dev/pts/1
      16884  links              -1   2 /dev/gpmctl
      11348  tmux: server        7   0 /proc/16884/cmdline
      11348  tmux: server        7   0 /proc/16880/cmdline
      11348  tmux: server        7   0 /proc/16880/cmdline
      
  2. statsnoop
    • Das BCC-Programm statsnoop-bpfcc zeigt systemweit Dateizugriffe mit den stat Systemaufruf:
      # statsnoop-bpfcc
      PID    COMM               FD ERR PATH
      11348  tmux: server        0   0 /etc/localtime
      11349  bash                0   0 .
      11349  bash               -1   2 /usr/local/sbin/stat
      11349  bash               -1   2 /usr/local/bin/stat
      11349  bash               -1   2 /usr/sbin/stat
      11349  bash                0   0 /usr/bin/stat
      11349  bash                0   0 /usr/bin/stat
      11349  bash                0   0 /usr/bin/stat
      11349  bash                0   0 /usr/bin/stat
      11349  bash                0   0 /usr/bin/stat
      11349  bash                0   0 /usr/bin/stat
      16893  stat               -1   2 /sys/fs/selinux
      16893  stat               -1   2 /selinux
      
  3. memleak
    • Das BCC-Programm memleak-bpfcc zeigt Memory-Leaks auf und kann benutzt werden, um Programme mit fehlerhafter Speicherverwaltung zu finden
      [12:03:09] Top 10 stacks with outstanding allocations:
              40 bytes in 5 allocations from stack
                      __kmalloc_node+0x171 [kernel]
              64 bytes in 1 allocations from stack
                      __kmalloc_track_caller+0x163 [kernel]
              64 bytes in 1 allocations from stack
                      kmem_cache_alloc_node+0x152 [kernel]
              320 bytes in 5 allocations from stack
                      kmem_cache_alloc_node_trace+0x14e [kernel]
                      __get_vm_area_node+0x7a [kernel]
              480 bytes in 5 allocations from stack
                      kmem_cache_alloc_node_trace+0x14e [kernel]
                      alloc_vmap_area+0x75 [kernel]
                      alloc_vmap_area+0x75 [kernel]
                      __get_vm_area_node+0xb0 [kernel]
                      __vmalloc_node_range+0x67 [kernel]
                      __vmalloc+0x30 [kernel]
                      bpf_prog_alloc+0x40 [kernel]
                      bpf_prog_load+0xf3 [kernel]
                      __x64_sys_bpf+0x279 [kernel]
                      do_syscall_64+0x53 [kernel]
                      entry_SYSCALL_64_after_hwframe+0x44 [kernel]
              1632 bytes in 14 allocations from stack
                      __kmalloc+0x16e [kernel]
              4840 bytes in 19 allocations from stack
                      kmem_cache_alloc+0x149 [kernel]
              14592 bytes in 30 allocations from stack
                      kmem_cache_alloc_trace+0x14c [kernel]
              21913600 bytes in 240 allocations from stack
                      __alloc_pages_nodemask+0x1e0 [kernel]
      
      
  4. mountsnoop
    • Das BCC-Programm mountsnoop-bpfcc zeigt alle Aufrufe der mount und umount Systemaufrufe (Systemcalls):
      # mountsnoop-bpfcc
      COMM             PID     TID     MNT_NS      CALL
      umount           16930   16930   4026531840  umount("/boot/efi", 0x0) = 0
      mount            16932   16932   4026531840  mount("/dev/sda15", "/boot/efi", "vfat", MS_NOSUID|MS_NOEXEC|MS_REMOUNT|MS_MANDLOCK|MS_DIRSYNC|MS_NOATIME|MS_NODIRATIME|MS_BIND|MS_MOVE|MS_REC|MS_I_VERSION|MS_NOUSER|0x7f9a00000300, "") = 0
      
  5. execsnoop
    • Das BCC- Programm execsnoop protokolliert alle neu gestarteten Prozesse des Linux-Systems:
      # execsnoop-bpfcc
      PCOMM            PID    PPID   RET ARGS
      systemd-getty-g  16948  16941    0 /usr/lib/systemd/system-generators/systemd-getty-generator /run/systemd/generator /run/systemd/generator.early /run/systemd/generator.late
      systemd-gpt-aut  16949  16941    0 /usr/lib/systemd/system-generators/systemd-gpt-auto-generator /run/systemd/generator /run/systemd/generator.early /run/systemd/generator.late
      cloud-init-gene  16942  16941    0 /usr/lib/systemd/system-generators/cloud-init-generator /run/systemd/generator /run/systemd/generator.early /run/systemd/generator.late
      systemd-hiberna  16950  16941    0 /usr/lib/systemd/system-generators/systemd-hibernate-resume-generator /run/systemd/generator /run/systemd/generator.early /run/systemd/generator.late
      lvmconfig        16951  16943    0
      systemd-detect-  16952  16942    0 /usr/bin/systemd-detect-virt --container --quiet
      systemd-system-  16955  16941    0 /usr/lib/systemd/system-generators/systemd-system-update-generator /run/systemd/generator /run/systemd/generator.early /run/systemd/generator.late
      systemd-run-gen  16954  16941    0 /usr/lib/systemd/system-generators/systemd-run-generator /run/systemd/generator /run/systemd/generator.early /run/systemd/generator.late
      systemd-sysv-ge  16956  16941    0 /usr/lib/systemd/system-generators/systemd-sysv-generator /run/systemd/generator /run/systemd/generator.early /run/systemd/generator.late
      systemd-veritys  16957  16941    0 /usr/lib/systemd/system-generators/systemd-veritysetup-generator /run/systemd/generator /run/systemd/generator.early /run/systemd/generator.late
      systemd-rc-loca  16953  16941    0 /usr/lib/systemd/system-generators/systemd-rc-local-generator /run/systemd/generator /run/systemd/generator.early /run/systemd/generator.late
      systemd-detect-  16958  16942    0 /usr/bin/systemd-detect-virt --container --quiet
      ds-identify      16959  16942    0 /usr/lib/cloud-init/ds-identify
      mkdir            16960  16942    0 /usr/bin/mkdir -p /run/systemd/generator.early/multi-user.target.wants
      ln               16961  16942    0 /usr/bin/ln -snf /lib/systemd/system/cloud-init.target /run/systemd/generator.early/multi-user.target.wants/cloud-init.target
      
  6. killsnoop
    • Das BCC-Programm killsnoop-bpfcc zeichnet alle Aufrufe des Systemaufruf kill auf:
    # killsnoop-bpfcc
    TIME      PID    COMM             SIG  TPID   RESULT
    12:46:34  16998  pkill            1    632    0
    
  7. pidpersec
    • Das BCC-Programm pidpersec-bpfcc zeichnet die Anzahl der neuen Prozesse pro Sekunde auf
      # pidpersec-bpfcc
      Tracing... Ctrl-C to end.
      12:48:11: PIDs/sec: 0
      12:48:12: PIDs/sec: 23
      12:48:13: PIDs/sec: 3
      12:48:14: PIDs/sec: 0
      

3.8.4 bpftrace

  • bpftrace ist eine kleine Programmiersprache (ähnlich wie awk), welche es Administratoren ermöglicht, kleine eBPF Scripts zu schreiben
  • Histogram-Daten werden in der Regel nach dem Beenden des Script mit CTRL+C ausgegeben
  • Unter Debian liegen die mitgelieferten bpftrace Programme unterhalb von /usr/sbin/ und haben die Dateiendung .bt (für bpftrace)
# ls /usr/sbin/*.bt
/usr/sbin/bashreadline.bt  /usr/sbin/execsnoop.bt       /usr/sbin/pidpersec.bt  /usr/sbin/tcpconnect.bt
/usr/sbin/biolatency.bt    /usr/sbin/gethostlatency.bt  /usr/sbin/runqlat.bt    /usr/sbin/tcpdrop.bt
/usr/sbin/biosnoop.bt      /usr/sbin/killsnoop.bt       /usr/sbin/runqlen.bt    /usr/sbin/tcpretrans.bt
/usr/sbin/bitesize.bt      /usr/sbin/loads.bt           /usr/sbin/statsnoop.bt  /usr/sbin/vfscount.bt
/usr/sbin/capable.bt       /usr/sbin/mdflush.bt         /usr/sbin/syncsnoop.bt  /usr/sbin/vfsstat.bt
/usr/sbin/cpuwalk.bt       /usr/sbin/oomkill.bt         /usr/sbin/syscount.bt   /usr/sbin/writeback.bt
/usr/sbin/dcsnoop.bt       /usr/sbin/opensnoop.bt       /usr/sbin/tcpaccept.bt  /usr/sbin/xfsdist.bt
  • Beispiel eines bpftrace Scriptes
# cat /usr/sbin/syscount.bt
#!/usr/bin/env bpftrace
/*
 * syscount.bt  Count system callls.
 *              For Linux, uses bpftrace, eBPF.
 *
 * This is a bpftrace version of the bcc tool of the same name.
 * The bcc versions translates syscall IDs to their names, and this version
 * currently does not. Syscall IDs can be listed by "ausyscall --dump".
 *
 * Copyright 2018 Netflix, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License")
 *
 * 13-Sep-2018  Brendan Gregg   Created this.
 */

BEGIN
{
        printf("Counting syscalls... Hit Ctrl-C to end.\n");
        // ausyscall --dump | awk 'NR > 1 { printf("\t@sysname[%d] = \"%s\";\n", $1, $2); }'
}

tracepoint:raw_syscalls:sys_enter
{
        @syscall[args->id] = count();
        @process[comm] = count();
}

END
{
        printf("\nTop 10 syscalls IDs:\n");
        print(@syscall, 10);
        clear(@syscall);

        printf("\nTop 10 processes:\n");
        print(@process, 10);
        clear(@process);
}
  1. bpftrace Beispiel-Skripte für Server-Diagnose
    • syscount.bt protokolliert Systemaufrufe
    # syscount.bt
    Attaching 3 probes...
    Counting syscalls... Hit Ctrl-C to end.
    ^C
    Top 10 syscalls IDs:
    @syscall[217]: 851
    @syscall[4]: 863
    @syscall[232]: 999
    @syscall[46]: 1532
    @syscall[9]: 2069
    @syscall[0]: 2366
    @syscall[47]: 3532
    @syscall[5]: 3573
    @syscall[3]: 4147
    @syscall[257]: 4883
    
    Top 10 processes:
    @process[systemd-fstab-g]: 439
    @process[cloud-init-gene]: 540
    @process[systemd-detect-]: 732
    @process[systemd-machine]: 1018
    @process[systemd-gpt-aut]: 1697
    @process[dbus-daemon]: 1733
    @process[systemd-logind]: 1812
    @process[systemctl]: 2268
    @process[systemd-sysv-ge]: 3532
    @process[systemd]: 12369
    
    • Liste der Linux-Syscalls ausgeben (ausyscall ist Teil des Linux Audit-Daemons, Paket auditd)
           # ausyscall --dump | awk 'NR > 1 { printf("\t@sysname[%d] = \"%s\";\n", $1, $2); }'
      
    • capable.bt überwacht Syscalls, welche die Capabilities von Linux-Prozessen ändern:
    # capable.bt
    Attaching 3 probes...
    Tracing cap_capable syscalls... Hit Ctrl-C to end.
    TIME      UID    PID    COMM             CAP  NAME                 AUDIT
    13:05:07  0      17406  ln               21   CAP_SYS_ADMIN        2                                         [145/1917]
    13:05:07  0      295    systemd-journal  21   CAP_SYS_ADMIN        0
    13:05:07  0      1      systemd          19   CAP_SYS_PTRACE       2
    13:05:07  0      1      systemd          19   CAP_SYS_PTRACE       2
    13:05:07  0      1      systemd          19   CAP_SYS_PTRACE       2
    13:05:07  0      1      systemd          19   CAP_SYS_PTRACE       2
    13:05:07  0      1      systemd          19   CAP_SYS_PTRACE       2
    13:05:07  0      1      systemd          1    CAP_DAC_OVERRIDE     0
    13:05:07  0      1      systemd          5    CAP_KILL             0
    13:05:07  0      1      systemd          1    CAP_DAC_OVERRIDE     0
    13:05:07  0      1      systemd          5    CAP_KILL             0
    13:05:07  0      17385  systemctl        21   CAP_SYS_ADMIN        2
    13:05:07  0      1      systemd          21   CAP_SYS_ADMIN        0
    13:05:07  0      1      systemd          21   CAP_SYS_ADMIN        0
    13:05:07  0      1      systemd          21   CAP_SYS_ADMIN        0
    
    • bashreadline.bt instrumentiert die von der bash benutzten readline Bibliothek und zeichnet alle in der bash (systemweit) eingegebenen Befehle auf:
    # bashreadline.bt
    Attaching 2 probes...
    Tracing bash commands... Hit Ctrl-C to end.
    TIME      PID    COMMAND
    13:07:39  11349  bash
    13:07:48  17414  su - nutzer
    13:08:06  17416  ls
    13:08:16  17416  rm -rf *
    13:08:20  17416  ls -la
    13:08:25  17416  exit
    
  2. bpftrace One-Liner
    • Systemaufrufe nach Prozessen
    bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[pid, comm] = count(); }'
    
    • execve Systemaufrufe (neue Prozesse inkl. Argumente)
    bpftrace -e 'tracepoint:syscalls:sys_enter_execve { join(args->argv); }'
    
    • Den Aufrufstapel (Execution-Stack) eines Prozesses (hier PID 189) in fünf Ebenen protokollieren
    bpftrace -e 'profile:hz:49 /pid == 189/ { @[ustack(5)] = count(); }'
    
    • Speicheranforderungen von Prozessen protokollieren (ACHTUNG: verursacht hohe Systemlast)
    bpftrace -e 'u:/lib/x86_64-linux-gnu/libc.so.6:malloc { @[ustack, comm] = sum(arg0); }'
    

3.8.5 Bücher zu eBPF/BCC

  1. Linux Observability with BPF
    • by Lorenzo Fontana, David Calavera
    • Publisher: O’Reilly Media, Inc.
    • Release Date: November 2019
    • ISBN: 9781492050209
  2. BPF Performance Tools: Linux System and Application Observability
  3. Systems Performance, 2nd Edition

3.8.6 Links

3.9 Namespaces

  • Dieses Kapitel zeigt, das Namespaces (und damit Container) eine Standard-Technologie des Linux-Kernel ist und keiner weiteren Software benötigt. systemd-nspawn und auch Docker sind nur Verwaltungsprogramme für die Namespaces und Controll-Groups des Linux-Kernels.
  • Namepspaces ’virtualisieren’ die Sicht auf Ressourcen des Linux-Kernels
  • Programme wie Docker, Chrome, systemd-nspawn, LXC/LXD, Firejail etc. benutzen die Namespaces im Linux-Kernel
  • Verfügbare Namespaces in Linux
Namespace Konstante Isolation
Cgroup CLONE_NEWCGROUP Cgroup root Verzeichnis
IPC CLONE_NEWIPC System V IPC, POSIX message queues
Network CLONE_NEWNET Network devices, stacks, ports, etc.
Mount CLONE_NEWNS Mount points
PID CLONE_NEWPID Process IDs
User CLONE_NEWUSER Benutzer und Gruppen IDs
UTS CLONE_NEWUTS Hostname und NIS Domain Name

3.9.1 Namespace Beispielprogramm

apt install build-essential
  • Unser Ausgangs-C-Programm: Leeres Verzeichnis anlegen und die leere Quelltextdatei im Editor öffnen
cd /usr/src
mkdir namespaces
cd namespaces
$EDITOR namespaces.c
----
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

#define STACK_SIZE (1024 * 1024)

static char child_stack[STACK_SIZE];
char* const child_args[] = {
  "/bin/bash",
  NULL
};

int child_main(void* arg)
{
  printf("Namespace aktiv\n");
  execv(child_args[0], child_args);
  printf("Ooops\n");
  return 1;
}

int main()
{
  printf("Namespace wird erzeugt\n");
  int child_pid = clone(child_main, child_stack+STACK_SIZE, \
   CLONE_NEWUTS | CLONE_NEWIPC | SIGCHLD, NULL);

  if (child_pid < 0) {
    printf("Es konnte kein namespace erzeugt werden (Fehler %d)\n", child_pid);
    return 1;
  }

  waitpid(child_pid, NULL, 0);
  printf("Namespace beendet\n");
  return 0;
}

----
  • Programm übersetzen
gcc -o namespaces namespaces.c
  • Programm ausführen
./namespaces
  • Den Namespace mit exit verlassen, dann einen Process-Namespace zum Programm hinzufügen
...
 int child_pid = clone(child_main, child_stack+STACK_SIZE, \
   CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | SIGCHLD, NULL);
...
  • Neu übersetzen und ausführen (im Namespace das Proc-Dateisystem neu mounten um die Prozess-Isolierung via top oder ps zu sehen: mount -t proc proc /proc
gcc -o namespaces namespaces.c
  • Namespace via exit beenden und das proc Dateisystem auf dem Host neu mounten mount -t proc proc /proc
  • Einen Netzwerk-Namespace hinzufügen
...
  int child_pid = clone(child_main, child_stack+STACK_SIZE, \
   CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID |  CLONE_NEWNET | SIGCHLD, NULL);
...
  • Die Netzwerkconfiguration im Namespace mit ip oder ifconfig anschauen

3.10 Netzwerk Namespaces per ip Kommando

  • Netzwerk Namespace netns1 erzeugen
# ip netns add netns1
# ip netns list
  • Befehl im Netzwerk-Namespace ausführen
# ip netns exec netns1 ip link list
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  • Loopback ist “down”, ein ping geht nicht
# ip netns exec netns1 ping 127.0.0.1
connect: Network is unreachable
  • Nun bringen wir das Loopback-Interface “up”
# ip netns exec netns1 ip link set dev lo up
# ip netns exec netns1 ping 127.0.0.1
  • Wir erstellen nun virtuelle Netzwerkschnittstellen
# ip link add veth0 type veth peer name veth1
# ip link
  • Netzwerkschnittstelle veth1 wird in den Netzwerk-Namespace netns1 verschoben
# ip link set veth1 netns netns1  # auch physische NICs koennen in Namespaces verschoben werden
# ip link
  • Wir konfigurieren ein IP-Adresse auf veth1 im Namespace
# ip netns exec netns1 ifconfig veth1 10.1.1.1/24 up
# ip netns exec netns1 ip a
# ping 10.1.1.1  # ping in den Namespace geht jetzt noch nicht!
  • Eine IP-Adresse auf dem veth0 auf dem Linux-Host konfigurieren
ifconfig veth0 10.1.1.2/24 up
  • Ping von aussen in den Namespace geht jetzt!
# ping 10.1.1.1
  • Ping aus den Namespace nach draussen sollte auch gehen
ip netns exec netns1 ping 10.1.1.2
  • der Namespace hat eine eigene Routing-Tabelle und eine eigene Netfilter-Firewall
ip netns exec netns1 route
ip netns exec netns1 ip route show
ip netns exec netns1 iptables -L
  • Namespace wieder löschen
ip netns delete netns1

4 Tag 4

4.1 Einfache Container mit unshare

  • mit dem Programm unshare können die einzelnen Namespaces separat erstellt und eingeschaltet werden. Wird kein zu startendes Programm angegeben, so wird die Standard-Shell des Systems mit den neuen Namespaces gestartet. Beispiel: ein Namespace mit privatem Netzwerk, Mount- und Prozess-ID- Namespace:
         # unshare -n -p -f --mount-proc
    
  • Container mit Benutzer root, welcher nicht root auf dem Host ist
        sudo unshare --map-root-user --user sh
    

4.2 Namespaces auflisten   RedHat

  • Befehl lsns:
[root@centos-sec-oct-2017 ~]# lsns
        NS TYPE  NPROCS   PID USER   COMMAND
4026531836 pid       81     1 root   /usr/lib/systemd/systemd --system --deserialize 22
4026531837 user      81     1 root   /usr/lib/systemd/systemd --system --deserialize 22
4026531838 uts       81     1 root   /usr/lib/systemd/systemd --system --deserialize 22
4026531839 ipc       81     1 root   /usr/lib/systemd/systemd --system --deserialize 22
4026531840 mnt       78     1 root   /usr/lib/systemd/systemd --system --deserialize 22
4026531856 mnt        1    12 root   kdevtmpfs
4026531956 net       81     1 root   /usr/lib/systemd/systemd --system --deserialize 22
4026532212 mnt        1 11299 root   /usr/lib/systemd/systemd-udevd
4026532227 mnt        1   551 chrony /usr/sbin/chronyd

4.3 Container/Namespace mit Systemd

  • Jedes Linux mit Systemd bietet mächtige Container-Verwaltungs-Werkzeuge mit
  • systemd-nspawn arbeitet neben Image-Dateien für Container auch mit installieren Linux-Root-Dateien in einem beliebigen Verzeichnis auf dem Container-Host-System
    • Damit ist es sehr einfach, ein Container-System aufzusetzen und Dateien zwischen dem Container-Host und dem Linux im Container auszutauschen
  • In diesem Kapitel installieren wir als Beispiel ein Rocky-Linux (eine freie Red Hat Enterprise Linux Distribution) in einem Verzeichnis unter Debian
    • Andere Linux-Distributionen wie Ubuntu, Suse, Arch-Linux oder ältere Debian-Versionen wären auch möglich
    • Wichig ist das die Dateien im Container-Verzeichnis für die CPU-Architektur des Container-Hosts übersetzt wurden und die Programme keinen neueren Kernel benötigen (keine neuen System-Calls)
  • Seit Debian 9 müssen die Systemd-Container-Tools separat installiert werden:
apt install systemd-container
  • Wir erstellen ein Verzeichnis für den neuen Container
mkdir -p /srv/container/rocky-linux8
  • Initialisieren eine neue RPM-Instanz im Container-Verzeichnis (bei Debian mit debboostrap, bei SUSE mit RPM und zypper)
apt -y install rpm dnf
rpm --root /srv/container/rocky-linux8 --initdb
  • Das Basis-Paket für Rocky-Linux laden (Achtung: URLs ändern sich regelmäßig)
wget https://ftp.plusline.net/rockylinux/8/BaseOS/x86_64/os/Packages/r/rocky-release-8.8-1.8.el8.noarch.rpm
wget https://ftp.plusline.net/rockylinux/8/BaseOS/x86_64/os/Packages/r/rocky-repos-8.8-1.8.el8.noarch.rpm
rpm --nodeps --root /srv/container/rocky-linux8 -ivh rocky-release-8.5-3.el8.noarch.rpm rocky-repos-8.5-3.el8.noarch.rpm
  • Das Rocky-Linux Basis-System installieren
dnf -y --nogpg --releasever=8 --installroot=/srv/container/rocky-linux8 \
  install systemd passwd dnf procps-ng iproute tmux rocky-gpg-keys
echo 8 > /srv/container/rocky-linux8/etc/dnf/vars/releasever
  • Eine Shell im Container starten
systemd-nspawn -D  /srv/container/rocky-linux8
  • Root-Passwort setzen und neuen Benutzer anlegen
-bash-4.2$ passwd
-bash-4.2$ adduser nutzerXX
-bash-4.2$ passwd nutzerXX
  • Shell im Container verlassen
-bash-4.2# exit
  • Container booten
systemd-nspawn -bD  /srv/container/rocky-linux8
  • Weitere Software im Container installieren (hier den Apache Webserver)
dnf install httpd
  • Anwendung im Rocky Linux Container starten (prüfen das kein andere Prozess auf dem Container-Host die Ports 80 und/oder 443 belegt)
systemctl enable --now httpd
  • Der Apache Webserver innerhalb des Rocky Linux Containers sollte nun vom Firefox des Debian unter http://localhost erreichbar sein.
  • Container stoppen (im Container eingeben)
conainter# poweroff
  • Container mit privatem Netzwerk-Namespace starten:
systemd-nspawn -bD  /srv/container/rocky-linux8 --private-network
  • Container können auch mit virtuellen Netzwerkkarten und/oder Port-Mappings konfiguriert werden
  • Systemd-Befehle um einen Container vom Host aus zu kontrollieren
machinectl list
machinectl status centos
machinectl terminate centos
machinectl kill centos
  • Per nsenter mit dem Container verbinden (es wird eine Prozess-ID eines Container-Prozesses benötigt!)
nsenter -m -u -i -n -p -t <pid-im-container> /bin/bash

**

4.4 Firejail

  • Firejail ist eine leichtgewichtige Sandbox für Linux-Programme auf Basis von Linux-Namespaces, secomp-bpf und der Linux-Firewall
    • Firejail wurde ursprünglich für die Absicherung des Firefox-Browsers erstellt, kann heuter auch für die Absicherung vieler andere Programme benutzt werden
    • Der Fokus von Firejail liegt auf Desktop-Linux-Programmen, jedoch kann Firejail auf auch Linux-Servern eingesetzt werden
  • Homepage https://firejail.wordpress.com/
  • Quellcode https://github.com/netblue30/firejail
  • Moderne Versionen von Firejail unterstützen die Absicherung der DNS Namensauflösung mittels DNS-over-HTTPS und DNS-over-TLS mit dem FDNS Projekt https://firejaildns.wordpress.com/
  • Firejail installieren
       apt install firejail firejail-profiles
    
  • Den Konsolen-Webbrowser links installieren (als Beispielprogramm)
 # apt install links
  • Einen unprivilegierten Benutzer (z.B. nutzer, gabi etc., ggf. den Benutzer neu anlegen) in der Datei /etc/firejail/firejail.users eintragen (Die Datei ggf. anlegen, pro Benutzer eine Zeile), um die Benutzung von firejail durch diesen Benutzer zu erlauben
  • Zum unprivilegierten Benutzer wechseln
 # su - nutzer
  • Für den Benutzer das Verzeichnis .ssh (SSH Schlüssel und Konfiguration) erstellen. Firejail sichert dieses Verzeichnis gesondert ab, so das Programme ohne spezielle Firejail-Rechte (wie das ssh Programm) auf die Inhalte dieses Verzeichnisses nicht zugreifen können
 $ cd ~
 $ mkdir .ssh
 $ chmod 600 .ssh
  • Test von Firejail: wir starten eine Bash-Shell kontrolliert von Firejail
 # firejail bash
  • Teste die folgenden Aktionen in der Firejail-Bash:
    • Prozessliste auflisten
    • Programm top starten
    • Zeige die Datei .bash_history an (wenn die Datei noch nicht existiert dann die Bash einmal verlassen und wieder neu mit firejail bash starten)
    • Wechsle in das Verzeichnis .ssh
    • Liste alle Dateien im Heimverzeichnis mit ls -la und vergleiche mit der Ausgabe ohne Firejail. Was fällt auf?
  • Firejail bash verlassen
  • Firejail mit einem Browser (hier Links)
    • Den Browser links im Jail starten (als unprivilegierter Benutzer)
      # su - nutzer
      $ firejail links https://notes.defaultroutes.de
      
    • Auf der Webseite des Trainings die PDF-Datei LinuxSecurityEinfuehrung.pdf finden, auswählen und per Taste d (Download) sichern, danach den Browser links mit der Taste q verlassen
      • Wo ist die Datei gespeichert worden?
  • Erstelle im Heimverzeichnis des Benutzers ein Verzeichnis mit den Namen Downloads
       $ mkdir ~/Downloads
    
  • Starte links nochmals via firejail, lade das PDF von der Trainings-Webseite und speichere es im Verzeichnis Dowloads. Nach dem Beenden des Browsers ist die Datei dort zu finden
  • Starte den Browser mit einer Datei-System-URL des Heimverzeichnisses links file://. mit und ohne FireJail. Welche Unterschiede gibt es?
  • Erstelle (als Benutzer root) einen symbolischen Link von /usr/bin/firejail zu /usr/local/bin/links
    • Wird Firejail über einen solchen Symlink aufgerufen, so startet es das Programm mit dem Namen unter der Kontrolle von Firejail. Der Benutzer kann daher das Programm “direkt” aufrufen, ohne den Befehl firejail voranstellen zu müssen
           $ ln -s /usr/bin/firejail /usr/local/bin/links
      
  • Firejail kann automatisiert für unterstützte Programme solche Wrapper-Links installieren. Die Wrapper-Links überlagern die Programm-Namen von schützenswerten Linux-Anwendungen.
$ sudo firecfg
  • Firejail Programme überwachen (in einem separaten Terminal starten und dann z.B. links starten)
firejail --top
  • Im System verfügbare Firejail Profile auflisten
ls /etc/firejail

4.5 Docker

  • Podman ist eine “drop-in” (Kommandozeilen-Kompatible) Alternative zu Docker (Podman wird von RedHat als Open Source Projekt vorangetrieben). Die weiteren Ausführungen in diesen Kapitel gelten bis auf wenige Ausnahmen auch für Podman.

4.5.1 Docker als Sicherheits-Werkzeug

  • Docker bietet gegenüber dem Betrieb von klassischen Linux-Installationen (auf „bare Metal“ oder virtualisiert) einige Vorteile:
    • Anwendungen werden voneinander isoliert. Selbst die Bestandteile einer Anwendung (z.B. LAMP - Linux/Apache/MySQL/PHP) können in eigene Docker-Container ausgelagert und voneinander isoliert werden.
    • die Rechte einer Anwendung im Docker-Container kann per Seccomp-bpf und Linux-Capabilities beschränkt werden
    • die Sicht auf den Netzwerkstack kann für Anwendungen eingeschränkt werden (Admin-Netzwerk für Anwendungen nicht sichtbar)
    • Docker unterstützt ein Implementations-Design, bei dem Anwendungs-Programme und Daten getrennt gehalten werden (Anwendungen in Container-Images, Daten in Speicher-Volumes ausserhalb der Container)
    • Über Dockerfiles sind die Container jederzeit reproduzierbar. Bei einem Einbruch in einen Docker-Container kann dieser zu Beweiszwecken eingefroren werden und durch ein neues, sauberes Container-Image ersetzt werden
    • Docker-Container werden nicht per Software-Update aktualisiert, sondern durch ein neues Container-Image mit aktueller Software ersetzt. Hierdurch kann sich ein (auch bisher unbemerkter) Einbrecher nicht im System festsetzen
  • Nachteile:
    • die Isolierung von Anwendungen durch Linux-Container-Virtualisierung ist nicht so stark und vollständig wie bei einer Voll-Virtualisierung (VMWare, HyperV, VirtualBox). Linux-Container können jedoch innerhalb einer Voll-Virtualisierung eingesetzt werden und somit werden die Vorteile beider Systeme genutzt
    • Anwendungs-Installationen müssen angepasst werden, um Programme und Daten sauber zu trennen
    • Docker erhöht die Komplexität der Installation
    • Docker-Verwaltungswerkzeuge (Kubernetes etc) erhöhen die Komplexität und haben ggf. eigene Sicherheitsprobleme

4.5.2 Docker Installieren

  • Docker installieren und starten
apt install docker.io
usermod -aG docker <username>
  • Docker testen
docker run hello-world

4.5.3 erste Schritte mit Docker

  • Docker Image herunterladen
# docker pull almalinux
# docker images
  • Ein Alma-Linux (eine weitere freie Distribution von Red Hat Enterprise Linux) mit Bash starten
# docker run --name=application1 -it almalinux /bin/bash
docker# dnf update -y
docker# dnf install -y procps httpd
docker# dnf clean all
docker# exit
# docker ps -a
  • mit laufendem Docker Container verbinden
docker attach application1
  • Docker Container Statistiken anzeigen
# docker top <container>
# docker stats <container1> <container2> ...
  • einen weiteren Prozess im Docker Container ausfuehren
# docker exec -d <container> touch /etc/new-config
# docker exec -t -i <container> /bin/sh
  • Docker Container stoppen
# docker stop application1
  • Docker bei Applikations-Ende automatisch neu starten
docker run --restart=always
docker run --restart=on-failure:5
docker inspect <container>
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <container>
  • Docker Container im Hintergrund (-d) starten
docker run --name <name> -d <image> <command>
  • Ausgaben der Anwendung im Docker Container anschauen
docker logs <container>
docker logs -f <container>
docker logs --tail -f <container>
docker logs --tail 50 <container>
  • Docker Log-Ausgaben können mittels eigener log drivers auf andere Ziele umgelenkt werden(json-file, syslog, none, …)
docker run --log-driver="syslog" ...
  • Ein Docker Image aus einem Dockerfile (Docker-Image Bauanleitung) erstellen
mkdir -p docker-work
cd docker-work
$EDITOR Dockerfile
-----
# Debian with nginx
# Version 1
FROM debian:latest

MAINTAINER Linuxhotel Trainer

# Update image
RUN apt update
# Add httpd package. procps and iproute are only added to investigate the image later.
RUN apt -y install nginx
RUN echo container.example.com > /etc/hostname

# Create an index.html file
RUN bash -c 'echo "Your Web server test on Debian Docker Container is successful." >> /var/www/html/index.html'
# create a nginx start-command
CMD ["nginx", "-g", "daemon off;"]
------
docker build -t debian-nginx --no-cache .
docker run -d -t --name=deb-nginx1 -p 8080:80 debian-nginx

4.5.4 Docker Container verbinden

  • Volumes
docker run -v <local-dir>:<container-dir>[:ro] ...
  • Volumes im Dockerfile definieren. Hierdurch werden Volumes beim Erstellen des Containers ausserhalb des Containers erstellt (unter /var/lib/docker/... auf dem Linux-Host) und in den Container eingebunden
# Dockerfile
[...]
VOLUME /data
VOLUME /var/www/html

4.5.5 Docker Übung: Caddy-Webserver:

  • installiere ein Image mit dem ’Caddy’ Webserver (https://caddyserver.com) aus der Docker Hub Registry (abiosoft/caddy). Caddy ist ein in der Sprache go geschriebener Webserver, welcher automatisch TLS/x509 Zertifikate von Let’s Encrypt besorgt und aktualisiert.
  • starte einen Container aus dem Image, verbinde Port 2015 vom Container auf einen freien Port auf dem Host
  • teste die Caddy-Webseite mit dem Firefox auf dem Laptop http://<ip-des-Laptop>:<port>
  • starte eine Shell im Caddy-Webserver Container per docker exec. Suche das Verzeichnis mit den HTML-Dateien.
    • stoppe den Container, lösche den Container (docker rm)
    • erstelle ein leeres Verzeichnis auf dem Container-Host (Laptop) unter /srv/websites/html. Erstelle eine einfache HTML-Datei index.html in diesem Verzeichnis.
    • starte einen neuen Container, verbinde das Verzeichnis /srv/websites/html vom Container-Host in den Container (Parameter -v, siehe oben).
    • Teste den Webserver mit dem Firefox Browser
    • Ändere die Datei index.html unter /srv/websites/html, teste das die Änderungen im Browser sichtbar sind
    • erstelle einen neuen NGINX Container (auf Basis des NGINX Dockerfiles oben in der Anleitung), bei dem das Verzeichnis /srv/websites/html in den Webroot des NGINX-Webservers gemappt wird (Achtung: anderen Port als für den Caddy-Webserver benutzen. Beide Webserver-Container sollten zur gleichen Zeit aktiv sind)
    • Einige Befehle zum Probieren (als Benutzer root auf dem Host)
docker logs <container>   # Anzeige der Logausgaben des Hauptprozesses
docker top <container>    # Anzeige der Prozesse im Container
docker stats <container>  # Anzeige der vom Container benutzten Resourcen
  1. Beispiellösung
    • Caddy-Webserver Image aus dem Docker Repository
      docker run --name=caddyweb -d -p 8088:2015 abiosoft/caddy
    
    • Im Docker-Container nach den HTML-Dateien suchen
      docker exec caddyweb find / -name index.html
    
    • Caddy Container stoppen und löschen
      docker stop caddyweb
      docker rm caddyweb
    
    • Verzeichnis für die Webseiten anlegen und eine index.html Datei erstellen
      mkdir -p /srv/websites/html
      echo "Dies ist meine Webseite" > /srv/websites/html/index.html
    
    • Caddy Container mit dem externen Webseiten-Verzeichnis starten
      docker run --name=caddyweb -v /srv/websites/html:/srv -d -p 8088:2015 abiosoft/caddy
    
    • (wenn notwendig) vorherigen NGINX Container stoppen und löschen
      docker stop debian-nginx
      docker rm debian-nginx
    
    • NGINX Container mit dem Web-Verzeichnis starten
      docker run --name=debian-nginx -v /srv/websites/html:/var/www/html -p 8080:80 debian-nginx
    

4.5.6 mit Docker Images arbeiten

  • Docker Image History anschauen
docker images
docker history <image-name>
  • Docker Image(s) in eine Datei sichern. Metadaten und Schichten bleiben erhalten
docker save -o mydockerapp.tar <image-name> [<image-name2>]
  • Docker-Image aus einer Datei laden (welche mit docker save erstellt wurde)
docker load -i mydockerapp.tar
  • Docker Container exportieren (nur das Dateisystem wird exportiert, die Schichten/Layer verschwinden)
docker ps -a
docker export -o mydockerapp.tar <container-name>
xz -v mydockerapp.tar
  • Docker Container vom Tarball importieren
 xzcat mydockerapp.tar.xz | docker import - <image-name>
  • Docker Container in ein Image umwandeln (z.B. für forensische Analyse)
docker commit <container-ID> <image-name>

4.6 Docker Sicherheit

4.6.1 Docker Images

4.6.2 Container Sicherheit

  • keine SUID Programme im Container
  • keinen “echten” Benutzer “root” (UID0) im Container (Capabilities benutzen)
  • Anwendungen im Container nicht unter einem Root-Account betreiben
  • Capabilities sparsam einsetzen (kein CAP_SYS_ADMIN)
  • Dateien in /tmp sind keine Daten, nicht von extern mounten
  • Programme (im Container) und Daten (ausserhalb des Containers) trennen
  • sensitive Programme read-only in den Container mappen/mounten
  • Container auf bekannte Sicherheitslücken der im Container benutzen Software überwachen
  • Container oft und regelmässig auffrischen

4.6.3 Audit-Regeln für Docker einrichten

  • Beispiel-Regelwerk (generisch, muss ggf. für die eigene Repository angepasst werden)
 -w /etc/docker -k docker
-w /etc/docker/key.json -k docker
-w /etc/docker/daemon.json -k docker
-w /etc/docker/certs.d -k docker
-w /etc/sysconfig/docker -k docker
-w /etc/sysconfig/docker-network -k docker
-w /etc/sysconfig/docker-storage -k docker
-w /etc/sysconfig/docker-storage-setup -k docker
-w /usr/lib/systemd/system/docker.service -k docker
-w /usr/bin/docker-containerd -k docker
-w /usr/bin/docker-containerd-current -k docker
-w /usr/bin/docker-containerd-shim -k docker
-w /usr/bin/docker-containerd-shim-current -k docker
-w /usr/bin/docker -k docker
-w /usr/bin/docker-current -k docker
-w /usr/bin/docker-ctr-current -k docker
-w /usr/bin/dockerd -k docker
-w /usr/bin/dockerd-current -k docker
-w /usr/bin/container-storage-setup -k docker
-w /var/lib/docker -k docker
-w /var/run/docker.sock -k docker

4.6.4 Docker-Engine nicht auf einem (ungeschützten) TCP Port betreiben

4.6.5 Docker Repository mit TLS absichern (x509 Zertifikate benötigt)

  • in der Datei /etc/sysconfig/docker
 dockerd --tlsverify ...

4.6.6 User-Namespaces verwenden

  • in der Datei /etc/sysconfig/docker
 dockerd --userns-remap=default ...

4.6.7 Legacy-Registry abschalten

  • in der Datei /etc/sysconfig/docker
 dockerd --disable-legacy-registry ...

4.6.8 Ulimits auf Container setzen

  • in der Datei /etc/sysconfig/docker, Format --default-ulimit <ulimit-spec>=<soft-limit>:<hard-limit>
  • Information ueber ULIMIT Schluesselwoerter in /etc/security/limits.conf
  • Default-Ulimit setzen
 dockerd --default-ulimit nofile=50:150 --default-ulimit nproc=10:20
  • Ulimit fuer einzelnen Container
 docker run --ulimit nofile=20:50 ...

4.6.9 Docker Container nicht als Benutzer root betreiben

    docker run -u dockeruser -d ...

4.6.10 Capabilities von Container-Prozessen beschränken

  • Docker Container mit beschraenkten Capabilities starten
 docker run --cap-drop=all --cap-add [notwendige capabilities] ...
  • Capabilities eines Prozesses in einem Docker Container herausfinden am Beispiel des nginx Webservers
 # Prozess-ID des nginx Prozesses herausfinden
docker exec $(docker ps -q) pgrep -a nginx
# Capabilities der Prozess-ID 1 (nginx) abfragen
docker exec $(docker ps -q) cat /proc/1/status | grep CapEff | awk '{print $NF}'
00000000a80425fb
# Capabilties dekodieren und Docker-Parameter ausgeben
capsh --decode=00000000a80425fb | echo "--cap-drop=all --cap-add={$(sed -e 's/.*=//' -e 's/cap_//g')}"
--cap-drop=all --cap-add={chown,dac_override,fowner,fsetid,kill,setgid,setuid,setpcap,net_bind_service,net_raw,sys_chroot,mknod,audit_write,setfcap}
  • Die Capabilities unter –cap-add pruefen und ggf. einschraenken

4.6.11 /etc/localtime im Container Read-only

  • die Datei /etc/localtime im Container Read-Only setzen, verhindert, das die Zeitzone im Container veraendert wird
 docker run -v /etc/localtime:/etc/localtime:ro

4.6.12 Speicher- und CPU-Resources des Containers einschränken

Docker Parameter Beschreibung
–cpu-period Laenge der CPU CFS (Completely Fair Scheduler) Zeitscheibe
–cpu-quota CPU CFS (Completely Fair Scheduler) quota
–cpuset-cpus Container an CPUs binden (0-3, 0,1).
–cpuset-mems Container an Speicher-Nodes binden (0-3, 0,1) nur fuer NUMA Maschinen
–kernel-memory Kernel Speicher-Limit
-m, –memory Speicher Limit
–memory-reservation Limit fuer Speicherreservierungen (Virtueller noch nicht benutzer Speicher)
–memory-swap Vollstaendiges Speicherlimit (memory + swap), ’-1’ schaltet virtuellen Speicher (SWAP) aus

4.6.13 Dateisysteme “nur-lesbar” einbinden

  • Das Root-Dateisystem im Container „nur-lesend“ einbinden
 docker run --read-only ...
  • Container Volume nur-lesend einbinden
 docker run -v /volume:ro ...
  • Pfade des Hosts nur-lesend in den Container einbinden
 docker run -v /srv/container/name:/srv:ro ...

4.6.14 Fähigkeiten eines Docker Containers per SELinux einschränken

Für Linux-Sicherheits-Module (LSM) auf Label Basis (Role Based Access Control, RBAC) kann der Benutzer, die Rolle, der Tyoe und der Level für einen Container festgelegt werden. LSM funktionieren nicht innerhalb von Containers, sondern nur für einen gesamten Container.

      docker run --security-opt=[label=user:USER]

4.6.15 Fähigkeiten eines Docker Containers per AppArmor einschränken

4.6.16 Syscalls einschränken mit Seccomp

4.6.17 Vorsicht bei dem Einsatz von KSM (Kernel-Same-Pages-Merging)   RedHat

# systemctl status ksm
● ksm.service - Kernel Samepage Merging
   Loaded: loaded (/usr/lib/systemd/system/ksm.service; enabled; vendor preset: enabled)
   Active: active (exited) since Mi 2017-10-25 19:20:35 CEST; 13h ago
  Process: 777 ExecStart=/usr/libexec/ksmctl start (code=exited, status=0/SUCCESS)
 Main PID: 777 (code=exited, status=0/SUCCESS)
    Tasks: 0
   Memory: 0B
   CGroup: /system.slice/ksm.service

Okt 25 19:20:35 notebook51 systemd[1]: Starting Kernel Samepage Merging...
Okt 25 19:20:35 notebook51 systemd[1]: Started Kernel Samepage Merging.
# /usr/libexec/ksmctl stop
# echo 0 > /sys/kernel/mm/ksm/run
# systemctl disable ksm
# systemctl disable ksmtuned
# echo 2 > /sys/kernel/mm/ksm/run

4.7 weitere Container-Tools

4.7.1 Das mbox Programm

  • das mbox Programm bietet eine einfache, simple sandbox mittels CGroups und Namespaces. mbox kann benutzt werden um die Ausführung von unbekannten Programmen (Scripts, Binärprogramme) einzuschränken und zu überwachen https://github.com/tsgates/mbox

4.7.3 Bocker

4.8 Incidence Response

4.8.1 Vorbereitungen auf den Notfall

  • Forensik Live-Linux-CD-ROM bereithalten und regelmässig üben (1/2 jährlich)
  • Kontaktadressen von Forensikern/Strafverfolgungsbehörden bereithalten
  • das Erstellen von Platten-Images üben
  • PGP/GPG Schlüssel erstellen und aktuell halten. PGP/GPG-E-Mail regelmässig benutzen, um in Übung zu bleiben
  • Ersatz-Hardware vorhalten (Festplatten, SSD), Speicherplatz für Platten-Images
  • Beutel für manipulationssichere Beweissicherung bestellen und “vor Ort” bereithalten
  • Hardware-RAID meiden (Alternativen: Software RAID - DM-RAID, btrfs, zfs)
  • alternative Kommunikationswege (Twitter, externes E-Mail-System, externer Web-Server) vorbereiten. Kunden über diese alternativen Kommunikationswege informieren!
  • Minimale-Installationen benutzen
  • Datensparsamkeit - nur Daten, die nicht gespeichert werden, können nicht mißbraucht werden -> Datenhaltung kostet
  • Incident-Modus für die IT-Systeme definieren –> welche Teile der IT können im Fall eines Angriffs ohne starke Auswirkungen auf den Firmenbetrieb ausgeschaltet oder abgeschottet werden
  • Incident-Modus automatisiert per Configuration-Management System anschalten –> Testen

4.8.2 Kunden/Benutzer im Falle eines Sicherheitsvorfalls informieren

  • Wenn die eigene Kommunikationsstruktur (z.B. E-Mail) betroffen ist, die alternativen Kommunikationswege benutzen
  • Dokumentierte Notfall-Prozedur zur Kunden-Kommunikation vorhalten und verteilen
  • Bei erkannten Angriffen 4 Augen-Prinzip beachten, nicht alleine arbeiten!

4.8.3 Spurensicherung

  • VM Snapshots erstellen (per GPG signieren)
  • Von einem Forensik-Linux booten (Kali-Linux, Deft o.ä.)
  • Revisionssichere Images (dcfldd, aff4) erstellen http://www.osforensics.com/tools/create-disk-images.html
         apt install dcfldd
         dcfldd if=/dev/sda1 hash=sha256 hashwindow=100M sha256log=sha256.txt \
           hashconv=after bs=512 conv=noerror,sync split=100M splitformat=aa of=sda1.dd
    
  • Images sofort nach der Erstellung per GPG signieren (mit externer Signaturdatei)
  • Erst Platten-Images erstellen, dann Log-Dateien etc. anschauen
  • Festplatten ausbauen und durch fabrikneue Platten ersetzen, Festplatten mit kompromittiertem System versiegeln (lassen)
  • Analyse des Einbruches auf den Read-Only-Dateisystem-Images (nicht auf den echten Platten, die echten Platten sind ein Beweismittel und dürfen nach der Versiegelung nicht angefasst werden)

4.8.4 Backup/Rebuild eines kompromitierten Systems

  • Server komplett neu aufsetzen (Docker dockerfile, Foreman/Ansible/Salt etc, VM Templates)
  • Festplatte(n) austauschen
  • Nur Daten ohne ausführbare Teile (Maschinencode, Java, .NET, Python pyc, PHP, Scripte etc) zurückspielen
    • Bei der Einrichtung der Server schon auf eine Trennung von System, Anwendungen und Daten achten!
  • Scripte neu erstellen, von einem bekannt sauberen Backup zurückspielen oder einzeln per Pair-Review (2 Personen Review) prüfen

4.9 Rootkits aufspüren

  • Root-Kit-Hunter installieren
apt install rkhunter
  • RKHunter Baseline Datenbank erstellen
rkhunter --propupd
  • nach Root-Kits suchen
rkhunter --check
less /var/log/rkhunter.log

4.10 Intrusion Detection

4.10.1 rhash

  • rhash Installation
apt install rhash
  • Datenbank mit den Hash-Werten erstellen (Hash=SHA3/Keccak mit 224 bit, Datenbankformat wie bei BSD)
rhash -r --sha3-224 --bsd /etc -o hash.lst
  • Datenbank anschauen
less hash.lst
  • Datenbank sichern (in Produktionsumgebung)
scp hash.lst benutzer@sicherer-server.example.com
  • Dateien gegen die Datenbank prüfen
rhash -r -c --bsd hash.lst
  • Die Benutzer-Authentisierungsdateien durch Anlegen eines neuen Benutzers ändern
adduser intruder
  • nochmal Dateien gegen die Datenbank prüfen
rhash -r -c --bsd hash.lst
  • Nur die “nicht-OK” Dateien anzeigen
rhash --skip-ok -r -c --bsd hash.lst

4.10.2 AIDE

  • Installation
apt install aide aide-common
  • Konfiguration anschauen und ggf. ändern
$EDITOR /etc/aide/aide.conf
  • AIDE Datenbank erstellen (Dauer ca. 3-6 Minuten auf den Linuxhotel Laptops)
aideinit
  • Ausgabe von aideinit
Start timestamp: 2019-11-13 07:58:08 +0100 (AIDE 0.16.1)
AIDE initialized database at /var/lib/aide/aide.db.new
Verbose level: 6

Number of entries:      178250

---------------------------------------------------
The attributes of the (uncompressed) database(s):
---------------------------------------------------

/var/lib/aide/aide.db.new
  RMD160   : w/xQIwY8je09TrZAMFOFN2JqAY4=
  TIGER    : MRqyf0hq+8N+Kv/wILF7v0X3HEFcvhdv
  SHA256   : 8Jvgtqq0amatTf+Tj0o42W2HYne6Jf2g
             i5PClJmWv04=
  SHA512   : OWGC4zRYKyBTEg9fBBDgUCLVDoERZjve
             GI5EdEPCoGXwRnTR6tBP67tAa9tj7llh
             bd2O2CbTZ08pVI9AQ22Q2g==
  CRC32    : B9czIg==
  HAVAL    : 9GLjw3cDS/k2qpnZhoiZHmKYoSMZ1I3h
             mL2pUnyMoCQ=
  GOST     : mfBemqOHFSzWHf49h33R7gysjoLA4JiH
             oA+P3T9v6xU=

End timestamp: 2019-11-13 08:01:19 +0100 (run time: 3m 11s)
  • Datenbank sichern
scp  /var/lib/aide/aide.db.new.gz user@secure-machine
  • eine unbefugte Änderung am System simulieren
groupadd intruders
  • AIDE Check laufen lassen
aide --check -c /etc/aide/aide.conf

4.10.3 Samhain

  • Installation
apt install samhain
  • Samhain internen Schlüssel ergänzen (<key> sollte durch eine lange, zufällige Zahl ersetzt werden)
systemctl stop samhain
samhain --add-key=<key>@/usr/sbin/samhain
cp /usr/sbin/samhain.out /usr/sbin/samhain
rm -f /var/lib/samhain/samhain_file
systemctl start samhain
  • Samhain Konfigurationsdatei anschauen/anpassen.
$EDITOR /etc/samhain/samhainrc
  • Datenbank auf einen sicheren Server kopieren (in Produktionsumgebungen)
scp /var/lib/samhain/samhain_file nutzer@secure-host:.
  • Samhain ist als Service-Dämon gestartet
systemctl status samhain
  • Test Passwort-Dateien ändern
# test, Datei (/etc/shadow und /etc/passwd) ändern
passwd nutzerXX
  • Check mit Ausgaben nur Level “crit”
samhain -t check --foreground -l none -p crit
  • Samhain Datenbank aktualisieren
samhain -t update --foreground

4.11 Unter Debian Dienste nicht sofort nach der Installation starten

  • Datei /etc/systemd/system-preset/00-disable-all.preset anlegen mit dem Inhalt
disable *
  • Unter /usr/sbin/policyd-rc.d ein Shell Script erzeugen, welches Fehler #101 zurückliefert
# echo -e '#!/bin/bash\nexit 101' > /usr/sbin/policy-rc.d
# chmod +x /usr/sbin/policy-rc.d
# /usr/sbin/policy-rc.d
# echo $?
101

4.12 CVE (Common Vulnerabilities and Exposures)   RedHat

4.12.1 Common Vulnerability Scoring System (CVSS)

  1. CVSS V2
    • Access Vector (AV) - wie kann der Angreifer die Lücke ausnutzen
      • AV:L lokaler Angriff möglich
      • AV:A Angriff aus den gleichen Subnetz möglich
      • AV:N Remote über das Netzwerk
    • Access Complexity (AC) - wie schwierig ist es für einen Angreifer die Lücke auszunutzen, sobald er im System ist
      • AC:H Hoch
      • AC:M Medium
      • AC:L Niedrig
    • Authentication (Au) - wie oft muss sich der Angreifer am System anmelden/authentisieren muss
      • Au:M mehrfache Authentisierung notwendig (Benutzer -> sudo Root)
      • Au:S einmalige Anmeldung genügt (normaler Benutzer)
      • Au:N garnicht
    • Confidentiality Impact (C) - Auswirkung auf die Datensicherheit
      • C:N keine
      • C:P Teil-Daten
      • C:C alle Daten
    • Integrity Impact (I) - Auswirkung auf die Integrität des Systems
      • I:N keine Auswirkung
      • I:P System teilweise nicht mehr vertrauenswürdig
      • I:C System nicht mehr vertrauenswürdig
    • Availability Impact (A) - Auswirkung auf die Verfügbarkeit des Systems
      • A:N keine Auswirkung
      • A:P teilweise beeinträchtigung der Verfügbarkeit
      • A:C Komplettausfall des Systems
  2. CVSS V3
    • Angriffs Vektor (AV)
      • Network (N) - Angriff über Netzwerk möglich
      • Adjacent (A) - Angreifer muss im lokalen Netz sein
      • Local (L) - Angreifer muss lokal auf dem System sein
      • Physical (P) - Angreifer muss physischen Zugang zu dem System haben
    • Angriffs Komplexität (AC)
      • Low (L) - keine besondern Kentnisse beim Angreifer erforderlich
      • High (H) - der Angreifer braucht spezielle Kenntnisse
    • benötigte Privilegien (PR)
      • None (N) - keine besonderen Privilegien notwendig
      • Low (L) - Normale Benutzeranmeldung notwendig
      • High (H) - Angreifer benötigt spezielle Rechte
    • Unterstützung duch einen Benutzer (UI)
      • None (N) - der Angriff kann ohne Aktion eines lokalen Benutzers erforderlich sein
      • Required (R) - der Angriff benötigt die Unterstützung eines lokalen Benutzers
    • Scope (Reichweite) (S)
      • Unchanged (U) - die Sicherheitslücke beeinträchtigt nur das angegriffene System
      • Changed (C) - über die Sicherheitslücke werden auch andere Systeme als das angegriffene beeinträchtigt
    • Auswirkungen auf den Schutz von Daten (Confidentiality Impact) (C)
      • High (H) - Datenschutz kann nicht mehr sichergestellt werden
      • Low (L) - einige Daten können in die Hände des Angreifers fallen
      • None (N) - die Sicherheitslücke hat keine Auswirkungen auf den Schutz der Daten
    • Auswirkungen auf die Integrität der Daten (I)
      • High (H) - die Daten können vom Angreifer verändert werden und der Angreifer kann damit direkt Schaden verursachen
      • Low (L) - der Angreifer kann Daten verändern, hat aber keine Kontrolle über die Auswirkungen
      • None (N) - der Angreifer kann keine Daten verändern
    • Auswirkungen auf die Verfügbarkeit des Systems (A)
      • High (H) - das System fällt aus
      • Low (L) - es gibt Beeinträchtigungen der Verfügbarkeit
      • None (N) - die Sicherheitslücke hat keine Auswirkungen auf die Verfügbarkeit
    • Verfügbarkeit von Angriffscode
      • Undefiniert (X) - es liegen keine Informationen über die Verfügbarkeit von Schadcode vor
      • High (H) - es gibt automatisierte Angriffs-Programme
      • Functional (F) - es existiert Schadcode der manuell ausgeführt werden kann und in den meisten Fällen erfolgreich ist
      • Proof-of-Concept (P) - es gibt Beispiele für Schadcode, dieser ist jedoch auf dem meisten Systemen nicht einsetzbar
      • Unproven (U) - es gibt noch keinen Code oder die Sicherheitslücke ist nur theoretisch
    • Abhilfe
      • Undefiniert (X) - es liegen noch keine Informationen über Patche vor
      • Unavailable (U) - es gibt noch keinen Schutz gegen die Sicherheitslücke
      • Workaround (W) - es gibt keinen Fix, aber eine Anleitung die Ausnutzung der Sicherheitslücke zu verhindern
      • temporary fix (T) - es gibt einen vorläufigen Patch
      • official fix (O) - es gibt einen offiziellen Patch
    • Glaubwürdigkeit
      • Undefiniert (X) - es können keine Aussagen zur Glaubwürdigkeit der Meldung gemacht werden
      • Confirmed (C) - die Sicherheitslücke wurde bestätigt
      • Reasonable (R) - die Sicherheitslücke ist glaubhaft
      • Unknown (U) - es gibt Berichte über Sicherheitsprobleme, aber eine Verbindung zur Sicherheitslücke konnte noch nicht bestätigt werden

4.13 Kernel Parameter

  • Kernel Parameter können auf der Kernel-Kommando-Zeile im Bootloader angegeben werden, um Kernel-Funktionen zu steuern

4.13.1 Audit-Subsystem

  • Audit-Subsystem anschalten
audit=[0|1]
  • wenn audit nicht gesetzt ist, dann wir das Audit-Subsystem erst mit dem Starten des Audit-Daemon auditd aktiv
  • Wert 0 – Audit-Subsystem ist ausgeschaltet
  • Wert 1 – Audit-Subsystem wird sofort aktiv, der Kernel sammelt Audit Informationen und übergibt diese an den Audit-Daemon, sobald dieser gestartet ist

4.13.2 AppArmor

apparmor=[0|1]
  • AppArmor an/ausschalten

4.13.3 SELinux

  • SELinux an/ausschalten
selinux=[0|1]
  • SELinux Regeln durchsetzen (enforcing)
enforcing=[0|1]
  • Wert 0 = SELinux im permissive Modus
  • Wert 1 = SELinux im enforcing Modus

4.13.4 Signierte Module

module.sig_enforce
  • wenn gesetzt, können nur Kernel-Module mit einer gültigen Signatur geladen werden

4.13.5 NOEXEC

noexec=[on|off]
  • bei 32bit PAE Kerneln, schaltet Schreibschutz auf Daten-Speicherseiten an

4.13.6 Datei-Capabilities

no_file_caps
  • Schaltet die Datei-Capabilities aus

4.13.7 Keine Module nachladen

nomodule
  • es können keine Module nachgeladen werden

4.13.8 Kernel-Panic

panic=<timeout>
  • Wert > 0 - Sekunden bis zum Reboot
  • Wert = 0 - kein Reboot (* aus Sicherheitsgründen empfohlen)
  • Wert < 0 - sofortiger Reboot

4.13.9 sysctl

sysctl -a
  • Permanente sysctl Einstellungen in /etc/sysctl.conf
kernel.randomize_va_space = 2

# Restrict core dumps
fs.suid_dumpable = 0

# Hide exposed kernel pointers
kernel.kptr_restrict = 1

#Prevent SYN attack, enable SYNcookies (they will kick-in when the max_syn_backlog reached)
# use iptables synproxy
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096

# Disables packet forwarding
net.ipv4.ip_forward = 0
net.ipv4.conf.all.forwarding = 0
net.ipv4.conf.default.forwarding = 0
net.ipv6.conf.all.forwarding = 0
net.ipv6.conf.default.forwarding = 0

# Disables IP source routing
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0

# Enable IP spoofing protection, turn on source route verification
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Disable ICMP Redirect Acceptance
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0

# Enable Log Spoofed Packets, Source Routed Packets, Redirect Packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Don't relay bootp
net.ipv4.conf.all.bootp_relay = 0

# Don't proxy arp for anyone
net.ipv4.conf.all.proxy_arp = 0

# Enable ignoring broadcasts request
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Enable bad error message Protection
net.ipv4.icmp_ignore_bogus_error_responses = 1

5 Tag 5

5.1 LSM - Linux-Sicherheits-Module

  • LSM (Linux Security Module) sind Erweiterungen des Linux-Kernels
    • Der Linux-Kernel definiert Schnittstellen, in welche sich die LSMs einklinken können:
      • Syscalls
      • Dateizugriffe
      • Prozess-Erstellung
      • Namespaces und cgroups
      • Benutzer-Identität (UID/GID)
    • Ein LSM Modul kann sich in eine oder mehrere dieser Schnittstellen einklinken
    • Wird diese Kernel-Funktion benutzt, so wird das LSM aktiv und wird die Kernel-Funktion nach Prüfung erlauben oder verbieten
  • Link: A Brief Tour of Linux Security Modules
  • Major LSMs: Mandatory Access Controls - nur eines dieser LSM kann (derzeit) im Linux-Kernel aktiviert sein
    • SELinux
    • AppArmor
    • SMACK (Simplified Mandatory Access Control)
    • TOMOYO
  • Minor LSMs: diese LSMs können zusätzlich zu den Major-LSMs und anderen Minor-LSMs aktiviert sein
    • YAMA
    • LoadPin
    • SafeSetID
    • Lockdown
    • Landlock
    • BPF - LSM Sicherheitsrichtlinien können mittels eBPF durchgesetzt werden
    • capabilities - Linux capabilities

5.1.1 Prüfen, welche LSMs im aktuell aktiven Linux-Kernel aktiv sind

    # cat /sys/kernel/security/lsm
    lockdown,capability,yama,tomoyo,bpf

5.1.2 YAMA

  • YAMA sammelt Sicherheitsfunktionen aus Linux-Kernel-Sicherheitspatches, welche nicht in eine der anderen Linux-Sicherheits-Module passen
  • in aktuellen Linux-Kerneln bietet mit YAMA einen Schutz gegen ptrace (ptrace_scope), d.h. das ein Prozess den Speicher und die Ausführung eines anderen Prozesses überwachen kann (diese Funktion wird für die Benutzung von Debuggern bei der Programmentwicklung benötigt). Auf Produktions-Serversystemen ist diese Funktion oft nicht benötigt.
  • Werte für ptrace_scope
    Wert Beschreibung
    0 normales Verhalten, jeder Prozess und Benutzer kann andere Prozesse überwachen
    1 ein Prozess kann nur einen eigenen Kind-Prozess überwachen
    2 nur ein Systemadministrator mit CAP_SYS_PTRACE kann Prozesse überwachen
    3 keine Überwachen von Prozessen mittels ptrace möglich, diese Einstellung kann im laufenden System nicht überschrieben werden
  1. Beispiel (Firefox als nutzerXX gestartet):
    root$ apt install strace
    nutzerXX$ strace -p $(pgrep firefox)
    root$ echo "1" > /proc/sys/kernel/yama/ptrace_scope
    nutzerXX$ strace -p $(pgrep firefox)
    strace: attach: ptrace(PTRACE_ATTACH, 3135): Operation not permitted
    

5.1.3 LoadPin

5.1.4 SafeSetID

  • Das SafeSetID Modul überwacht die Benutzung der SetUID/SetGID Syscalls (UID oder GID eines Prozesses ändern, z.B. via su oder sudo oder per SetUID-Bit in den Dateisystemrechten) und prüft die Benutztung gegen eine systemweite Whitelist
    • Mittels SafeSetID können Prozesse die Capability CAP_SETUID/CAP_SETGID benutzen um von einem unpriviligierten Benutzeraccount in einen anderen zu wechseln (um Rechte abzugeben), ohne das diese Programme die Rechte ausweiten können oder sogar Root- Rechte erlangen können
    • Die Whitelist wird als Text-Datei mit je einer Regel pro Zeile in das securityfs Pseudo-Dateisystem unter dem Pfad safesetid/uid_allowlist_policy (für UID Übergänge) und safesetid/gid_allowlist_policy (für GID Übergänge) geschrieben
    • Das Format jedes Eintrages ist <ausgangs-UID>:<neue-UID>\n
  • Dokumentation: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/LSM/SafeSetID.rst

5.1.5 Lockdown

  • Das Lockdown Modul beschränkt bestimmte Funktionen des Linux Kernels (Laden von unsignierten Modulen, PTRACE, eBPF, Hibernation = Speicherinhalte auf Datenträger schreiben, Zugriffe auf spezielle Gerätedateien unter /dev, Kernel perf Schnittstellen, ACPI-Tabellen …)
    • Lockdown kann per Kernel-Commandozeile aktiviert werden: Parameter lockdown=
    • Nachträglich kann Lockdown über das Pseudo-Dateisystem unter /sys/kernel/security/lockdown ein- oder aus-geschaltet werden
    • Lockdown kennt zwei Modi
      • integrity - Funktionen sind ausgeschaltet, welche den laufenden Kernel verändern können
      • confidentiality - Funktionen aus dem Modus integrity sind ausgeschaltet, plus Funktionen über welche sensible Daten aus dem Kernel ausgelesen werden können (z.B. Zugriffe auf /dev/mem)
  • Lockdown LSM ist seit Kernel 5.4 verfügbar
  • Lockdown Status ausgeben (hier none, Modi integrity und confidentiality sind möglich)
       # cat /sys/kernel/security/lockdown
       [none] integrity confidentiality
    
  • Links

5.1.6 Landlock

  • Landlock ist ein LSM welches Prozessen erlaubt, die eigenen Dateisystem-Rechte (und die Rechte von Kind-Prozessen) über die Unix-Dateisystemrechte hinaus einzuschränken.
    • Da die Landlock Rechte-Einschränkungen vererbt werden, können auch Supervisor Programme erstellt werden, um Kind-Prozesse zu beschränken, ohne diese Kind-Prozesse im Quellcode ändern zu müssen
    • Landlock ist von der Idee vergleichbar mit dem OpenBSD pledge Mechanismus, wirkt jedoch nur auf Dateisystemrechte (pledge wirkt auf verschiedenen Syscall-Gruppen)
  • Seit Kernel 5.13 verfügbar
  • Dokumentation: https://landlock.io/
  • Kernel Dokumentation: https://www.kernel.org/doc/html/latest/security/landlock.html

5.1.7 TOMOYO

  • TOMOYO LSM kann zur Analyse eines Linux-Systems, oder zur Implementation einer Sicherheitrichtlinie für das Linux-System verwendet werden
  • TOMOYO beschränkt Linux-Prozesse auf Basis des Dateisystem-Pfads und der Prozess-Hierarchy (“Domain” in der TOMOYO Terminology, hat aber keinen Zusammenhang mit DNS, dem Domain-Name-System)
  • TOMOYO fasst einen oder mehrere Prozesse zu einer Domain zusammen
    • Jede Domain wird über ein Profil reglementiert
    • Es können 255 unterschiedliche Profile im TOMOYO LSM definiert werden
    • Jedes Profil kann unabhängig von anderen Profilen in einem von 3 Modi verwendet werden
      • Learning: Syscall-Aufrufe und Dateisystem-Interaktionen werden protokolliert und in das Profil aufgenommen (Erstellung eines Baseline-Profils für eine Prozess-Gruppe/Domain)
      • Permissive: Verstösse gegen die Policy werden protokolliert, aber nicht durchgesetzt
      • Enforcing: Verstösse gegen die Policy werden aktiv verhindert und protokolliert
  • Kernel-Dokumentation: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/LSM/tomoyo.rst
  • Handbuch: https://tomoyo.osdn.jp/2.6/index.html.en
  • TOMOYO kann alternativ auch als Linux-Kernel-Modul geladen werden (dann ist es kein LSM, sondern kann zusätzlich zu anderen Major-LSMs benutzt werden)

5.1.8 SMACK

  • SMACK ist ein Mandatory Access Controll System im Linux Kernel, welches im Vergleich zu SELinux weniger komplex ist
  • SMACK ist seit Kernel 2.6.25 Teil des Linux-Kernels
  • SMACK wird heute hauptsächlich in Linux-Systemen von IoT-Geräten und in Automotive-Anwendungen verwendet (z.B. im Tizen OS von Samsung)
    • Wie auch SELinux arbeitet SMACK auch mit Sicherheits-Label auf Basis von erweiterten Attributen in den Linux-Dateisystemen
      • Es ist möglich SMACK in mittels der eingebauten Sicherheitspolicy auch ohne erweiterte Attribute zu betreiben, dann kann die Sicherheitsrichtlinie jedoch nicht angepasst werden
    • SMACK bindet Sicherheitslabel beim Empfang an IP-Pakete
      • Die Sicherheitsrichtlinie kann benutzt werden, um die Kommunikation von Anwendungen auf bestimmte IP-Adressen oder Netzwerke zu beschränken
      • Diese Funktion von SMACK kann zu Performance-Verlusten bei der Netzwerkkommunikation führen, wenn SMACK im Kernel aktiv ist
  • SMACK Kernek Dokumentation
  • Heise iX: SMACK im Linux Kernel

5.1.9 SELinux

  • SELinux (Security-Enhanced Linux; engl. „sicherheitsverbessertes Linux“) ist eine Erweiterung des Linux-Kernels. Es implementiert die Zugriffskontrollen auf Ressourcen im Sinne von Mandatory Access Control. SELinux wurde von der NSA für eigene Bedürfnisse entwickelt und wird von dem Linux-Distributor Red Hat gepflegt.
  • SELinux ist Open-Source-Software und setzt sich aus einem Kernel-Modul, Hilfsprogramme und aus zahlreichen Erweiterungen für Systemprogramme zusammen.
  • Kernbestandteil von SELinux sind die Policies, welche sehr detailliert beschreiben, welche Zugriffe (Dateisystem, Syscalls, Netzwerk) einem Prozess oder einem Benutzer erlaubt sind.
  • SELinux kann mit verschiedenen Policy-Einstellungen betrieben werden:
    • full - alle Ressourcen und Anwendungen im Linux-System sind von der SELinux Policy abgedeckt. Dies ist sehr aufwändig und wird von den Linux-Distributionen nicht angeboten
    • targeted - SELinux Policies existieren für kritische Komponenten im Linux-System (z.B. Systemd, Webserver, Mailserver etc). Nur diese Komponenten sind von SELinux abgesichert, alle anderen Komponenten befinden sich im unconfined Modus und werden von SELinux nicht beschränkt. Die Linux-Distributionen bieten Policies für den targeted Modus an.
  1. SELinux erkunden
    • wir arbeiten auf einer Rocky Linux VM im Internet. Benutzername user und Passwort villa, Benutzer root kann durch sudo erreicht werden
    • SELinux Hilfspakete installieren
       yum install policycoreutils setools libselinux-utils selinux-policy-doc setools-console policycoreutils-python3 selinux-policy-devel policycoreutils-newrole
    
    • SELinux Label (Context) auf Dateien/Prozesse/Benutzer anzeigen
       ls -lZ <pfad>
       ps -auxZ
       id -Z
    
    • SELinux Status abfragen
       getenforce
       sestatus
       sestatus -v
    
    • SELinux Module auflisten
       semodule -l | less
    
    • Modul-Dateien (binär) und die fertige Policy
       ls -l /etc/selinux/targeted/active/modules/100/
       ls -lh /etc/selinux/targeted/policy/
    
    • SELinux Policy Quelldateien
       ls -l /usr/share/selinux/devel/
    
    • Apache Webserver installieren und starten
       yum install httpd
       systemctl enable --now httpd
    
    • Kleine Webseite anlegen
       $EDITOR /var/www/html/index.html
    
    • Inhalt der HTML-Datei
       <html>
       <body>
       <h1>Apache Webserver</h1>
       </body>
       </html>
    
    • SELinux Security Context auf der Datei
       ls -lZ /var/www/html/index.html
    
  2. Ein Problem für SELinux erzeugen und bereinigen
    • index-html Datei im Verzeichnis des Benutzers root erstellen und dann in das Apache-WWW-Verzeichnis verschieben:
      rm /var/www/html/index.html
      $EDITOR /root/index.html
      mv /root/index.html /var/www/html/index.html
      ls -lZ /var/www/html/index.html
    
    • Apache sollte nun nicht mehr in der Lage sein, die HTML-Datei auszuliefern (Default-Apache 2 Webseite erscheint)
    • SELinux Meldungen im Audit-Log
       ausearch -m avc -ts recent -c httpd -i
    
    • SELinux Security Context prüfen
       matchpathcon -V /var/www/html/index.html
    
    • SELinux Security Context anpassen
       chcon --type httpd_sys_content_t /var/www/html/index.html
    
    • (Alternativ) SELinux Security Context aus der SELinux Policy angleichen
       restorecon -v /var/www/html/index.html
    
    • SELinux Security Context für Apache
       sesearch --allow --source httpd_t --target httpd_sys_content_t --class file
    
    • weitere SELinux Tools
       seinfo       # Übersicht über das SELinux Regelwerk
       seinfo -u    # Übersicht der SELinux Benutzer
       seinfo -r    # Übersicht der SELinux Rollen
       seinfo -t    # Übersicht der SELinux (Datei-) Typen
    
  3. SELinux und Benutzer
    • Benutzer user in die Benutzerklasse user_u einfügen
      semanage login -l
      semanage user -l
      semanage login -a -s user_u user
      # su oder sudo sollten nun für den Benutzer nicht mehr möglich sein
      cat /etc/selinux/targeted/seusers
      semanage login -a -s guest_u user
      getsebool allow_guest_exec_content
      setsebool allow_guest_exec_content off
      # scripts sind nun nicht mehr direkt ausführbar (indirekt über BASH oder SH funktioniert es trotzdem)
    
    • Fehlersuche bei SELinux Problemen
      ausearch -m avc -ts recent
    
  4. Aufgabe: Apache auf einem anderen Port als 80 oder 443
    • Schritte auf der VM ausführen
    • Ändere die Apache Konfiguration unter /etc/httpd/conf/httpd.conf so das der Apache auf Port 1235/TCP auf HTTP-Anfragen horcht (Konfigurationsparameter Listen: 1235)
    • Versuche den Apache Webserver mittels systemd neu zu starten (systemctl restart httpd). Dies wird fehlschlagen, da httpd sich nicht auf Port 1235 binden kann.
    • Schaue in per ausearch in die Audit-Logdatei nach SELinux Fehlern des Prozesses httpd
    • Benutze den Befehl semanage port um den Port 1234 für den Prozess httpd im SELinux freizuschalten und starte den Apache Webserver neu.
    • Teste, on der Firefox-Browser unter der URL http://selinuxNNN.dnslab.org:1235/ die Webseite des Webservers sehen kann.
  5. Beispiellösung
    • Apache Konfiguration bearbeiten
    $EDITOR /etc/httpd/conf/httpd.conf
    
    • Apache Prozess neu starten. Dies sollte fehlschlagen, da SELinux die Benutzung von Port 1235 für den Prozess httpd verbietet
    • SELinux Fehler für httpd im Audit-Log suchen
    ausearch -m avc -c httpd -ts recent -i
    
    • Port 1235 für Apache in der SELinux Richtlinie freischalten
    semanage port -m -t http_port_t -p tcp 1235
    
    • Apache Webserver neu starten
    systemctl restart httpd
    
    • Änderungen mit semanage sind persistent, die Port-Änderung ist unter /etc/selinux/targeted/active/ports.local abgespeichert:
    # This file is auto-generated by libsemanage
    # Do not edit directly.
    
    portcon tcp 1235 system_u:object_r:http_port_t:s0
    

5.1.10 AppArmor

  • AppArmor ist bei Debian 11 installiert und aktiviert
  • AppArmor Wiki http://wiki.apparmor.net/index.php/Main_Page
  • Im Gegensatz zu SELinux definiert AppArmor die Sicherheits-Richtlinien auf Basis von Dateisystem-Pfaden und nicht auf Dateisystem-Attributen
  1. AppArmor Anleitung
    • Installation weiterer AppArmor Tools
    apt install apparmor apparmor-profiles apparmor-utils
    
    • AppArmor Status prüfen
    aa-status
    
    less  /etc/apparmor.d/bin.ping
    
    • Änderungen am Profil für ping, das ping Programm sollte danach keine ICMP(v6) Pakete versenden können
    $EDITOR /etc/apparmor.d/bin.ping
    ---
    [...]
      #include <abstractions/nameservice>
    
    #  capability net_raw,
    #  capability setuid,
      network inet raw,
    [...]
    
    • Profil neu laden
    apparmor_parser -r /etc/apparmor.d/bin.ping
    
    • Enforce-Modus für ein Programm setzen
    # aa-enforce  /etc/apparmor.d/bin.ping
    Setting /etc/apparmor.d/bin.ping to enforce mode.
    
    • Test des ping Programms:
    # ping 8.8.8.8
    ping: socket: Die Operation ist nicht erlaubt
    # ping fe80::3e97:eff:feeb:a358%enp0s25
    ping: socket: Die Operation ist nicht erlaubt
    

    (Achtung: Wenn firejail installiert ist, ist /usr/bin/ping ein Symlink zu firejail)

    • Complain-Modus für ein Programm setzen
    aa-complain  /etc/apparmor.d/bin.ping
    Setting /etc/apparmor.d/bin.ping to complain mode.
    
    • gestartete Programme ohne AppArmor Profil listen
    # aa-unconfined
    622 /usr/sbin/NetworkManager not confined
    623 /usr/sbin/cupsd confined by '/usr/sbin/cupsd (enforce)'
    630 /usr/sbin/avahi-daemon confined by '/usr/sbin/avahi-daemon (complain)'
    650 /usr/sbin/cups-browsed confined by '/usr/sbin/cups-browsed (enforce)'
    698 /usr/sbin/sshd not confined
    1250 /usr/sbin/minissdpd not confined
    1504 /usr/sbin/exim4 not confined
    2013 /sbin/dhclient not confined
    
    • AppArmor Profil-Vorlage automatisiert erstellen. Die Vorlage muss immer manuell nachgearbeitet werden. (Aufgrund des Debian-Fehlers in Debian 10, siehe https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=928160, funktioniert aa-genprof nicht, wenn das Paket apparmor-profiles installiert ist. Um aa-genprof zu benutzen erst dieses Paket deinstallieren apt remove apparmor-profiles und dann aa-genprof benutzen).
    aa-genprof <programm>
    
  2. AppArmor Aufgabe
    • Entferne (auskommentieren) aus dem AppArmor-Profil für “ping” die Capability net_raw
    • Starte AppArmor neu
    systemctl restart apparmor
    
    • Setze ping in den complain Modus. Prüfe mit aa-status
    • Protokolliere das Audit-Log
    tail -f /var/log/audit/audit.log
    
    • Benutze den ping Befehl. Der ping Befehl sollte funktionieren, aber im Audit-Log vermerkt sein
    • Setze ping in den enforce Modus
    • Benutze den ping Befehl. Der ping Befehl sollte nicht funktionieren, im Audit-Log wird dieser Event registriert
    • Benutze den interaktiven Assistenten, um Policies zu erweitern:
    aa-logprof -f <(cat /var/log/audit/audit.log) #ggfs. log noch greppen
    

5.2 Logdateien auswerten

  • Artificial Ignorance: bei diesem von Marcus Ranum beschriebenen Konzept werden Filter aufgebaut durch welche die Log-Ausgaben gefiltert werden. Log-Ausgaben werden in zwei Kategorien eingeteilt:
    • Meldung beschreibt eine kritische Fehlfunktion im System. Die Ursache der Fehlfunktion muss beseitigt werden, damit die Log-Ausgaben nicht mehr angezeigt werden
    • Meldung beschreibt eine unkritische Situation im System. Die Filter werden erweitert, um die Log-Meldung in Zukunft zu unterdrücken

    Ziel von AI-Logauswertung ist es, das die Log-Dateien nach dem Filtern leer sind. Alle neuen Log-Meldungen, welche in den Log-Dateien auftauchen, müssen entweder bereinigt werden oder durch einen Filter unterdrückt werden: http://www.ranum.com/security/computer_security/papers/ai/

5.2.1 Log-Templater

mkdir ~/src
cd ~/src
apt -y install git build-essential automake autoconf
git clone https://github.com/rondilley/tmpltr.git
cd tmpltr
./bootstrap
autoreconf -i
./configure
make
make install
  • Systemd-Journal für den Dienst sshd mit tmpltr auswerten
journalctl -u ssh | tmpltr - | sort -n |  sed -e 's/%s.*||//'
  • Templates abspeichern, dann ignore Datei bearbeiten
journalctl -u ssh | tmpltr -w /var/log/ssh.ignore -
  • Log mit ignore Datei auswerten
journalctl -u ssh | tmpltr -t /var/log/ssh.ignore - | sort -n |  sed -e 's/%s.*||//'
  • SSH-Fehler produzieren (z.B. Anmeldeversuch mit falschem Passwort) und Log-Datei neu auswerten
ssh bar@localhost
bar@localhost's password:
Permission denied, please try again.
bar@localhost's password:
  • Log-Auswerten
[bar@notebook32 tmpltr]# journalctl -u sshd | tmpltr -t /var/log/sshd.ignore - | sort -n |  sed -e 's/%s.*||//'
Opening [-] for read
           1 Aug 31 12:29:25 notebook32 sshd[24691]: Connection closed by ::1 port 40372 [preauth]
           1 Aug 31 12:29:25 notebook32 sshd[24691]: Failed password for bar from ::1 port 40372 ssh2
           1 Aug 31 12:29:23 notebook32 sshd[24691]: pam_succeed_if(sshd:auth): requirement "uid >= 1000" not met by user "bar"
           1 Aug 31 12:29:23 notebook32 sshd[24691]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=localhost  user=bar
  • Neue Log-Einträge in die Ignore-Datei aufnehmen
journalctl -u sshd | tmpltr -t /var/log/sshd.ignore -w /var/log/sshd.ignore.new - && \
  cat /var/log/sshd.ignore.new >> /var/log/sshd.ignore

5.2.2 Greylog (Open Source)

5.2.3 Splunk (Kommerziell)

5.3 Dateisystem-Verschlüsselung

5.3.1 ext4 mit Verschlüsselung

  • ACHTUNG: unter Debian 9 nicht die Boot-Partition mit ext4-Verschlüsselung betreiben. Der von Debian 9 benutzte Boot-Loader GRUB2 kann noch nicht von ext4 Dateisystemen mit Verschlüsselung booten
    • https://lwn.net/Articles/639427/
    • Installation der Linux Key-Utilities:
              apt install keyutils
      
    • Die Volume-Partition /dev/sda4 mit ext4 formatieren (mit 4096 Byte Blöcken!)
              mkfs.ext4 -b 4096 /dev/sda4
      
    • Die ext4 Funktion “Verschlüsselung” im Dateisystem auf /dev/sda4 anschalten
              tune2fs -O encrypt /dev/sda4
      
    • Volume /dev/sda4 unter /encrypted einhängen
              mkdir /encrypted
              mount /dev/sda4 /encrypted
      
    • einen neuen Schlüssel dem Linux-Session-Keyring hinzufügen und dem Verzeichnis /encrypted/test zuordnen
              mkdir /encrypted/test
              e4crypt add_key /encrypted/test
              keyctl show
      
    • Daten in das verschlüsselte Verzeichnis kopieren und die erweiterten BSD-Attribute der Dateien anzeigen. Es sollten die Attribute ---------E----e---- /encrypted/test/passwd erscheinen (E = encrypted, c = komprimiert, siehe auch man chattr)
              cp /etc/passwd /encrypted/test
              lsattr /encrypted/test
      

5.3.2 dmcrypt/LUKS

  • LUKS Tools und LVM installieren
apt install cryptsetup lvm2
  • Neues Physisches Volume in /dev/sda5 erstellen
# pvcreate /dev/sda5
  Physical volume "/dev/sda5" successfully created.
  • Eine neue Volumegroup erstellen
# vgcreate crypt_vg /dev/sda5
  Volume group "crypt_vg" successfully created
  • ein neues logisches Volume im LVM erstellen (in der Volumegroup crypt_vg):
lvcreate --size 500M --name crypt crypt_vg
  • Ein verschlüsseltes Laufwerk auf dem LV erstellen
 cryptsetup --verbose --verify-passphrase luksFormat \
     /dev/mapper/crypt_vg-crypt
  • Das verschlüsselte Laufwerk im Linux-Device-Mapper anmelden
cryptsetup luksOpen /dev/mapper/crypt_vg-crypt crypt
  • An dieser Stelle muss das neue Laufwerk nun im Device-Mapper auftauchen
ls -l /dev/mapper/crypt
  • Das ’crypt’ Laufwerk formatieren (hier ext4, andere Dateisysteme und SWAP sind möglich)
mkfs.ext4 /dev/mapper/crypt
  • Ein leeres Verzeichnis anlegen und das neue Dateisystem dort mounten:
mkdir /crypt
mount /dev/mapper/crypt /crypt
  • Das Dateisystem auf dem verschlüsselten Laufwerk mit Test-Daten füllen
 # cp -a /etc /crypt/
  • Konfigurationsdatei für verschlüsselte Laufwerke anlegen
$EDITOR /etc/crypttab
  • Eintrag für unser verschlüsseltes Laufwerk
crypt /dev/mapper/crypt_vg-crypt  none luks,timeout=180
  • Eintrag in der /etc/fstab
/dev/mapper/crypt     /crypt    ext4    defaults  0 0
  • Partition in der /etc/fstab eintragen, Reboot testen

5.4 Secret Sharing

apt install ssss
  • Ein Geheimniss (Passwort) auf 5 Shares aufteilen, bei denen 3 Shares reichen um das Geheimnis wiederherzustellen
ssss-split -t 3 -n 5
  • Geheimnis aus 3 Shares wiederherstellen
ssss-combine -t 3

5.5 APT Updates automatisieren

  • nach der Installation sind die automatischen Updates angeschaltet. Die Konfiguration der automatischen Updates findet sich unter /etc/apt/apt.conf.d/50unattended:
apt-get install unattended-upgrades apt-listchanges
$EDITOR /etc/apt/apt.conf.d/50unattended-upgrades
----
Unattended-Upgrade::Mail "root";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
  • automatische Updates können über den Schalter APT::Periodic::Unattended-Upgrade in der Datei /etc/apt/apt.conf.d/20auto-upgrades an- bzw. ausgeschaltet werden.

5.6 Antivirus

5.6.1 ClamAV

  • ClamAV installieren
 apt install clamav clamav-daemon clamav-base clamav-freshclam
  • Ist SELinux aktiviert (z.B. Rocky/Alma/Fedora/CentOS/Red Hat), muss einen Antivirus-Scan im SELinux zulassen werden
 setsebool -P antivirus_can_scan_system 1
 setsebool -P clamd_use_jit on
  • FreshClam Konfiguration pruefen, Option DatabaseMirror von db.local.clamav.net auf db.de.clamav.net ändern, dann den FreshClam Dienst neu starten
 $EDITOR /etc/clamav/freshclam.conf
 systemctl restart clamav-freshclam
  • Im Journal nach Meldungen schauen
 journalctl -u clamav-freshclam
  • Wurde FreshClam ohne Fehler gestartet?
 systemctl status clamav-freshclam
  • Beispiel: Virensignaturen erfolgreich geladen
 [root@notebook33 src]# systemctl status clamav-freshclam
 freshclam.service - freshclam update ClamAV databases
    Loaded: loaded (/etc/systemd/system/freshclam.service; enabled)
    Active: inactive (dead) since Wed 2015-11-25 14:59:35 CET; 1min 2s ago
   Process: 28088 ExecStart=/usr/bin/freshclam -c 12 (code=exited, status=0/SUCCESS)
  Main PID: 28088 (code=exited, status=0/SUCCESS)

 Nov 25 14:59:20 notebook33 freshclam[28088]: Downloading daily.cvd [100%]
 Nov 25 14:59:21 notebook33 freshclam[28088]: [440B blob data]
 Nov 25 14:59:29 notebook33 freshclam[28088]: daily.cvd updated (version: 21096, sigs: 1700789, f-level: 63, builder: neo)
 Nov 25 14:59:29 notebook33 freshclam[28088]: daily.cvd updated (version: 21096, sigs: 1700789, f-level: 63, builder: neo)
 Nov 25 14:59:29 notebook33 freshclam[28088]: [293B blob data]
 Nov 25 14:59:29 notebook33 freshclam[28088]: Downloading bytecode.cvd [100%]
 Nov 25 14:59:30 notebook33 freshclam[28088]: bytecode.cvd updated (version: 270, sigs: 46, f-level: 63, builder: shurley)
 Nov 25 14:59:30 notebook33 freshclam[28088]: bytecode.cvd updated (version: 270, sigs: 46, f-level: 63, builder: shurley)
 Nov 25 14:59:35 notebook33 freshclam[28088]: Database updated (4125060 signatures) from database.clamav.net (IP: 62.201.161.84)
 Nov 25 14:59:35 notebook33 freshclam[28088]: Database updated (4125060 signatures) from database.clamav.net (IP: 62.201.161.84)
  • ClamAV Konfiguration prüfen
        clamconf | less
    
  • Manueller Scan (im Vordergrund)
 clamscan -vr /usr
  • EICAR Test-Virus in einem Heimverzeichnis erstellen, Heimverzeichnisse scannen (per Clam-Daemon)
 echo -n 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' \
         > /home/nutzerXX/eicar.com
 clamscan -vr /home
  • ClamAV Daemon starten
       systemctl start clamav-daemon
    
  • Clam-Daemon Auslastung überwachen
       clamdtop
    
  • Auf Virenfunde reagieren, in der Datei /etc/clamav/virusevent.d/ ein Shellskript anlegen
      #!/bin/sh
      logger -t virus "Signature detected: $CLAM_VIRUSEVENT_VIRUSNAME in $CLAM_VIRUSEVENT_FILENAME"
    
  • Shell Skript ausführbar machen
  • und in der Datei /etc/clamav/clamd.conf eintragen
      VirusEvent /etc/clamav/virusevent.d/log-virus
    

5.7 Netzzwerksicherheit

5.7.1 offene Port am Server prüfen

  • netstat - auf welchen Ports horchen Programme
netstat -tulpen
  • netstat - welche Verbindungen sind aktuell offen
netstat -puten
  • socket-stat
ss -tu46a
  • lsof, alle Verbindungen und offenen Ports anzeigen
lsof -i
  • Scan von aussen auf den Server per nmap
yum install nmap
# TCP-Scan mit Betriebssystem-Erkennung
nmap -sT -O 192.168.1.235
# kein DNS, kein Ping, TCP-Connect-Scan, UDP-Connect-Scan, alle Ports
nmap -n -Pn -sT -sU -p-  192.168.1.235
  • IPv6 nmap Scan
nmap -6 -sT -O 2001:4dd0:ff00:809d:216:d3ff:feb0:9c3

5.8 BIOS/UEFI Sicherheit

5.8.1 TODO SMT (Meltdown/Spectre etc)

5.8.2 Intel Management Engine (ME)

5.8.3 Coreboot/Libreboot

Coreboot ist eine freie (open source) Firmware für Intel und ARM Rechner. Coreboot hiess früher LinuxBIOS.

5.9 SELinux - Policy Development

  • Für dieses Kapitel arbeiten wir auf dem VM Maschinen
  • Andere Web-Server (Apache/NGINX etc) auf der VM stoppen
  • Für die Dauer dieser Übung die Firewall auf der VM deaktivieren
systemctl stop firewalld

5.9.1 SELinux Policy erweitern - Ein simpler HTTP-Server

  • Schöne Erklärung: https://debian-handbook.info/browse/de-DE/stable/sect.selinux.html
  • C-Compiler installieren
dnf install gcc
  • Pakete für die SELinux Policy-Entwicklung installieren
dnf install policycoreutils-python3 selinux-policy-devel
  • der Quellcode
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <err.h>

 char response[] = "HTTP/1.1 200 OK\r\n"
 "Content-Type: text/html; charset=UTF-8\r\n\r\n"
 "<!DOCTYPE html><html><head><title>Bye-bye baby bye-bye</title>"
 "<style>body { background-color: #111 }"
 "h1 { font-size:4cm; text-align: center; color: black;"
 " text-shadow: 0 0 2mm red}</style></head>"
   "<body><h1>Goodbye, world!</h1></body></html>\r\n";

 int main()
 {
   int one = 1, client_fd;
   struct sockaddr_in svr_addr, cli_addr;
   socklen_t sin_len = sizeof(cli_addr);

   int sock = socket(AF_INET, SOCK_STREAM, 0);
   if (sock < 0)
     err(1, "can't open socket");

   setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
   int port = 8080;
   svr_addr.sin_family = AF_INET;
   svr_addr.sin_addr.s_addr = INADDR_ANY;
   svr_addr.sin_port = htons(port);

   if (bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
     close(sock);
     err(1, "Can't bind");
   }

   listen(sock, 5);
   while (1) {
     client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
     printf("got connection\n");

     if (client_fd == -1) {
       perror("Can't accept");
       continue;
     }

     write(client_fd, response, sizeof(response) - 1); /*-1:'\0'*/
     close(client_fd);
   }
 }

  • Quellcode vorbereiten
 mkdir ~/src
 cd ~/src
 $EDITOR simple-server1.c
  • Übersetzen
 gcc -o simple-server simple-server1.c
  • Installieren
 cp simple-server /usr/local/bin
  • Server starten, Testen, mit einem Web-Browser an Port 8080 verbinden
 simple-server &
  • SELinux Label des Dienstes anzeigen
 ps -eZ | grep simple
 ls -lZ /usr/local/bin/simple-server
  • SELinux Policy Modul erstellen
 mkdir ~/selinux-src
 cd ~/selinux-src
  • ein Basis SELinux Policy Modul erstellen
 sepolicy generate -n simple-server --init /usr/local/bin/simple-server
  • die erstellen Policy-Dateien anschauen
 less simple-server.te
 less simple-server.fc
 less simple-server.if
  • `.te` (type enforcing) legt die Regeln fest
  • `.fc` (file contexts) bestimmt die „Dateikontexte“ (Typen, die den auf diese Module bezogenen Dateien zugeordnet sind)
  • `.if` (interfaces) Schnittstelle der Module: Satz „öffentlicher Funktionen“, die andere Module verwenden können
  • `.spec` RPM Spec Datei fuer spaetere Pakete
  • `.sh` Helfer-Shellscript, das Regel-Kompilation, Installation und Label-fixes automatisiert
  • SELinux Policy compilieren und ein RPM-Paket erstellen
 yum -y install rpm-build
 sh simple-server.sh
 ls -l
  • neues Modul aktivieren
 semodule -i simple-server.pp
  • den vorher gestarteten simple-server Prozess stoppen
 pkill simple-server
  • eine SystemD Service-Unit für den Server Dienst erstellen
 $EDITOR /etc/systemd/system/simple-server.service
  • die Unit-Datei
 [Unit]
 Description=a simple http server
 After=syslog.target network.target

 [Service]
 ExecStart=/usr/local/bin/simple-server

 [Install]
 WantedBy=multi-user.target
  • neue Systemd-Service-Datei mit dem richtigen SELinux Label versehen
 restorecon -R -v /etc/systemd/system/simple-server.service
  • Systemd Service-Units neu laden und den Simple-Server starten
 systemctl daemon-reload
 systemctl start simple-server
 systemctl enable simple-server
  • Nun den Dienst benutzen. Das Modul ist noch im Permissive Mode, Verstösse gegen die Policy werden im Audit-Log protokolliert
 ausearch -m avc -ts recent -c simple-server
  • Erklärungen zu den Policy-Fehlermeldungen
 ausearch -m avc -ts today -c simple-server | audit2why  | less
  • Policy-Regeln aus den Audit-Meldungen erstellen
 sepolgen-ifgen
 ausearch -m avc -ts today -c simple-server | audit2allow -R
 require {
         type simple-server_t;
         class tcp_socket { bind create setopt accept listen };
 }

 #============= simple-server_t ==============
 allow simple-server_t self:tcp_socket { bind create setopt accept listen };
 corenet_tcp_bind_generic_node(simple-server_t)
 corenet_tcp_bind_http_cache_port(simple-server_t)
  • Neue Policy-Regeln in die Policy einfügen, Modul entfernen, neu kompilieren und dann neu laden
 semodule -r simple-server
 sh ./simple-server.sh
 semodule -i simple-server.pp
 systemctl restart simple-server

5.9.2 Eine Änderung an einer SELinux Policy

  • Unser Server lernt Logging. Den Inhalt in eine Datei simple-server.patch in das Verzeichnis mit dem Quellcode des simple-server speichern:
 --- simple-server1.c    2016-08-24 20:12:56.379000000 +0000
 +++ simple-server2.c    2016-08-24 21:13:31.648000000 +0000
 @@ -15,13 +15,20 @@
  "h1 { font-size:4cm; text-align: center; color: black;"
  " text-shadow: 0 0 2mm red}</style></head>"
    "<body><h1>Goodbye, world!</h1></body></html>\r\n";
 -
 +
  int main()
  {
    int one = 1, client_fd;
 +  FILE *f = fopen("/var/log/simple-server.log", "a");
 +  if (f == NULL)
 +  {
 +      printf("Error opening file!\n");
 +      exit(1);
 +  }
 +
    struct sockaddr_in svr_addr, cli_addr;
    socklen_t sin_len = sizeof(cli_addr);
 -
 +
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
      err(1, "can't open socket");
 @@ -41,7 +48,7 @@
    listen(sock, 5);
    while (1) {
      client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
 -    printf("got connection\n");
 +    fprintf(f,"got connection\n");
 +    fflush(f);

      if (client_fd == -1) {
        perror("Can't accept");
  • Patch einspielen
 patch -p1 < simple-server.patch
  • das gepatchte Programm:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <err.h>

char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html><html><head><title>Bye-bye baby bye-bye</title>"
"<style>body { background-color: #111 }"
"h1 { font-size:4cm; text-align: center; color: black;"
" text-shadow: 0 0 2mm red}</style></head>"
  "<body><h1>Goodbye, world!</h1></body></html>\r\n";

int main()
{
  int one = 1, client_fd;
  struct sockaddr_in svr_addr, cli_addr;
  socklen_t sin_len = sizeof(cli_addr);

  int sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0)
    err(1, "can't open socket");

  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
  int port = 8080;
  svr_addr.sin_family = AF_INET;
  svr_addr.sin_addr.s_addr = INADDR_ANY;
  svr_addr.sin_port = htons(port);

  if (bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
    close(sock);
    err(1, "Can't bind");
  }

  FILE *f = fopen("/var/log/simple-server.log", "a");
  if (f == NULL)
  {
      printf("Error opening file!\n");
      exit(1);
  }

  listen(sock, 5);
  while (1) {
    client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
    fprintf(f,"got connection\n");
    fflush(f);

    if (client_fd == -1) {
      perror("Can't accept");
      continue;
    }

    write(client_fd, response, sizeof(response) - 1); /*-1:'\0'*/
    shutdown(client_fd,2);
    close(client_fd);
  }
}
  • den neuen Server-Dienst übersetzen, alten simple-server stoppen, neue Programm-Datei nach /usr/local/bin kopieren, SELinux Label anpassen und den Dienst neu starten
 gcc -o simple-server simple-server2.c
 systemctl stop simple-server
 cp simple-server /usr/local/bin
 restorecon -R -v /usr/local/bin/simple-server
 systemctl start simple-server
  • per Web-Browser die Webseite auf http://localhost:8080/ aufrufen
  • neue SELinux Log-Meldungen tauchen auf
 # ausearch -m avc -ts recent
 ----
 time->Wed Aug 24 21:17:34 2016
 type=SYSCALL msg=audit(1472073454.717:1390): arch=c000003e syscall=2 success=yes exit=3 a0=400ae2 a1=441 a2=1b6 a3=21000 items=0 ppid=1 pid=7869 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="simple-server" exe="/usr/local/bin/simple-server" subj=system_u:system_r:simple-server_t:s0 key=(null)
 type=AVC msg=audit(1472073454.717:1390): avc:  denied  { open } for  pid=7869 comm="simple-server" path="/var/log/simple-server.log" dev="vda1" ino=268256 scontext=system_u:system_r:simple-server_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=file
 type=AVC msg=audit(1472073454.717:1390): avc:  denied  { create } for  pid=7869 comm="simple-server" name="simple-server.log" scontext=system_u:system_r:simple-server_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=file
 type=AVC msg=audit(1472073454.717:1390): avc:  denied  { add_name } for  pid=7869 comm="simple-server" name="simple-server.log" scontext=system_u:system_r:simple-server_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=dir
 type=AVC msg=audit(1472073454.717:1390): avc:  denied  { write } for  pid=7869 comm="simple-server" name="log" dev="vda1" ino=258603 scontext=system_u:system_r:simple-server_t:s0 tcontext=system_u:object_r:var_log_t:s0 tclass=dir
  • Policy-Erweiterung ausgeben, prüfen und in die Type-Enforcement-Datei simple-server.te einfügen:
 # ausearch -m avc -ts recent -c simple-server | audit2allow -R

 require {
         type var_log_t;
         type simple-server_t;
         class file { create open };
 }

 #============= simple-server_t ==============
 allow simple-server_t var_log_t:file { create open };
  • simple-server SELinux Modul entfernen, Policy neu übersetzen, Modul neu laden, testen
  • Solange die Policy anpassen, bis keine Permission-Meldungen im Audit-Log erscheinen
  • “Permissive” aus der finalen Policy herausnehmen
 # less simple-server.te
 policy_module(simple-server, 1.0.0)

 ########################################
 #
 # Declarations
 #

 type simple-server_t;
 type simple-server_exec_t;
 init_daemon_domain(simple-server_t, simple-server_exec_t)

 #permissive simple-server_t;

 ########################################
 #
 # simple-server local policy
 #
 require {
         type simple-server_t;
         type var_log_t;
         class tcp_socket { bind create setopt accept listen shutdown write };
         class file { create open write };
         class dir { write add_name };
 }

 allow simple-server_t self:fifo_file rw_fifo_file_perms;
 allow simple-server_t self:unix_stream_socket create_stream_socket_perms;
 allow simple-server_t self:tcp_socket { bind create setopt accept listen shutdown write };
 allow simple-server_t var_log_t:file { create open write };
 allow simple-server_t var_log_t:dir { write add_name };

 corenet_tcp_bind_generic_node(simple-server_t)
 corenet_tcp_bind_http_cache_port(simple-server_t)
 domain_use_interactive_fds(simple-server_t)
 logging_manage_generic_logs(simple-server_t)
 logging_rw_generic_log_dirs(simple-server_t)
  • simple-server SELinux Modul laden, simple-server Prozess per Systemd neu starten, Programm testen

5.10 DNSSEC DNS-Resolver

  • Installation des Unbound DNS-Resolvers und des DNS-Kommandozeilen Werkzeuge dig unter Debian
apt install unbound dnsutils
  • DNSSEC Auflösung und Validierung testen
dig @localhost dnssec.works a
  • DNSSEC Signaturen anzeigen (+dnssec) und Ausgabe auf 80-Zeichen formatieren (+multi)
dig @localhost dnssec.works a +dnssec +multi
  • DNSSEC defekte Domains geben den Status SERVFAIL zurück. SERVFAIL kann aber auch andere Gründe (Serverfehler, Konfigurationsfehler) haben
dig @localhost fail01.dnssec.works a +dnssec +multi
  • der Schalter +cd (Checking Disabled) setzt die DNSSEC Validierung des DNS-Resovlers für eine Anfrage ausser Kraft; die fehlerhaften Daten werden angezeigt
dig @localhost fail01.dnssec.works a +dnssec +multi +cd

6 Wunschthemen

6.1 sssd