모든 SSH 명령의 로컬 타임스탬프 로깅?

모든 SSH 명령의 로컬 타임스탬프 로깅?

에서 사용하는 모든 원격 명령 ssh(을 통해 시작된 명령줄 openssh 클라이언트 )의 로컬 타임스탬프 기록을 어떻게 유지합니까 ?bash

필요하다:

  • 기초적인:

    • 100% 클라이언트 측, 서버 로깅에 의존하지 않음
    • 사용자가 구성하거나 설치하면 로그는 사용자의 홈 디렉터리에 저장됩니다.
    • 서로 다른 사용자 및 호스트와의 여러 동시 세션 구별을 지원합니다.
    • 비침해적(매번 활성화할 필요가 없으며 SSH 사용을 크게 방해하지 않음)
  • 높은 우선순위:

    • 출력을 기록하지 않거나 가능하면 출력을 필터링하십시오.
    • 비밀번호 항목이 기록되지 않았거나 파일이 암호화되었습니다.
    • 실제 사용된 명령을 나타냅니다(탭/기록 완료, 백스페이스, CTRL+ C등...이 처리되었습니다).
  • 가져서 좋다:

    • 또한 연결된 세션의 명령을 기록합니다( 원격으로 ssh또는 세션 중에 su <user>입력된 명령 ).
    • 세션 시작 및 종료가 기록되어야 합니다.
    • 루트가 아닌 간단한 bash기반 솔루션이 가장 좋습니다(명령 기반 alias또는 bash래퍼 스크립트 일 수도 있음 ssh).

내 기술 수준:

  • 저는 프로그래밍이 처음이 아니지만 여전히 bash"Linux 방식"을 배우고 있으므로 간략한 설명이 포함된 코드 예제를 주시면 감사하겠습니다.

가능한 전략

  • 키로거-- 문제: 탭/기록 완료가 아닌 비밀번호 로깅(참조글렌의 대답)
  • screen매초마다 롤백하고 diff그 사이에 새로운 롤백 행을 찾습니다.-- 질문: 유용하고 자동화된 방식으로 이를 달성하려면 어떻게 해야 합니까?
  • ssh "$@" | tee >(some_cleaner_function >> $logfile)-- 문제: 연결된 세션에서 여러 줄 명령이나 기록을 처리할 수 없으며 주의 깊게 정리해야 합니다(내 답변 참조).
  • 위의 내용 중 일부를 조합한 것

한 가지 예

다음 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

~/logs/ssh.log다음 로그가 생성될 수 있습니다.

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]

또는 파일 상단에서 세션을 시작하는 데 사용되는 명령줄을 사용하여 각 세션에 대해 별도의 로그를 생성할 수 있습니다.

답변1

나는 당신의 질문에 매우 관심이 있습니다. 대답을 안 하려고 했는데 푹 빠졌어요.

이것은 expect실제로 키로거입니다.

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

노트:

  • 이름에 ssh 대상이 포함된 파일에 추가됩니다.
  • 키로거입니다. SSH 키를 아직 설정하지 않은 경우 로그 파일에서 사용자 비밀번호를 얻을 수 있습니다.
  • 탭 완성으로 인해 실패합니다. 사용자가 명령을 입력하면 uptTab로그 uptime파일에 "uptime"이 아닌 "upt\t"가 표시됩니다.
  • "원시" 모드에서 문자를 가져옵니다. 사용자가 타이핑을 잘 못하는 경우 ^?로그 파일에 많은 백스페이스 문자가 표시됩니다.

답변2

현재 아래 bash 스크립트를 사용하고 있습니다. 많은 문제가 있지만 모든 요구 사항, 우선 순위 및 "좋은 점과 나쁜 점" 측면(적어도 대부분의 경우)을 충족하는 유일한 솔루션입니다.

이 답변SSH 세션을 로컬로 기록하는 것이 왜 그렇게 어려운지 토론하십시오.

