Based picoCTF 2019 Solution

Published: April 2, 2026

Description

This encoding is base as it gets. Convert between binary, octal, and hex quickly. Connect to the server with nc.

Connect to the challenge server.

bash
nc <HOST> <PORT_FROM_INSTANCE>

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Understand the challenge format
    Observation
    I noticed the challenge description mentioned binary, octal, and hex conversion and that the server communicates interactively, which suggested I needed to understand the exact prompt format and time constraints before attempting any conversions.
    The server sends you encoded strings one at a time in binary, octal, or hex format and asks you to convert them to the word they represent. You must respond correctly within a short time limit.
    Learn more

    The three bases you need to handle:

    • Binary (base 2): digits 0 and 1. E.g., 01110000 = 112 = 'p'
    • Octal (base 8): digits 0-7. E.g., 160 = 112 = 'p'
    • Hexadecimal (base 16): digits 0-9 and a-f. E.g., 70 = 112 = 'p'

    In Python: int('01110000', 2) for binary, int('160', 8) for octal, int('70', 16) for hex. Then chr() to get the character.

  2. Step 2
    Write a pwntools script to automate responses
    Observation
    I noticed the server enforces a tight time limit per round and cycles through multiple encoding bases, which suggested that manual conversion would consistently time out and that a pwntools script automating read-parse-convert-send in a loop was the only reliable approach.
    The time limit is tight, so write a Python script using pwntools to automate the conversion. Read each encoded string, detect the base from context, convert it, and send the answer.
    bash
    pip3 install pwntools
    python
    python3 << 'EOF'
    from pwn import *
    
    r = remote('<HOST>', <PORT_FROM_INSTANCE>)
    
    def decode_word(encoded, base):
        parts = encoded.strip().split()
        chars = []
        for p in parts:
            chars.append(chr(int(p, base)))
        return ''.join(chars)
    
    for _ in range(3):
        line = r.recvuntil(b'?').decode()
        print(line)
        if 'binary' in line.lower():
            encoded = r.recvline().decode().strip()
            answer = decode_word(encoded, 2)
        elif 'octal' in line.lower():
            encoded = r.recvline().decode().strip()
            answer = decode_word(encoded, 8)
        else:
            encoded = r.recvline().decode().strip()
            answer = decode_word(encoded, 16)
        r.sendline(answer.encode())
    
    r.interactive()
    EOF
    What didn't work first

    Tried: Manually typing the converted value into the terminal for each round.

    The server enforces a strict time limit of a few seconds per round. Manual conversion and typing is too slow, and the connection closes before you can submit. The pwntools script reads and responds programmatically in milliseconds, well within the limit.

    Tried: Using recvline() instead of recvuntil(b'?') to capture the prompt before parsing the base type.

    The server may send the base label and the encoded string across multiple lines or in a single transmission that does not align neatly with recvline() boundaries. recvuntil(b'?') waits for the question mark that ends the prompt, ensuring the base keyword (binary, octal, hex) is fully buffered before you parse it, whereas recvline() may return only part of the prompt and cause the base-detection logic to miss the keyword entirely.

    Learn more

    pwntools is a Python library designed for CTF challenges involving network connections and binary exploitation. The remote() function creates a TCP connection. recvuntil() reads until a specific byte sequence appears, and sendline() sends data followed by a newline.

  3. Step 3
    Receive the flag
    Observation
    I noticed the pwntools script's final call to r.interactive() keeps the connection open after the last round, which is where the server delivers the flag once all three conversions are answered correctly.
    After correctly converting all encoded strings, the server outputs the flag.
    Learn more

    Number base conversion is fundamental to computer science. Computers store all data in binary; hexadecimal is a compact human-readable notation for binary (each hex digit represents 4 bits); octal (each octal digit represents 3 bits) was common in early Unix systems.

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.
Alternate Solution

Use the Number Base Converter on this site to quickly convert individual binary, octal, or hex values to their ASCII characters - useful for manual verification before scripting with pwntools.

Flag

Reveal flag

picoCTF{...}

Automate binary/octal/hex to ASCII conversion using pwntools to respond within the server's time limit.

Key takeaway

Binary, octal, and hexadecimal are all positional numeral systems representing the same underlying integer values; the only difference is the base used to express each digit. Computers store and transmit everything in binary, while hex serves as its compact human-readable shorthand (4 bits per digit) and octal as a legacy 3-bits-per-digit notation from early Unix file permissions. Recognizing and converting between these representations quickly is a foundational skill in reverse engineering, network analysis, and binary exploitation.

Related reading

Want more picoCTF 2019 writeups?

Useful tools for General Skills

What to try next