This appears to be an Android emulator reverse engineering challenge. The first step is to set up and run the emulator using the Android Command Line Tools.
Our agents captured some North Korean military software. Your task: find the correct launch code!
Approach & Solution
What We’re Dealing With
I got my hands on this Windows PE binary that was asking for a 42-character flag. Right off the bat, I could tell this wasn’t going to be your typical reverse engineering challenge when I threw some random input at it.
DATA ="eNrtfQt8k0XW96RNei8p0mBBxIDBFhAoTXUrpZp........."import argparse, base64, ctypes, zlib, pathlib, sys
PASSWORD ="cheese"FLAG ="jqsD0um75+TyJR3z0GbHwBQ+PLIdSJ+rojVscEL4IYkCOZ6+a5H1duhcq+Ub9Oa+ZWKuL703"KEY ="68592cb91784620be98eca41f825260c"HELPER =Nonedefdecrypt_flag(password):
A ="utf-8" flag = bytearray(base64.b64decode(FLAG))
buffer = (ctypes.c_byte * len(flag)).from_buffer(flag)
key = ctypes.create_string_buffer(password.encode(A))
result = get_helper().Decrypt(key, len(key) -1, buffer, len(buffer))
return flag.decode(A)
defget_helper():
global HELPER
if HELPER:
return HELPER
data = globals().get("DATA")
if data:
dll_path = pathlib.Path(__file__).parent /"hello.bin"ifnot dll_path.is_file():
with open(dll_path, "wb") as dll_file:
dll_file.write(zlib.decompress(base64.b64decode(data)))
HELPER = ctypes.cdll.LoadLibrary(dll_path)
else:
0return HELPER
defcheck_three(password):
return check_ex(password, "Check3")
defcheck_four(password):
return check_ex(password, "Check4")
defcheck_ex(password, func):
GetIntCallbackFn = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_wchar_p)
classCallbackTable(ctypes.Structure):
_fields_ = [("E", GetIntCallbackFn)]
@GetIntCallbackFndefeval_int(v):
return int(eval(v))
table = CallbackTable(E=eval_int)
helper = get_helper()
helper[func].argtypes = [ctypes.POINTER(CallbackTable)]
helper[func].restype = ctypes.c_int
return helper[func](ctypes.byref(table))
defcheck_two(password):
@ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
defcallback(i):
return ord(password[i -3]) +3return get_helper().Check2(callback)
defcheck_one(password):
if len(password) !=12:
returnFalsereturn get_helper().Check1(password) !=0defcheck_password(password):
global PASSWORD
PASSWORD = password
checks = [check_one, check_two, check_three, check_four]
result =Truefor check in checks:
result = result and check(password)
return result
defmain():
parser = argparse.ArgumentParser(description="CTF Challenge")
parser.add_argument("password", help="Enter the password")
args = parser.parse_args()
if check_password(args.password):
flag = decrypt_flag(args.password)
print("Correct! The flag is DUCTF{%s}"% flag)
return0else:
print("That is not correct")
return1if __name__ =="__main__":
sys.exit(main())
When running this on Linux, I encountered an error due to an invalid ELF header. This suggests that hello.bin is not a native Linux binary, but rather a Windows DLL or some other non-ELF format. The script attempts to load it using ctypes.cdll.LoadLibrary, which confirms it’s expecting a shared library (DLL) to call functions . This behavior is evident in the get_helper function.
deoxy ribo nucleic acid deoxy meaning without oxygen ribo meaning the 5-carbon sugar backbone nucleic meaning of the nucleus acid meaning proton donor
Solution
Initial Recon
We start by looking at the challenge directory:
➜ dna ls
main.cpython-310.pyc vm.dna
We can see that this is a virtual machine challenge, and the Python code has been compiled with Python 3.10 into a .pyc file ,Before diving into the challenge, let’s take a moment to understand what a virtual machine (VM) is.
This challenge involves reverse engineering a custom “brain” simulation to extract a flag. The brain operates on a set of neurons and performs transformations using a combination of hashing, rotation, and matrix operations. The goal is to deduce the input that produces the required outputs.
Solution
The solution involves implementing the brain simulation in Python and using the Z3 solver to reverse the transformations. Below is the code and explanation:
This challenge involves reverse engineering and cryptographic analysis to extract keys and decrypt an encrypted flag. The solution uses GDB scripting to automate the extraction of keys from memory frames and applies XOR decryption to retrieve the original flag.
Solution
GDB Script: ExtractKeys
The following GDB script automates the extraction of keys from memory frames:
import gdb
import re
classExtractKeys(gdb.Command):
def__init__(self):
super(ExtractKeys, self).__init__("extract_keys", gdb.COMMAND_USER)
defparse_gdb_line(self, line):
"""
Extracts byte values from a single line of GDB output.
Example input: "0x7ffe603d0100: 0x45 0x65 0x41 0x15 0x57 0xc0 0xdb 0xda"
Returns: ["45", "65", "41", "15", "57", "c0", "db", "da"]
"""match= re.search(r":\s+((?:0x[0-9a-f]{2}\s*)+)", line)
ifmatch:
return re.findall(r"0x([0-9a-f]{2})", match.group(1))
return []
defparse_gdb_output(self, gdb_output):
"""
Parses the entire GDB output to extract key bytes.
Returns a single hex string.
""" key_bytes = []
for line in gdb_output.split("\n"):
key_bytes.extend(self.parse_gdb_line(line))
return"".join(key_bytes)
definvoke(self, arg, from_tty):
start_frame, end_frame =4, 1003with open("keys.txt", "w") as key_file:
for frame_id in range(start_frame, end_frame +1):
try:
gdb.execute(f"frame {frame_id}", to_string=True)
key_output = gdb.execute(f"x/59bx key", to_string=True)
key_hex_string = self.parse_gdb_output(key_output)
if key_hex_string:
key_file.write(key_hex_string +"\n")
except gdb.error:
print(f"[-] Skipping frame {frame_id} (No key found)")
continue print("[✔] All keys extracted to keys.txt")
ExtractKeys()
Decryption Process
The decryption process involves loading the encrypted flag and the extracted keys, then applying XOR decryption in reverse order:
This challenge involves reverse engineering a binary to determine the required input that produces the desired output. The solution involves XOR operations and understanding the binary’s constants and register values.
Solution
The following Python script demonstrates the solution:
import struct
# Constants from the binaryconstant = [
0x2a8c7f3acdf36ffb, # First 8 bytes of the constant0x8cc2eef32660caaa, # Next 8 bytes0xefa1fd61d7a3b592, # Next 8 bytes0xa9ddc2d22a90025e# Last 8 bytes]
# YMM7 register values from GDB (converted to 4x 64-bit integers)ymm7 = [
0x1eca2043bfc01980,
0xd386a3ba753fbe9f,
0x87d5cc1688d185ea,
0xd4aebbb741cf3001]
defqwords_to_bytes(qwords):
returnb''.join(struct.pack('<Q', q) for q in qwords)
constant_bytes = qwords_to_bytes(constant)
ymm7_bytes = qwords_to_bytes(ymm7)
required_input = bytes(a ^ b for a, b in zip(constant_bytes, ymm7_bytes))
flag =b"gigem"+ required_input
print("Raw bytes:", flag)
# Try to decode as ASCII (some bytes may not be printable)try:
print("ASCII:", flag.decode('ascii'))
exceptUnicodeDecodeError:
print("Contains non-ASCII bytes")
Malakar has ensnared you with a dark spell, banishing you to the depths of the Nether world. Escape hinges on recalling the ancient enchantments of your forefathers. Wield their arcane power to shatter the Aether gateways and reclaim your freedom. Only the correct incantation—32 bytes of mystical precision—will unlock the path back to the mortal realm. Can you decipher the spell and blast through the barriers of this infernal trap?
The challenge presents a seemingly simple ncurses-based program where the player navigates through a maze-like interface. The goal is to uncover a hidden flag by understanding the program’s intricate mechanics.
Key Observations
The program uses ncurses library for terminal-based interaction
Allows movement using arrow keys
Displays terminal dimensions
Contains a specific hidden mechanism when terminal is exactly 13x37
Reverse Engineering Approach
Code Breakdown
The main function reveals several interesting characteristics: