diff --git a/README.md b/README.md index 249a3c0..eb2dc13 100644 --- a/README.md +++ b/README.md @@ -118,91 +118,10 @@ SEE ALSO # Auditshell -Auditshell submits the typescript and the timings of a patched util-linux/script binary to syslog which prevents modification by regular terminal users. -The logged information can also be forwarded to secured logging servers using standard syslog logfile distribution. +In former times there was was a patch for [util-linux](https://github.com/karelzak/util-linux) and some shell scripts here to implement a auditshell. +(you can find this at tag [before-auditshell-removal](https://github.com/scoopex/scriptreplay_ng/releases/tag/before-auditshell-removal)) -## Installation of "auditshell" +There is a new attemt to implement this by using the [apparmor security framework](http://wiki.apparmor.net/index.php/Main_Page). +Review the [Bastion Host Guthub Project](https://github.com/scoopex/puppet-bastion_host). -The following instructions describe the procedure how to install a audit shell in combination with -the scriptreplay utility. - - * Install tools - - ```bash - cp scriptreplay helpers/auditshell helpers/auditshell_create_sessionfiles /usr/local/bin/ - chown root:root /usr/local/bin/{scriptreplay,auditshell,auditshell_create_sessionfiles} - chmod 755 /usr/local/bin/{scriptreplay,auditshell,auditshell_create_sessionfiles} - ``` - * Install Build dependencies - - ```bash - apt-get install libtoolize libtool autopoint pkg-config make gcc - zypper install libtool gettext-tools pkg-config make gcc autoconf automake - ``` - * Patch and install custom "script" implementation - - ```bash - cd helpers/ - wget https://www.kernel.org/pub/linux/utils/util-linux/v2.23/util-linux-2.23.tar.gz - tar zxvf util-linux-2.23.tar.gz - cd util-linux-2.23/ - patch -p1 < ../auditshell_script.patch - ./configure --without-ncurses --disable-nls - make - cp script /usr/local/bin/ - chown root:root /usr/local/bin/script - chmod 755 /usr/local/bin/script - ``` - * Syslog configuration: - * Disable string escaping on system which are using rsyslogd (i.e. Ubuntu systems with rsyslogd) - * Redirect the auditshell logs to another logfile using syslog configuration - * Change shell of user - - ```bash - chsh -s /usr/local/bin/auditshell - ``` - * Prevent regular users to change their shell - * Remove all shells from /etc/shells - * Remove all perrmissions from the the /usr/bin/chsh binary - * Use the FAKE_SHELL variable in /etc/login.defs - -## Watch auditshell sessions - - * Start session, and execute commands - * Extract session files - - ```bash - /usr/local/bin/auditshell_create_sessionfiles /var/log/messages /tmp/foo - ``` - * Replay session - - ```bash - scriptreplay -t /tmp/foo/2013-09-11_18-47-45.user1.11931.timing \ - /tmp/foo/2013-09-11_18-47-45.user1.11931.typescript - ``` - -## Logging configuration - -### Syslog-NG Configuration - - - * Edit /etc/syslog-ng/syslog-ng.conf - ``` - # define audit shell filter - filter f_auditshell { match('^auditshell'); }; - # enhance existing messages filter by f_auditshell to ignore messages matched by f_auditshell - filter f_messages { not facility(news, mail) and not filter(f_iptables) and not filter(f_auditshell); }; - - # define a log-sink for auditshell - destination auditshell { - file ("/var/log/auditshell/$YEAR-$MONTH/$FACILITY-$YEAR-$MONTH-$DAY" - owner(root) group(root) perm(0600) dir_perm(0700) create_dirs(yes) - ); - }; - log { source(src); filter(f_auditshell); destination(auditshell); }; - ``` - * Restart Syslogd - ``` - /etc/init.d/syslog restart - ``` diff --git a/helpers/auditshell b/helpers/auditshell deleted file mode 100755 index c7023e4..0000000 --- a/helpers/auditshell +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -l - -IDENT="`date --date="today" "+%Y-%m-%d_%H-%M-%S"`.`whoami`.$$" - -# This is a file transfer, no audit shell neccessary -if (echo "$@"|egrep -q "^-c.*scp.*$");then - logger -t auditshell.filetransfer.${IDENT} <<< "/bin/sh $@" - exec /bin/sh "$@" -# Remote command execution -elif (echo "$@"|egrep -q "^-c.*$");then - logger -t auditshell.remotecommand.${IDENT} <<< "/bin/bash $@" - exec /bin/bash "$@" -fi - -TYPESCRIPT="auditshell.typescript.${IDENT}" -TIMING="auditshell.timing.${IDENT}" - -export SHELL=/bin/bash - -cat < >(base64|logger -t $TYPESCRIPT) \ - 2> >(base64|logger -t $TIMING) -echo "Finish" diff --git a/helpers/auditshell_create_sessionfiles b/helpers/auditshell_create_sessionfiles deleted file mode 100755 index bf23113..0000000 --- a/helpers/auditshell_create_sessionfiles +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use FileHandle; - -my $file = shift(); -my $dir = shift(); - -if ( (!defined $file) || (!defined $file) ){ - print "auditshell_create_sessionfiles \n"; - exit(1); -} - -chdir($dir); - -unless(chdir($dir)) -{ - die "Error: Can't change directory!: $!"; -} - -open( INFILE, "<$file" ) || die "input-file '$file' could not be opened"; - -my $fdcache = {}; - -while (my $zeile = ) { - if ($zeile =~m /auditshell\.(typescript|timing)\.(.*?): (.*)$/){ - chomp($zeile); - my $type = $1; - my $ident = $2; - my $line = $3; - - if ( !exists $fdcache->{$ident}){ - $fdcache->{$ident} = {}; - print "Create $ident.typescript.base64\n"; - $fdcache->{$ident}->{typescript} = FileHandle->new("> $ident.typescript.base64"); - print "Create $ident.timing.base64\n"; - $fdcache->{$ident}->{timing} = FileHandle->new("> $ident.timing.base64"); - } - - my $fd = $fdcache->{$ident}->{$type}; - print $fd $line."\n"; - } -} - -close(INFILE); - -foreach my $ident(keys %{$fdcache}){ - close $fdcache->{$ident}->{typescript}; - close $fdcache->{$ident}->{timing}; - system("base64 -d $ident.typescript.base64 |gzip -c > $ident.typescript.gz"); - system("base64 -d $ident.timing.base64 |gzip -c > $ident.timing.gz"); - unlink("$ident.timing.base64"); - unlink("$ident.typescript.base64"); - print "removed $ident.typescript.base64, created $ident.typescript.gz\n"; - print "removed $ident.timing.base64, created $ident.timing.gz\n"; -} diff --git a/helpers/auditshell_script-upstream.patch b/helpers/auditshell_script-upstream.patch deleted file mode 100644 index e3f2ff0..0000000 --- a/helpers/auditshell_script-upstream.patch +++ /dev/null @@ -1,131 +0,0 @@ -diff --git a/term-utils/script.1 b/term-utils/script.1 -index 5c366b129..33789a927 100644 ---- a/term-utils/script.1 -+++ b/term-utils/script.1 -@@ -86,14 +86,21 @@ or symbolic link. The command will follow a symbolic link. - Be quiet (do not write start and done messages to either standard output - or the typescript file). - .TP --\fB\-t\fR, \fB\-\-timing\fR[=\fIfile\fR] --Output timing data to standard error, or to -+\fB\-t\fR, \fB\-\-timing\fR[=\fIfile|descriptor\fR] -+Output timing data to standard error, or to a - .I file -+or -+.I descriptor - when given. This data contains two fields, separated by a space. The first - field indicates how much time elapsed since the previous output. The second - field indicates how many characters were output this time. This information - can be used to replay typescripts with realistic typing and output delays. - .TP -+\fB\-d\fR, \fB\-\-descriptor\fR -+Use this option in combination with -+.I --timing -+for using the given resource as a file descriptor number as destination for timing data -+.TP - \fB\-V\fR, \fB\-\-version\fR - Display version information and exit. - .TP -diff --git a/term-utils/script.c b/term-utils/script.c -index d1ef07203..4b56b671d 100644 ---- a/term-utils/script.c -+++ b/term-utils/script.c -@@ -116,7 +116,8 @@ struct script_control { - #endif - unsigned int - append:1, /* append output */ -- rc_wanted:1, /* return child exit value */ -+ tsdesc:1, /* output typescript to file descriptor */ -+ rc_wanted:1, /* return child exit value */ - flush:1, /* flush after each write */ - quiet:1, /* suppress most output */ - timing:1, /* include timing file */ -@@ -169,6 +170,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out) - " --force use output file even when it is a link\n" - " -q, --quiet be quiet\n" - " -t, --timing[=] output timing data to stderr (or to FILE)\n" -+ " -d, --descriptor[=] output timing data to a defined descriptor number\n" - " -V, --version output version information and exit\n" - " -h, --help display this help and exit\n\n"), out); - -@@ -195,8 +197,14 @@ static void __attribute__((__noreturn__)) done(struct script_control *ctl) - - if (ctl->isterm) - tcsetattr(STDIN_FILENO, TCSADRAIN, &ctl->attrs); -- if (!ctl->quiet && ctl->typescriptfp) -- printf(_("Script done, file is %s\n"), ctl->fname); -+ if (!ctl->quiet && ctl->typescriptfp) { -+ if (ctl->tsdesc == 1) { -+ printf(_("Script done, file descriptor number is %s\n"), ctl->fname); -+ }else{ -+ printf(_("Script done, file is %s\n"), ctl->fname); -+ } -+ } -+ - #ifdef HAVE_LIBUTEMPTER - if (ctl->master >= 0) - utempter_remove_record(ctl->master); -@@ -407,6 +415,7 @@ static void do_io(struct script_control *ctl) - int ret, ignore_stdin = 0, eof = 0; - time_t tvec = script_time((time_t *)NULL); - char buf[128]; -+ int fdnum_typescript = 0; - enum { - POLLFD_SIGNAL = 0, - POLLFD_MASTER, -@@ -420,7 +429,18 @@ static void do_io(struct script_control *ctl) - }; - - -- if ((ctl->typescriptfp = -+ -+ if (ctl->tsdesc == 1){ -+ fdnum_typescript = atoi(ctl->fname); -+ if (fdnum_typescript == 0){ -+ warn(_("file descriptor is not a number")); -+ fail(ctl); -+ } -+ if ((ctl->typescriptfp = fdopen (fdnum_typescript, "w")) == NULL) { -+ warn(_("cannot open fd %s"), ctl->fname); -+ fail(ctl); -+ } -+ }else if ((ctl->typescriptfp = - fopen(ctl->fname, ctl->append ? "a" UL_CLOEXECSTR : "w" UL_CLOEXECSTR)) == NULL) { - warn(_("cannot open %s"), ctl->fname); - fail(ctl); -@@ -678,6 +698,7 @@ int main(int argc, char **argv) - {"force", no_argument, NULL, FORCE_OPTION,}, - {"quiet", no_argument, NULL, 'q'}, - {"timing", optional_argument, NULL, 't'}, -+ {"descriptor", no_argument, NULL, 'd' }, - {"version", no_argument, NULL, 'V'}, - {"help", no_argument, NULL, 'h'}, - {NULL, 0, NULL, 0} -@@ -698,8 +719,10 @@ int main(int argc, char **argv) - - script_init_debug(); - -- while ((ch = getopt_long(argc, argv, "ac:efqt::Vh", longopts, NULL)) != -1) -+ while ((ch = getopt_long(argc, argv, "dac:efqt::Vh", longopts, NULL)) != -1) - switch (ch) { -+ case 'd': -+ ctl.tsdesc = 1; - case 'a': - ctl.append = 1; - break; -@@ -748,8 +771,13 @@ int main(int argc, char **argv) - ctl.shell = _PATH_BSHELL; - - getmaster(&ctl); -- if (!ctl.quiet) -- printf(_("Script started, file is %s\n"), ctl.fname); -+ if (!ctl.quiet) { -+ if (ctl.tsdesc == 1) { -+ printf(_("Script started, file descriptor number is %s\n"), ctl.fname); -+ }else{ -+ printf(_("Script started, file is %s\n"), ctl.fname); -+ } -+ } - fixtty(&ctl); - - #ifdef HAVE_LIBUTEMPTER diff --git a/helpers/auditshell_script.patch b/helpers/auditshell_script.patch deleted file mode 100644 index bbe3533..0000000 --- a/helpers/auditshell_script.patch +++ /dev/null @@ -1,126 +0,0 @@ -diff --git a/term-utils/script.1 b/term-utils/script.1 -index 1e430d8..1808a37 100644 ---- a/term-utils/script.1 -+++ b/term-utils/script.1 -@@ -84,14 +84,21 @@ or symbolic link. The command will follow a symbolic link. - \fB\-q\fR, \fB\-\-quiet\fR - Be quiet. - .TP --\fB\-t\fR, \fB\-\-timing\fR[=\fIfile\fR] --Output timing data to standard error, or to -+\fB\-t\fR, \fB\-\-timing\fR[=\fIfile|descriptor\fR] -+Output timing data to standard error, or to a - .I file -+or -+.I descriptor - when given. This data contains two fields, separated by a space. The first - field indicates how much time elapsed since the previous output. The second - field indicates how many characters were output this time. This information - can be used to replay typescripts with realistic typing and output delays. - .TP -+\fB\-d\fR, \fB\-\-descriptor\fR -+Use this option in combination with -+.I --timing -+for using the given resource as a file descriptor number as destination for timing data -+.TP - \fB\-V\fR, \fB\-\-version\fR - Output version information and exit. - .TP -diff --git a/term-utils/script.c b/term-utils/script.c -index 242b815..778fbbe 100644 ---- a/term-utils/script.c -+++ b/term-utils/script.c -@@ -101,12 +101,14 @@ int l; - char line[] = "/dev/ptyXX"; - #endif - int aflg = 0; -+int dflg = 0; - char *cflg = NULL; - int eflg = 0; - int fflg = 0; - int qflg = 0; - int tflg = 0; - int forceflg = 0; -+int fdnum_typescript = 0; - - int die; - int resized; -@@ -171,6 +173,7 @@ main(int argc, char **argv) { - { "force", no_argument, NULL, FORCE_OPTION, }, - { "quiet", no_argument, NULL, 'q' }, - { "timing", optional_argument, NULL, 't' }, -+ { "descriptor", no_argument, NULL, 'd' }, - { "version", no_argument, NULL, 'V' }, - { "help", no_argument, NULL, 'h' }, - { NULL, 0, NULL, 0 } -@@ -182,8 +185,10 @@ main(int argc, char **argv) { - textdomain(PACKAGE); - atexit(close_stdout); - -- while ((ch = getopt_long(argc, argv, "ac:efqt::Vh", longopts, NULL)) != -1) -+ while ((ch = getopt_long(argc, argv, "dac:efqt::Vh", longopts, NULL)) != -1) - switch(ch) { -+ case 'd': -+ dflg = 1; - case 'a': - aflg = 1; - break; -@@ -229,7 +234,22 @@ main(int argc, char **argv) { - fname = DEFAULT_OUTPUT; - die_if_link(fname); - } -- if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) { -+ -+ -+ if (dflg == 1){ -+ -+ fdnum_typescript = atoi(fname); -+ -+ if (fdnum_typescript == 0){ -+ warn(_("file descriptor is not a number")); -+ fail(); -+ } -+ -+ if ((fscript = fdopen (fdnum_typescript, "w")) == NULL) { -+ warn(_("cannot open fd %s"), fname); -+ fail(); -+ } -+ }else if((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) { - warn(_("cannot open %s"), fname); - fail(); - } -@@ -239,8 +259,15 @@ main(int argc, char **argv) { - shell = _PATH_BSHELL; - - getmaster(); -- if (!qflg) -+ -+ if (!qflg) { -+ if (dflg == 1){ -+ printf(_("Script started, file descriptor number is %s\n"), fname); -+ }else{ - printf(_("Script started, file is %s\n"), fname); -+ } -+ } -+ - fixtty(); - - #ifdef HAVE_LIBUTEMPTER -@@ -495,8 +520,16 @@ done(void) { - master = -1; - } else { - tcsetattr(STDIN_FILENO, TCSADRAIN, &tt); -- if (!qflg) -+ -+ if (!qflg) { -+ if (dflg == 1){ -+ printf(_("Script done, file descriptor number is %s\n"), fname); -+ }else{ - printf(_("Script done, file is %s\n"), fname); -+ } -+ } -+ -+ - #ifdef HAVE_LIBUTEMPTER - if (master >= 0) - utempter_remove_record(master);