3

私はシェルコードを試していて、nop-slide テクニックを見つけました。buffer-size をパラメーターとして取り、次のようなバッファーを構築する小さなツールを作成しました。SC | SC | RET ]、NOP がバッファーの半分を取り、その後にシェルコードが続き、残りは (推測された) 戻りアドレスで埋められます。彼の有名な論文で説明されているツール aleph1 に非常に似ています。

私の脆弱なテストアプリは、彼の論文と同じです:

int main(int argc, char **argv) {
char little_array[512];
if(argc>1)
    strcpy(little_array,argv[1]);   
return 0;
}

私はそれをテストしましたが、うまくいきます:

jth@insecure:~/no_nx_no_aslr$ ./victim $(./exploit 604 0)
$ exit

しかし、正直なところ、私には理由がわかりません。さて、保存された eip は意図したとおりに上書きされましたが、バッファのどこかにジャンプする代わりに、argv にジャンプしたと思います。

strcpy() が呼び出される前に、gdb は次のアドレスを表示しました。

(gdb) i f  
Stack level 0, frame at 0xbffff1f0:  
 eip = 0x80483ed in main (victim.c:7); saved eip 0x154b56  
 source language c.  
 Arglist at 0xbffff1e8, args: argc=2, argv=0xbffff294  
 Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0  
 Saved registers:  
  ebp at 0xbffff1e8, eip at 0xbffff1ec  

little_array のアドレス:

(gdb) print &little_array[0]
 $1 = 0xbfffefe8 "\020"

strcpy() の後:

(gdb) i f
Stack level 0, frame at 0xbffff1f0:
 eip = 0x804840d in main (victim.c:10); saved eip 0xbffff458
 source language c.
 Arglist at 0xbffff1e8, args: argc=-1073744808, argv=0xbffff458
 Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0
 Saved registers:
  ebp at 0xbffff1e8, eip at 0xbffff1ec

それで、ここで何が起こったのですか?私は604バイトのバッファを使用してlittle_arrayをオーバーフローさせたため、保存されたebp、保存されたeip、argc、および推測されたアドレス0xbffff458でargvを確実に上書きしました。

その後、戻った後、EIP は 0xbffff458 を指していました。しかし、little_buffer は 0xbfffefe8 にあり、1136 バイトの違いがあるため、little_array を実行していないことは確かです。stepiコマンドで実行を追跡したところ、0xbffff458 以降で NOP を実行し、シェルコードに到達しました。

なぜこれが起こっているのかよくわかりません。まず第一に、彼が私のシェルコードを little_array ではなく argv で実行するのは正しいですか? そして、ローダー(?) は argv をスタックのどこに配置しますか? argc の直後に続くと思っていたのですが、argc と 0xbffff458 の間に 620 バイトのギャップがあります。0xbffff1ec に保存されている eip のはるか上にあるアドレス 0xbffff458 の NOP-Pad に、彼が首尾よく「着陸」できるのはどうしてでしょうか?

誰かがこれを明確にできますか?なぜこれが機能しているのか、実際にはわかりません。私のテスト マシンは、ASLR のない Ubuntu 9.10 32 ビット マシンです。犠牲者には、execstack -s で設定された実行可能なスタックがあります。

前もって感謝します。

4

1 に答える 1

3

まず、スタックを図解します。

0xBFFFF4F9 | |
            ----------
          ..。   
0xBFFFF29E | NOP |
0xBFFFF29D | NOP | argv[1]*ゲスト
            ----------
0xBFFFF29C | '\ 0'|
          ..。
0xBFFFF295 | '/' |
0xBFFFF294 | '。' | argv [0] "./victim"
            ----------
          ..。
            ----------
0xBFFFF1F8 | NULL |
0xBFFFF1F8 | &argv [1] |
0xBFFFF1F4 | &argv [0] | argv
            ----------
0xBFFFF1F0 | 0x000002 | argc
            ----------
          ..。
0xBFFFEFE9 | |
0xBFFFEFE8 | | little_array
            ----------

(注:図では、一部のボックスは1行あたり1バイトを保持し、他のボックスは内部に格納されているタイプに応じて4または8バイトを保持します)

そして、ローダー(?)はargvをスタックのどこに配置しますか?

それargcとは、それらがおそらく上にあることargvを示唆するための呼び出しの後に上書きされます。それらを0xBFFFF1F0に配置しました。これは、前のフレームのスタックが終了した場所であり、GDBがarglistが0xBFFFF1E8にあると言っているにもかかわらず、のフレームにスペースがないように見えるためです。それは私のシステム– <code> argcにあり、little_arrayの下にありました。それらがどこに配置されているかを確認してみてください。strcpylittle_arraymainargvp &argvp &argc

0xBFFFF458はargv[1]内にあるため、argv [1]のシェルコードは、にあるものではなく、実際に実行されるものlittle_arrayです。シェルコードのコピーが2つあるため(1つはlittle_arrayに、もう1つはにargv[1])、推測する差出人アドレスに応じて、どちらかを実行できます。

[argv]はargcの直後に続くと思いましたが、argcと0xbffff458の間には、620バイトのギャップがあります。

0xBFFFF458は、エクスプロイト後に保存された値です (と同じであることに注意してください)。前に、0xbffff294を保持します。どちらの場合も、それ自体は別の場所に保存されます。argvargc(signed)0xBFFFF458 == -1073744808argvargv

于 2010-05-01T15:19:21.003 に答える