2018年5月11日金曜日

Hacking 美しき策謀2

前回は0x200のプログラミング基礎だったので、今回は0x300のバッファオーバーフローを進めていきます。

前章で扱ったプログラムに攻撃を仕掛けに行く展開で面白い。shellcodeはデコードしてもよく分からなかったので次へ。

次はstrcpy()を利用したバッファオーバーフローでした。コマンドラインから文字列を受け取って、特定の文字列と一致していれば認証、みたいなプログラムです。
check_authentication()はauth_flagを戻り値にする関数であり、main関数からは、
if(check_authentication(argv[1])){printf("ok");}
という形で呼び出されて利用されます。
この時、ifは「0でなければ」を判断しているため、何らかの方法で戻り値になる初期値0のauth_flagが、0以外に書き変わっていれば通ってしまう形になります。

check_authentication()内部ではstrcpy()を利用して文字列をバッファ用の配列にコピーし、strcmp()を使って比較します。

実行結果ですが、入力文字列が29文字以上の場合どのような文字列を入力しても認証成功となり、40文字以上だとif-else文それぞれに入っていたprintfが実行されなくなりました。


29文字以上で認証成功については、authentication()内で宣言したint型変数auth_flagとchar型配列password_buffer[16]のメモリの位置が関係しているようです。

int auth_flag=0;
char password_buffer[16];

の順で宣言した結果、ポインタはそれぞれ

&auth_flag 0xffffcb5c
&password_buffer 0xffffcb40;

となり、メモリの状態は

 (gdb) x/20wx 0xffffcb40
0xffffcb40:     0x8021bf56      0x00000001      0x8018949a      0x00000001
0xffffcb50:     0x0003a1a0      0x00000006      0xffffcbe0      0x00000000
(省略)

でした。

(gdb) x/20wx 0xffffcb40
0xffffcb40:     0x30303030      0x30303030      0x30303030      0x30303030
0xffffcb50:     0x30303030      0x30303030      0x30303030      0x30303030

0x30はアスキーコードで0であることを踏まえると、auth_flagは29文字の0に埋め立てられてしまい、0以外になってしまっているようです。想定よりも長い文字列でのstrcpyによって、書き換えられた模様。
(宣言した順とは逆にメモリに配置されているようです)

29文字以上で書き換えという点については、二つの変数の差を確認すると

(gdb) print 0xffffcb5c-0xffffcb40
&1=28

という結果になるようなので、きちんと理由があることが確認できました。



今度は40文字以上の"0"を実行すると何も出なくなる現象について確認。

実行するとreturn auth_flagでアクセス違反が発生していました。指定アドレスが0x3030303030303040という謎の値に。
このタイミングで他の変数も確認しましたが、

(gdb) p &auth_flag
$2 = (int *) 0x303030303030302c
(gdb) p &password_buffer
$3 = (char (*)[16]) 0x3030303030303010

とポインタそのものが書き変わっている感じになっていました。

Segmentation fault前後のレジスタ状況とメモリを確認するとベースポインタが書き換えられていることを確認。

Segmentation fault前
 (gdb) i r
rax            0x17     23
rbx            0xffffcbe0       4294953952
rcx            0x600018040      25769902144
rdx            0x0      0
rsi            0x60003a140      25770041664
rdi            0x8000   32768
rbp            0xffffcb60       0xffffcb60
rsp            0xffffcb20       0xffffcb20
r8             0xffffc85c       4294953052
(gdb) x/20wx 0xffffcb20
0xffffcb20:     0xffffcc65      0x00000000      0xffffcb40      0x00000000
0xffffcb30:     0xffffc85c      0x00000000      0x8013e970      0x00000001
0xffffcb40:     0x8021bf56      0x00000001      0x8018949a      0x00000001
0xffffcb50:     0x0003a1a0      0x00000006      0xffffcbe0      0x00000000
0xffffcb60:     0xffffcb90      0x00000000      0x004011e1      0x00000001

Segmentation fault後
(gdb) i r
rax            0x303030b0       808464560
rbx            0xffffcbe0       4294953952
rcx            0x600018040      25769902144
rdx            0x0      0
rsi            0x60003a140      25770041664
rdi            0x8000   32768
rbp            0x3030303030303030       0x3030303030303030
rsp            0xffffcb70       0xffffcb70
r8             0xffffc85c       4294953052

(gdb) x/20wx 0xffffcb20
0xffffcb20:     0xffffcc65      0x00000000      0xffffcb40      0x00000000
0xffffcb30:     0xffffc85c      0x00000000      0x8013e970      0x00000001
0xffffcb40:     0x30303030      0x30303030      0x30303030      0x30303030
0xffffcb50:     0x30303030      0x30303030      0x30303030      0x30303030
0xffffcb60:     0x30303030      0x30303030      0x00401100      0x00000001

スタック周りにダメージが来ているようでした。rbpはbreak mainして確認した時から本来変わらない値であるはずなのに、変化してしまっていることがプログラムが落ちる原因だったようです。
(p $rbp-$rspはmain関数時点では32,check_authentication関数に入ると64でした)

 なお、auth_flagとpassword_bufferの位置を逆にしたところ、auth_flag上書きによるif分強制trueはありませんでした(password_bufferよりauth_flagの方が先にあるので上書きが発生しない)。
ただし、 24文字以上でrbpが上書きされ、アクセス違反になりました。
書き換えが発生しない代わりに、スタックまでが近いので微妙…。

 とりあえずこんな感じかなと予想は立てたので、引き続き進めながらエラーの詳細を追っていこうと思います。








0 件のコメント:

コメントを投稿