pwndbgを使ってみた
これはUEC Advent Calendar 2021の15日目の記事です。
前日はにゃんさんの記事でした。
はじめに
GDBのプラグインといえばpeda、pwndbg、gefあたりが有名です。私は普段peda+Pwngdbを使っていますが、最近のつよつよpwnerがよくpwndbgを使ってる気がしたので試してみることにしました。
環境
推奨環境ではないですが、glibc 2.33を使いたかったのでUbuntu21.04にしました。
$ cat /etc/issue
Ubuntu 21.04 \n \l
$ gcc --version
gcc (Ubuntu 10.3.0-1ubuntu1) 10.3.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gdb --version
GNU gdb (Ubuntu 10.1-2ubuntu2) 10.1.90.20210411-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.33-0ubuntu5) release release version 2.33.
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 10.2.1 20210320.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
インストール
$ git clone https://github.com/pwndbg/pwndbg
$ cd pwndbg
$ ./setup.sh
サンプルプログラム
#include <stdlib.h> int main(){ char *p[0x200]; int i = 0; for(int s=0x98; s>=0x18; s-=0x10){ for(int j=0; j<14; j++) p[i++] = malloc(s); } while(i > 0) free(p[--i]); return 0; }
$ gcc sample.c
$ gdb -q ./a.out
コマンド
よく使いそうなコマンドを挙げていきます。
help
使い方が表示されます。
pwndbg> help
コマンド名を与えるとそのコマンドのドキュメントが表示されます。
pwndbg> help heap
Iteratively print chunks on a heap, default to the current thread's active heap.
pwndbg> help bins
Print the contents of all an arena's bins and a thread's tcache, default to the current thread's arena and tcache.
pwndbg> help tele
Recursively dereferences pointers starting at the specified address
($sp by default)
apropos
与えられた単語に関連するコマンドを検索します。
pwndbg> apropos heap
heap -- Iteratively print chunks on a heap, default to the current thread's active heap.
set heap-dereference-limit -- Set number of bins to dereference
set memory-heap-color -- Set color for heap memory
show heap-dereference-limit -- number of bins to dereference:
show memory-heap-color -- color for heap memory:
vis_heap_chunks -- Visualize chunks on a heap, default to the current arena's active heap.
disas/disass/disassemble
ディスアセンブルを表示します。disas
はpwntoolsを入れたら使えなくなりました。
pwndbg> disass main
nearpc
ディスアセンブルを一部だけ表示します。
pwndbg> nearpc
tele/telescope
メモリをいい感じに表示してくれます。アドレスと表示する数を指定できます。
pwndbg> tele
elfheader
セクションのアドレスが表示されます。下の例ではPIE有効なのでオフセットになってます。
pwndbg> elfheader
0x318 - 0x334 .interp
0x338 - 0x368 .note.gnu.property
0x368 - 0x38c .note.gnu.build-id
0x38c - 0x3ac .note.ABI-tag
0x3b0 - 0x3d4 .gnu.hash
0x3d8 - 0x4b0 .dynsym
0x4b0 - 0x554 .dynstr
0x554 - 0x566 .gnu.version
0x568 - 0x598 .gnu.version_r
0x598 - 0x658 .rela.dyn
0x658 - 0x6a0 .rela.plt
0x1000 - 0x101b .init
0x1020 - 0x1060 .plt
0x1060 - 0x1070 .plt.got
0x1070 - 0x10a0 .plt.sec
0x10a0 - 0x12e5 .text
0x12e8 - 0x12f5 .fini
0x2000 - 0x2004 .rodata
0x2004 - 0x2048 .eh_frame_hdr
0x2048 - 0x2158 .eh_frame
0x3da8 - 0x3db0 .init_array
0x3db0 - 0x3db8 .fini_array
0x3db8 - 0x3fa8 .dynamic
0x3fa8 - 0x4000 .got
0x4000 - 0x4010 .data
0x4010 - 0x4018 .bss
got
GOTが表示されます。pwntoolsが入ってないと使えないようです。
pwndbg> got
GOT protection: Full RELRO | GOT functions: 3
[0x55a3cb9f2fc0] free@GLIBC_2.2.5 -> 0x7fda9a390740 (free) ◂— endbr64
[0x55a3cb9f2fc8] __stack_chk_fail@GLIBC_2.4 -> 0x7fda9a4213b0 (__stack_chk_fail) ◂— endbr64
[0x55a3cb9f2fd0] malloc@GLIBC_2.2.5 -> 0x7fda9a390130 (malloc) ◂— endbr64
vmmap
メモリマップが表示されます。
pwndbg> vmmap
retaddr
リターンアドレスが表示されます。
pwndbg> retaddr
0x7ffcc5200298 —▸ 0x7f392feca565 (__libc_start_main+213) ◂— mov edi, eax
0x7ffcc5200368 —▸ 0x557757f110ce (_start+46) ◂— hlt
heap
チャンクが表示されます。
pwndbg> heap
arena
arenaの情報が表示されます。
pwndbg> arena
{
mutex = 0,
flags = 0,
have_fastchunks = 1,
fastbinsY = {0x557758fce010, 0x557758fcdd70, 0x557758fcd9f0, 0x557758fcd590, 0x557758fcd050, 0x557758fcca30, 0x557758fcc330, 0x0, 0x0, 0x0},
top = 0x557758fce1d0,
last_remainder = 0x0,
bins = {0x557758fcb290, 0x557758fcbb50, 0x7f3930082c10 <main_arena+112>,
...},
binmap = {0, 0, 0, 0},
next = 0x7f3930082ba0 <main_arena>,
next_free = 0x0,
attached_threads = 1,
system_mem = 135168,
max_system_mem = 135168
}
bins
binsが表示されます。
pwndbg> bins
特定のbinsだけ表示することもできます。
pwndbg> fastbins
fastbins
0x20: 0x561a1f410010 —▸ 0x561a1f410030 —▸ 0x561a1f410050 —▸ 0x561a1f410070 —▸ 0x561a1f410090 ◂— ...
0x30: 0x561a1f40fd70 —▸ 0x561a1f40fda0 —▸ 0x561a1f40fdd0 —▸ 0x561a1f40fe00 —▸ 0x561a1f40fe30 ◂— ...
0x40: 0x561a1f40f9f0 —▸ 0x561a1f40fa30 —▸ 0x561a1f40fa70 —▸ 0x561a1f40fab0 —▸ 0x561a1f40faf0 ◂— ...
0x50: 0x561a1f40f590 —▸ 0x561a1f40f5e0 —▸ 0x561a1f40f630 —▸ 0x561a1f40f680 —▸ 0x561a1f40f6d0 ◂— ...
0x60: 0x561a1f40f050 —▸ 0x561a1f40f0b0 —▸ 0x561a1f40f110 —▸ 0x561a1f40f170 —▸ 0x561a1f40f1d0 ◂— ...
0x70: 0x561a1f40ea30 —▸ 0x561a1f40eaa0 —▸ 0x561a1f40eb10 —▸ 0x561a1f40eb80 —▸ 0x561a1f40ebf0 ◂— ...
0x80: 0x561a1f40e330 —▸ 0x561a1f40e3b0 —▸ 0x561a1f40e430 —▸ 0x561a1f40e4b0 —▸ 0x561a1f40e530 ◂— ...
pwndbg> tcachebins
tcachebins
0x20 [ 7]: 0x561a1f410100 —▸ 0x561a1f410120 —▸ 0x561a1f410140 —▸ 0x561a1f410160 —▸ 0x561a1f410180 —▸ 0x561a1f4101a0 —▸ 0x561a1f4101c0 ◂— 0x0
0x30 [ 7]: 0x561a1f40fed0 —▸ 0x561a1f40ff00 —▸ 0x561a1f40ff30 —▸ 0x561a1f40ff60 —▸ 0x561a1f40ff90 —▸ 0x561a1f40ffc0 —▸ 0x561a1f40fff0 ◂— 0x0
0x40 [ 7]: 0x561a1f40fbc0 —▸ 0x561a1f40fc00 —▸ 0x561a1f40fc40 —▸ 0x561a1f40fc80 —▸ 0x561a1f40fcc0 —▸ 0x561a1f40fd00 —▸ 0x561a1f40fd40 ◂— 0x0
0x50 [ 7]: 0x561a1f40f7d0 —▸ 0x561a1f40f820 —▸ 0x561a1f40f870 —▸ 0x561a1f40f8c0 —▸ 0x561a1f40f910 —▸ 0x561a1f40f960 —▸ 0x561a1f40f9b0 ◂— 0x0
0x60 [ 7]: 0x561a1f40f300 —▸ 0x561a1f40f360 —▸ 0x561a1f40f3c0 —▸ 0x561a1f40f420 —▸ 0x561a1f40f480 —▸ 0x561a1f40f4e0 —▸ 0x561a1f40f540 ◂— 0x0
0x70 [ 7]: 0x561a1f40ed50 —▸ 0x561a1f40edc0 —▸ 0x561a1f40ee30 —▸ 0x561a1f40eea0 —▸ 0x561a1f40ef10 —▸ 0x561a1f40ef80 —▸ 0x561a1f40eff0 ◂— 0x0
0x80 [ 7]: 0x561a1f40e6c0 —▸ 0x561a1f40e740 —▸ 0x561a1f40e7c0 —▸ 0x561a1f40e840 —▸ 0x561a1f40e8c0 —▸ 0x561a1f40e940 —▸ 0x561a1f40e9c0 ◂— 0x0
0x90 [ 7]: 0x561a1f40df50 —▸ 0x561a1f40dfe0 —▸ 0x561a1f40e070 —▸ 0x561a1f40e100 —▸ 0x561a1f40e190 —▸ 0x561a1f40e220 —▸ 0x561a1f40e2b0 ◂— 0x0
0xa0 [ 7]: 0x561a1f40d700 —▸ 0x561a1f40d7a0 —▸ 0x561a1f40d840 —▸ 0x561a1f40d8e0 —▸ 0x561a1f40d980 —▸ 0x561a1f40da20 —▸ 0x561a1f40dac0 ◂— 0x0
pwndbg> unsortedbin
unsortedbin
all: 0x561a1f40d290 —▸ 0x561a1f40db50 —▸ 0x7fc6cc86cc00 (main_arena+96) ◂— 0x561a1f40d290
pwndbg> largebins
largebins
empty
pwndbg> smallbins
smallbins
empty
glibc 2.33にも対応しているようです。
malloc_chunk
チャンクの情報が表示されます。
pwndbg> malloc_chunk 0x557758fcbb50
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x557758fcbb50
Size: 0x3f1
fd: 0x7f3930082c00
bk: 0x557758fcb290
tcache
tcacheの情報が表示されます。
pwndbg> tcache
{
counts = {7, 7, 7, 7, 7, 7, 7, 7, 7, 0 <repeats 55 times>},
entries = {0x561a1f410100, 0x561a1f40fed0, 0x561a1f40fbc0, 0x561a1f40f7d0, 0x561a1f40f300, 0x561a1f40ed50, 0x561a1f40e6c0, 0x561a1f40df50, 0x561a1f40d700, 0x0 <repeats 55 times>}
}
top_chunk
topチャンクが表示されます。
pwndbg> top_chunk
Top chunk
Addr: 0x557758fce1d0
Size: 0x1de31
try_free
freeしたときのチェックをしてくれます。
pwndbg> try_free 0x557758fce100
General checks
Tcache checks
Will do checks for tcache double-free (memory_tcache_double_free)
----------
Errors found!
vis_heap_chunks
チャンクをいい感じに表示してくれます。
pwndbg> vis_heap_chunks
おわりに
もうpedaは捨てました。
明日はExitさんです。