bytemancy 2 picoCTF 2026 Solution

Published: March 20, 2026

Description

Can you conjure the right bytes? Download app.py and recover the exact input the server expects.

Download and read app.py.

Launch the challenge instance and connect via netcat.

bash
cat app.py
  1. Step 1Read the source code
    Download app.py. It reads via sys.stdin.buffer (raw bytes) and checks that the input equals b'\xff\xff\xff' (hex byte 0xFF, three times, no space). The key difference from bytemancy-0/1 is that it reads raw binary, not text, so you must send literal byte 0xFF, not the string 'ff'.
    bash
    cat app.py
    Learn more

    The critical distinction here is between text mode and binary mode I/O. Python's sys.stdin is a text stream that decodes bytes to Unicode strings using the terminal encoding (usually UTF-8). sys.stdin.buffer is the underlying binary stream - it gives you raw bytes without any Unicode decoding. A server using sys.stdin.buffer.read() compares raw bytes, so you must send actual byte values, not their text representations.

    Byte 0xFF (255 decimal) is the highest possible byte value. It is not a valid UTF-8 byte on its own (UTF-8 uses 0xFF only in specific multi-byte sequences) and is not printable ASCII. Terminals typically cannot type or display it directly, which is why you need either printf with octal/hex escapes or a Python socket that sends b'\xff' as a raw byte.

    printf '\xff\xff\xff\n' in bash interprets \xff as a hex escape and outputs the literal byte 0xFF. This is different from echo '\xff', which on most shells outputs the six characters backslash, x, f, f (text) rather than the binary byte. Understanding this shell behavior is essential for binary exploitation work where you need to inject exact byte sequences.

  2. Step 2Send the raw bytes
    Send three raw 0xFF bytes plus a newline. Try the text form first; if the server rejects it, switch to raw bytes. printf '\xff\xff\xff\n' works in bash but not all sh implementations, so prefer the Python socket form for portability. See Python for CTF.
    bash
    # bash only - dash/busybox printf may not honor \x escapes:
    bash
    printf '\xff\xff\xff\n' | nc <HOST> <PORT_FROM_INSTANCE>
    bash
    # Portable Python form, with try/except. Server-side close mid-handshake is common:
    python
    python3 - <<'PY'
    import socket
    try:
        s = socket.create_connection(('<HOST>', <PORT_FROM_INSTANCE>))
        s.recv(512)
        s.sendall(b'\xff\xff\xff\n')
        print(s.recv(2048).decode(errors='replace'))
    except (BrokenPipeError, ConnectionResetError) as e:
        print('server closed:', e)
    PY
    Learn more

    Python byte literals (b'\xff') let you specify exact byte values using hex escapes. The bytes object is a sequence of integers 0-255 - completely independent of any character encoding. When you call socket.sendall(b'\xff\xff\xff\n'), Python sends four bytes to the server: 255, 255, 255, 10 (the newline is byte 10 in ASCII).

    This challenge teaches the concept of raw binary protocol interaction, which is essential for network binary exploitation. Tools like pwntools are designed specifically for this: p.sendline(b'\xff\xff\xff') sends the bytes plus a newline, and p.recv() reads raw bytes back. You never need to worry about encoding layers because pwntools stays in binary mode throughout.

    The progression from bytemancy-0 (printable ASCII) to bytemancy-2 (raw non-printable bytes) mirrors real exploit development: shellcode and ROP gadget addresses contain arbitrary byte values, many of which are non-printable. Mastering raw byte I/O is a prerequisite for buffer overflow and format string exploitation.

Flag

picoCTF{byt3m4ncy_2_...}

app.py reads raw bytes via sys.stdin.buffer and expects the three literal bytes 0xFF 0xFF 0xFF. Use printf '\xff\xff\xff\n' | nc; sending the text string 'ff' will not work.

Want more picoCTF 2026 writeups?

Useful tools for General Skills

Related reading

What to try next