翻译原出处:www.pointsoftware.ch/de/howto-bash-audit-command-logger/

翻译并整理了一下,水平有限,多请见谅。

有一个完整的输入命令记录在很多情况下是非常有用的:

当几个管理员在同一台server上一起工作时,需要知道每个人做了什么

当有人需要重做以前一系列命令或者理解一些未登记的维护过程

故障排除或者取证分析,通过检查一个事件日期或者在此时间的命令执行文件

标准的.bash_history文件在崩溃情况下不幸没有写入磁盘,也可能被用户删除,或者可以轻易绕过。

并且当很多shell同时运行时,他只有当它关闭时才进行记录,此时的history记录也并不是按照时间顺序进行排列的

而且,.bash_history并不包含命令执行的工作路径,并且默认情况下重复的命令不会记录。

因此有一些解决方案存在来改善这些问题:

1.      给bash打补丁:BASH_BOFH,  打补丁并重新编译bash,但需要每一个版本的bash对应一个新补丁

2.      snoopy : 记录所有命令除了内联shell

3.      rootsh/sniffy/ttyrpid/ttysnoop,  记录一切, 包括了命令的输出,这些非常有用但会产生一些冗余的日志。

rootsh: 普通用户在通过sudo /usr/local/rootsh/bin/rootsh -u root变更为root权限后,会将所有的操作指令和终端输出记录下来(如不指定,默认为/var/log/messages),在记录文件中会清晰表明是哪个普通用户变更权限到root

snitty: snitty 可以追踪、记录系统伪终端上的数据, 可以完整的显示、回显伪终端上发生了什么信息, 通过内核模块去实现的。

ttyrpid:  基于内核实现的键盘记录和屏幕记录,支持很多tty类型

ttysnoop:   重定向一个终端号的所有输入、输出到另一个终端的程序

4.      gresecurity内核补丁,非常强大但不是一个合适的解决方案,需要官方的内核

