Description
Can you conjure the right bytes? Download app.py and recover the exact input the server expects.
Setup
cat app.pySolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Read the source code
ObservationThe challenge hands over app.py and asks for the right bytes, so an exact byte comparison is happening. Read the source for the values and the I/O mode it uses.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'.bashcat app.pyWhat didn't work first
Tried: Sending the string 'ffffff' or 'ff ff ff' to the server via netcat directly.
The server wants three raw bytes of value 255. Typing ff sends two ASCII letters instead, and the comparison fails silently with no flag.
Tried: Using sys.stdin instead of sys.stdin.buffer and trying to decode 0xFF as a Unicode character.
0xFF is not a valid standalone UTF-8 byte, so text-mode stdin raises a decode error on it. The server uses the buffer interface precisely to skip the encoding layer, because text mode cannot carry byte values above 127 that do not form valid sequences.
Learn more
The critical distinction here is between text mode and binary mode I/O. Python's
sys.stdinis a text stream that decodes bytes to Unicode strings using the terminal encoding (usually UTF-8).sys.stdin.bufferis the underlying binary stream - it gives you raw bytes without any Unicode decoding. A server usingsys.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 in any position (UTF-8 never uses 0xFF -- valid multi-byte sequences use leading bytes 0xC2-0xF4 and continuation bytes 0x80-0xBF, so 0xFF and 0xFE are explicitly excluded from all UTF-8 encodings) and is not printable ASCII. Terminals typically cannot type or display it directly, which is why you need either
printfwith octal/hex escapes or a Python socket that sendsb'\xff'as a raw byte.printf '\xff\xff\xff\n'in bash interprets\xffas a hex escape and outputs the literal byte 0xFF. This is different fromecho '\xff', which on most shells outputs the four 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.Step 2Send the raw bytes
Observationapp.py reads from sys.stdin.buffer and compares against three 0xFF bytes, so literal bytes have to go over the wire, not a text representation. pwntools or printf with hex escapes are the reliable ways to send them.Send three raw 0xFF bytes plus a newline. The challenge hint explicitly recommends pwntools for this. Note that naively pipingpython3 -c "print(b'\xff'*3)"sends the wrong thing:printof a bytes object writes its repr, so the server receives the 15 ASCII charactersb'\xff\xff\xff'. Dropping thebprefix is no better, because text-mode stdout then re-encodes each U+00FF as the two UTF-8 bytesc3 bf. You must use a method that stays in binary mode throughout, such as pwntools orsys.stdout.buffer.write. See Python for CTF.bash# Primary: pwntools (stays in binary mode, no encoding corruption):pythonpython3 - <<'PY' from pwn import * p = remote('<HOST>', <PORT_FROM_INSTANCE>) p.sendline(b'\xff\xff\xff') p.interactive() PYbash# Alternative (bash only - dash/busybox printf may not honor \x escapes):bashprintf '\xff\xff\xff\n' | nc <HOST> <PORT_FROM_INSTANCE>What didn't work first
Tried: Using python3 -c "print(b'\xff'*3)" piped into nc to send the bytes.
print() on a bytes object writes its repr, so what goes out is the literal text b'\xff\xff\xff'. Print the str form instead and text-mode stdout re-encodes each character as the two UTF-8 bytes c3 bf. Either way the server sees the wrong bytes. Write through sys.stdout.buffer, or use pwntools, and stay in binary mode the whole way.
Tried: Using echo '\xff\xff\xff' piped into nc instead of printf.
Most shells do not interpret backslash-hex in echo, so you get the literal text three times over. printf with a hex or octal escape is the POSIX way to emit raw bytes. Some shells interpret escapes with echo -e, but printf is portable and explicit.
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 callsocket.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, andp.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.
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{3ff5_4_d4yz_...}
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.