April 11, 2026

Beginner's Guide to Netcat for CTFs

A beginner-friendly guide to using netcat (nc) in CTF competitions — connecting to challenge servers, piping payloads, automating with Python pwntools, and reading challenge output.

Introduction

If you have opened a picoCTF challenge and seen a line like nc challenge.picoctf.org 12345, you already know you need netcat. What you might not know is what to do next. This guide walks you through everything: installing netcat, making your first connection, reading server output, piping in answers, and automating multi-round interactions with pwntools.

Netcat is used in almost every remote picoCTF challenge in the General Skills, Binary Exploitation, and Cryptography categories. Learning it once pays off across hundreds of challenges. Many individual challenge writeups on this site link here when they include a netcat step.

Related guides on this site

By the end of this guide you will be able to connect to any picoCTF service, pipe a payload directly into it, and know when to reach for pwntools instead of typing manually.

Installing netcat

Netcat ships under a few different names depending on the platform. The commands below cover the most common environments you will encounter.

Linux (Debian, Ubuntu, Kali)

Kali Linux includes netcat pre-installed. On stock Ubuntu or Debian you may need to install it:

# Install the OpenBSD variant (recommended for CTF work)
sudo apt update && sudo apt install netcat-openbsd
# Verify the install
nc -h

Prefer netcat-openbsd over netcat-traditional. The OpenBSD variant supports the -N flag (close on EOF), which prevents nc from hanging after you pipe a payload.

macOS

macOS ships with a version of nc pre-installed. You can use it directly without any additional install:

# Already available — just check the version
nc -h
# If you want the OpenBSD variant via Homebrew
brew install netcat

Windows (WSL2)

The easiest path on Windows is WSL2 with Ubuntu. Once WSL2 is set up, install netcat the same way as on Linux:

# Inside your WSL2 terminal (Ubuntu)
sudo apt update && sudo apt install netcat-openbsd
Note: Native Windows netcat ports exist (e.g. ncat from the Nmap for Windows package) but they behave differently in edge cases. WSL2 is the recommended environment for CTF work on Windows because it gives you a full Linux shell.

Confirming the install

# You should see usage output, not 'command not found'
nc -h
# Quick connectivity test against a known server
nc -zv google.com 80
# Expected: Connection to google.com 80 port [tcp/http] succeeded!

Your first connection

When a picoCTF challenge gives you a host and port, your first move is always the same:

nc challenge.picoctf.org 12345

That is the entire command. Netcat opens a TCP connection to challenge.picoctf.org on port 12345 and then does two things simultaneously: it prints anything the server sends, and it forwards anything you type to the server.

What to expect: the banner

Almost every challenge service prints a banner immediately after you connect. The banner tells you what the challenge expects. It might look like this:

$ nc challenge.picoctf.org 12345
Welcome to the Super SSH challenge!
The flag is: picoCTF{s3cur3_sh3ll_12ab34cd}

In simple challenges the flag is right there in the banner. Copy it, paste it into the picoCTF submission box, and you are done.

Challenges that ask a question

Many services print a prompt and wait for your input before revealing the flag. The workflow is:

  1. Connect with nc host port.
  2. Read the banner and any question the server asks.
  3. Type your answer and press Enter.
  4. Read the server's response. Repeat if there are multiple rounds.
  5. When the server prints picoCTF{...}, copy it.
$ nc challenge.picoctf.org 12345
What is 2 + 2?
> 4
Correct! The flag is: picoCTF{math_is_hard_a1b2c3d4}

Exiting the connection

To close the connection, press Ctrl+C. If the server closed its side first, nc will exit on its own.

Example challenge using nc

Reading and parsing server output

Some challenge services dump a large wall of text. If the output scrolls past your terminal buffer, you might miss the flag. These techniques prevent that.

Save output with tee

tee writes everything to both your terminal and a file at the same time. You can read the flag in real time and still have a file to grep afterward.

nc challenge.picoctf.org 12345 | tee output.txt
# After the session ends, search the saved file
grep 'picoCTF' output.txt

Page through output with less

If the server sends everything at once and then closes the connection, you can pipe the entire output into less for scrollable viewing:

nc challenge.picoctf.org 12345 | less
# Inside less:
# /picoCTF search for the flag
# n jump to the next match
# q quit
Limitation: Piping to less only works if the server sends all its output and then closes the connection. If the server waits for you to type something, less will not show the prompt because it is buffering. Use tee for interactive sessions.

Increase your terminal scroll buffer

