Lokale, mit Zeitstempel versehene Protokollierung aller SSH-Befehle?

Lokale, mit Zeitstempel versehene Protokollierung aller SSH-Befehle?

Wie kann ich eine lokale, mit Zeitstempel versehene Aufzeichnung aller Remote-Befehle führen, die ich verwende ssh(über die Befehlszeile gestarteter OpenSSH-Client bash)?

Anforderungen:

  • Essentiell:

    • 100 % clientseitig, ohne auf Serverprotokollierung angewiesen zu sein
    • Pro Benutzer konfiguriert oder installiert, wobei die Protokolle im Stammverzeichnis des Benutzers gespeichert werden.
    • Unterstützung für die Unterscheidung zwischen mehreren gleichzeitigen Sitzungen mit verschiedenen Benutzern und Hosts.
    • Nicht aufdringlich (muss nicht jedes Mal aktiviert werden und beeinträchtigt die Verwendung von SSH nicht wesentlich)
  • Hohe Priorität:

    • Entweder wird die Ausgabe nicht protokolliert oder so weit wie möglich herausgefiltert
    • Entweder werden Passworteingaben nicht protokolliert oder die Datei ist verschlüsselt
    • Zeigt die tatsächlich verwendeten Befehle an (nachdem Tabulator/Verlaufsvervollständigung, Rücktaste, CTRL+ Cusw. verarbeitet wurden)
  • Schön zu haben:

    • Protokolliert auch Befehle in verketteten Sitzungen (Befehle, die während Remote- sshoder su <user>Sitzungen eingegeben werden)
    • Sitzungsbeginn und -ende sollen protokolliert werden
    • bashAm besten wäre eine einfache -basierte Lösung ohne Rootberechtigung (vielleicht ein alias- oder bash-Wrapper-Skript für den sshBefehl?)

Mein Können:

  • Ich bin kein Neuling in der Programmierung, lerne aber immer noch bashden „Linux-Weg“, daher wären Codebeispiele mit kurzen Erklärungen sehr willkommen.

Mögliche Strategien

  • Keylogger-- Problem: Passwörter werden protokolliert, Tab-/Verlaufsvervollständigung jedoch nicht (sieheGlenns Antwort)
  • screenmit Scrollback-Dumping einmal pro Sekunde und diffdazwischen, um neue Scrollback-Zeilen zu finden– Problem: Wie kann dies auf sinnvolle automatisierte Weise implementiert werden?
  • ssh "$@" | tee >(some_cleaner_function >> $logfile)- Problem: Mehrzeilige Befehle oder Verlauf können in verketteten Sitzungen nicht verarbeitet werden, sorgfältige Bereinigung erforderlich (siehe meine Antwort)
  • Eine Kombination einiger der oben genannten

Ein Beispiel

Die folgende SSH-Sitzung:

user@local:~$ ssh user@remote
Last login: Tue Jun 17 16:34:23 2014 from local
user@remote:~$ cd test
user@remote:~/test$ ls
a  b
user@remote:~/test$ exit

Dies könnte zu einem Protokoll wie ~/logs/ssh.logdem folgenden führen:

2014-06-17 16:34:50   [user@remote - start]
2014-06-17 16:34:51   [user@remote] cd test
2014-06-17 16:34:52   [user@remote] ls
2014-06-17 16:34:53   [user@remote] exit
2014-06-17 16:34:53   [user@remote - end]

Oder es wird für jede Sitzung ein separates Protokoll erstellt, wobei die zum Starten der Sitzung verwendete Befehlszeile am Anfang der Datei steht.

Antwort1

Ihre Frage hat mich fasziniert. Ursprünglich wollte ich keine Antwort darauf geben, aber dann hat es mich gepackt.

Dies verwendet expectund ist wirklich ein Keylogger.

#!/usr/bin/expect -f

proc log {msg} {
    puts $::fh "[timestamp -format {%Y-%m-%d %H:%M:%S}]: $msg"
}

set ssh_host [lindex $argv 0]
set ::fh [open "sshlog.$ssh_host" a]

log "{session starts}"

spawn ssh $ssh_host

interact {
    -re "(.)" {
        set char $interact_out(1,string)
        if {$char eq "\r"} {
            log $keystrokes
            set keystrokes ""
        } else {
            append keystrokes $char
        }
        send -- $char
    }
    eof
}

log "{session ends}"

