Lokalne rejestrowanie wszystkich poleceń ssh ze znacznikiem czasu?

13

Jak mogę przechowywać lokalny, opatrzony znacznikiem czasu rejestr wszystkich zdalnych poleceń, z których korzystam ssh(uruchomiono klienta openssh z wiersza poleceń bash)?

Wymagania:

  • Kluczowy:

    • 100% po stronie klienta, bez polegania na logowaniu na serwerze
    • Skonfigurowany lub zainstalowany na użytkownika z dziennikami przechowywanymi w katalogu osobistym użytkownika.
    • Obsługa rozróżniania wielu sesji jednocześnie z różnymi użytkownikami i hostami.
    • Nieinwazyjne (nie trzeba go aktywować za każdym razem i nie koliduje znacząco z używaniem ssh)
  • Wysoki priorytet:

    • Każde wyjście nie jest rejestrowane ani filtrowane w jak największym stopniu
    • Wpisy hasła nie są rejestrowane lub plik jest szyfrowany
    • Wskazuje używane polecenia (po przetworzeniu tabulacji / historii, spacje, CTRL+ Citd.)
  • Miło jest mieć:

    • Rejestruje również polecenia w połączonych sesjach (polecenia wprowadzone podczas sesji zdalnej sshlub su <user>sesji)
    • Początek i koniec sesji powinny być rejestrowane
    • Prosty bash-na, rozwiązanie niż root byłoby najlepsze (być może aliaslub bashwrapper script do sshpolecenia?)

Mój poziom umiejętności:

  • Nie jestem nowy w programowaniu, ale nadal uczę się bashi „Linux”, więc próbki kodu z krótkimi objaśnieniami byłyby bardzo mile widziane.

Możliwe strategie

  • keylogger - Problem: rejestruje hasła, nie rejestruje zakończenia karty / historii (patrz odpowiedź Glenna )
  • screenze zrzutem przewijania raz na sekundę i diffmiędzy nimi, aby znaleźć nowe linie przewijania - Problem: jak można to zaimplementować w przydatny zautomatyzowany sposób?
  • ssh "$@" | tee >(some_cleaner_function >> $logfile) - Problem: nie można obsłużyć wieloliniowych poleceń ani historii w połączonych sesjach, konieczne jest staranne czyszczenie (patrz moja odpowiedź)
  • Połączenie niektórych z powyższych

Przykład

Następująca sesja SSH:

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

Może to prowadzić do dziennika ~/logs/ssh.logtakiego jak:

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]

Lub być może zostanie utworzony osobny dziennik dla każdej sesji z wierszem poleceń używanym do rozpoczęcia sesji na górze pliku.

Oleg
źródło
Powinien także obsługiwać edytory takie jak nano lub vim
daisy

Odpowiedzi:

5

Zaintrygowało mnie twoje pytanie. Początkowo nie zamierzałem udzielać odpowiedzi, ale mnie uzależniło.

Wykorzystuje expectto i jest naprawdę kluczowym rejestratorem.

#!/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}"

Uwagi:

  • dołącza się do pliku z miejscem docelowym ssh w nazwie
  • jest to rejestrator kluczy: jeśli nie skonfigurowałeś kluczy ssh, w pliku dziennika pojawi się hasło użytkownika
  • jest to udaremniane przez uzupełnienie tabulacji: jeśli użytkownik wpisze uptTab(dla uptimepolecenia), w pliku dziennika pojawi się „upt \ t”, a nie „uptime”
  • chwyta znaki w trybie „surowym”: jeśli użytkownik jest złym typistą, ^?w pliku dziennika pojawi się wiele znaków (backspace).
Glenn Jackman
źródło
Bardzo dziękuję za odpowiedź. Interesujące jest to, że wydaje się, że nie ma na to łatwej odpowiedzi, być może rodzimej dla klienta ssh. Dziękujemy za wyjaśnienie ograniczeń; Wydaje mi się, że uzupełnianie tabulatorów / rejestrowanie znaków backspace / logowanie hasłem są wystarczające, aby uniemożliwić mi to częste używanie. Zmusił mnie również do zastanowienia się nad moimi priorytetami i wyjaśnię te pytania.
Oleg
Dane wyjściowe z odrodzonego procesu można przeanalizować w celu wyodrębnienia żądanego polecenia. Aby ułatwić, musisz znać monit użytkownika.
glenn jackman
Często używam uzupełniania tabulatorów. Czy to nie znaczy, że te polecenia nie będą rejestrowane?
Oleg
Ach, rozumiem co mówisz. Jak parsowane byłyby dane wyjściowe? Monit można wprowadzić gdzieś jako opcję konfiguracji.
Oleg
Dodałem listę możliwych rozwiązań na dole pytania. ssh ... | tee -ai <plik dziennika> działa dobrze, aby bezpiecznie rejestrować dane wejściowe i wyjściowe, ale nie wiem, jak dodać znaczniki czasu i / lub odfiltrować dane wyjściowe w tle.
Oleg
3

Obecnie używam poniższego skryptu bash. Ma wiele problemów, ale jest to jedyne znalezione przeze mnie rozwiązanie, które spełnia wszystkie wymagania, priorytety i „miło jest mieć” (przynajmniej przez większość czasu).