5.  这里也有一个旧的sshd补丁(http://www.kdvelectronics.eu/ssh-logging/ssh-logging.html)

6. screen -x 对于协同工作也非常有用, 但它并不是一个命令记录器

7.  修改环境变量:PROMPT_COMMAND

相比之下,当前的方法非常容易部署,他只是运行在bash(大多数系统的shell)上的shell脚本, 因此它是独立于架构的。

它将允许完全审计在bash交互执行的所有命令/内联

注意:一个用户可以避免调用这个文件通过比如“--norc”选项启动shell,  他也可以取消或者重写变量比如“PROMPT_COMMAND”.

因此这个脚本对于审计来说非常有用,但是有办法取消绕过,对于安全需求较高的可以选择bash 补丁的方式吧。

这个脚本记录命令并通过syslog记录日志,日志格式如下:

2012-05-31T15:40:52.530657+02:00 debian1 [audit root/31240 as root/31240 on pts/0/192.168.1.50:40067->192.168.1.120:22] /root: id
2012-05-31T15:41:10.533963+02:00 debian1 [audit root/31240 as root/31240 on pts/0/192.168.1.50:40067->192.168.1.120:22] /root: id #again, up-key
2012-05-31T15:41:26.421925+02:00 debian1 [audit root/31240 as root/31240 on pts/0/192.168.1.50:40067->192.168.1.120:22] /root: id #again, ctrl-r
2012-05-31T15:41:44.223986+02:00 debian1 [audit root/31240 as root/31240 on pts/0/192.168.1.50:40067->192.168.1.120:22] /root: (echo a; echo b); { echo c; echo d; }; echo e | ( cat && echo f)
2012-05-31T15:41:49.687712+02:00 debian1 [audit root/31240 as root/31240 on pts/0/192.168.1.50:40067->192.168.1.120:22] /root: exit
2012-05-31T15:41:49.690234+02:00 debian1 [audit root/31240 as root/31240 on pts/0/192.168.1.50:40067->192.168.1.120:22]: #=== bash session ended. ===
2012-05-31T15:51:01.399710+02:00 debian1 [audit root/31843 as root/31843 on pts/0/192.168.1.50:48710->192.168.1.120:22]: #=== New bash session started. ===
2012-05-31T15:51:02.980606+02:00 debian1 [audit root/31843 as root/31843 on pts/0/192.168.1.50:48710->192.168.1.120:22] /root: id
2012-05-31T15:51:09.327614+02:00 debian1 [audit root/31843 as root/31843 on pts/0/192.168.1.50:48710->192.168.1.120:22] /root: ssh localhost
2012-05-31T15:51:14.768578+02:00 debian1 [audit root/. as root/31874 on pts/1/127.0.0.1:47702->127.0.0.1:22]: #=== New bash session started. ===
2012-05-31T15:51:48.031612+02:00 debian1 [audit root/. as root/31874 on pts/1/127.0.0.1:47702->127.0.0.1:22] /root: echo hi from ssh
2012-05-31T15:51:49.875367+02:00 debian1 [audit root/. as root/31874 on pts/1/127.0.0.1:47702->127.0.0.1:22] /root: exit
2012-05-31T15:51:49.877675+02:00 debian1 [audit root/. as root/31874 on pts/1/127.0.0.1:47702->127.0.0.1:22]: #=== bash session ended. ===
2012-05-31T15:51:51.075034+02:00 debian1 [audit root/31843 as root/31843 on pts/0/192.168.1.50:48710->192.168.1.120:22] /root: id
2012-05-31T15:51:53.027380+02:00 debian1 [audit root/31843 as root/31843 on pts/0/192.168.1.50:48710->192.168.1.120:22] /root: less /var/log/user.log
2012-05-31T16:00:06.676849+02:00 debian1 [audit pointsoftware/31950 as pointsoftware/31977 on pts/2/192.168.1.50:48804->192.168.1.120:22]: #=== New bash session started. ===
2012-05-31T16:00:12.690457+02:00 debian1 [audit pointsoftware/31950 as pointsoftware/31977 on pts/2/192.168.1.50:48804->192.168.1.120:22] /home/pointsoftware: ls
2012-05-31T16:00:16.114366+02:00 debian1 [audit pointsoftware/31950 as pointsoftware/31977 on pts/2/192.168.1.50:48804->192.168.1.120:22] /home/pointsoftware: cd /
2012-05-31T16:00:21.002682+02:00 debian1 [audit pointsoftware/31950 as pointsoftware/31977 on pts/2/192.168.1.50:48804->192.168.1.120:22] /: ps aux
2012-05-31T16:00:30.714988+02:00 debian1 [audit root/31843 as root/31843 on pts/0/192.168.1.50:48710->192.168.1.120:22] /root: less /var/log/user.log
2012-05-31T16:00:37.754175+02:00 debian1 [audit pointsoftware/31950 as pointsoftware/31977 on pts/2/192.168.1.50:48804->192.168.1.120:22] /: ps aux
2012-05-31T16:00:37.758383+02:00 debian1 [audit pointsoftware/31950 as pointsoftware/31977 on pts/2/192.168.1.50:48804->192.168.1.120:22]: #=== bash session ended. ===

方法解释:

首先我们调整一些history相关的bash的设置

#'history' options
#declare -rx 设置只读环境变量
declare -rx HISTFILE="$HOME/.bash_history"
declare -rx HISTSIZE=500000                                 #nbr of cmds in memory
declare -rx HISTFILESIZE=500000                             #nbr of cmds on file
declare -rx HISTCONTROL=""                                  #does not ignore spaces or duplicates
declare -rx HISTIGNORE=""                                   #does not ignore patterns
declare -rx HISTCMD                                         #history line number
#history -r                                                  #to reload history from file if a prior HISTSIZE has truncated it
if [ "${OSTYPE:0:7}" != "solaris" ] #following not working in solaris
then
if groups | grep -q root
thendeclare -x TMOUT=3600                                     #timeout for root's sessionschattr +a "$HISTFILE"  #设置历史文件只能追加,不能删除                                  #set append-only
fi
fi
shopt -s histappend  #shopt -s 激活shell行为选项
shopt -s cmdhist#history substitution ask for a confirmation
shopt -s histverify

bash历史也可以通过下面的选项包括时间戳, 但是我们这里不需要, 因为我们的解决方案将创建另一个日志文件(/var/log/userlog.info),包含所有细节比如时间戳,工作目录,PID, userid等

#add timestamps in history - obsoleted with logger/syslog
#'http://www.thegeekstuff.com/2008/08/15-examples-to-master-linux-command-line-history/#more-130'
#declare -rx HISTTIMEFORMAT='%F %T '

一个良好的颜色shell格式在我们滚动终端时是非常方便的。随便说一句,这是非常有用的设置你的终端回滚栏至少10000行.

#prompt & color
#'http://www.pixelbeat.org/docs/terminal_colours/#256'
#'http://www.frexx.de/xterm-256-notes/'
_backnone="\e[00m"
_backblack="\e[40m"
_backblue="\e[44m"
_frontred_b="\e[01;31m"
_frontgreen_b="\e[01;32m"
_frontgrey_b="\e[01;37m"
_frontgrey="\e[00;37m"
_frontblue_b="\e[01;34m"
PS1="\[${_backblue}${_frontgreen_b}\]\u@\h:\[${_backblack}${_frontblue_b}\]\w\\$\[${_backnone}${_frontgreen_b}\] "

默认情况下ctrl-s将阻塞shell直到你按下ctrl-q(流控制)。 为了能够向前或向后搜索命令(ctrl-s / ctrl-r)这里我们禁用了默认的ctrl-s阻塞

#enable forward search ('ctrl-s')
#'http://ruslanspivak.com/2010/11/25/bash-history-incremental-search-forward/'
if shopt -q login_shell && [ -t 0 ]
thenstty -ixon
fi

下面的快捷键在bash中可用:

# bash shortcuts
#'http://www.techrepublic.com/article/master-the-linux-bash-command-line-with-these-10-shortcuts/5827311'
#'http://www.hypexr.org/bash_tutorial.php'
# ctrl-r                reverse search
# ctrl-s                forward search
# alt-. or esc-.        reuse 1st arg
# ctrl-a                Move cursor to beginning of line
# ctrl-e                Move cursor to end of line
# meta-b                Move cursor back one word
# meta-f                Move cursor forward one word
# ctrl-w                Cut the last word
# ctrl-u                Cut everything before the cursor
# ctrl-k                Cut everything after the cursor
# ctrl-y                Paste the last thing to be cut
# ctrl-_                Undo
#bash-history-cheat-sheet.pdf 'http://www.catonmat.net/download/bash-history-cheat-sheet.pdf'
# Emacs Mode Shortcuts:
# CTRL-p                Fetch the previous command from the history list.
# CTRL-n                Fetch the next command from the history list.
# CTRL-r                Search history backward (incremental search).
# CTRL-s                Search history forward (incremental search).
# Meta-p                Search backward using non-incremental search.
# Meta-n                Search forward using non-incremental search.
# Meta-<                Move to the first line in the history.
# Meta->                Move to the end of the history list.
# Vi Mode Shortcuts:
# k                     Fetch the previous command from the history list.
# j                     Fetch the next command from the history list.
# /string or CTRL-r     Search history backward for a command matching string.
# ?string or CTRL-s     Search history forward for a command matching string.
# n                     Repeat search in the same direction as previous.
# N                     Repeat search in the opposite direction as previous.
# G                     Move to the N-th history line (for example, 15G).

为了得到原始的用户名(不是当前用户名,这可能通过su改变了),我们尝试使用在/proc/循环搜索父进程pid这种方法

#seek the oldest parent 'bash' process, to get $AUDIT_LOGINID and $AUDIT_LOGINUSER,
#which may be different from $USER after 'su' or 'sudo' commands
AUDIT_LOGINID=$$
AUDIT_LOGINID2=$AUDIT_LOGINID
while AUDIT_LOGINID2="$(awk '/PPid:/ {print $2}' /proc/$AUDIT_LOGINID2/status)" && [ "$AUDIT_LOGINID2" != "1" ]
doif [ "$(awk '/Name:/ {print $2}' /proc/$AUDIT_LOGINID2/status)" == "bash" ]thenAUDIT_LOGINID="$AUDIT_LOGINID2"fi
done
AUDIT_LOGINUSER=$(awk "/^Uid:/ {print \$2}" /proc/$AUDIT_LOGINID/status)
AUDIT_LOGINUSER=$(awk -F":" "\$3 ~ /$AUDIT_LOGINUSER/ {print \$1}" /etc/passwd)
#old: AUDIT_LOGINUSER=$(awk -F":" "/^[^:]*:[^:]*:$AUDIT_LOGINUSER:/ {print \$1}" /etc/passwd)
#old: AUDIT_LOGINUSER=$(getent passwd $AUDIT_LOGINUSER | sed -e 's%:.*%%')"

我们再使用一个简单的方法,使用“who -mu”命令

#seek the oldest parent 'bash' process, to get $AUDIT_LOGINID and $AUDIT_LOGINUSER,
#which may be different from $USER after 'su' or 'sudo' commands
AUDIT_LOGINID=$$
AUDIT_LOGINID2=$AUDIT_LOGINID
while AUDIT_LOGINID2="$(awk '/PPid:/ {print $2}' /proc/$AUDIT_LOGINID2/status)" && [ "$AUDIT_LOGINID2" != "1" ]
doif [ "$(awk '/Name:/ {print $2}' /proc/$AUDIT_LOGINID2/status)" == "bash" ]thenAUDIT_LOGINID="$AUDIT_LOGINID2"fi
done
AUDIT_LOGINUSER=$(awk "/^Uid:/ {print \$2}" /proc/$AUDIT_LOGINID/status)
AUDIT_LOGINUSER=$(awk -F":" "\$3 ~ /$AUDIT_LOGINUSER/ {print \$1}" /etc/passwd)
#old: AUDIT_LOGINUSER=$(awk -F":" "/^[^:]*:[^:]*:$AUDIT_LOGINUSER:/ {print \$1}" /etc/passwd)
#old: AUDIT_LOGINUSER=$(getent passwd $AUDIT_LOGINUSER | sed -e 's%:.*%%')"

现在我们需要一个方法来来执行记录每一条执行命令。下面的解决方法使用‘PROMPT_COMMAND’有效但是在命令执行后syslog消息被发送,这将导致'su'或者‘sudo’命令只有在登出后才回出现,并且cd命令展现错误的工作目录.

#'http://jablonskis.org/2011/howto-log-bash-history-to-syslog/'
declare -rx PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p user.info -t "$AUDIT_STR $PWD")' #no subshell is used here, it would else duplicate execution!

