Visit Our UNIX and Linux User Community

Issue with Bash Audit Command Logger script | Need help to debug this

Thread Tools Search this Thread
Top Forums Shell Programming and Scripting Issue with Bash Audit Command Logger script | Need help to debug this
# 1  
Old 04-04-2020
Issue with Bash Audit Command Logger script | Need help to debug this

Hi Experts,

Request your support
These are step for Bash Audit Command Logger.

I am running below script following below steps.
But the issue is i am not able to generate "" file after syslog service restart which is supposed to be produced by following below procedure.

Below is my system OS version.
Red Hat Enterprise Linux Server release 7.4(Maipo)

Step 1
#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 ('')
#  '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:
#      /var/adm/
#       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 ssh

if [ "${SHELL##*/}" != "bash" ]; then

#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, source it later from "-bash-li"
  #if we would source it from, 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/"' ]; }; then
    declare -rx AUDIT_INCLUDED="$$"

#prompt & color
#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 history

if [ -n "${OSTYPE##solaris*}" ]; then #following not working in solaris
  if groups | grep -q root; then
    declare -x TMOUT=43200                                    #timeout for root's sessions
    chattr +a "$HISTFILE"                                     #set append-only
shopt -s histappend
shopt -s cmdhist

#history substitution ask for a confirmation
shopt -s histverify

#add timestamps in history - obsoleted with logger/syslog
#declare -rx HISTTIMEFORMAT='%F %T '

#enable forward search ('ctrl-s')
if shopt -q login_shell && [ -t 0 ]; then
  stty -ixon

#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 -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                     #initialization
    local AUDIT_CMD="$(fc -l -1 -1)"                        #previous history command
    AUDIT_LASTHISTLINE="${AUDIT_CMD%%+([^ 0-9])*}"
  local AUDIT_CMD="$(history 1)"                            #current history command
  AUDIT_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 syslog
    if [ -n "$AUDIT_SYSLOG" ]; then
      if ! logger -p -t "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])?(\*)+( ))}"; then
        echo error "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])?(\*)+( ))}"
      echo $( date +%F_%H:%M:%S ) "$AUDIT_STR $PWD" "${AUDIT_CMD##*( )?(+([0-9])?(\*)+( ))}" >>/var/log/
    #echo "===cmd:$BASH_COMMAND/subshell:$BASH_SUBSHELL/fc:$(fc -l -1)/history:$(history 1)/histline:${AUDIT_CMD%%+([^ 0-9])*}/last_histline:${AUDIT_LASTHISTLINE}===" #for debugging
    return 0
    return 1
#audit the session closing
function AUDIT_EXIT() {
  local AUDIT_STATUS="$?"
  if [ -n "$AUDIT_SYSLOG" ]; then
    logger -p -t "$AUDIT_STR" "#=== session closed ==="
    echo $( date +%F_%H:%M:%S ) "$AUDIT_STR" "#=== session closed ===" >>/var/log/
  exit "$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" ]; then
  logger -p -t "$AUDIT_STR" "#=== session opened ===" #audit the session openning
  echo $( date +%F_%H:%M:%S ) "$AUDIT_STR" "#=== session opened ===" >>/var/log/
#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


