                 check_ps v1.1 -- RootKit 'ps' program detector

RCS info: $Id: README,v 1.3 1998/05/07 01:01:12 dps Exp $

HISTORY

On September 17, 1997, Duncan Simpson (D.P.Simpson@ECS.SOTON.AC.UK)
posted a program called check_ps to the Bugtraq mailing list. The
program was in response to having a "rootkit" installed on one of his
machines. Rootkit's typically include a hacked version of the 'ps'
program that will not list specific processes, thereby hiding them
from the SysAdmin and other users of the system (e.g. so the hacker
can run a version of Crack without being caught).

This program runs in the background, periodically executing the 'ps'
program and checking its contents against the list of processes in a
SysV-style /proc file system. Any processes that appear in /proc and
DO NOT appear in the information returned by 'ps' are logged and can
even be killed. Any processes that appear in the output of 'ps' and
not /proc are also reported (this might be done to give you the
impression that syslogd is running when it is not, for
example). Restriction: non-extant processes with non-fixed pids
reported are not detected but easy for humans to detect.

This version with minor additions got called version 1.0, despite
a number of serious security problems (part of the reason I posted
asking for comments). The only additions were
        1) Can be run as a one-time check, rather than as a continuous
           daemon process.

        2) Can log to an alternative log file so that the cracker will not
           see the messages from check_ps.

        3) Can just log that the hidden processes exist, rather than killing
           them outright and arousing the suspicion of the cracker.

Subsequently I did some fixes and got provoked into creating this
version by a message from NASA (informing me that CIAC and various
others where interested...obviously this baby fills a need). The code
has been improved and various nasty security problems eliminated (it
ran ps as root and if ps has been hacked that is obvious a *bad
idea*).

If you use linux you get sophisitcated information about what files
the processes have open, including the source and destination of the
TCP connection to your machine in many cases (even if you use
telnet). You also learn the port on your machine, thus which service
got cracked. If the cracker is using UDP this does not work of
course. It should know about IPX connections too... sadly a bug seems
to lock the superuser out of some /proc/<pid>/fd directories so their
information remains private.

N.B. The program is *only* effective if the cracker fails to notice it
until it has told you and done whatever level of zapping you ask it to
perform. OTOH A known clean version in single shot mode might be handy
in an incident response situation, I guess.


INSTALLATION AND TESTING


Extract the check_ps-1.1.tar.gz file into a source directory:

        $ cd /usr/local/src
        $ tar xzf <download-dir>/check_ps-1.1.tar.gz  (GNU tar)
        $ cd check-ps-1.1
        $ ./configure

Where "<download-dir>" is the directory you downloaded the
check_ps-1.1.tar.gz file to. Run the configure script to probe your
system for the right settings. The items this fixes are marked with
(***auto configure***). The script is generated by GNU autoconf from
configure.in, aclocal.m4 and acconfig.h, which you can verify to
ensure I did not put any evil trojans in that script. Note that
configure is smart enough to look up user and group ids by reading
/etc/passwd and /etc/group.

System specific but site indepent settings are largely stored in
config.h which is an edited copy of config.h.in, a job best left to
./configure.

Edit the header lines to suit your system. Items marked CHANGE THIS
must be changed *or all hell will be let loose*. Major items are
cfg_check.h:
	PS_PATH		path of ps on your system (***auto configure***)
	PS_ARGS		argument to list all processes (***auto configure***)
	PROCPATH	path of proc filing system for fetching pids
	RECHECKNAP	Time to sleep before rechecking PS (once per cycle
			maximum) if something suspect appears in secs.
			(default 1).

cfg_smtp.h:
	RECIPIENTS	comma seperated list of recipients in quotes.
			Change this or get flamed *every* time I get an
			email you should have got. (CHANGE THIS)
	ADDR		Address of machine to use (IP numbers)
	SENDER		Email sender (CHANGE THIS)
	SUBJECT		Email subject (default "problem report")
	MACHINE		Machine name to give in HELO command. (CHANGE THIS)

