[226] in linux-security and linux-alert archive

home help back first fref pref prev next nref lref last post

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.]

home help back first fref pref prev next nref lref last post