Lokale, zeitgestempelte Protokollierung aller ssh-Befehle?

11

Wie kann ich eine lokale Aufzeichnung mit Zeitstempel aller Remote-Befehle führen, die ich verwende ssh(Befehlszeilen-OpenSSh-Client wurde über gestartet bash)?

Bedarf:

  • Wesentlich:

    • 100% clientseitig ohne Serverprotokollierung
    • Konfiguriert oder installiert pro Benutzer mit Protokollen, die im Home-Verzeichnis des Benutzers gespeichert sind.
    • 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 so weit wie möglich protokolliert oder herausgefiltert
    • Entweder werden Passworteinträge nicht protokolliert oder die Datei wird verschlüsselt
    • Zeigt die tatsächlich verwendeten Befehle an (nachdem Tab / Verlauf abgeschlossen wurde, wurden Backspaces, CTRL+ Cusw. verarbeitet).
  • Schön zu haben:

    • Protokolliert auch Befehle in verketteten Sitzungen (Befehle, die während der Remote- Sitzung sshoder in su <user>Sitzungen eingegeben wurden ).
    • Sitzungsstart und -ende sollten protokolliert werden
    • Eine einfache bash, nicht root-basierte Lösung wäre am besten (vielleicht ein aliasoder ein bashWrapper-Skript für den sshBefehl?)

Mein Können:

  • Ich bin nicht neu in der Programmierung, lerne aber noch bashund die "Linux-Methode", daher wären Codebeispiele mit kurzen Erklärungen sehr willkommen.

Mögliche Strategien

  • Keylogger - Problem: Protokolliert Passwörter, protokolliert keine Registerkarte / Verlaufsvervollständigung (siehe Glenns Antwort )
  • screenmit Scrollback-Dumping einmal pro Sekunde und diffdazwischen, um neue Scrollback-Zeilen zu finden - Problem: Wie kann dies auf nützliche automatisierte Weise implementiert werden?
  • ssh "$@" | tee >(some_cleaner_function >> $logfile) - Problem: Kann nicht mit mehrzeiligen Befehlen oder Verlauf in verketteten Sitzungen umgehen, 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

Könnte zu einem Protokoll führen ~/logs/ssh.logwie:

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 möglicherweise für jede Sitzung ein separates Protokoll mit der Befehlszeile erstellt, mit der die Sitzung oben in der Datei gestartet wird.

Oleg
quelle
Es sollte auch Editoren wie Nano oder Vim
Daisy

Antworten:

4

Ihre Frage hat mich fasziniert. Ich wollte ursprünglich keine Antwort geben, aber ich war süchtig.

Dies verwendet expectund es ist wirklich ein Key Logger.

#!/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 ist ein Schlüsselprotokollierer: Wenn Sie keine SSH-Schlüssel eingerichtet haben, erhalten Sie das Kennwort des Benutzers in der Protokolldatei
  • Es wird durch die Vervollständigung der Registerkarte vereitelt: Wenn der Benutzer uptTab(für den uptimeBefehl) eingibt, wird in der Protokolldatei "upp \ t" angezeigt, nicht "uptime".
  • Es erfasst Zeichen im "rohen" Modus: Wenn der Benutzer ein schlechter Typist ist, werden viele ^?(Rücktaste-) Zeichen in der Protokolldatei angezeigt.
Glenn Jackman
quelle
Ich danke Ihnen sehr für Ihre Antwort. Es ist interessant, dass es keine einfache Antwort darauf zu geben scheint, die vielleicht dem SSH-Client eigen ist. Vielen Dank, dass Sie die Einschränkungen erklärt haben. Ich denke, Tab-Vervollständigung / Backspace-Zeichenprotokollierung / Passwortprotokollierung sind genug, um mich daran zu hindern, dies häufig zu verwenden. Es hat mich auch dazu gebracht, mehr über meine Prioritäten nachzudenken, und ich werde diese in der Frage klären.
Oleg
Die Ausgabe des erzeugten Prozesses kann analysiert werden, um den gewünschten Befehl zu extrahieren. Sie müssen die Eingabeaufforderung des Benutzers kennen, um dies zu vereinfachen.
Glenn Jackman
Ich benutze viel Tab-Vervollständigung. Bedeutet dies nicht, dass diese Befehle nicht protokolliert werden?
Oleg
Ah, ich verstehe, was du sagst. Wie würde die Ausgabe analysiert werden? Die Eingabeaufforderung kann irgendwo als Konfigurationsoption eingegeben werden.
Oleg
Ich habe die Liste der möglichen Lösungen am Ende der Frage hinzugefügt. ssh ... | tee -ai <logfile> funktioniert gut, um Ein- und Ausgaben sicher zu protokollieren, aber ich weiß nicht, wie man Zeitstempel hinzufügt und / oder Ausgaben im Hintergrund herausfiltert.
Oleg
2

Ich verwende derzeit das unten stehende Bash-Skript. Es hat viele Probleme, aber es ist die einzige Lösung, die ich gefunden habe und die alle Anforderungen, Prioritäten und "nice to haves" (zumindest die meiste Zeit) erfüllt.