As a last resort, simply increase your terminal emulator's scroll-back buffer. In most Linux terminals: Edit > Preferences > Scrolling, and set the scroll-back lines to 10000 or unlimited. Then use Ctrl+Shift+F to search backward through the buffer.

Grep on the fly with process substitution

If you want to filter output as it streams (not after the session), combine nc with grep:

# Print only lines containing 'picoCTF'
nc challenge.picoctf.org 12345 | grep --line-buffered 'picoCTF'

The --line-buffered flag forces grep to flush each matching line immediately rather than waiting to fill an internal buffer.

Piping payloads into nc

When you already know the answer to a challenge and do not want to type it manually, you can pipe the payload directly into nc. The server receives your input as if you had typed it and pressed Enter.

echo: single-line payloads

# Send the string '42' followed by a newline
echo '42' | nc challenge.picoctf.org 12345
# Send a specific password
echo 'letmein' | nc challenge.picoctf.org 12345

cat: file-based payloads

When your payload is more than one line, write it to a file and pipe that file into nc:

# Write your answers to a file, one per line
cat payload.txt
42
yes
picoCTF
# Send the entire file
cat payload.txt | nc challenge.picoctf.org 12345
# Equivalent shorthand using input redirection
nc challenge.picoctf.org 12345 < payload.txt

Heredocs: inline multi-line payloads

A heredoc lets you write a multi-line payload inline without creating a separate file:

nc challenge.picoctf.org 12345 << 'EOF'
42
yes
picoCTF
EOF

The -N flag: close on EOF

After piping a payload, nc (OpenBSD variant) may hang waiting for more input even though you have nothing left to send. The -N flag tells nc to shut down the connection when it reaches the end of stdin:

echo '42' | nc -N challenge.picoctf.org 12345
When piping works and when it does not: Piping works well when the server processes all your input at once and then prints the result. It breaks down in multi-round interactions where the server asks a different question each round based on your previous answer. For those, use pwntools (covered in the next section).

Example challenge where piping helps

Binary Search is a multi-round guessing game. You can script the guess logic and pipe each answer in, or use pwntools for the interactive loop.

Scripting interactions with pwntools

Some challenges cannot be solved by typing manually or piping a static payload. Examples:

  • The server asks 100 random math questions and you have 5 seconds per question.
  • Each round the server sends a new number to guess and you must send a number based on the previous response (binary search, guessing games).
  • You need to parse the server's response and compute the next payload dynamically.

For all of these, pwntools is the right tool. It is a Python library designed for CTF interactions. Install it with:

pip install pwntools

The remote() pattern

The core pwntools workflow replaces nc with a Python object that you can read from and write to programmatically:

from pwn import *
# Open a connection (same as: nc challenge.picoctf.org 12345)
conn = remote('challenge.picoctf.org', 12345)
# Read everything until the server stops sending
banner = conn.recvall(timeout=2)
print(banner.decode())
conn.close()

Interactive loop example

Here is the pattern for a challenge that asks multiple questions and expects an answer to each one before moving on:

from pwn import *
conn = remote('challenge.picoctf.org', 12345)
# Read the intro text up to the first '>' prompt
conn.recvuntil(b'> ')
for _ in range(100):
# Read the question line
line = conn.recvline().decode().strip()
# Parse and compute the answer (example: eval a math expression)
answer = str(eval(line))
# Send the answer
conn.sendline(answer.encode())
# Read server feedback before the next question
response = conn.recvuntil(b'> ', timeout=5).decode()
if 'picoCTF' in response:
print(response)
break
conn.close()

Key pwntools methods

MethodWhat it does
conn.recvline()Read one line (up to newline)
conn.recvuntil(b'...')Read until a specific byte string appears
conn.recvall()Read everything until the server closes
conn.sendline(b'...')Send bytes followed by a newline
conn.send(b'...')Send raw bytes (no newline appended)
conn.interactive()Hand control back to you to type manually
More on pwntools: The Python for CTF guide at /posts/python-for-ctf covers pwntools in more depth, including binary exploitation patterns, struct packing, and working with ELF files.

Common netcat challenge patterns

Most nc-based picoCTF challenges fall into one of four patterns. Identify which pattern you are dealing with before you start typing.

Pattern 1: Read the banner

The flag is in the server's first response. Just connect and read.

nc challenge.picoctf.org 12345
# The flag is printed immediately. Copy it.

Pattern 2: Answer a question

The server asks one question and hands you the flag if your answer is correct. Pipe the answer in:

# If you already know the answer
echo 'the_answer' | nc -N challenge.picoctf.org 12345
# If you need to see the question first
nc challenge.picoctf.org 12345
# Read the question, type your answer, press Enter

