Startcon 2016 (and Late Writeup – 12 / Format String)

Last weekend, I attended the Startcon 2016 event. This event was a startup conference, pitched at both entrepreneurs and venture capitalists. As part of the event, there was also a “Security Cup” CTF, which lasted for most of Saturday. I decided to form an alliance between Farming Simulator 2015, Capture the Swag and K17 to tackle this event: together, we entered as “farmingsimulator2015 – Swag Pack DLC”, with the intention of taking first prize.

Unfortunately, Freelancer refused us entry as one team, and asked us to split up into teams of five or less. We were happy to oblige, as more teams meant more opportunities to win prizes. We placed well after the first day, with one team tying for third place.

Freelancer then staged a tie breaker lockpicking challenge, which our erstwhile comrade idont brought home with flying colours…

startcon_tiebreaker

… allowing us to take first, second and third prize (instead of only first).

startcon_trolololol

During this event, I didn’t manage to solve a single challenge, and only contributed with my thought leadership. In order to feel slightly less useless, I went home and tackled one of the challenges which our team did not solve during the CTF.

Without further ado:

Startcon Challenge 12 – a.out / Format String

This challenge was presented as a Linux 32-bit ELF file, which you can download here: fmtstring. This binary was running on an ASLR-enabled system.

Note that I know the files provided for this challenge was changed at least once during the challenge, of which the participants did not receive explicit notice. This is provided as-is, and may not represent the final state of the challenge at the conclusion of the CTF.

This challenge openly presents itself as a format string challenge: the main vulnerable function is presented below:

void do_the_format(void){
 char format_string[101];
 printf("Once thought to be just a lazy short cut,\n"
 "actually leads to remote code execution!\n\n"
 "\n"
 "\n"
 "Lets give that a crack shall we?.\n"
 "format string> ");
 fflush(stdout);
 fgets(format_string, 99, stdin);
 int i = 0;
 int valid = LEGIT;
 for (i = 0; i < 100; ++i) {
 switch (format_string[i]) {
 case '7': valid = NOPE;
 case '3': valid = NOPE;
 }
 }
 if (valid == NOPE){
 printf("Bad input detected!\n");
 return;
 }
 format_string[100] = '\0';
 printf(format_string);
 puts("Having fun?");
 fflush(stdout);
}

At this point, the astute reader may notice that the format_string buffer is actually uninitialized, and never cleaned: this results in the “Bad input” check being triggered more often than it should be, unless the buffer is “cleaned” by supplying an overly long input containing a character other than “3” or “7”.

The vulnerable printf is in red. There is no looping – that is, the program calls this function once, then exits. In order to overcome ASLR, our first task is to patch the binary such that we are able to call printf multiple times with user-controlled input. We can easily do this by redirecting the puts function (in blue) to the start of do_the_format.

From here, our next step is to leak a useful address off the stack, by supplying a pile of :”[%p]” to printf. There are two approaches for this:

  • Leak an address on the stack: This application is compiled with an executable stack, so if we can leak an absolute address to the stack, we can save shellcode to it, then redirect execution there to get a shell.
  • Leak an address in libc: By leaking an address in libc, we can calculate the address of of a useful function call like system. Then, we redirect the printf function to system(), and call it with /bin/sh;

Given my laziness, I opted for the second approach (this requires less writes using %n, meaning there’s less exploit to write). In a twist of good fortune, leaking an address in libc via “[%p]” is relatively trivial:

startcon_12_leak

We then extract the offset, calculate the address of system() – which is always a static distance away – and then overwrite printf with this address. Unfortunately, doing this would often trigger the “bad input” message, as the address of system() would often contain ‘3’ and ‘7’ when converted into a format string write.

To address this, I quickly built a manual function, to allow a user to convert “bad” input to equivalent input containing no restricted characters:

startcon_12_badchar

All in all, our exploit looks like this:

  • Overwrite puts() in the GOT with the address of do_the_format()
  • Using “[%p]”, leak a libc address off the stack
  • Calculate the address of system()
  • Overwrite printf() with the address of system()
  • Call printf (redirected to system()) with /bin/sh;

Put together, it looks like this:

startcon_12_fuckyou

You can download the commented exploit code here. For those of you playing along at home, you will likely need to adjust the calculation for system() depending on your libc, and I recommend using a netcat wrapper instead of the pwntools process interaction (it seems much more reliable).

Thankyou to the organisers of Startcon 2016 (Freelancer). While this event could use some improvement with regards to communication (specifically, the use of the “CC” button as opposed to “BCC”), it was an enjoyable event overall.

To our erstwhile brothers from Operation Swag Pack DLC, may our alliance continue unbroken for years to come.

See you in the SANS Holiday Hack challenge soon 🙂

About Norman

Sometimes, I write code. Occasionally, it even works.
This entry was posted in Bards, Computers, Jesting and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s