'history -a > (tee -a ~/.bash_history | logger -p user.info -t "$AUDIT_STR $PWD")' 将拿到没有提交到磁盘的历史命令(‘history -a’), 并且把命令写到一个替代进程('>()'),这将是tee -a命令的标准输入,并将输出结果追加的~/.bash_history, 并通过一个管道发送到logger命令, logger将发送到本地syslog守护程序

另一个方法是使用trap调试,将在命令之前执行

看‘http://superuser.com/questions/175799/does-bash-have-a-hook-that-is-run-before-executing-a-command‘ and ‘http://www.davidpashley.com/articles/xterm-titles-with-bash.html‘

短的实例,没有用到管道命令

set -o functrace; trap 'echo -ne "===$BASH_COMMAND===${_backnone}${_frontgrey}\n"' DEBUG

更长的例子,(用到了管道命令)

set +o functrace                                            #disable trap DEBUG inherited in functions, command substitutions or subshells, normally the default setting already
function AUDIT_DEBUG() {echo -ne "${_backnone}${_frontgrey}"                      #disable prompt colors for the command's output(history -a >(logger -p user.info -t "$AUDIT_STR $PWD" < <(tee -a ~/.bash_history))) && sync && history -c && history -r
}
set -o functrace                                            #enable trap DEBUG inherited for all subsequent functions; required to audit commands beginning with the char '(' for a subshell
#=> problem: auto-completion in commands avoids logging them
#launches AUDIT_DEBUG() and then stops the trap DEBUG, to avoid a useless rerun of AUDIT_DEBUG() during the execution of $PROMPT_COMMAND
declare -rx PROMPT_COMMAND="trap 'AUDIT_DEBUG; trap DEBUG' DEBUG; $PROMPT_COMMAND"