cfg_log.h:
	Nothing major here.

cfg_prog.h:
	HAVE_FSUID	Define this if you have setfsuid(2)
	DAEMON_ZAP_MD	Deamon mode zap behavour.
			0=Do nothing
			1=Send SIGSTOP
			2=Send SIGKILL (default)

cfg_linux.h:
	Only revelant on linux and minor.

There are also some esoteric items that you probably want to leave
alone. If you are an incorrigable #define editor the values are
cfg_check.h:
	MAX_PROCS	max processes PS is allowed (default 1)
	DEFUID		uid to runs ps as (***auto configure***)
	DEFGID		gid to runs ps as (***auto configure***)
	TOLERANCE	Max leading white space/trailing junk (default 5120)
	NUM_TOLERANCE	Max digits in pid (default 10)
	SHORTNAP	Time to sleep before re-trying getting process id
			list (the real one from /proc) in secs. (default 50)
	LONGNAP		Time to sleep between checks in secs (default 600)
	PS_MAXTIME	Time to wait before killing PS in secs (default 300)
	DISABLE_TIME	Time to sleep if ps gets killed by above timeout in
			secs (default 1200).
	PROCFNAME_MAX	Buffer size for making sure a pid is still active,
			used by the hidden pid tester to avoid false +ve
			cases due to races. Be generous. (Default 1024).

cfg_smtp.h:
	USE_GETHOST	define this if you are stupid enough to use a hostname
	SMTP_MACHINE	name of machine to use if the above is defined
	SMTP_PORT	port to use to send mail (default IPPORT_SMTP aka. 25)
	TIMEOUT		SMTP response time in secs (default 300 which is <RFC
			but too long might give the game away).

cfg_log.h:
	INITIAL_BUFFER	Initial buffer size (default 1024)
	TEXT_INC	Increment size when expanding buffer (default 512)
	TEXT_MAX	Biggest message to send you. (default 10240)
	MAXLINE		longest line to support (default 4096)

cfg_prog.h:
	DAEMON_ARGV	argv to exec program with (defualt { "httpd", NULL })
	DAEMON_UID	real user id to set (***auto configure***)
	DAEMON_GD	real group id to set (***auto configure***)

cfg_linux.h:
	FNAME_LEN	maximum filename length (default 200)
	STAT_BYTES	bytes to read from /proc/<pid>/stat (default 2000)
	CMD_BYTES	bytes to read from /proc/<pid>/cmdline (default 3000)


numbuf.h
	MAXX_NUMS	Maximum numbers to accept, to stop DoS attacks
		        (default 10000)
	INITIAL_NUMS	Initial number buffer size (default 200)
	INC		Number of numbers to add when expanding (default 50)


Check the Makefile for your operating system and version of the C
compiler.  As generated it is set for a generic ANSI C compiler and
prefers procs fs over using the ps database (which has the problem
that support is not implemented yet). Compile check_ps with the 'make'
command.

A simple shell script, called 'fake_ps', has been provided so that you
can test check_ps without actually having to install a rootkit
yourself. 'fake_ps' just runs the ps command through an 'egrep' filter
to block out one or more processes, emulating a rootkit ps. Here is
the fake_ps script in its entirety:

-------------------------------------------------------------------------------
#!/bin/sh
#
# A simple little fake ps to test check_ps with
#
# WARNING: Using this little shell script to test check_ps may generate some
# spurious 'hacked ps' messages because the AVOID string will also block out
# the call to egrep in the pipeline. The extra process will also generate a
# message (unless there really is such a process, which I hope not).
#
# Fake pid added by Duncan. Output is "ps ax" format on Linux.
REALPS="/bin/ps"
AVOID="sleep"
($REALPS $* | egrep -v $AVOID); echo " 5999  ?  R    0:00 not_such_process"
-------------------------------------------------------------------------------

