Author: WhiteHat Wargame
Points: 100
Category: pwn


ssh pwnguest@ 1094



part 1

We have been given shell access to a remote machine. The pwnguest user was extremely limited – no access to anything except the home directory. There lied two particularly interesting files:

  • flag.txt, which was owned by root and readable only by pwnreader group
  • and signal, which was executable by the current user, owned by pwnreader group and had SGID set.

This has given a clear idea what was the intended solution to the task.

However, …

Broken task

The machine was running an outdated kernel, Linux ubuntu 3.13.0-32-generic be exact, with a known privilege escalation exploit. Here are some resources on this topic:

The not necessarily intended solution

The easiest solution was to obtain a root shell using the aforementioned public exploit. The server has quickly been torn down. This gave an irresistable impression that, in fact one of the teams did obtain a root shell and they have also decided to sabotage the contest and took the machine down, preventing the other participants from scoring points.


part 2 – the intended solution

Because the user available was extremely limited – no access to /dev (and therefore /dev/null), scp was going mad. This has not been a serious limitation, the code for this task could be downloaded using a workaround, for example:
ssh -p1094 -lpwnguest dd if=/home/ubuntu/signal >/tmp/signal

The file is 32-bit ELF executable binary:
signal: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=cb0c7cda48b50c413181c4641fe98efe840f3364, not stripped

When executed, it installs a custom SIGINT handler, runs several threads, asks for input and when signalled with INT, sleeps, does some string operations and prints some garbage.

Simplified C pseudocode for the signal handler looks like:

It is fairly easy to spot several flaws in this function.

  1. At line 22 there is a print format string vulnerability possible.
  2. At line 21 there is a stack buffer overflow vulnerability.
  3. At line 18 there is another stack buffer vulnerability.

We have decided to exploit the third option, however the second one overwrites the stack with shared data. Therefore a controlled user input must be safeguarded with a NULL terminating byte.

The binary has a non-executable stack and no canaries.

Therefore it is not possible to inject shellcode onto the stack.

Searching the binary .rel.plt section for possible exploit entry points with readelf

yields nothing of interest (no system or execve).

So the last resort will be a classic return to libc attack.

To perform it

both libc and libpthread from the original system will be required(Unfortunately the system was and is down, so we were unable to retrieve the libraries).

The signal function actually loops through the given name, parsing two characters at a time as a hexadecimal value and writes it into a buffer on the stack, without checking for the buffer length. So the goal is to provide enough data to fill the buffer, overflow it and build a valid stack frame for a libc function that executes shell, system@glibc in this case, but, for example, execve would also work.

The required input is: 4142434445464748495041424344454647484950414243444546474849504142434400which becomes

on the stack. Characters from the first C to J are the addresses of system@glibc and the pointer to it’s argument – "/bin/sh".

To retrieve the aforementioned addresses gdb can be used:

The architecture is x86 and therefore pointers are in little endian convention, so the addresses must be written in reverse.

Finally, the exploit is: 4142censoredCensored41424344454647484950414243444546474849504142434400

Tagged with:

Leave a Reply

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