'history -a > (logger -p user.info -t "$AUDIT_STR $PWD" << (tee -a ~/.bash_history))'将接管还没有写到磁盘的命令(history -a),  将写到一个进程替换('>()'), 这将是tee -a命令的标准输入, 并且会追加结果到~/.bash_history文件中以及另一个进程替换('<()'),  最后被logger命令读取

'history -c && history 0r'在这里强制刷新历史记录,因为history -a将在subshell内调用,因此刚才追加的文件的新历史记录将在subshell外保持新的状态,导致这些日志重复出现在每一个函数调用。(cf. 'http://stackoverflow.com/questions/103944/real-time-history-export-amongst-bash-terminal-windows‘)

注意:没有subshell, 管道命令将会被挂起(这好像是这trap + 进程替换干扰stdin重定向)

这最终的解决方案更快,避免了‘sync’和 ‘history -r’耗费时间

事实证明这个解决方案简单有效的多,利用管道命令,subshell,   终止命令'ctrl-c',  所有的测试用例我们可以试一试

关键是再次使用了trap DEBUG函数,设置所需的历史记录选项(HISTCONTROL, HISTIGNORE)并且在函数,命令替换,subshell中禁用了trap。

set +o functrace                                            #disable trap DEBUG inherited in functions, command substitutions or subshells, normally the default setting already
shopt -s extglob                                            #enable extended pattern matching operators
function AUDIT_DEBUG() {if [ -z "$AUDIT_LASTHISTLINE" ]                           #initializationthenlocal AUDIT_CMD="$(fc -l -1 -1)"                        #previous history commandAUDIT_LASTHISTLINE="${AUDIT_CMD%%+([^ 0-9])*}"elseAUDIT_LASTHISTLINE="$AUDIT_HISTLINE"filocal AUDIT_CMD="$(history 1)"                            #current history commandAUDIT_HISTLINE="${AUDIT_CMD%%+([^ 0-9])*}"if [ "${AUDIT_HISTLINE:-0}" -ne "${AUDIT_LASTHISTLINE:-0}" ] || [ "${AUDIT_HISTLINE:-0}" -eq "1" ]        #avoid logging unexecuted commands after 'ctrl-c', 'empty+enter', or after 'ctrl-d'thenecho -ne "${_backnone}${_frontgrey}"                    #disable prompt colors for the command's output#remove in last history cmd its line number (if any) and send to syslogif [ -n "$AUDIT_SYSLOG" ]thenif ! logger -p user.info -t "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])?(\*)+( ))}"thenecho error "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])?(\*)+( ))}"fielseecho $( date +%F_%H:%M:%S ) "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])?(\*)+( ))}" >>/var/log/userlog.infofi#echo "===cmd:$BASH_COMMAND/subshell:$BASH_SUBSHELL/fc:$(fc -l -1)/history:$(history 1)/histline:${AUDIT_CMD%%+([^ 0-9])*}/last_histline:${AUDIT_LASTHISTLINE}===" #for debuggingreturn 0elsereturn 1fi
}#audit the session closing
function AUDIT_EXIT() {local AUDIT_STATUS="$?"if [ -n "$AUDIT_SYSLOG" ]thenlogger -p user.info -t "$AUDIT_STR" "#=== session closed ==="elseecho $( date +%F_%H:%M:%S ) "$AUDIT_STR" "#=== session closed ===" >>/var/log/userlog.infofiexit "$AUDIT_STATUS"
}#make audit trap functions readonly; disable trap DEBUG inherited (normally the default setting already)
declare -frx +t AUDIT_DEBUG
declare -frx +t AUDIT_EXIT#audit the session opening
if [ -n "$AUDIT_SYSLOG" ]
thenlogger -p user.info -t "$AUDIT_STR" "#=== session opened ===" #audit the session openning
elseecho $( date +%F_%H:%M:%S ) "$AUDIT_STR" "#=== session opened ===" >>/var/log/userlog.info
fi#enable the trap DEBUG (at every call of $PROMPT_COMMAND) and trap EXIT
declare -rx PROMPT_COMMAND="trap 'AUDIT_DEBUG; trap DEBUG' DEBUG"
declare -rx BASH_COMMAND                                    #current command executed by user or a trap
declare -rx SHELLOPT                                        #shell options, like functrace
trap AUDIT_EXIT EXIT                                        #audit the session closing

当一个bash命令执行,他首先启动AUDIT_DEBUG(), 然后禁止trap DEBUG 来避免AUDIT_DEBUG()在执行管道命令期间无效的返回,最后,当提示显示,可以重新开启trap DEBUG

脚本安装

第一步:用root登录并创建一个/etc/bash_franzi文件,下载地址:http://www.pointsoftware.ch/wp-content/uploads/2012/09/bash_franzi.txt,   /etc/bash_franzi内容如下:

#Pointsoftware AG, 2013-11-03
#created by francois scheurer
#filename: '/etc/bash_franzi'
#This file must be sourced by '~/.bashrc', which is the last runned startup script for bash invocation for login interactive, login non-interactive and non-login interactive shells.
#
#Having a complete history of all typed commands can be very helpful in many scenarios:
#  when several administrators work together on the same server and need to know what was done previously
#  when someone need to redo an older sequence of commands or to understand an undocumented maintenance process
#  for troubleshooting or forensic analysis, by crosschecking the date of an event or of a file with the commands executed at that date
#
#The standard '.bash_history' file of the shell is unfortunately not written on disk in the case of a crash and it may be deleted by the user.
#Another problem is that when many shell sessions are running concurrently, their logging will only occur when they are closed, therefore the commands of the history will not appear in their chronological order.
#Furthermore, '.bash_history' will not include essential information like the 'working directory' of the command; and by default the repetition or re-edition of commands will not be logged, too.
#
#Some solutions exist to improve this, either by patching or installing binaries:
#  'bash-BOFH' patching and recompiling: works well but need a new patch for each release of the bash
# 'snoopy': is logging all commands except shell builtins
#  'rootsh / sniffy / ttyrpld / ttysnoop': logs everything, also output of commands, it may be useful but it generates very verbose logs
#  'grsecurity' patched kernels: powerful but it may be a not suitable solution if an official kernel is required (e.g. for Oracle DB)
#  there is also an old 'sshd' patch ('http://www.kdvelectronics.eu/ssh-logging/ssh-logging.html')
#  'screen -x' can also be useful for cooperation work, but it is not a command logger
#
#In contrast to that, the presented method is very easy to deploy; it is just a shellscript that is running in bash (standard shell on most systems) and therefore it is architecture independent.
#It will allow a complete audit of all commands/builtins executed interactively in the bash.
#Note that a user can avoid calling this file by starting a shell with options like '--norc'; he also can unset or overwrite variables like 'PROMPT_COMMAND'.
#Therefore this script is useful for audit but an alternative solution with bash patching should be considered if the security requirements are the priority.
#
#Note on Solaris:
#       In Solaris please use 'grep' without the '-q' option, like this:
#               if groups | grep root &>/dev/null
#       Please also remove the following line (chattr unsupported in Solaris:
#               chattr +a "$HISTFILE"
#       Then modify your /etc/syslog.conf to include this line:
#               user.info /var/adm/userlog.info
#       To assign 'bash' as the login shell in Solaris: passwd -e /bin/bash .
#       Make sure that the audit-script is sourced (=included) correctly during the bash invocation.
#       If your bash version is too old, $HISTCONTROL will not allow you to log duplicated commands correctly.
#       svcadm restart system/system-log
#       svcadm disable ssh
#       svcadm enable sshif [ "${SHELL##*/}" != "bash" ]; thenreturn
fi#to avoid sourcing this file more than once
if [ -n "${OSTYPE##solaris*}" ]; then #following not working in solaris#do not source this file twice; also do not source it if we are in forcecommand.sh, source it later from "-bash-li"#if we would source it from forcecommand.sh, the environment would be lost after the call of 'exec -l bash -li'if [ "$AUDIT_INCLUDED" == "$$" ] || { [ -z "$SSH_ORIGINAL_COMMAND" ] && [ "$(cat /proc/$$/cmdline)" == 'bash-c"/etc/forcecommand.sh"' ]; }; thenreturnelsedeclare -rx AUDIT_INCLUDED="$$"fi
fi#prompt & color
#'http://www.pixelbeat.org/docs/terminal_colours/#256'
#'http://www.frexx.de/xterm-256-notes/'
_backnone="\e[00m"
_backblack="\e[40m"
_backblue="\e[44m"
_frontred_b="\e[01;31m"
_frontgreen_b="\e[01;32m"
_frontgrey_b="\e[01;37m"
_frontgrey="\e[00;37m"
_frontblue_b="\e[01;34m"
#PS1="\[${_backblue}${_frontgrey_b}\]\u@\h:\[${_backblack}${_frontblue_b}\]\w\\$\[${_backnone}${_frontgrey_b}\] " #grey
PS1="\[${_backblue}${_frontgreen_b}\]\u@\h:\[${_backblack}${_frontblue_b}\]\w\\$\[${_backnone}${_frontgreen_b}\] " #green
#PS1="\[${_backblue}${_frontred_b}\]\u@\h:\[${_backblack}${_frontblue_b}\]\w\\$\[${_backnone}${_frontred_b}\] " #red
declare -rx PS1#'history' options
declare -rx HISTFILE="$HOME/.bash_history"
declare -rx HISTSIZE=500000                                 #nbr of cmds in memory
declare -rx HISTFILESIZE=500000                             #nbr of cmds on file
declare -rx HISTCONTROL=""                                  #does not ignore spaces or duplicates
declare -rx HISTIGNORE=""                                   #does not ignore patterns
declare -rx HISTCMD                                         #history line number
#following line is commented to avoid following issue: loading the history during the sourcing of this file (non-interactive bash) is also loading history lines that begin with '#', but then during the trap DEBUG calls it reloads the whole history without '#'-lines and produces an double-length history.
#history -r                                                  #to reload history from file if a prior HISTSIZE has truncated it#following 2 lines commented because 'history -r' was still loading '#'-lines
#shopt -s extglob                                            #enable extended pattern matching operators
#HISTIGNORE="*([ \t])#*"; history -r                         #reload history without commented lines; this force non-interactive bash to behave like interactive bash, without this AUDIT_HISTLINE will get a wrong initial value, leading then to a small issue where empty bash sessions are actually logging the last command of historyif [ -n "${OSTYPE##solaris*}" ]; then #following not working in solarisif groups | grep -q root; thendeclare -x TMOUT=43200                                    #timeout for root's sessionschattr +a "$HISTFILE"                                     #set append-onlyfi
fi
shopt -s histappend
shopt -s cmdhist#history substitution ask for a confirmation
shopt -s histverify#add timestamps in history - obsoleted with logger/syslog
#'http://www.thegeekstuff.com/2008/08/15-examples-to-master-linux-command-line-history/#more-130'
#declare -rx HISTTIMEFORMAT='%F %T '#enable forward search ('ctrl-s')
#'http://ruslanspivak.com/2010/11/25/bash-history-incremental-search-forward/'
if shopt -q login_shell && [ -t 0 ]; thenstty -ixon
fi#bash audit & traceability
#
#
#
declare -rx AUDIT_LOGINUSER="$(who -mu | awk '{print $1}')"
declare -rx AUDIT_LOGINPID="$(who -mu | awk '{print $6}')"
declare -rx AUDIT_USER="$USER"                              #defined by pam during su/sudo
declare -rx AUDIT_PID="$$"
declare -rx AUDIT_TTY="$(who -mu | awk '{print $2}')"
declare -rx AUDIT_SSH="$([ -n "$SSH_CONNECTION" ] && echo "$SSH_CONNECTION" | awk '{print $1":"$2"->"$3":"$4}')"
declare -rx AUDIT_STR="[audit $AUDIT_LOGINUSER/$AUDIT_LOGINPID as $AUDIT_USER/$AUDIT_PID on $AUDIT_TTY/$AUDIT_SSH]"
declare -x AUDIT_LASTHISTLINE=""                            #to avoid logging the same line twice
declare -rx AUDIT_SYSLOG="1"                                #to use a local syslogd
#
#
#
#the logging at each execution of command is performed with a trap DEBUG function
#and having set the required history options (HISTCONTROL, HISTIGNORE)
#and to disable the trap in functions, command substitutions or subshells.
#it turns out that this solution is simple and works well with piped commands, subshells, aborted commands with 'ctrl-c', etc..
set +o functrace                                            #disable trap DEBUG inherited in functions, command substitutions or subshells, normally the default setting already
shopt -s extglob                                            #enable extended pattern matching operators
function AUDIT_DEBUG() {if [ -z "$AUDIT_LASTHISTLINE" ]; then                     #initializationlocal AUDIT_CMD="$(fc -l -1 -1)"                        #previous history commandAUDIT_LASTHISTLINE="${AUDIT_CMD%%+([^ 0-9])*}"elseAUDIT_LASTHISTLINE="$AUDIT_HISTLINE"filocal AUDIT_CMD="$(history 1)"                            #current history commandAUDIT_HISTLINE="${AUDIT_CMD%%+([^ 0-9])*}"if [ "${AUDIT_HISTLINE:-0}" -ne "${AUDIT_LASTHISTLINE:-0}" ] || [ "${AUDIT_HISTLINE:-0}" -eq "1" ]; then  #avoid logging unexecuted commands after 'ctrl-c', 'empty+enter', or after 'ctrl-d'echo -ne "${_backnone}${_frontgrey}"                    #disable prompt colors for the command's output#remove in last history cmd its line number (if any) and send to syslogif [ -n "$AUDIT_SYSLOG" ]; thenif ! logger -p user.info -t "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])?(\*)+( ))}"; thenecho error "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])?(\*)+( ))}"fielseecho $( date +%F_%H:%M:%S ) "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])?(\*)+( ))}" >>/var/log/userlog.infofi#echo "===cmd:$BASH_COMMAND/subshell:$BASH_SUBSHELL/fc:$(fc -l -1)/history:$(history 1)/histline:${AUDIT_CMD%%+([^ 0-9])*}/last_histline:${AUDIT_LASTHISTLINE}===" #for debuggingreturn 0elsereturn 1fi
}
#
#
#
#audit the session closing
function AUDIT_EXIT() {local AUDIT_STATUS="$?"if [ -n "$AUDIT_SYSLOG" ]; thenlogger -p user.info -t "$AUDIT_STR" "#=== session closed ==="elseecho $( date +%F_%H:%M:%S ) "$AUDIT_STR" "#=== session closed ===" >>/var/log/userlog.infofiexit "$AUDIT_STATUS"
}
#
#
#
#make audit trap functions readonly; disable trap DEBUG inherited (normally the default setting already)
declare -frx +t AUDIT_DEBUG
declare -frx +t AUDIT_EXIT
#
#
#
#audit the session opening
if [ -n "$AUDIT_SYSLOG" ]; thenlogger -p user.info -t "$AUDIT_STR" "#=== session opened ===" #audit the session openning
elseecho $( date +%F_%H:%M:%S ) "$AUDIT_STR" "#=== session opened ===" >>/var/log/userlog.info
fi
#
#
#
#when a bash command is executed it launches first the AUDIT_DEBUG(),
#then the trap DEBUG is disabled to avoid a useless rerun of AUDIT_DEBUG() during the execution of pipes-commands;
#at the end, when the prompt is displayed, re-enable the trap DEBUG#declare -rx PROMPT_COMMAND="AUDIT_DONE=; trap 'AUDIT_DEBUG && AUDIT_DONE=1; trap DEBUG' DEBUG; [ -n \"\$AUDIT_DONE\" ] && echo '-----------------------------'"#NOK: declare -rx PROMPT_COMMAND="echo "-----------------------------"; trap 'AUDIT_DEBUG; trap DEBUG' DEBUG; echo '-----------------------------'"#OK:  declare -rx PROMPT_COMMAND="echo "-----------------------------"; trap 'AUDIT_DEBUG; trap DEBUG' DEBUG"
declare -rx PROMPT_COMMAND="[ -n \"\$AUDIT_DONE\" ] && echo '-----------------------------'; AUDIT_DONE=; trap 'AUDIT_DEBUG && AUDIT_DONE=1; trap DEBUG' DEBUG"
declare -rx BASH_COMMAND                                    #current command executed by user or a trap
declare -rx SHELLOPT                                        #shell options, like functrace
trap AUDIT_EXIT EXIT                                        #audit the session closing#endof

改变文件的所有者和权限

chown root:root /etc/bash_franzi
chmod 644 /etc/bash_franzi

2.这个文件需要在启动shell自动source, 需要将/etc/bash_franzi添加到初始化文件/etc/.bashrc

可以通过下面的自动或脚本来完成

for i in /etc/profile /etc/skel/.bashrc /root/.bashrc /home/*/.bashrc; doif ! grep -q ". /etc/bash_franzi" "$i"; thenecho "===updating $i==="echo "[ -f /etc/bash_franzi ] && . /etc/bash_franzi #added by francois scheurer" >>"$i"fi
done

注意在ubuntu中通过/etc/profile来进行source时,桌面开始启动是会出现问题

因此最好只从~/.bashrc 中source,但是这里有另外一个问题,在Debian中, 每一个用户主目录获取通过默认的一个. bash_profile, 其优先权高于.bashrc。 bash手册页声明:

当一个bash作为一个交互登录shell被调用时,或者作为一个有--login选项的非交互shell时,它第一次从/etc/profile读取并执行命令。在读取了/etc/profile, 它寻找~/.bash_profile, ~/.bash_login, ~/.profile, 按照这个顺序,从第一个存在并可读的文件读取并执行命令。 shell启动时可以使用--nooption选项来阻止这种行为。

换句话说,只有在你删除或重命名~/.bash_profile后~/.barc才会被读取.

3. 配置rsyslog

通过下面的行来配置/etc/rsyslog.conf

cat >>/etc/rsyslog.conf <<"EOF"
#added by francois scheurer
$ActionFileDefaultTemplate RSYSLOG_FileFormat
#stop avahi if messages are dropped (cf. /var/log/messages with 'net_ratelimit' or 'imuxsock begins to drop')
#update-rc.d -f avahi-daemon remove && service avahi-daemon stop
#https://isc.sans.edu/diary/Are+you+losing+system+logging+information+%28and+don%27t+know+it%29%3F/15106
#$SystemLogRateLimitInterval 10
#$SystemLogRateLimitBurst 500
$SystemLogRateLimitInterval 0
#endof
EOF

运行下面命令来创建/etc/rsyslog.d/45-franzi.conf

cat >/etc/rsyslog.d/45-franzi.conf <<"EOF"
#added by francois scheurer# Filter duplicated messages
$RepeatedMsgReduction off# Enable high precision timestamps
$ActionFileDefaultTemplate RSYSLOG_FileFormat# Log bash audit generated log messages to file
if $syslogfacility-text == 'user' and $syslogseverity-text == 'info' and $syslogtag startswith '[audit' then /var/log/userlog.info#then drop them
& ~#'http://content.hccfl.edu/pollock/aunix2/logging.htm'
#'http://www.rsyslog.com/doc/rsyslog_conf_filter.html'
EOF

重启rsyslog

/etc/init.d/rsyslog restart

现在登入登出就可以发现审计文件:/var/log/userlog.info, 在里面就包含着记录bash执行的命令。

4.如果你想审计scp/sftp, 创建一个文件‘/etc/forcecommand.sh’(下载http://www.pointsoftware.ch/wp-content/uploads/2012/09/forcecommand.sh_.txt)

cat >/etc/forcecommand.sh <<"EOF"
#!/bin/bash
#Pointsoftware AG, 2012-08-24
#filename: '/etc/forcecommand.sh'
#created by francois scheurer
#used for bash audit, see '/etc/bash_franzi'if [ -n "${SSH_ORIGINAL_COMMAND}" ]; thenexec bash -c "${SSH_ORIGINAL_COMMAND}"
elseexec -l bash -li
fi
#endof
EOF

改变属主和权限

chown root:root /etc/forcecommand.sh
chmod 755 /etc/forcecommand.sh

然后配置/etc/ssh/sshd_config 运行下面行

cat >>/etc/ssh/sshd_config <<"EOF"
ForceCommand "/etc/forcecommand.sh"
EOF

重启ssh服务

/etc/init.d reload

英文原版

http://www.pointsoftware.ch/howto-bash-audit-command-logger/

Bash审计与命令记录相关推荐

  1. linux中Shell历史命令记录文件的路径是什么

    Bash shell在"~/.bash_history"("~/"表示用户目录)文件中保存了500条使用过的命令,这样能使你输入使用过的长命令变得容易.每个在系 ...

  2. bash功能特性二 命令别名和历史命令

    一.历史命令 bash提供存储历史命令的功能,下面来详细介绍一下. 1.history命令 命令格式:history [options] options: 不带参数选项:显示所有使用过的命令: #(数 ...

  3. 【Linux学习笔记】20:Bash基础-历史命令

    把操作的记录保存在系统当中,当需要的时候还可以查看和调用,这是一种必要的机制. 最早的Bourne Shell--sh是不支持历史命令的,发展到现在的Bash已经支持的很好了. [1]history ...

  4. linux中bash是什么命令,Bash简介 Bash是如何处理命令的

    什么是shell 简单点理解,就是系统跟计算机硬件交互时使用的中间介质,它只是系统的一个工具.实际上,在shell和计算机硬件之间还有一层东西那就是系统内核了.打个比方,如果把计算机硬件比作一个人的躯 ...

  5. 【RDMA】InfiniBand IB常用命令|历史命令记录

    目录 0.使用命令记录 1.常规 IB 监视命令 2.常规 IB 性能测试命令 3.光纤网络诊断工具 4.查询并报告非零 IB 端口计数器 5.其常用指令 作者:bandaoyu,随时更新,源文地址: ...

  6. Docker常用的命令记录

    Docker&k8s常用的命令记录 一.Docker命令 1.查看docker版本及信息 2.docker命令帮助 3.镜像仓库命令 4.查看镜像列表 5.删除镜像 6.搜索镜像 7.通过do ...

  7. 常用linux命令记录

    常用linux命令记录 1.常用linux命令基本使用列表 序号 命令 英文 作用 01 ls list 查看当前文件夹的内容 02 pwd print work directory 查看当前所在文件 ...

  8. kubenetes kubectl命令记录

    2019独角兽企业重金招聘Python工程师标准>>> kubenetes kubectl命令记录 博客分类: Kubernetes 1.显示所有pod  kubectl get p ...

  9. 达梦数据库操作记录_达梦数据库常用功能及命令记录 -- 持续更新

    达梦数据库常用功能及命令记录 -- 持续更新 达梦数据库常用功能及命令记录 达梦数据库语句的使用总体来说跟 oracle 很接近的, 这篇文章主要是把常用的情况和语句做了记录, 并且后续还会不断的持续 ...

最新文章

  1. linux命令ssh
  2. sqlprofiler 常用调试方法
  3. 笔记-项目采购管理-规划采购管理
  4. Spring Aop之Advisor解析
  5. oracle拓展磁盘空间,Oracle磁盘空间使用统计
  6. 【Java】hashCode和identityHashCode的区别
  7. display none 隐藏后怎么显示_第12天:打破常规之 display
  8. 关于加快OpenCV下载速度的解决方法
  9. RobotStudio软件:ABB机器人弧焊焊接虚拟仿真实现方法
  10. 腾讯QQ会员技术团队:人人都可以做深度学习应用:入门篇(下)
  11. 蒟蒻的做题录(时间)
  12. 正态分布、指数分布的特征函数及期望与方差 - 随机过程
  13. 【JavaWeb】1、XML、Tomcat
  14. 眼血管分割matlab,视网膜血管分割matlab
  15. 【寻找最佳小程序】11期:车来了——时时公交就在你身边,到站准确率可控制在90%以上...
  16. 未能创建 SSL/TLS 安全通道解决方案
  17. 如何使用谷歌colab
  18. opencv生成棋盘格
  19. Linux服务器操作系统快速删除大量/大文件
  20. 【Nav2中文网】五、普通教程(三)用实体Turtlebot3机器人导航

热门文章

  1. 【CSS】1209- TailwindCSS v3.0 正式发布!一大波新特性来袭!
  2. C语言字符型PPT,C语言字符串ppt课件
  3. 为什么说 交叉验证能 防止过拟合 呢?
  4. 《Oracle 入门教程》第 05 篇 数据过滤
  5. 嵌入式Qt-表格使用测试
  6. 第一讲 检索系统与数据库编程
  7. Java中数据类型 + 强制转换
  8. android 斜边_今天,我撸了一个“可爱”的环形 Android 图表
  9. AMD 2700x安装黑苹果
  10. iOS仿QQ空间时间显示