지금까지 발견한 스크립트의 문제점:

  1. 여러 줄 명령으로 인해 문제가 발생할 수 있습니다.

    • 원격 기록에서 여러 줄의 항목을 페이지로 이동하는 경우(위/아래 키 사용) 최신 명령 대신 기록 항목이 기록됩니다. 당신은 이것을 피할 수 있습니다Bash 기록에서 제거여러 줄 명령은 사용 후 즉시 실행됩니다.
    • 여러 줄 명령의 첫 번째 줄만 기록됩니다.
  2. 세션을 연결하면( 원격 측에서 ssh또는 su명령 사용) 실제로 사용된 명령이 아닌 스크롤에 의해 전달된 명령을 기록하기 위해 기록이 스크롤됩니다.

  3. 정규식은 개선될 수 있으며 특정 환경에서는 수정해야 할 수도 있습니다.

    • cat -v청소하기 전에 인쇄되지 않는 문자를 변환하여 속임수를 썼습니다 . 따라서 ^[[명령에 문자열을 사용 하면 페이로드가 삭제될 수 있습니다.
    • 예를 들어 기록을 매우 빠르게 넘기는 경우 명령 전에 추가 레코드 입력을 받는 경우가 있습니다. 일반적으로 실제 명령 앞에 "^M"이 표시되므로 필요한 경우 제거할 수 있습니다.
    • 때때로 다른 제어 문자가 나타납니다. 어떤 것이 제거해도 안전한지 알 때까지 지금은 모두 그대로 두겠습니다. 방금 언급한 ^M은 잘못된 레코드 입력을 감지하는 데 유용하며, ^C는 명령이 중단되었는지 알려줍니다.
    • 특정 프롬프트에 대해 프롬프트 정규식을 수정해야 할 수도 있으며, 원격 환경마다 제어 문자 패턴이 다를 수 있다고 상상할 수 있습니다.
  4. 호스트 이름과 같은 SSH 명령에 대한 bash 완료는 없습니다. ssh이 스크립트의 별칭을 with로 지정하면 bash 완료를 얻을 수 있습니다.alias ssh="sshlog"

스크립트 소스 및 설치:

설치하려면 다음을 ~/bin/sshlog에 붙여넣고 실행 가능하게 만듭니다. 을 호출합니다 sshlog <ssh command options>. 선택적으로 사용자의 .bashrc 파일에서 "ssh"로 별칭을 지정합니다.

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

로그 콘텐츠의 예:

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]

답변3

어때요 strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd)? 그러면 모든 SSH 세션이 기록됩니다. 로그를 구문 분석하거나 grep등을 사용하는 도구가 필요할 수 있습니다.awk

  • -f: 분기된 하위 항목 추적
  • -ff: 각 어린이를 개별적으로 기록합니다.ssh_log.PID
  • -s8192: 문자열 로깅 제한을 늘립니다(필요한 경우).
  • -T -ttt: 에포크 이후 마이크로초 표시(초)
  • -p N: pid에 추가N

답변4

너무 복잡하지 않은 답변이 있으며 확실히 키로거가 아닙니다. 서버 로그와 독립적이라는 점을 이해하지 못합니다(즉, 모든 작업은 서버에서 수행되어야 하며 모든 로그는 서버 측 로그임). 시스템 전체에 전달하는 것이 좋은 생각이라고 생각합니다 bashrc 프롬프트 명령 좋다:


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

데비안에서는 /etc/bash.bashrc 파일을 편집해야 합니다. centos에서는 /etc/bashrc 파일을 편집해야 합니다.

현재 세션 기록을 시작하려면 편집한 파일을 가져와야 합니다. 예를 들어 다음과 같습니다.


source /etc/bash.bashrc

데비안 시스템 또는


source /etc/bashrc
센토스 시스템에서.

이제부터 모든 SSH 세션에 대한 모든 명령이 로그인됩니다./var/log/시스템 로그데비안 시스템에서는/var/log/메시지센토스 시스템에서.

별도의 파일에 기록하고 다른 로그 파일과 혼합하지 않으려면 다음을 사용할 수 있습니다.


PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p local6.info -t "$USER[$$] $SSH_CONNECTION")'
이전 PROMPT_COMMAND 예시 대신 필요에 따라 rsyslogd를 구성합니다.

예를 들어 Debian 시스템에서 편집합니다./etc/rsyslog.conf파일:변경 줄:


.;auth,authpriv.none           -/var/log/syslog
도착하다

.;auth,authpriv.none,local6           -/var/log/syslog
파일 끝에 다음 줄을 추가합니다.

local6.info                     /var/log/history.log

그런 다음 다음을 실행합니다.

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

관련 정보