web-dev-qa-db-ja.com

すべてのsshコマンドのローカルのタイムスタンプ付きロギング?

sshbashから開始されたコマンドラインopensshクライアント)で使用するすべてのリモートコマンドのローカルのタイムスタンプ付きレコードをどのように保持できますか?

要件:

  • 必須:

    • サーバーのログ記録に依存しない100%クライアント側
    • ログはユーザーのホームディレクトリに保存され、ユーザーごとに構成またはインストールされます。
    • さまざまなユーザーおよびホストとの複数の同時セッションを区別するためのサポート。
    • 非侵入型(毎回それをアクティブにする必要はなく、sshの使用を大幅に妨害しません)
  • 高優先度:

    • 出力はログに記録されないか、可能な限り除外されません。
    • パスワードエントリがログに記録されていないか、ファイルが暗号化されています
    • 使用される実際のコマンドを示します(タブ/履歴の完了、バックスペース、 CTRL+C、など...処理されました)
  • 持っていると便利:

    • チェーンセッションのコマンドも記録します(リモートsshまたは_su <user>_セッション中に入力されたコマンド)
    • セッションの開始と終了をログに記録する必要があります
    • 単純なbashベースの非ルートソリューションが最適です(おそらく、aliasまたはbashラッパースクリプトでsshコマンドを実行しますか?)

私のスキルレベル:

  • 私はプログラミングに不慣れですが、bashと「Linuxの方法」をまだ学習しているので、簡単な説明付きのコードサンプルをいただければ幸いです。

可能な戦略

  • keylogger-問題:パスワードをログに記録しますが、タブ/履歴の完了をログに記録しません( glennの回答 を参照)
  • screenスクロールバックダンプを1秒に1回、それらの間で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]
_

または、ファイルの先頭でセッションを開始するために使用されるコマンドラインを使用して、セッションごとに個別のログが作成される可能性があります。

12
Oleg

私はあなたの質問に興味をそそられました。もともと答えるつもりはなかったのですが、夢中になりました。

これは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キーを設定していない場合は、ログファイルでユーザーのパスワードを取得します
  • タブ補完によって失敗します:ユーザーが入力した場合 uptTabuptimeコマンドの場合)、「uptime」ではなく「upt\t」がログファイルに記録されます。
  • 「raw」モードで文字を取得します。ユーザーがタイピストが上手でない場合、ログファイルにたくさんの^?(バックスペース文字)が表示されます。
4
glenn jackman

現在、以下のbashスクリプトを使用しています。これには多くの問題がありますが、すべての要件、優先度、および「所有するのが良い」(少なくともほとんどの場合)に対処する唯一の解決策です。

この回答 は、sshセッションをローカルでログに記録することが非常に難しい理由を説明しています。

これまでに見つけたスクリプトの問題:

  1. 複数行コマンドは問題を引き起こします:

    • リモート履歴の複数行の項目を(上下キーで)ページングすると、最新のコマンドの代わりに履歴項目がログに記録されます。 bash履歴から削除する 複数行コマンドを使用した直後に、これを回避できます。
    • 複数行コマンドの最初の行のみがログに記録されます。
  2. チェーンされたセッション(リモートエンドでsshまたはsuコマンドを使用)を使用すると、履歴のスクロールで、実際に使用されたコマンドではなく、スクロールされて渡されたコマンドが記録されます。

  3. 正規表現は改善することができ、特定の環境では変更が必要になる場合があります。

    • クリーニングの前に、印刷されない文字をcat -vで変換してごまかします。その結果、コマンドで^[[のような文字列を使用した場合、有効なコンテンツが削除される可能性があります。
    • 履歴を非常に高速にページングする場合など、コマンドの前に追加のログ入力を取得することがあります。これは通常、実際のコマンドの前に「^ M」が続くため、必要に応じて削除できます。
    • 他の制御文字が時々発生します。どちらを削除しても安全かがわかるまで、今はすべてそのままにしておきます。先ほど述べた^ Mは、無効なログ入力を検出するのに役立ちます。^ Cは、コマンドが中止されたかどうかを通知します。
    • プロンプトの正規表現は特定のプロンプトに合わせて変更する必要がある場合があり、リモート環境が異なると制御文字パターンが異なる場合があると想像できます。
  4. ホスト名などのsshコマンドのbash補完はありません。alias ssh="sshlog"を使用してこのスクリプトをsshにエイリアスすると、bash補完を取得できます

スクリプトのソースとインストール:

インストールするには、以下を〜/ 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]
2
Oleg

strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd)はどうですか?これにより、すべてのsshセッションがログに記録されます。後でログを解析するためのツールが必要になるか、単にgrepawkなどを使用します。

  • -f:分岐した子のトレース
  • -ff:各子を個別にssh_log.PIDに記録します
  • -s8192:文字列のログ制限を増やす(必要な場合)
  • -T -ttt:エポックからの秒単位のマイクロ秒スタンプ
  • -p N:pidにアタッチN
0
Anul

私の答えはそれほど複雑ではなく、キーロガーではありません。サーバーログから独立しているという点はわかりません(つまり、すべてのアクションをサーバーに対して実行する必要があり、すべてのログはサーバー側のログです)。したがって、システム全体のbashrcに渡すことをお勧めします次のようなプロンプトコマンド:


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

Debianではファイル/etc/bash.bashrcを編集し、centosではファイル/ etc/bashrcを編集する必要があります。

現在のセッションのロギングを開始する場合は、編集したファイルを入手する必要があります。たとえば、次のコマンドを実行します。


source /etc/bash.bashrc

debianシステムまたは


source /etc/bashrc

これ以降、すべてのsshセッションのすべてのコマンドは、debianシステムでは/ var/log/syslogに記録され、/ var/log/messagesではログに記録されますcentosシステム。

別のファイルにログを記録し、他のログファイルを台無しにしたくない場合は、以下を使用できます。


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

たとえば、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
0
strimpak