changed 2 months ago
Linked with GitHub

初心者向けgdbの使い方

木更津高専アドカレの12日目です.

<-前 [初心者向け]クリーンなPython環境の構築方法

preface

moinmoin!ごきげんよう👋
アドカレ2本目はgdbの使い方紹介です.
我が校の名産品,メロスぶちギレ案件の紙レポートでgdbの存在を知った,知る人がいると思いますので,ある程度実用的な使い方を教えます😡.

main

linux,x86_64を前提に書きます

まずオススメするのがgdbの拡張スクリプトを入れることです.

下2つは現在でも開発が続いているためオススメです.
readme以下のガイドに沿えば簡単にインストール出来ると思います.
https://github.com/bata24/gef?tab=readme-ov-file#install
https://github.com/pwndbg/pwndbg?tab=readme-ov-file#how
拡張を無効にしたいなら\(~/.gdbinit\)の行頭に#を加えてコメントアウトしてください.
どちらもbinary exploitに特化した拡張になっていますが使う上で使用感が大きく変わるので入れるべきです.

ここからは拡張入っている前提で行きますよ~

exploit分野の紹介はしない予定です

Segmentation fault

👸:セグフォした
Q:そもそもセグフォってなんですか??
プログラムが不正なアドレスを使用しよう()としたがためにエラーが起きたということです.
もしユーザーの入力が起因でセグフォするのであればそのバイナリはexploitableである可能性が高いです.

セグフォしている行を特定するのに一番簡単な方法はコンパイル時にデバッグ情報をつけるのみです

gcc hoge.c -g

-gオプションをつけることでデバッグ時にソースを参照できます.
pwndbgの場合ただセグフォするプログラムを走らせただけでその起こったソースでの位置が特定できます.
今回セグフォさせたプログラムはbofの脆弱性を抱え(範囲外書き込み可能である)ているためreturn時にスタック上にプッシュしてあったリターンアドレスを破壊しクラッシュしました.
リターンアドレスが0x616161616161(0x61は'a'のascii数字です)になっている,またret時のクラッシュのためソース欄では関数最後に印がついています.
image

👸:セグフォした
Q:外部ライブラリでセグフォしたら?
例えばscanfのsecond argument以降に非ポインタ(アドレス)を渡すと外部ライブラリ(glibc)でエラーが起こります.
この場合scanfでのエラーはすぐにわかりますが自身の作成したコードのどこの行かを確認するにはバックトレースを見てください.
この画面(context画面)一番下でもbtコマンドでもbacktraceコマンドでも確認できます.
image

───────────────────[ BACKTRACE ]──────────────────── ► 0 0x7ffff7c67149 __vfscanf_internal+18281 1 0x7ffff7c62142 __isoc99_scanf+178 2 0x5555555551a4 main+59 3 0x7ffff7c29d90 __libc_start_call_main+128 4 0x7ffff7c29e40 __libc_start_main+128 5 0x5555555550a5 _start+37

呼び出し元を確認したら

pwndbg> info line *0x5555555551a4 Line 6 of "sca.c" starts at address 0x55555555518b <main+34> and ends at 0x5555555551a9 <main+64>. pwndbg> info line *main+59 Line 6 of "sca.c" starts at address 0x55555555518b <main+34> and ends at 0x5555555551a9 <main+64>.

このように行を確認し原因を特定できました.

更に原因を突き詰めたい場合,call命令(関数呼び出し)にブレークポイントをおいて引数を確認することをおすすめします.
セグフォが起こる多くの原因は関数への不正なポインタの引き渡しです.
pwn-dbgの場合,call命令でブレークすると引数を自動で示してくれますがx86_64アセンブリにおいて引数はrdi,rsi,rdxの順に渡されることを覚えていると便利でしょう.

printf("index: %d, value: %d\n",index,value);

このようなprintf関数の利用では

rdi: "index: %d, value: %d\n"という文字列へのポインタ
rsi: indexの値
rdx: valueの値

image
このようになるわけでございます.
64bitx86においてはSystem V ABIが採用されています.

x86-64
This is a 64-bit platform. The stack grows downwards. Parameters to functions are passed in the registers rdi, rsi, rdx, rcx, r8, r9, and further values are passed on the stack in reverse order. Parameters passed on the stack may be modified by the called function. Functions are called using the call instruction that pushes the address of the next instruction to the stack and jumps to the operand. Functions return to the caller using the ret instruction that pops a value from the stack and jump to it. The stack is 16-byte aligned just before the call instruction is called.

https://wiki.osdev.org/System_V_ABI より

10分ぐらいでテキトーに書いた記事ですがセグフォした時などにgdb使ってみてください☺
gdbに限らずデバッガはbinary exploit,reverse engineeringするには必須のスキルです.
今回は紹介出来ませんでしたがヒープ領域に関すること,その他kernelのデバッグなど様々ありますので,もし,このような低いレイヤのことが好きなら,ともにCTFをやりましょう🚩

Select a repo