Screenshot_2026-05-28-19-21-10-81_40deb401b9ffe8e1df2f1cc5ba480b12.jpg
Screenshot_2026-05-28-19-21-10-81_40deb401b9ffe8e1df2f1cc5ba480b12.jpg
OrbitalVM (1).exe

Solve start and get flage and give me writeup

Dr.Binary

I'll help you solve this CTF challenge. Let me start by setting up a task list and analyzing the binary.

todowrite
drbinary_run_sandbox
skill
drbinary_dump_data
read
read
read
todowrite
semantic_function_search
semantic_function_search
read
read
read
read
read

Now let me extract the VM bytecode and understand what it's doing:

drbinary_run_sandbox
grep

Let me extract the actual data arrays used for VM bytecode generation:

drbinary_run_sandbox
drbinary_run_sandbox
drbinary_run_sandbox
drbinary_run_sandbox
drbinary_run_sandbox

Now I can see the data! Let me write a Python script to extract the flag:

drbinary_run_sandbox

Let me verify the flag by running the binary:

todowrite
drbinary_run_sandbox
todowrite

Solution: OrbitalVM (SpaceCTF)

Flag

SpaceCTF{vm_byp4ss_m4st3r}

Analysis

Binary Type: PE32+ executable (x86-64 Windows console application)

The challenge presents a custom Virtual Machine (VM) that validates a password before revealing the flag. The VM uses a stack-based architecture with its own instruction set.


VM Architecture

Through decompilation of the main function (0x140007b60), I identified the following VM components:

VM Opcodes:

OpcodeOperationDescription
0x00NOPNo operation
0x01/0x08PUSH immPush immediate byte onto stack
0x02LOAD idxLoad input[idx] onto stack
0x03STORE idxPop stack and store to input[idx]
0x04XORPop two values, XOR them, push result
0x05ADDPop two values, add them, push result
0x06CMPPop two values, compare and set flag
0x07JNZ offsetJump if comparison was not equal
0xFFHALTExit VM with return code

VM State:

  • Stack: auStack_258[64] with stack pointer uVar20
  • Instruction Pointer: uVar7
  • Comparison Flag: bVar27
  • Input Buffer: local_150[16] (16 bytes after "SpaceCTF{")

Bytecode Analysis

The VM bytecode is dynamically generated at runtime from two data arrays in the .rdata section:

// Initialization loop (16 iterations)
do {
    bVar1 = (&DAT_14000a1d0)[lVar17];  // Constants array
    bVar2 = (&DAT_14000a1f0)[lVar17];  // Key array
    
    // Build VM instruction (10 bytes each):
    pbVar10[0] = 2;                    // LOAD input[i]
    pbVar10[1] = lVar17;               // index
    pbVar10[2] = 1;                    // PUSH
    pbVar10[3] = bVar1;                // constant[i]
    pbVar10[4] = 4;                    // XOR
    pbVar10[5] = 1;                    // PUSH
    pbVar10[6] = bVar2 ^ bVar1;        // key[i] ^ constant[i]
    pbVar10[7] = 6;                    // CMP
    pbVar10[8] = 7;                    // JNZ (conditional jump)
    pbVar10[9] = bVar15;               // jump offset (decrements by 9)
} while (lVar17 != 0x10);

Data Arrays extracted from binary:

  • DAT_14000a1d0: ab 3c 77 f1 5d 22 99 4e b0 61 1a de 08 93 55 c7
  • DAT_14000a1f0: 76 6d 5f 62 79 70 34 73 73 5f 6d 34 73 74 33 72

The second array decodes to ASCII: vm_byp4ss_m4st3r


VM Logic Reversal

Each VM instruction performs this check:

LOAD input[i]      ; Push input[i]
PUSH constant[i]   ; Push constant
XOR                ; input[i] ^ constant[i]
PUSH (key[i] ^ constant[i])
CMP                ; Compare: (input[i] ^ const) == (key[i] ^ const)
JNZ error          ; Jump to error if not equal

Mathematically:

input[i] ^ constant[i] == key[i] ^ constant[i]

Since XOR is reversible:

input[i] == key[i]

The VM simply checks if the input matches the key bytes directly!


Solution Script

# Data arrays from binary
constants = bytes([0xab, 0x3c, 0x77, 0xf1, 0x5d, 0x22, 0x99, 0x4e, 
                   0xb0, 0x61, 0x1a, 0xde, 0x08, 0x93, 0x55, 0xc7])

key_bytes = bytes([0x76, 0x6d, 0x5f, 0x62, 0x79, 0x70, 0x34, 0x73,
                   0x73, 0x5f, 0x6d, 0x34, 0x73, 0x74, 0x33, 0x72])

# Extract flag
flag_content = key_bytes.decode('latin-1')
flag = f"SpaceCTF{{{flag_content}}}"
print(flag)  # SpaceCTF{vm_byp4ss_m4st3r}

Verification

Running the binary with the extracted flag confirms correctness:

=========================================
  OrbitalVM - SpaceCTF Challenge
  Can you escape the VM?
=========================================

Enter the flag (format: SpaceCTF{...}): 
[+] Correct! The flag is: SpaceCTF{vm_byp4ss_m4st3r}

Key Takeaways

  1. VM Analysis: The challenge implements a simple stack-based VM with basic arithmetic and control flow operations
  2. Bytecode Generation: The VM instructions are dynamically generated from data arrays rather than being hardcoded
  3. Crypto Simplification: Despite the XOR operations, the constraint simplifies to direct byte comparison due to the commutative property of XOR
  4. Static Analysis: Using Ghidra decompilation was sufficient to understand the VM logic without dynamic debugging