Software, technology, sysadmin war stories, and more. Feed
Thursday, May 26, 2011

Sneaky shell hacks

Many years ago, I worked as the sole sysadmin for a concern with about 40 Linux boxes spread across a few dozen sites. At one point, I started worrying about the wrong sorts of people getting root on my machines via administrative decrees who might then break things and proceed to blame me for it. I figured they might know how to "unset HISTFILE" or "rm .bash_history" and might be able to run a sniffer, but they wouldn't catch anything more sophisticated than that.

I decided I needed to add something to the shell itself which would throw all commands run as root over the wall to another system. It would still work even if you turned off HISTFILE or did other craziness, since it was early enough in the chain that it saw all of your activity.

I decided to write it as a single function in an object file which would then be linked into the shell. The shell itself just needed one small modification to call my function in the right place. My one function used a few static variables to keep track of whether it had been initialized or not and did the right thing to further minimize the impact on the shell's normal code.

One thing that worried me was that some of it might stand out in "strings". To avoid obvious problems of that sort, I avoided using any kind of host name or DNS at all. I also passed on baking in a dotted quad IP address, instead just putting the raw value in there as a #define.

Then there was the matter of looking up the "USER" environment variable to see if this was a shell I cared about (root). I recycled a variable that needed to exist for other reasons and rigged it like this:

cookie[0] = 'U';
cookie[1] = 'S';
cookie[2] = 'E';
cookie[3] = 'R';
cookie[4] = '\0';
un = getenv(cookie);

In a hex dump of the final binary, it looked like this -- not the sort of thing a casual scan would detect:

00000070 |<...U...=..S..>.|
00000080 |..E..?...R..@...|

In addition to all of this, it also threw traffic over the network using the UDP flavor of a port number which was already being used via TCP. The machine in question had a lot of PPTP traffic on port 1723/tcp, so this thing tattled on port 1723/udp. Anyone looking at a packet trace would probably do "not port 1723" to avoid the so-called known-good traffic, and thus miss my stuff entirely.

Obviously, I wasn't about to rely on that to avoid detection, so I further had it mangle the outgoing data using a really dumb xor adjustment. The point was to make it look relatively uninteresting so it wouldn't stand out in "strings" or a packet trace, and xoring with a few rotating bit patterns did the job nicely. It didn't have to be perfect.

So enough technical gunk. The obvious question is: did it accomplish anything? I say it did. How about snooping on one of the users?

cd ~(username-removed)
cd mail
ls -l
less saved-messages
ls -l
less sent-mail 
grep user sent-mail 

Or there's such brilliant stuff as this...

chmod messages.7.gz 777

... clearly not someone you want to have root on your machine.