Anmerkungen:

  • es wird an eine Datei mit dem SSH-Ziel im Namen angehängt
  • es handelt sich um einen Keylogger: wenn Sie keine SSH-Schlüssel eingerichtet haben, erhalten Sie das Passwort des Benutzers in der Protokolldatei
  • Dies wird durch die Tab-Vervollständigung verhindert: Wenn der Benutzer uptTab(für den uptimeBefehl) eingibt, wird in der Protokolldatei „upt\t“ angezeigt, nicht „uptime“.
  • ^?Es erfasst Zeichen im „Rohdaten“-Modus: Wenn der Benutzer schlecht tippt, werden in der Protokolldatei viele (Backspace-Zeichen) angezeigt .

Antwort2

Ich verwende derzeit das unten stehende Bash-Skript. Es hat viele Probleme, ist aber die einzige Lösung, die ich gefunden habe und die alle Anforderungen, Prioritäten und „Nice-to-haves“ (zumindest meistens) berücksichtigt.

Diese Antworterläutert, warum das lokale Protokollieren von SSH-Sitzungen so schwierig ist.

Bisher gefundene Probleme mit dem Skript:

  1. Mehrzeilige Befehle verursachen Probleme:

    • Wenn Sie durch ein mehrzeiliges Element im Remote-Verlauf blättern (mit den Auf-/Ab-Tasten), wird anstelle des letzten Befehls ein Verlaufselement protokolliert. Sie können dies vermeiden, indem SieLöschen aus dem Bash-Verlaufalle mehrzeiligen Befehle unmittelbar nach ihrer Verwendung.
    • Bei mehrzeiligen Befehlen wird nur die erste Zeile protokolliert.
  2. Verkettete Sitzungen (mit sshoder suBefehlen auf der Remote-Seite) führen dazu, dass beim Scrollen im Verlauf die gescrollten Befehle anstelle der tatsächlich verwendeten Befehle aufgezeichnet werden

  3. Die regulären Ausdrücke können verbessert werden und müssen möglicherweise für bestimmte Umgebungen geändert werden:

    • Ich schummele, indem ich nicht druckbare Zeichen cat -vvor dem Bereinigen mit konvertiere. Infolgedessen kann gültiger Inhalt entfernt werden, wenn Sie jemals Zeichenfolgen wie ^[[in Ihren Befehlen verwenden.
    • Manchmal erhalten Sie vor dem Befehl zusätzliche protokollierte Eingaben, z. B. wenn Sie sehr schnell durch den Verlauf blättern. Darauf folgt im Allgemeinen ein „^M“ vor dem eigentlichen Befehl und kann daher bei Bedarf entfernt werden.
    • Manchmal kommen auch andere Steuerzeichen vor. Ich lasse sie alle vorerst drin, bis ich weiß, welche ich sicher entfernen kann. ^M ist, wie ich gerade erwähnt habe, nützlich, um ungültige protokollierte Eingaben zu erkennen, und ^C würde Ihnen sagen, ob der Befehl abgebrochen wurde.
    • Der reguläre Ausdruck für die Eingabeaufforderung muss möglicherweise für bestimmte Eingabeaufforderungen geändert werden, und ich könnte mir vorstellen, dass unterschiedliche Remote-Umgebungen unterschiedliche Steuerzeichenmuster haben.
  4. Keine Bash-Vervollständigung des SSH-Befehls, beispielsweise für den Hostnamen. Sie können die Bash-Vervollständigung erhalten, wenn Sie dieses Skript sshmitalias ssh="sshlog"

Skriptquelle und Installation:

Zur Installation fügen Sie Folgendes in ~/bin/sshlog ein und machen es ausführbar. Rufen Sie es mit auf sshlog <ssh command options>. Optional können Sie in der .bashrc-Datei des Benutzers einen Alias ​​für „ssh“ erstellen.

#!/bin/bash
# A wrapper for the ssh command that produces a timestamped log of all ssh commands
declare -r logfile=~/logs/ssh.log
declare -r description="sshlog-${$} ${@}"
declare -r TAB=$'\t'

logdir=`dirname ${logfile}`
[ -d ${logdir} ] || mkdir "${logdir}";

clean_control_chars() {
    while IFS= read -r line; do
        # remove KNOWN control characters. Leave the rest for now.
        # line=$(echo "${line}" | sed 's/\^\[\[K//g')  # unkown control character: ^[[K
        # line=$(echo "${line}" | sed 's/\^\[\[[0-9]\+[P]//g')  # these are generated by up/down completion - e.g. ^[[2P
        line=$(echo "${line}" | sed 's/\^\[\[[0-9]*[A-Z]//g')  # all other ^[[..
        # replay character deletions (backspaces)
        while [[ $(echo "${line}" | grep -E --color=never '.\^H') != "" ]]; do
            line=$(echo "${line}" | sed 's/.\^H//')
        done
        # remove common control characters
        line=$(echo "${line}" | sed 's/\^M$//')  # remove end of line marker from end
        line=$(echo "${line}" | sed 's/^\^G//g')  # remove start marker from start
        # remove ^G from other locations - possibly a good idea
        # line=$(echo "${line}" | sed 's/\^G//g')
        # remove all other control characters - not recommended (many like ^C and ^M indicate which section was processed/ ignored)
        # line=$(echo "${line}" | sed 's/\^[A-Z]//g')
        echo ${line};
    done
}

filter_output() {
    while IFS= read -r line; do
        # convert nonprinting characters and filter out non-prompt (in Ubuntu 14.04 tests, ^G indicates prompt start)
        line=$(echo "${line}" | cat -v | grep -Eo '[\^][G].*[\$#].*')
        [[ ${line} != "" ]] && echo "${line}"
    done
}

format_line() {
    while IFS= read -r line; do
        raw=${line};
        line=$(echo "${line}" | clean_control_chars);
        prompt=$(echo "${line}" | grep -Po '^.*?(\$|#)[\s]*')
        command=${line:${#prompt}}
        timestamp=`date +"%Y-%m-%d %H:%M:%S %z"`
        echo -e "${timestamp}${TAB}${description}${TAB}${prompt}${TAB}${command}"
    done
}

echo "Logging ssh session: ${description}"
echo "[START]" | format_line >> ${logfile}
/usr/bin/ssh "$@" | tee >(filter_output | format_line >> ${logfile})
echo "[END]" | format_line >> ${logfile}

Beispiel für Protokollinhalt:

2014-06-29 23:04:06 -0700   sshlog-24176 remote [START]
2014-06-29 23:04:12 -0700   sshlog-24176 remote oleg@remote:~$  cd test
2014-06-29 23:04:13 -0700   sshlog-24176 remote oleg@remote:~/test$     ls
2014-06-29 23:04:14 -0700   sshlog-24176 remote oleg@remote:~/test$     exit
2014-06-29 23:04:14 -0700   sshlog-24176 remote [END]

Antwort3

Wie wäre es mit strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd)? Dadurch werden alle SSH-Sitzungen protokolliert. Möglicherweise benötigen Sie ein Tool, um das Protokoll anschließend zu analysieren, oder verwenden Sie einfach grep, awkusw.

  • -f: Verfolgen von gegabelten Kindern
  • -ff: Melden Sie jedes Kind einzeln an, umssh_log.PID
  • -s8192: Erhöhen Sie das Limit für die Zeichenfolgenprotokollierung (falls erforderlich).
  • -T -ttt: Mikrosekunden-Stempelung in Sekunden seit der Epoche
  • -p N: an PID anhängenN

Antwort4

Ich habe eine weniger komplizierte Antwort und sicher keinen Keylogger. Ich verstehe Ihren Punkt mit der Serverprotokollunabhängigkeit nicht (das bedeutet, dass alle Aktionen auf dem Server ausgeführt werden müssen und alle Protokolle serverseitige Protokolle sind), und deshalb dachte ich, dass es eine gute Idee wäre, an die systemweite Bashrc einen Eingabeaufforderungsbefehl wie diesen zu übergeben:


PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -t "$USER[$$] $SSH_CONNECTION")'

Unter Debian sollten Sie die Datei /etc/bash.bashrc bearbeiten und unter CentOS die Datei /etc/bashrc

Wenn Sie mit der Protokollierung für die aktuelle Sitzung beginnen möchten, müssen Sie die von Ihnen bearbeitete Datei als Quelle verwenden. Führen Sie dazu beispielsweise Folgendes aus:


source /etc/bash.bashrc

in einem Debian-System oder


source /etc/bashrc
in einem CentOS-System.

Ab sofort wird jeder Befehl jeder SSH-Sitzung protokolliert unter/var/log/syslogauf einem Debian-System und bei/var/log/Nachrichtenauf einem CentOS-System.

Falls Sie sie in einer separaten Datei protokollieren und nicht mit anderen Protokolldateien durcheinanderbringen möchten, können Sie Folgendes verwenden:


PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p local6.info -t "$USER[$$] $SSH_CONNECTION")'
anstelle des vorherigen PROMPT_COMMAND-Beispiels und konfigurieren Sie dann rsyslogd nach Bedarf.

Bearbeiten Sie beispielsweise auf einem Debian-System die/etc/rsyslog.confDatei: ändern Sie die Zeile:


.;auth,authpriv.none           -/var/log/syslog
Zu

.;auth,authpriv.none,local6           -/var/log/syslog
und fügen Sie am Ende der Datei die folgende Zeile hinzu:

local6.info                     /var/log/history.log

dann ausführen:

touch /var/log/history.log && /etc/init.d/rsyslog restart

verwandte Informationen