Probably the easiest and safest way to test check_ps is to put a 'sleep'
command in the background and then try to find it. Linux offers the best
performance, other systems will not tell you all the detial about the
"hidden" pid and related processes; to fix this write a processor for
/proc/<pid> on your system (linux.c is probably a good start).

        $ sleep 1200 &
        [1] 512
        $ ./check_ps
        Dec 03 11:54:32 Checking /usr/local/src/check_ps-1.0/fake_ps ax
        Dec 03 11:54:33 hacked ps: pid 512 not matched
	Dec 03 11:54:43 hacked ps: fake pid 5999 inserted

In this example, process 512 was detected and reported as a hidden
process id.  The message that saying 'fake pid ... inserted'
illustrate another feature of check_ps: it reports non-existent
processes that are being listed by the ps command. Rootkit ps programs
may do this, for example, to make it look like a syslog daemon is
running, when in fact it is not.

<News from Duncan>

If a non-extant process id is reported by ps in two sucessive checks
it is reported. This is designed to stop race conditions generating
false hits but detect things like syslogd insertions. These would be
obvious to you if the attacker used different pids each time you ran
ps!  Remember that the program is not a subsitute for you, just a
simple trap for those who hack ps and fail to notice it. (If this tool
becomes widely avialable someone will probably trojanize a version of
this program...)

I was lucky: the attacker failed to deploy the rootkit
correctly. After netstat dumped core twice I applied strace and saw
untoward system calls. Investigation revealed the rootkit. After
determining the damage and re-installing software from known clean
sources I added a cron job to remove the rootkit control files every 5
minutes (no trojan version of rm supplied). I think ls and ps were not
trojanize but I used "echo *" and "echo .*" just in case... and
re-installed ls from a clean source. I checked ps using echo * in
/proc.

Man page deliberately absent so no fool installs it! (Installing it
would make "man check_ps" an easy way of detecting the program, which is
obviously bad!). The code is very resistant to races now.

<End news from Duncan>

COMMAND LINE OPTIONS

check_ps has the following command line options:

        -d              Run as a daemon

        -k              Kill hidden processes (uses KILL)

	-h		Stop to hidden processes (uses STOP).

        -l [file]       Log messages to [file] rather than to the syslog

	-V 		version information

By default, check_ps will run only once, not as a daemon; it will not
kill the hidden processes; and it will log its messages to standard
output. See the example given above. Note that daemon mode always uses
email even if you use the -l option---this stops crackers do anything
about it. The email is innocuos (an email titled "problem report" from
MAILER-DAEMON) bar the content. If you have a permanent connection you
can afford a dail-up account to ensure you get this email! The program
talks to port 25 directly to avoid all the system logs and programs.

To run as a daemon, kill processes and log to execute the following:

        $ check_ps -dk

BUGS

Check_ps tries to set itself up as hard to kill, totally ignoring most
signals and restarting itself on others. However, a cracker that has
installed a rootkit has by definition gotten root access and can just
as easily kill the program with a SIGKILL ('kill -9 pid'). So maybe
the code to avoid being killed is overkill (?).

Daemon mode can *only* use email. This is most secure and sleathly though.

Code to kill the parent of the hidden process, originally given by Duncan
Simpson, but #ifdef'd out, has not yet been implemented.

Code to "mask" the check_ps process with DAEMON_ARGV not yet implemented.
For now, change the name of the executable in the Makefile to something
innocuous, like "lpd" or "httpd".

AUTHORS

Original check_ps.c, Duncan Simpson (D.P.Simpson@ECS.SOTON.AC.UK).

Code to implement command line options, README, and fake_ps script, 
Lee E. Brotzman, Allied Technology Group, Inc., NASA Incident Response 
Capability (NASIRC), leb@nasirc.hq.nasa.gov.

Further Changes and lots of security fixes to original version, Duncan
Simpson. Yet more race fixes by Duncan Simspon... I kill I have them
all now.