In dieser Antwort wird erläutert, warum das lokale Protokollieren von SSH-Sitzungen so schwierig ist.

Probleme mit dem Skript, die ich bisher gefunden habe:

  1. Mehrzeilige Befehle verursachen Probleme:

    • Wenn Sie durch ein mehrzeiliges Element im Remote-Verlauf blättern (mit Auf- / Ab-Tasten), wird anstelle des neuesten Befehls ein Verlaufselement protokolliert. Sie können dies vermeiden, indem Sie alle mehrzeiligen Befehle unmittelbar nach ihrer Verwendung aus dem Bash-Verlauf löschen .
    • Es wird nur die erste Zeile mehrzeiliger Befehle protokolliert.
  2. Verkettete Sitzungen (Verwenden von sshoder suBefehle am Remote-Ende) führen dazu, dass beim Scrollen des Verlaufs anstelle der tatsächlich verwendeten Befehle gescrollte 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 betrüge, indem ich cat -vvor dem Reinigen nicht druckbare Zeichen 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. Diesem folgt im Allgemeinen ein "^ M" vor dem eigentlichen Befehl und kann daher auf Wunsch entfernt werden.
    • Manchmal treten andere Steuerzeichen auf. Ich lasse sie alle erst einmal, bis ich weiß, welche sicher zu entfernen sind. ^ M ist, wie ich gerade erwähnte, nützlich, um ungültige protokollierte Eingaben zu erkennen, und ^ C würde Ihnen mitteilen, ob der Befehl abgebrochen wurde.
    • Die Eingabeaufforderung muss möglicherweise für bestimmte Eingabeaufforderungen geändert werden, und ich könnte mir vorstellen, dass verschiedene Remote-Umgebungen unterschiedliche Steuerzeichenmuster aufweisen.
  4. Kein Bash-Abschluss des SSH-Befehls, z. B. für den Hostnamen. Sie können bash Abschluss erhalten , wenn Sie dieses Skript Alias sshmitalias ssh="sshlog"

Skriptquelle und Installation:

Fügen Sie zur Installation Folgendes in ~ / bin / sshlog ein und machen Sie es ausführbar. Rufen Sie an mit sshlog <ssh command options>. Optional Alias ​​'ssh' in der .bashrc-Datei des Benutzers.

#!/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 einen 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]
Oleg
quelle
0

Ich habe eine weniger komplizierte Antwort und sicherlich keinen Keylogger. Ich verstehe nicht, dass Sie vom Serverprotokoll unabhängig sind (dies bedeutet, dass alle Aktionen auf dem Server ausgeführt werden müssen und alle Protokolle serverseitige Protokolle sind), und daher dachte ich, dass eine gute Idee darin besteht, an systemweites bashrc zu übergeben ein Eingabeaufforderungsbefehl wie:


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

In Debian sollten Sie die Datei: /etc/bash.bashrc und in Centos die Datei / etc / bashrc bearbeiten

Wenn Sie mit der Protokollierung für die Sitzung beginnen möchten, in der Sie sich befinden, müssen Sie die von Ihnen bearbeitete Datei als Quelle angeben, z. B. ausführen:


source /etc/bash.bashrc

in einem Debian-System oder


source /etc/bashrc
in einem Centos-System.

Von nun an wird jeder Befehl jeder SSH-Sitzung unter / var / log / syslog auf einem Debian-System und unter / var / log / messages auf einem Centos-System protokolliert.

Wenn Sie sie in einer separaten Datei protokollieren und nicht mit anderen Protokolldateien verwechseln 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 konfigurieren Sie dann das rsyslogd nach Bedarf.

Bearbeiten Sie beispielsweise in einem Debian-System die Datei /etc/rsyslog.conf : Ändern Sie die Zeile:


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

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

local6.info                     /var/log/history.log

dann ausführen:

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

Strimpak
quelle
Diese Frage bezieht sich speziell auf das Problem der Protokollierung von SSH-Sitzungen auf der Seite des initiierenden / lokalen / Client-Computers, ohne dass jeder Remote-Server konfiguriert (gespeichert / zugelassen) werden muss oder die Protokolle manuell von allen Remote-Servern heruntergeladen werden müssen, die Sie verbinden zu. Ich denke, Ihre Antwort beantwortet diese Frage zwar nicht, wäre jedoch für jemanden nützlich, der daran interessiert ist, die Überwachung seines Servers zu verbessern, und sollte möglicherweise auf eine relevantere Frage verschoben werden.
Oleg
0

Wie wäre es strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd)? Dies protokolliert alle SSH-Sitzungen. Sie können ein Werkzeug benötigen , das Protokoll anschließend, oder einfach nur Gebrauch zu analysieren grep, awkusw.

  • -f: Spur gegabelte Kinder
  • -ff: Melden Sie jedes Kind separat an ssh_log.PID
  • -s8192: Erhöhen Sie das String-Protokollierungslimit (falls erforderlich).
  • -T -ttt: Mikrosekundenstempelung in Sekunden seit der Epoche
  • -p N: an pid anhängen N
Anul
quelle