🐙

Writeup|picoCTF PIE TIME

に公開

PIEとアドレス計算の基本

そもそもバイナリファイルとは?

  • .exe.out みたいな実行形式のファイル
  • 中には「CPUに命令するコード」がぎっしり詰まってる

プログラムの本体であり、関数もすべてこの中に存在する

実行されるとどうなる?

  • OSがこのファイルを メモリ上に読み込む
  • 関数や変数にはそれぞれ メモリ上のアドレス(番地)が割り当てられる
  • CPUはそのアドレスに沿って命令を1つずつ実行していく

CTFでの「リモートバイナリ実行」とは?

CTFではよく、問題サーバーに脆弱なバイナリが用意されていて

nc で接続して、そのプログラムをリモートから操作する形式になっている。

PIEとは

PIE(Position Independent Executable)とは、

実行するたびに関数などのアドレスが変化する仕組みのこと。

セキュリティ強化のために導入されており、アドレスを固定しないことで攻撃を困難にする。

なぜアドレス計算が必要?

PIEが有効なバイナリでは、関数にジャンプしたくても、

実行時の正確なアドレスが毎回変わってしまう。

→ だから「アドレスを計算で求める」必要がある!

バイナリ基本問題の用語

用語 意味
実行時のアドレス 「今この関数がどこにあるか」実行中に決まる(PIEのせい)
オフセット 「バイナリの中での関数の場所」。固定されてる
ベースアドレス 実行時の「バイナリの開始地点」。mainやwinの基準になる

実行アドレスを求める流れ

1. mainの実行アドレス(ncで表示)をメモ
2. mainのオフセットをnmで調べる
3. ベースアドレス = 実行アドレス - オフセット
4. 実行したいアドレスのオフセットを足す → 実行アドレス完成

補足:他の防御機構(超ざっくり)

機能 内容
PIE 関数のアドレスを毎回ランダムに
NX スタックなどに実行権限を与えない
Canary バッファオーバーフロー検知用の値を挿入
RELRO 関数ポインタの書き換え防止

解法

1.リモートプログラムに接続する

nc rescued-float.picoctf.net 51884

picoCTFが立ち上げてくれたリモートのプログラムに自分のPCからアクセスできる。

  • rescued-float.picoctf.net → 接続先のホスト名(サーバーのアドレス)
  • 51884 → 接続するポート番号(サーバー内のどのアプリかを指定)

結果:

Address of main: 0x57fd3814b33d
Enter the address to jump to, ex => 0x12345:
  • main 関数のアドレスが表示されてる(今いる場所)
  • 正しいアドレスを入れると flag() とかが呼ばれてフラグが出る

2.アドレスを取得するためにvuln.cを開く

win() 関数の実行アドレスを入力するとflag.txtが開くとの記載あり

  • 入力されたアドレスにジャンプする処理があるから
  • win() のアドレスさえ分かれば、そこに飛ばして flag.txt を表示できる!

3.main関数とwin関数のアドレスを調べる

nm -n ~/Downloads/vuln

実行ファイル vuln の中にある関数や変数の「アドレス一覧」を、アドレス順(-n)で表示する

結果:

00000000000012a7 T win
000000000000133d T main
アドレス(オフセット) シンボルの種類 名前
00000000000012a7 T(関数) win
000000000000133d T(関数) main

⚠️このアドレスは、実行ファイル内での相対的な位置(オフセット)」。

実行時にはこのアドレスは ベースアドレスに加算されて実際のアドレスになる!

4.実行時の win() アドレスを計算する

https://www.rapidtables.com/calc/math/hex-calculator.html?num1=&op=0&num2=

main の実行アドレスからベースアドレスを出す

ベースアドレス = 実行時の main アドレス - main のオフセット
  • 実行時のアドレス → ncAddress of main:
  • オフセット → nm コマンドで表示された main の位置(例:0x133d)

win の実行アドレスを求める

winのアドレス = ベースアドレス + win のオフセット
  • オフセットは同じく nm で出たもの(例:0x12a7)

5.win関数のアドレスを入力

nc [rescued-float.picoctf.net](http://rescued-float.picoctf.net/) 51884

の結果に4-②で取得したwinの実行アドレスを入力

→flagを取得できる

Discussion