Browse Source

Removing the auditshell

pull/5/head
Marc Schoechlin 8 years ago
parent
commit
2c43e573ab
5 changed files with 4 additions and 436 deletions
  1. +4
    -85
      README.md
  2. +0
    -37
      helpers/auditshell
  3. +0
    -57
      helpers/auditshell_create_sessionfiles
  4. +0
    -131
      helpers/auditshell_script-upstream.patch
  5. +0
    -126
      helpers/auditshell_script.patch

+ 4
- 85
README.md View File

@ -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 <user>
```
* 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
```

+ 0
- 37
helpers/auditshell View File

@ -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 <<EOF
_ _ _ ____ ___ _____ ____ _ _ _____ _ _
/ \ | | | | _ \_ _|_ _/ ___|| | | | ____| | | |
/ _ \| | | | | | | | | | \___ \| |_| | _| | | | |
/ ___ \ |_| | |_| | | | | ___) | _ | |___| |___| |___
/_/ \_\___/|____/___| |_| |____/|_| |_|_____|_____|_____|
NOTE: This shell session will be recorded
AUDIT KEY: $IDENT
EOF
/usr/local/bin/script -d -e -f -q -t 5 \
5> >(base64|logger -t $TYPESCRIPT) \
2> >(base64|logger -t $TIMING)
echo "Finish"

+ 0
- 57
helpers/auditshell_create_sessionfiles View File

@ -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 <logfile> <dir>\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 = <INFILE>) {
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";
}

+ 0
- 131
helpers/auditshell_script-upstream.patch View File

@ -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[=<file>] output timing data to stderr (or to FILE)\n"
+ " -d, --descriptor[=<n>] 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

+ 0
- 126
helpers/auditshell_script.patch View File

@ -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);

Loading…
Cancel
Save