作为PWN爱好者,在CTF比赛中进行堆利用时,我们总是需要调试器(例如gdb)来跟踪内存布局。但如果我们只是想看看堆布局是否与我们想象的一致,其实并不需要gdb。希望这个小工具能帮助我们更轻松地进行利用 ;)。
HeapInfo 在二进制程序存在某种反调试限制(例如被 ptrace)时非常有用。 HeapInfo 仍然有效,因为它不使用 ptrace。
使用Ruby实现因为我喜欢Ruby :P。不过未来可能会用Python实现(如果还没有其他人做的话)。
如果你更喜欢使用 pwntools 进行利用,你仍然可以在 irb/pry 中使用 HeapInfo 作为一个小型调试器。
欢迎提出任何功能建议或bug问题。
HeapInfo 仍在开发中,将添加更多功能,因此版本可能会频繁变化 :p
$ gem install heapinfo
victim 正在被跟踪时,HeapInfo 仍然有效!即你可以同时使用 ltrace/strace/gdb 和 HeapInfo!dump - 转储任意地址的内存。layouts - 显示当前的 bin 布局,对堆利用非常有用。offset - 显示给定地址与段之间的偏移量,对计算相对偏移非常有用。canary - 获取栈保护金丝雀的值!x - GDB风格的命令。s - GDB风格的命令。find - GDB风格的命令。require 'heapinfo'
# ./victim 正在运行
h = heapinfo('victim')
# 或者使用 h = heapinfo(20568) 来指定 PID
# 加载时会显示简单的信息:
# Program: /home/heapinfo/victim PID: 20568
# victim base @ 0x400000
# [heap] base @ 0x11cc000
# [stack] base @ 0x7fff2b244000
# libc-2.19.so base @ 0x7f892a63a000
# ld-2.19.so base @ 0x7f892bee6000
# canary value: 0x84b742f03d94c100
# 查询段的信息
"%#x" % h.libc.base
#=> "0x7f892a63a000"
h.libc.name
#=> "/lib/x86_64-linux-gnu/libc-2.19.so"
"%#x" % h.elf.base
#=> "0x400000"
"%#x" % h.heap.base
#=> "0x11cc000"
注意:当进程未找到时,大多数方法将返回 nil。一种避免错误的方法是使用 debug 包装方法,该块在远程利用时将被忽略。
h = heapinfo('remote')
# 进程未找到
h.pid # nil
# 使用 `debug` 包装,这样在攻击远程服务时不会引发错误
h.debug { fail unless leak_libc_base == h.libc.base }
查询特定地址的内容。
注意:你必须有附加程序的权限,否则 dump 会失败。
即 /proc/sys/kernel/yama/ptrace_scope 设置为 0 或以 root 身份运行。
h.debug do
p h.dump(:libc, 8)
#=> "\x7FELF\x02\x01\x01\x00"
p h.dump(:heap, 16)
#=> "\x00\x00\x00\x00\x00\x00\x00\x00\x31\x00\x00\x00\x00\x00\x00\x00"
p h.dump('heap+0x30', 16) # 支持偏移!
#=> "\x00\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00"
p h.dump('heap+0x30 * 3 + 0x8', 16) # 甚至支持复杂表达式!
#=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
p h.dump(:program, 8)
#=> "\x7FELF\x02\x01\x01\x00"
p h.dump(0x400000, 8) # 或者直接给出地址
#=> "\x7FELF\x02\x01\x01\x00"
end
# 无效示例:
# h.dump('meow') # 没有这样的段
h.layouts :fast

h.layouts :unsorted, :small

h.layouts :tcache

h.offset(0x7fda86fe8670)
# 0xf6670 after libc
h.offset(0x1839cd0, :heap) # 指定段名
# 0x20cd0 after heap
h.offset(0x1839cd0)
# 0x20cd0 after heap

h.canary.to_s(16)
#=> '84b742f03d94c100'
h.x 8, :heap

提供一个内存搜索器,比(原始的)gdb更容易使用。
支持搜索整数、字符串,甚至正则表达式。
h.find(0xdeadbeef, 'heap+0x10', 0x1000)
#=> 6299664 # 0x602010
h.find(/E.F/, 0x400000, 4)
#=> 4194305 # 0x400001
h.find(/E.F/, 0x400000, 3)
#=> nil
# 获取搜索结果的相对偏移
h.find('/bin/sh', :libc, rel: true)
#=> 1622391 # 0x18c177
h.offset(h.find('/bin/sh', :libc))
# 0x18c177 after libc
HeapInfo 目前仅在 Ubuntu 上运行测试,以下为经过测试的 glibc 版本: