Virtual Machine 0 picoCTF 2023 Solution

Published: April 26, 2023

Description

A COLLADA (.dae) 3D model file represents an enemy mechanical device. The red axle rotation is the input; the blue axle rotation is the output. A very large input number is given. Determine the gear ratio by opening the model in Blender, then multiply the input by that ratio and convert the result to ASCII to get the flag.

Download the challenge archive and extract the .dae file.

Install Blender (free, from blender.org) to open the COLLADA model.

bash
wget https://artifacts.picoctf.net/c/508/vm0 && unzip vm0.zip
bash
# Open the .dae file in Blender: File -> Import -> Collada (.dae)

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Open the model in Blender and count the gear teeth
    Observation
    I noticed the challenge provided a COLLADA (.dae) 3D model file and described a gear system with a red input axle and a blue output axle, which suggested I needed to open the model visually in Blender to count the teeth on each gear and determine the ratio.
    Import the .dae file into Blender. The model contains two gears: a large red gear and a small blue gear. Delete non-essential parts to expose the gears, then count the teeth on each. The large gear has 40 teeth and the small gear has 8 teeth, giving a gear ratio of 5:1.
    bash
    # In Blender:
    bash
    # File -> Import -> Collada (.dae) -> select the .dae file
    bash
    # Use X to delete non-gear objects
    bash
    # Count the cogs/teeth on each gear manually
    What didn't work first

    Tried: Trying to read gear tooth counts from the raw .dae XML instead of opening the file in Blender

    The .dae file is XML and does store mesh geometry, but the tooth count is encoded as 3D vertex positions, not a human-readable integer. Scanning the file with grep or a text editor yields thousands of floating-point coordinates with no obvious tooth counter. Blender renders the mesh visually so you can count teeth directly by rotating the viewport, which is the only practical approach here.

    Tried: Assuming the gear ratio is 1:1 (no multiplication needed) and treating the input number as the raw flag value

    If both gears had the same number of teeth the ratio would be 1:1, but the challenge explicitly shows a large red gear driving a smaller blue gear. Decoding the raw input directly as hex ASCII produces garbled output that does not start with picoCTF. The correct ratio of 5 (40 teeth / 8 teeth) must be applied first before the hex-to-ASCII conversion yields a valid flag.

    Learn more

    COLLADA (.dae) is an XML-based 3D model interchange format. Blender can import it directly via File -> Import -> Collada. The model in this challenge is a Lego-style gear assembly representing a simple machine.

    Gear ratios work as follows: if the large gear has 40 teeth and the small gear has 8 teeth, one full rotation of the large gear causes 5 full rotations of the small gear (40 / 8 = 5). So when the red axle (attached to the large gear) rotates by some amount, the blue axle (attached to the small gear) rotates 5 times as much.

    In this challenge the relationship is inverted: the input is the red axle (large gear) rotation and we must find the blue axle rotation. Since the small gear spins 5x faster, multiply the red rotation by 5 to get the blue rotation.

  2. Step 2
    Apply the gear ratio and convert to the flag
    Observation
    I noticed the challenge gave a very large input number and the gear ratio from the model was 5:1 (40 teeth driving 8 teeth), which suggested multiplying the input by 5 and then converting the result from decimal to hex and decoding it as ASCII to recover the flag.
    Take the large input number from the challenge description. Multiply it by the gear ratio (5) to get the blue axle output value. Convert the result from decimal to hexadecimal, then interpret the hex as ASCII to reveal the flag.
    python
    python3 - <<'PY'
    # Replace INPUT with the large number given in the challenge
    INPUT = 0  # paste the number here
    
    ratio = 5  # 40 teeth / 8 teeth = 5
    output = INPUT * ratio
    
    # Convert to hex and then to ASCII
    hex_str = hex(output)[2:]  # strip '0x'
    flag = bytes.fromhex(hex_str).decode('ascii', errors='replace')
    print(f"Output: {output}")
    print(f"Hex: {hex_str}")
    print(f"Flag: {flag}")
    PY
    What didn't work first

    Tried: Using the wrong gear ratio (inverting it to 1/5) because the small blue gear is the output and seems like it should slow things down

    It is easy to confuse which gear is driving which. The red (large) gear is the input and drives the small blue gear, so the blue axle spins faster - 5x, not 1/5x. Multiplying by 0.2 instead of 5 gives a decimal that does not convert cleanly to integer hex bytes, and the resulting ASCII decode produces no recognizable flag string. Always confirm which axle is input and which is output before applying the ratio.

    Tried: Interpreting the output number as decimal ASCII code points instead of converting it to hex first

    The output number is far too large to be a sequence of two-digit ASCII codes interpreted directly in decimal. The correct path is hex(output)[2:] to get a hexadecimal string, then bytes.fromhex() to decode it as ASCII. Skipping the hex step and trying int-to-chr on chunks of the decimal number yields wrong character boundaries and produces garbage rather than a picoCTF flag.

    Learn more

    The gear ratio translates the input rotation number into a larger output number (5 times the input). That output number, when viewed in hexadecimal and decoded as ASCII, reveals a picoCTF flag string like picoCTF{g34r5_0f_m0r3_<hash>}.

    This challenge teaches that CTF problems can come in non-traditional formats. Instead of a binary or web app, the "virtual machine" is a physical gear system modeled in 3D. The mathematical relationship (gear ratio) is the "instruction set" of this machine, and computing the output given the input is the "execution."

Interactive tools
  • Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
  • Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.

Flag

Reveal flag

picoCTF{g34r5_0f_m0r3_...}

The gear ratio is 5 (40-tooth gear drives an 8-tooth gear). Multiply the input by 5, convert to hex, decode as ASCII. The trailing 8-character hex hash is generated per instance (observed values include 05e5104d and 6170a1b1).

Key takeaway

Reverse engineering is not limited to software. Any deterministic system, mechanical, electrical, or mathematical, can be treated as a computation to be understood and replicated. A gear train is essentially a fixed-ratio multiplier; counting the teeth is the disassembly step, and applying the ratio is the emulation step. The same analytical mindset applies to hardware security research, chip decapping, and protocol reverse engineering where the 'source code' is a physical artifact rather than bytes.

Related reading

Want more picoCTF 2023 writeups?

Useful tools for Reverse Engineering

What to try next