This semester at RPI I’m taking the class “Modern Binary Exploitation”. This
post will detail how I reversed and cracked the tw33tchainz binary.

Understanding tw33tchainz

When we run tw33tchainz the first thing we are presented with is some art and a
prompt for our username, and salt. upon entering these values we are given a
generated password.

afterwards we are given a menu with 4 options, labelled 1, 2, 4, and 5. the
option labelled ‘3’ is missing. Naturally I entered into the prompt 3, then I
was asked to enter a password, my guess was incorrect.

Option 1 lets us enter a tweet which gets stored somewhere, and is appended to
the penguin’s beak the next time the menu is output to our term.

Option 2 lets us view all of our previous tweets.

Option 4 simply prints out the ascii art that’s on top of the menu. ( looks like
a mallet smashing a sombrero, or maybe a bird? nah… )

Option 5 quits the program.

Digging deeper

I decided a good first step would be to map out all the functions defined in the
binary, I did this through the use of gdb

From here I wanted to see if there were any vulnerable printf statements that
would let me make arbitrary memory writes.

I was looking for printfs that touched user input, in the entire program there
are only two locations where these reside: print_menu, and view_chainz.
I started by going through each printf statement in print_menu and surely
enough there is printf which takes the previous tweet and uses it as the first
argument, a cardinal sin.

Unfortunately the block of code containing the vulnerable printf looks like
this:

given this, with a carefully chosen user and salt, we can easily recover the
secret pass from the generated pass that we are given.

I chose to use 15 of 0x01 for the user and 15 of 0xff for the salt, I’m using 15
instead of 16 because in gdb I saw that fgets adds a null terminator as the 16th
byte in each.

with these values I know that when we’re adding the secret password to 0xff the
value will overflow and be 1 less than the original value.

afterwards when we xor this with the value 0x01 that will turn even numbers odd,
one greater than the original value, and odd numbers even, one less than the
original value.

for example if the secret byte was 0x55, when that’s added to 0xff we end up with
the value 0x54, which then turns back into 0x55 after we xor it with 0x01.

further if the secret byte was 0x56, when that’s added to 0xff we end up with
the value 0x55, which turns into 0x54 after we xor it with 0x01.

this means that in our generated password, we simply add 2 to the even bytes, and
leave the odd bytes unchanged. except for the last byte, which was null. The last
byte remains unchanged from the secret password.

I wrote a python script which takes the generated password as a command line
argument and returns the secret password.

Success!, now that we’re admin we have a menu option labelled 6, and more
importantly, access to the vulnerable printf statement in print_menu

since tweets are limited to 16 characters, the format string for the exploit
must be this length.

in gdb I noticed that the stack is actually misalighned by 1 byte so the first
character of the format string will be used to realign it.

tweet="A"

This means we have 15 bytes remaining for an arbitrary write.

First thing’s first, we need the address to write to, this will consume 4 more
bytes which leaves us 11 bytes for %x and %n to actually write the value.

With 11 bytes there is simply not enough room for enough %x tokens to get to
the address on the stack, which means I’ll have to use direct parameter access.
with all the required characters our tweet format looks like this

tweet="A....%???x%#$hhn"

…. will be the address

The only thing left is to determine what values to substitute for ???, and
which parameter # will be.

looking at the stack I can see that # has to be 8.

when doing some test writes in gdb I can see that whatever value I put in for
??? will be written to memory as 5 higher than the original value which
means I just simply subtract 5 from the value I want to write and then the
correct value will be written. This works unless the value I want to write is
less than 5 since I can’t write a negative number of bytes. To mediate this I
simply add 256 to every value which lets it overflow cleanly into the correct
value.

The final anatomy of a malicious tweet which writes the value 0x10 to the
location 0x43434343 looks like this.

tweet="ACCCC%267x%8$hhn"

Now it’s just a matter of finding a location to write my shellcode, then writing
it, overwriting exit to point to that location ( Thanks RELRO! ) and cat’ing the
password :)