[226] in linux-security and linux-alert archive
Not just "sniffers"
daemon@ATHENA.MIT.EDU (Alexander O. Yuriev)
Fri May 5 14:08:02 1995
Date: Wed, 3 May 1995 01:35:46 -0400 (EDT)
From: "Alexander O. Yuriev" <alex@bach.cis.temple.edu>
To: linux-security@tarsier.cv.nrao.edu
cc: Jeff Uphoff <juphoff@tarsier.cv.nrao.edu>, Olaf Kirch <okir@monad.swb.de>
[This is not really just about Linux but ...]
Couple of weeks ago I received a call from a company that could not
figure out what was going on with their Unix systems. They had found out
that their systems were invaded and were doing some cleaning. Anyway, as
usually, after systems were penetrated attackers installed sniffers on
them. The thing that made it different from any old-style attack was that
killing a sniffer resulted in "rm -rf /*" being executed. Every time a
sysadmin was killing running sniffer system disk was getting viped.
Here's what I found out: the sniffer was guarded by another process
running with a name (hold your breath) rpc.ugidd. Here's the way SOBs work:
a) intruder places rpc.ugidd into the rc.local
b) when rpc.ugidd starts it forks a child and get parents pid.
c) parent tests that child is alive by sending and then receiving
a signal, and after a sucessful "handshake" parent replaces itself
with the actual code of a sniffer.
d) forked child tests if a sniffer is running, and if it is not
executes ("rm -rf /") and sends SIGSEGV to process 1
The obvious way to kill SOB is to send a kill to guardian process and
then kill a sniffer.
The following code is something I wrote yesterday (instead of writing my
paper that is due in less then 9 hours ;-(. The code is a framework of
what can be done to create "immortal" guardian. There are two reasons for
it:
1) I want everybody to be aware of the fact that such programs
exist
2) This is a good start for a guardian of automated procedures that
people run on their systems.
3) You may find a way to break protection that I did not think of.
If you find program like this running on your system, remember: you need
to find all parts of it *before* killing it, otherwise it can fight you
back. NEVER use SIGKILL to stop a process like that - if there's a chance
that there are two guardians that guard each other, sending KILL signal
can and probably will triger the respose. The best way to do is to send
SIGSTOP to all running parts of program (which would suspend processes
but won't allow monitors to detect that guarded process is suspended).
After that you can safely use SIGKILL to finish them (the only problem
is that it does not work in all cases).
- doubleguard.c -
/*
Doubleguard.c is (C) 1995 Alexander O. Yuriev <alex@bach.cis.temple.edu
Computer and Information Science Laboratories,
TEMPLE UNIVERSITY.
This code is hereby placed under General Public License 2.0 or latter
CAREFUL: YOU MAY NEED TO BRING THE MACHINE INTO A SINGLE USER MODE TO
GET RID OF THE PROCESS AFTER THE START
*/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE 2
#endif
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
void vNewProcess(pid_t *, pid_t *);
void realMain(void)
{
pid_t pidtItself;
pid_t pidt2Guard;
pid_t pidtTemp;
pidtItself = getpid();
vNewProcess(&pidtItself,&pidt2Guard);
while(1)
{
if (fProcessAlive(pidt2Guard) == 0)
vNewProcess(&pidtItself,&pidt2Guard);
}
}
void vNewProcess(pid_t *pidtItself, pid_t *pidt2Guard)
{
*pidt2Guard = fork();
if (*pidt2Guard == (pid_t) -1)
{
fprintf(stdout,"\nUnable to fork() a child!\n");
exit(0);
}
else if (*pidt2Guard == (pid_t) 0)
{
*pidtItself = getpid();
*pidt2Guard = getppid();
signal(SIGCLD,SIG_IGN);
}
}
int fProcessAlive(pid_t pidtProcess)
{
if (kill(pidtProcess,0) == 0)
return 1;
return 0;
}
void deattach(void)
{
pid_t pidtNewMain;
pid_t pidtParent;
unsigned i;
fprintf(stdout,"\nDe-attaching main control process");
if ((pidtNewMain = fork()) == - 1 )
{
fprintf(stderr,"\nUnable to deattach main process\n");
perror("deattch() failed");
exit(-1);
}
else if (pidtNewMain == 0)
{
fprintf(stdout,"\nNew Process created... ");
fprintf(stdout,"Determining parent PID...");
pidtParent = getppid();
fprintf(stdout,"PID is %u... ",(unsigned) pidtParent);
fprintf(stdout,"Now killing parent...");
if (kill(pidtParent,SIGKILL))
{
fprintf(stdout,"Hmm.. Can't kill parent. Initiating termination sequence...");
fprintf(stdout,"Child exited...");
exit(1);
}
else
{
fprintf(stdout,"Deattach completed.");
realMain();
}
}
sleep(2);
fprintf(stdout,"\nParent exited by itself. Probably unsuccessful deattach\n");
exit(0);
}
void main(void)
{
signal(SIGCLD,SIG_IGN);
deattach();
}
- - -
=============================================================================
CIS Laboratories email: alex@bach.cis.temple.edu
TEMPLE UNIVERSITY ayuriev@yoda.cis.temple.edu
USA Tel: 1-800-DEV-NULL
http://bach.cis.temple.edu
=============================================================================
[Mod: Not strictly Linux-specific, but it can affect Linux systems
pretty horribly. We've already had some talk about rpc.ugidd here, so
this also fits in somewhat with that topic. I've not really looked at
Alex's code segment yet, so please don't assume that approval of this to
the list also means "approval" of the code. --Jeff.]