Skip to main content

bytemancy 1 picoCTF 2026 Solution

A server asks you to send a specific sequence of bytes. Decode what it wants and respond correctly.

Published: March 20, 2026Updated: September 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 to understand what byte sequence the server expects.
Launch the challenge instance and connect via netcat.
bash
cat app.py

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Read the source code
    Observation
    The challenge asks for the exact input the server expects and hands you app.py. The value is hardcoded in there, so read it.
    Open app.py. The check is literally if user_input == "\x65"*1751:, so 1751 isn't arbitrary, it's the source. ASCII 101 = 'e'. See Python for CTF for payload-shaping idioms.
    bash
    cat app.py
    bash
    grep -n 'user_input ==' app.py   # confirms "\x65" * 1751
    python
    python3 -c 'print(len("e"*1751))'  # sanity: 1751

    Expected output

    11:    if user_input == "\x65"*1751:
    1751
    What didn't work first

    Tried: Manually count from the bytemancy-0 pattern and guess 3 repetitions or another small number.

    The check wants 1751 characters, not three or any other small number. A shorter string gets an 'Incorrect' and a closed connection. The count is right there in the source, so there is nothing to guess.

    Tried: Interpret 'ASCII 101' as the repetition count and send 'e' 101 times.

    101 is the code point for the letter e, not how many times to repeat it. The character comes from the code, the count comes from the expected variable, and those are 101 and 1751 respectively.

    Learn more

    The step from 3 repetitions (bytemancy-0) to 1751 repetitions (bytemancy-1) is designed to rule out manual typing. You cannot reasonably type 1751 'e' characters by hand, so the challenge forces you to use a script or shell one-liner to generate the payload programmatically. This is a key lesson: automation is a core CTF skill.

    Python string multiplication ('e' * 1751) creates a string of exactly 1751 'e' characters in a single expression. The same works for byte strings: b'e' * 1751. This technique extends to generating padding bytes (b'\x00' * 64), creating cyclic patterns, and building exploit payloads where length matters precisely.

    The python3 -c flag runs a single Python expression from the command line, making it ideal for quick payload generation. Combined with shell pipes (|) and netcat, you get a complete one-liner exploit. For more complex interactions, pwntools' remote() class handles the full connection lifecycle including reading responses and sending multiple payloads.

  2. Step 2Send the payload
    Observation
    The expected value is the letter e repeated 1751 times, far too long to type. Generate it with a Python one-liner and pipe it to netcat.
    Generate 1751 es and send. Note the s.recv(512) in the Python form is not optional, it consumes the prompt banner so the next read aligns. See netcat for CTF.
    python
    python3 -c "print('e' * 1751)" | nc <HOST> <PORT_FROM_INSTANCE>
    bash
    # Interactive variant - recv(512) syncs with the banner before sending:
    python
    python3 -c "import socket; s=socket.create_connection(('<HOST>', <PORT_FROM_INSTANCE>)); s.recv(512); s.sendall(b'e'*1751 + b'\n'); print(s.recv(512).decode())"
    What didn't work first

    Tried: Type 'e' * 1751 literally into the netcat prompt by hand.

    The shell reads that as a literal string, not a multiplication, so six characters go out instead of 1751 and the server rejects them immediately. Let Python do the multiplication and pipe its output into netcat.

    Tried: Omit the trailing newline by using sys.stdout.write instead of print when piping to nc.

    The server's input() call returns only once it sees a newline or the connection closes. Without a newline, whether you get an answer comes down to whether your netcat closes the socket at EOF, so the run either hangs or looks like a silent rejection. print() adds the newline for you; writing bytes directly does not.

    Learn more

    The two approaches shown - piping through nc vs. using Python's socket module - differ in interactivity. The pipe approach is fire-and-forget: it sends the payload and displays whatever the server returns, but cannot respond to multiple prompts. The socket approach reads the banner first, then sends the payload, then reads the response - giving full control of the conversation.

    The socket module is Python's low-level network interface. socket.create_connection() is a convenience wrapper that resolves the host, creates a TCP socket, and connects - equivalent to socket.socket(AF_INET, SOCK_STREAM) followed by .connect(). For CTF use, pwntools' remote(host, port) is even more convenient and adds methods like recvuntil(), sendline(), and interactive().

    A subtle detail: the server reads input until a newline and then compares. Adding b'\n' (or using print() which adds one automatically) is important - without it, the server may block forever waiting for the line terminator. This is a common gotcha when working with line-buffered servers.

Interactive tools
  • Base64 & Base32 DecoderDecode Base64 and Base32 strings with auto-detection. Multi-layer mode unwraps nested encodings automatically.
  • Recipe ChainStack decoders into a pipeline: Base64, hex, ROT, XOR, Morse, URL, Atbash, Vigenère, and more. Magic mode auto-discovers the chain. Bookmark the URL to save it.
  • Number Base ConverterConvert numbers between binary, octal, decimal, and hexadecimal instantly. Enter any value and see all four bases update in real time.

Flag

Reveal flag

picoCTF{h0w_m4ny_e's???_...}

app.py asks for ASCII decimal 101 × 1751, no spaces. Send the string 'e' repeated 1751 times.

Key takeaway

When a service wants a long exact input, generate it in a language that evaluates expressions and pipe it in; the shell will not multiply a string for you. A line-buffered service reads until a newline before comparing, so the terminator is mandatory or the server waits forever. Literal-versus-evaluated input and a missing newline are the two recurring traps in netcat challenges.

Related reading

Useful tools for General Skills

Where to go next