pwnable.tw #2 orwの説明

CTF

実行すると”Give me your shellcode:”と挑発的なことを言ってくるプログラムが題材

使えれば良いやradare2(静的解析編):拾い物のコンパスによくまとめられている、radar2というフレームワークを使う。
gdbとかobjdumpとか、そういうオーソドックスなものより表示が人間にわかりやすい感じで大変嬉しい。
CTFマニアには常識だったのかもしれないが…ついさっき知った。

$ r2 orw
[0x080483d0]> aaa
<...中略...>
[0x080483d0]> afl
<...中略...>
[0x080483d0]> s sym.main
[0x08048548]> VV
<...中略...>
:> pdf@sym.main
            ;-- main:
/ (fcn) sym.main 81
|   sym.main ();
|           ; var int local_4h_2 @ ebp-0x4
|           ; var int local_4h @ esp+0x4
|              ; DATA XREF from 0x080483e7 (entry0)
|           0x08048548      8d4c2404       lea ecx, [local_4h]         ; 4
|           0x0804854c      83e4f0         and esp, 0xfffffff0
|           0x0804854f      ff71fc         push dword [ecx - 4]
|           0x08048552      55             push ebp
|           0x08048553      89e5           mov ebp, esp
|           0x08048555      51             push ecx
|           0x08048556      83ec04         sub esp, 4
|           0x08048559      e86dffffff     call sym.orw_seccomp
|           0x0804855e      83ec0c         sub esp, 0xc
|           0x08048561      68a0860408     push str.Give_my_your_shellcode: ; 0x80486a0 ; "Give my your shellcode:"
|           0x08048566      e815feffff     call sym.imp.printf         ; int printf(const char *format)
|           0x0804856b      83c410         add esp, 0x10
|           0x0804856e      83ec04         sub esp, 4
|           0x08048571      68c8000000     push 0xc8                   ; 200
|           0x08048576      6860a00408     push obj.shellcode          ; 0x804a060
|           0x0804857b      6a00           push 0
|           0x0804857d      e8eefdffff     call sym.imp.read           ; ssize_t read(int fildes, void *buf, size_t nbyte)
|           0x08048582      83c410         add esp, 0x10
|           0x08048585      b860a00408     mov eax, obj.shellcode      ; 0x804a060
|           0x0804858a      ffd0           call eax
|           0x0804858c      b800000000     mov eax, 0
|           0x08048591      8b4dfc         mov ecx, dword [local_4h_2]
|           0x08048594      c9             leave
|           0x08048595      8d61fc         lea esp, [ecx - 4]
           0x08048598      c3             ret

なお、参考までにobjdumpコマンドでの逆アセンブルだとこんな感じ。radare2での逆アセンブルの方がパッと見で理解しやすいと思う。

$ objdump -d orw 
 08048548 <main>:
 8048548:    8d 4c 24 04              lea    0x4(%esp),%ecx
 804854c:    83 e4 f0                 and    $0xfffffff0,%esp
 804854f:    ff 71 fc                 pushl  -0x4(%ecx)
 8048552:    55                       push   %ebp
 8048553:    89 e5                    mov    %esp,%ebp
 8048555:    51                       push   %ecx
 8048556:    83 ec 04                 sub    $0x4,%esp
 8048559:    e8 6d ff ff ff           call   80484cb <orw_seccomp>
 804855e:    83 ec 0c                 sub    $0xc,%esp
 8048561:    68 a0 86 04 08           push   $0x80486a0
 8048566:    e8 15 fe ff ff           call   8048380 <printf@plt>
 804856b:    83 c4 10                 add    $0x10,%esp
 804856e:    83 ec 04                 sub    $0x4,%esp
 8048571:    68 c8 00 00 00           push   $0xc8
 8048576:    68 60 a0 04 08           push   $0x804a060
 804857b:    6a 00                    push   $0x0
 804857d:    e8 ee fd ff ff           call   8048370 <read@plt>
 8048582:    83 c4 10                 add    $0x10,%esp
 8048585:    b8 60 a0 04 08           mov    $0x804a060,%eax
 804858a:    ff d0                    call   *%eax
 804858c:    b8 00 00 00 00           mov    $0x0,%eax
 8048591:    8b 4d fc                 mov    -0x4(%ebp),%ecx
 8048594:    c9                       leave  
 8048595:    8d 61 fc                 lea    -0x4(%ecx),%esp
 8048598:    c3                       ret    
 8048599:    66 90                    xchg   %ax,%ax
 804859b:    66 90                    xchg   %ax,%ax
 804859d:    66 90                    xchg   %ax,%ax
 804859f:    90                       nop

このwriteup[pwnable.tw] orw — 100pts : Giuseppeがよくできており、もうこれを見るだけで全部済む。
(この記事はソレのほぼ翻訳版みたいな内容なのでwriteupってタイトルにするのをためらった)

0x08048576から0x0804857dまでで、read関数を用いてobj.shellcodeの指すアドレスに最大200バイト、シェルコードを読み込ませている。(“Give me your shellcode:”の後に入力したものが格納される)

続く0x08048585 ~ 0x0804858aで、obj.shellcodeの指すアドレスにジャンプしている。

特に落とし穴はなく、問題文にある通りopen, read, writeシステムコールのみを使って/home/orw/flagを読めば良い。

実際のシェルコードは先ほどの参考writeupに載ってるのでそちらを参照するとして、
流れ的にはopenで/home/orw/flagのファイルディスクリプタを取得、readでファイルディスクリプタで指定した/home/orw/flagからシェルコードの末尾以降にファイルの内容を読み出し、writeで標準出力にそれを出力する。

コメント