To understand this document

This document assumes you need to track the actions of an escalated process, usually a shell. This means someone has asked you to produce an audit trail for some actions taken (by a person) to change a computer system. So we assume you know about processes, directories, and the syslog(3) interface to syslogd(8).

Since you are looking at an escalated process, you must use one of a few ways to get that process escalation to happen: a login as the target user, a su or sudo to the target login, an op command to run a specific program or MAGIC_SHELL, or a super, sud, or pfexec to the login, or lastly your own setuid program.

In all those cases it is possible to force snoopy.so into the LD_PRELOAD environment variable before the shell starts. This lets snoopy log each process created as it execve's a target application. In general this is enough to pass an audit.

How snoopy.so works

The preload file (snoopy.so) traps the system calls that execute a new binary after a process fork's a child. It logs the argument vector and path to the binary, then a credential tag for the escalated session. These two lines allow an audit trail to be constructed for every active escalated session. Once the preload is installed in a running process, all child processes will also see the preload environment, even is the process removes it from environ.

This is easier with op, sudo, or super. It is harder with a raw login, unless your system has login.conf or the like.

Under op's configuration structure just force the environment variable as an attribute of the rule:

mysql	MAGIC_SHELL ;
	groups=^wheel$,^dba$
	uid=mysql gid=dba initgroups=mysql $SHELL $TERM $TERMCAP
	...
	$LD_PRELOAD=/usr/local/lib/snoopy.so

For sudo, in sudoers point env_file to a file that contains the correct setting for your site.

For suprt, in super.tab use something like:

setenv=LD_PRELOAD=/usr/local/lib/snoopy.so

The trace log

The trace log is sent to authlog.info. Configure syslogd to log this to a secure machine, and possibly locally. Then you have 2 copies which must both be compromised to erase any actions.

Here is an example trace session:

ksb$  LD_PRELOAD=/usr/local/lib/snoopy.so ksh -i
$ id -u
11517
$ sync
$ sync
$ uptime
11:49AM  up 377 days, 21:55, 34 users, load averages: 0.02, 0.08, 0.34
$ exit

And here is the trace log from that session:

Oct 30 11:49:05 svr6 snoopy[74689]: ppid=74688 uid=11517 sid=50755 tty=/dev/ttyp9 cwd=/home/sac1/ksb
Oct 30 11:49:05 svr6 snoopy[74689]: +/usr/bin/id id -u
Oct 30 11:49:09 svr6 snoopy[74691]: ppid=74688 uid=11517 sid=50755 tty=/dev/ttyp9 cwd=/home/sac1/ksb
Oct 30 11:49:09 svr6 snoopy[74691]: +/bin/sync sync
Oct 30 11:49:12 svr6 snoopy[74737]: ppid=74688 uid=11517 sid=50755 tty=/dev/ttyp9 cwd=/home/sac1/ksb
Oct 30 11:49:12 svr6 snoopy[74737]: +/bin/sync sync
Oct 30 11:49:16 svr6 snoopy[74744]: ppid=74688 uid=11517 sid=50755 tty=/dev/ttyp9 cwd=/home/sac1/ksb
Oct 30 11:49:16 svr6 snoopy[74744]: +/usr/bin/uptime uptime
The trace shows the new process's parent pid, uid, session-id, tty, and current working directory. Then the path to the new command (prefixed with a +, *, or ! and all the arguments.
+
the line is the complete command, and tracing continues under that process
*
the arguments were truncated, and tracing continues
!
the program is either setuid or setgid, which may prevent the preload from tracing beyond process

Circumventing the preload

There are four ways to circumvent the preload, all of them require intent on the part of the driver:
Run a statically linked shell
Since most programs are dynamically linked now days, you really have to be trying to find one (or make one).
Use chmod to preserve a setuid/setgid bit and exit the shell
This shows clean intent to suborn the system.
Run another setuid (setgid) program
For example newgrp. Which won't allow the LD_PRELOAD to pass to the new shell.
Remove the snoopy.so file
If you really want to disable the trace, just remove (or move) the dynamic module. Then the preload silently fails.
Find a way to compromise LD_PRELOAD
There is a less obvious way to `unset' the preload variable. But I don't think it is a good idea to explain how here, since it doesn't leave as clear an trail as the others do.

See also

The op HTML document.
$Id: snoopy.html,v 1.2 2012/10/30 23:07:48 ksb Exp $