私はシェルコードを試していて、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 で設定された実行可能なスタックがあります。
前もって感謝します。