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-
ssh
odersu <user>
Sitzungen eingegeben werden) - Sitzungsbeginn und -ende sollen protokolliert werden
bash
Am besten wäre eine einfache -basierte Lösung ohne Rootberechtigung (vielleicht einalias
- oderbash
-Wrapper-Skript für denssh
Befehl?)
- Protokolliert auch Befehle in verketteten Sitzungen (Befehle, die während Remote-
Mein Können:
- Ich bin kein Neuling in der Programmierung, lerne aber immer noch
bash
den „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)
screen
mit Scrollback-Dumping einmal pro Sekunde unddiff
dazwischen, 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.log
dem 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 expect
und 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
uptime
Befehl) 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:
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.
Verkettete Sitzungen (mit
ssh
odersu
Befehlen auf der Remote-Seite) führen dazu, dass beim Scrollen im Verlauf die gescrollten Befehle anstelle der tatsächlich verwendeten Befehle aufgezeichnet werdenDie 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 -v
vor 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.
- Ich schummele, indem ich nicht druckbare Zeichen
Keine Bash-Vervollständigung des SSH-Befehls, beispielsweise für den Hostnamen.Sie können die Bash-Vervollständigung erhalten, wenn Sie dieses Skriptssh
mitalias 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
, awk
usw.
-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