Step 2
for i in /etc/profile /etc/skel/.bashrc /root/.bashrc /home/*/.bashrc; do
  if ! grep -q ". /etc/bash_franzi" "$i"; then
    echo "===updating $i==="
    echo "[ -f /etc/bash_franzi ] && . /etc/bash_franzi #added by francois scheurer" >>"$i"

Step 3
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
#$SystemLogRateLimitInterval 10 
#$SystemLogRateLimitBurst 500
$SystemLogRateLimitInterval 0

Step 4
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/

#then drop them
& ~


Step 5
Restart syslog service
systemctl restart rsyslog
ststemctl restart rsyslog.service
# 2  
Old 04-04-2020
How about using built-in audit systems in Linux and Solaris system ?
Writing scripts can only poorly emulate proper audit system, with easy circumvention.

History file is not audit and can easily be falsified or bypassed completely.

Hope that helps
This User Gave Thanks to Peasant For This Post:
# 3  
Old 04-05-2020
Thank you Peasant,

Achieved the solution by another way..
added "PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -t "$USER[$$] $SSH_CONNECTION")'" in /etc/profile and getting logs stored in messages file in /var/log directory...thank you

Previous Thread | Next Thread
Test Your Knowledge in Computers #321
Difficulty: Medium
DHCP stands for Dynamic Host Configuration Port.
True or False?

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

Logger command not working for one script

Hi, On RHEL 7.2, I created below script in cronjob for every minute. If this process is found to be not running, it should record message in /var/adm/xymessages, start it and send email. #!/bin/bash source /export/home/prodadm/.bash_profile if ; then ... (8 Replies)
Discussion started by: ron323232
8 Replies

2. Shell Programming and Scripting

Piping the "script" command through the logger command.

I use the snippet below in /etc/profile on RHEL Linux to capture command line logging and it all works well and good. Now I'd like to pipe the same output from script through the logger command so it all gets logged to syslog. The only additional code I've added is in bold below (|... (4 Replies)
Discussion started by: woodson2
4 Replies

3. Shell Programming and Scripting

bash ls command file issue

ls -l /md01/EL/MarketData/inbound/ststr/INVENTORY* |tail -5 |awk '{ print $5,$6,$7,$8,$9 }'If I run the above from the command line the output to md_email is formatted correctly as 78213497 May 1 12:50 /md01/EL/MarketData/inbound/ststr/INVENTORY.20120430.PINESTREET.CSV.done 77904740 May 2... (3 Replies)
Discussion started by: smenago
3 Replies

4. Shell Programming and Scripting

syntax issue mysql in bash script

I'm running mysql in a bash script mysql <<EOF query EOF one query is like this: UPDATE $dbname.$prefix"config" SET value = $var WHERE "$prefix" = 'table colname'; with variable but it's giving an error i'm not sure what to put for "$prefix" the table... (3 Replies)
Discussion started by: vanessafan99
3 Replies

5. Shell Programming and Scripting

syntax issue with quotes in mysql command for a bash script

i'm trying to write a bash script that executes a mysql statement mysql -sN -e INSERT INTO "$database"."$tableprefix"users (var1, var2,var3) VALUES (123, '1','') i don't know where to put the quotes it doesnt work with this one: ` it seems i can only put double quotes around the... (0 Replies)
Discussion started by: vanessafan99
0 Replies

6. Shell Programming and Scripting

login audit bash script

I am a bash beginner and I need to write an script to check my users login time. This has to be in a format of : This script has to work on a server to check all the users. I know that I have to use "last" command but I have no idea how to do it. any assistance is appreciated. Thanks (17 Replies)
Discussion started by: bashily
17 Replies

7. AIX

Aix 5.3 Audit issue - not orking properly

Hello Friends, I had enabled the audit and configured for sysadmin user alone in audit config file. but the audit starts logging for root user alone. Attached the conf file. I want the aduit to record only for sysadmin activities.. need your expertise and help in solving the issue. (1 Reply)
Discussion started by: kmvinay
1 Replies

8. Shell Programming and Scripting

Bash script: issue changing directories in script

I am working on a script that checks two arguments at the command line. The first argument is a search pattern, the second can be a file or a directory, if it is a file a second script is called that checks it for the search pattern. If the second argument is a directory, it checks for the search... (5 Replies)
Discussion started by: Breakology
5 Replies

9. UNIX for Advanced & Expert Users

Q on <user> of syslog message generated by logger command

Generally(at least on AIX5.3, Solaris9, OS X)'logger' command would create syslog messages which carry <login name> . On Solaris9, I have experienced two circumstances in which 'logname' command fails. In this circumstance I saw the 'logger' command generated syslog messages which carry... (0 Replies)
Discussion started by: masaki
0 Replies

10. Shell Programming and Scripting

Logger Command

Hi I have a command in a script . /usr/bin/iostat -E I would like to place an entry in /var/adm/messages (via syslog) as a daemon.notice using the logger command but i just cant work out the syntax for this , do I pipe the output of iostat into logger? or is it redirected...can somebody give me... (1 Reply)
Discussion started by: hcclnoodles
1 Replies

Featured Tech Videos