Pattern 3: Multi-round interaction

The server runs multiple rounds and your answer each round depends on what the server sent. Use pwntools:

from pwn import *
conn = remote('challenge.picoctf.org', 12345)
while True:
prompt = conn.recvline().decode().strip()
if 'picoCTF' in prompt:
print(prompt)
break
answer = compute_answer(prompt) # your logic here
conn.sendline(answer.encode())
conn.close()

Pattern 4: Send raw bytes

Some binary exploitation challenges require sending specific byte values that cannot be typed on a keyboard (e.g. 0x00, 0xff). Use Python to construct and send the payload:

# Using pwntools (recommended)
from pwn import *
conn = remote('challenge.picoctf.org', 12345)
payload = b'\x41' * 64 + p64(0xdeadbeef) # example buffer overflow
conn.sendline(payload)
conn.interactive()
# Using Python subprocess (no pwntools)
python3 -c "import sys; sys.stdout.buffer.write(b'\x41' * 64)" | nc challenge.picoctf.org 12345

Troubleshooting

Here are the most common problems beginners run into and how to fix them.

nc: command not found

Netcat is not installed. Run the install command for your platform from the Installing netcat section above. On Kali this should not happen; on a fresh Ubuntu install, run sudo apt install netcat-openbsd.

Connection refused

nc: connect to challenge.picoctf.org port 12345 failed: Connection refused

Possible causes:

  • Wrong port: Double-check the port number in the challenge description.
  • Challenge instance not started:Some picoCTF challenges require you to click a button to spin up a dedicated instance. Look for a "Start instance" button on the challenge page.
  • Instance expired: picoCTF instances time out. Restart the instance from the challenge page and use the new host/port.

Connection timeout

# nc just hangs, no output, cursor blinks

Possible causes:

  • Firewall blocking outbound connections: Some school or corporate networks block outbound connections on non-standard ports. Try from a home network or use a VPN.
  • Wrong hostname: Check for typos. picoCTF uses challenge.picoctf.org for most challenges but some use a different host shown in the challenge description.
# Add a 10-second timeout to avoid indefinite hanging
nc -w 10 challenge.picoctf.org 12345

nc hangs after sending a piped payload

You piped a payload and the server responded, but nc is still running and you cannot get your shell prompt back. This happens because nc is still listening on stdin waiting for more input.

# Fix: use -N to close on EOF (OpenBSD nc only)
echo 'payload' | nc -N challenge.picoctf.org 12345
# Alternative: add a short sleep to let the server respond, then exit
{ echo 'payload'; sleep 1; } | nc challenge.picoctf.org 12345

Output appears garbled or binary

Some challenges send binary data rather than ASCII. If you see garbage characters, the service is likely a binary exploitation challenge. Switch to pwntools and use conn.recvall() or conn.recv() to capture the raw bytes, then inspect them with Python.

I piped the answer but got no output

The server may have closed the connection before printing the flag because nc shut down stdin too early. Try adding a delay:

{ echo 'my_answer'; sleep 2; } | nc challenge.picoctf.org 12345

If that does not help, the challenge likely requires an interactive session. Connect without piping, read what the server sends, and type your answer manually.

Quick reference

Copy-pasteable commands for the most common netcat situations.

Connect and read

nc challenge.picoctf.org 12345

Connect with timeout (avoid hanging)

nc -w 10 challenge.picoctf.org 12345

Pipe a single answer

echo 'answer' | nc -N challenge.picoctf.org 12345

Pipe a file of answers

nc challenge.picoctf.org 12345 < payload.txt

Save output to file while watching

nc challenge.picoctf.org 12345 | tee output.txt

Search output for flag in real time

nc challenge.picoctf.org 12345 | grep --line-buffered 'picoCTF'

Pipe with delay (let server respond before nc exits)

{ echo 'answer'; sleep 2; } | nc challenge.picoctf.org 12345

pwntools: open a connection

from pwn import *
conn = remote('challenge.picoctf.org', 12345)
conn.recvuntil(b'> ')
conn.sendline(b'my_answer')
print(conn.recvall().decode())

Decision guide: which approach to use

  1. Connect with plain nc host port first. Read the banner. If the flag is there, you are done.
  2. If the server asks one question and you know the answer, pipe it: echo 'answer' | nc -N host port.
  3. If the server has multiple rounds with fixed answers, write them to a file and use nc host port < payload.txt.
  4. If the answer each round depends on the server's previous output, use pwntools with recvuntil and sendline.
  5. If you need to send raw bytes that cannot be typed, use pwntools or python3 -c "..." | nc host port.