Last weekend we participated in the defcon quals and I tought I'll make a writeup of the one challenge which drove me crazy. During the quals I was not able to exploit it because of the timezone difference, but then I thought I need to solve it otherwise I'll never be able to sleep quietly again.
So here's my writeup.
After downloading the file we check what binary we're facing:
And a quick peek into the strings available:
The password is already available in the strings but IDA shows it even better :) so here we go
From the strings we can see that it is some kind of SMTP server (EHLOHELOQUITMAILRCPTDATAUPTMAUTH).
After loading the binary into IDA I started searching for the usual calls but I found no strcpy or memcpy calls.
In the end I saw the fgets calls and look where they're referenced.
The auth fgets calls are not interesting for us as they don't have a overflow capability,
but with data we can work.
Here is the "data" function:
We can see that 512 bytes are copied into a2. a2 is only 256 bytes big which will result in a stack overflow.
We have only one problem, there are everywhere those secret canary checks and we will overflow the caller function client_callback() which will then fails because the secret is overwritten by us.
Check function is something like:
Let's see what happens if we send a large string.
Nothing happened it just exited, so the secret check must be outside this function crashing.
If you trace it further you'll see the check at 0x08049C44 is failing.
If we set a breakpoint there and send our big string again:
So the secret is 0x50b24d57 and our value is 0x41414141 so we overwrite the secret value and it
will just exit.
Let's set the secret to 0x414141 to see what happens if it would continue running.
and we will see the program segfault.
This means we can cause a simple stack overflow if we can get the secret right.
Let's take a look what this secret canary is all about.
The secret initiation looks like this:
First the time since epoch is calculated (since 01 of Jan 1970). This value is then used as seed for the random number generator.
The random number is then saved in the secret variable which represents our stack canary.
As it is time based, let's see if we can recompute it.
The binary gives us the localtime:
And as well the uptime
So localtime-uptm = start time which is used as seed for rand.
Let's take a look at the calculation.
(yes it's C not python, I tought I have time to do it in C as the quals are over now and it gives this oldschool feeling :)).
let's look at the code, thank at this point to hempel for the initial time handling code.
This correctly calculates the secret on the local machine.
In the challenge, the box was on a different time zone which made this fail, so you'd need to add
a small offset calculation like:
base =now - ((h * 3600 + m *60 + (s + (3600 * offset))) );
so for every time zone from 0 to 12 you try each offset an see if that works if not you'd need to do
the same from 0 to -12.
Let's try if this computation works.
So the calculation is correct.
Now let's check how much we need to overwrite the secret.
114 - C = 108 (264)
So with 264 byte we should overwrite the secret, we could do this as well with the metasploit pattern generator and pattern offset calculator.
But i thought using metasploit once in a blog post is enough :)
After 260 chars you start to overwrite the secret.
Let's will send another string [Junk][secret][AAAABBBBCCCC] to test for the EIP padding.
Now we know, that 8 bytes after the secret is EIP located.
Now we can start looking around how to get to the shellcode.
let's send a new string which looks like this:
Our shellcode would be located at esp, now we just need to find a working jmp/call esp instruction.
For that let's use metasploits msfelfscan.
hmm none available.
After that I started the pp100_05ad9efbc4b0c16f243.bin binary multiple times to check if the memory
areas are changing or not and surprisingly they don't.
So we can check if in the libc.so.7 we can find a usable value.
There we go some usable addresses.
So let's send another test string looking like this:
If everything works we should see a breakpoint trap in gdb.
Great, it works let's look around EIP.
our \xcc's are everywhere great, so we can put a real shellcode there.