Ta odpowiedź wyjaśnia, dlaczego lokalne rejestrowanie sesji ssh jest tak trudne.

Problemy ze skryptem, które znalazłem do tej pory:

  1. Polecenia wielowierszowe powodują problemy:

    • Jeśli przejrzysz element wielowierszowy w zdalnej historii (za pomocą klawiszy góra / dół), zarejestruje on element historii zamiast najnowszego polecenia. Można tego uniknąć, usuwając z historii bash wszelkie polecenia wieloliniowe natychmiast po ich użyciu.
    • Rejestrowany jest tylko pierwszy wiersz poleceń wielowierszowych.
  2. Połączone sesje (używanie sshlub supolecenia na zdalnym końcu) powodują przewijanie historii w celu rejestrowania przewijanych poleceń zamiast rzeczywistych używanych poleceń

  3. Wyrażenia regularne można ulepszyć i może wymagać modyfikacji w niektórych środowiskach:

    • Oszukuję, konwertując znaki niedrukowalne cat -vprzed czyszczeniem. W rezultacie ważna treść może zostać usunięta, jeśli kiedykolwiek użyjesz ciągów znaków jak ^[[w swoich poleceniach.
    • Czasami dostajesz dodatkowe zarejestrowane dane przed poleceniem, na przykład jeśli przeglądasz historię bardzo szybko. Zazwyczaj po rzeczywistym poleceniu występuje „^ M”, dlatego można go w razie potrzeby usunąć.
    • Czasami pojawiają się inne znaki kontrolne. Na razie zostawiam je wszystkie, dopóki nie będę wiedział, które można bezpiecznie usunąć. ^ M, jak już wspomniałem, jest przydatne do wykrywania nieprawidłowych zalogowanych danych wejściowych, a ^ C powie ci, czy polecenie zostało przerwane.
    • Wyrażenie regularne może wymagać modyfikacji dla poszczególnych podpowiedzi. Mogę sobie wyobrazić, że różne środowiska zdalne mogą mieć różne wzorce znaków kontrolnych.
  4. Brak sashowania komendy ssh, na przykład dla nazwy hosta. Można uzyskać zakończenia bash jeśli alias ten skrypt sshzalias ssh="sshlog"

Źródło i instalacja skryptu:

Aby zainstalować, wklej następujące elementy do ~ / bin / sshlog i uczyń plik wykonywalny. Zadzwoń z sshlog <ssh command options>. Opcjonalnie alias do „ssh” w pliku .bashrc użytkownika.

#!/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}

Przykładowa zawartość dziennika:

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
źródło
0

Mam mniej skomplikowaną odpowiedź, a na pewno nie keylogger. Nie rozumiem, że jesteś niezależny od dziennika serwera (oznacza to, że wszystkie działania muszą być podjęte na serwerze, a wszystkie dzienniki są dziennikami po stronie serwera), dlatego pomyślałem, że dobrym pomysłem jest przejście do całego systemu bashrc polecenie zachęty, takie jak:


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

W Debianie powinieneś edytować plik: /etc/bash.bashrc, aw centos plik: / etc / bashrc

Jeśli chcesz zacząć rejestrować sesję, w której jesteś, musisz źródłowy plik, który edytowałeś, na przykład wykonaj:


source /etc/bash.bashrc

w systemie debian lub


source /etc/bashrc
w systemie centos.

Odtąd każde polecenie każdej sesji ssh będzie rejestrowane w / var / log / syslog w systemie debian, a w / var / log / messages w systemie centos.

Jeśli chcesz zapisać je w osobnym pliku i nie zadzierać z innymi plikami dziennika, których możesz użyć:


PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p local6.info -t "$USER[$$] $SSH_CONNECTION")'
zamiast poprzedniego przykładu PROMPT_COMMAND, a następnie odpowiednio skonfiguruj rsyslogd.

Na przykład w systemie Debian edytuj plik /etc/rsyslog.conf : zmień wiersz:


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

.;auth,authpriv.none,local6           -/var/log/syslog
i dodaj następujący wiersz na końcu pliku:

local6.info                     /var/log/history.log

następnie wykonaj:

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

strimpak
źródło
To pytanie dotyczy w szczególności problemu rejestrowania sesji ssh po stronie komputera inicjującego / lokalnego / klienckiego, bez konieczności (pamiętania / zezwolenia) na konfigurację każdego zdalnego serwera lub ręcznego pobierania dzienników ze wszystkich podłączonych serwerów zdalnych do. Myślę, że twoja odpowiedź, choć nie odpowiada na to pytanie, byłaby przydatna dla kogoś, kto jest zainteresowany poprawą audytu swojego serwera i być może powinien zostać przeniesiony na bardziej odpowiednie pytanie.
Oleg
0

Jak o strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd)? To rejestruje wszystkie sesje ssh. Może trzeba narzędzie do analizowania dziennika następnie, lub po prostu użyć grep, awketc.

  • -f: śledzić rozwidlone dzieci
  • -ff: zaloguj każde dziecko osobno do ssh_log.PID
  • -s8192: zwiększ limit rejestrowania ciągu (w razie potrzeby)
  • -T -ttt: mikrosekundowe tłoczenie w ciągu kilku sekund od Epoki
  • -p N: dołącz do pid N
Anul
źródło