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
- Networking Tools for CTF Challenges — covers curl, Wireshark, nmap, and browser DevTools alongside netcat.
- Linux CLI for CTFs — essential terminal skills: file navigation, piping, grep, and more.
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 installnc -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 versionnc -h# If you want the OpenBSD variant via Homebrewbrew 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
Confirming the install
# You should see usage output, not 'command not found'nc -h# Quick connectivity test against a known servernc -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 12345Welcome 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:
- Connect with
nc host port. - Read the banner and any question the server asks.
- Type your answer and press Enter.
- Read the server's response. Repeat if there are multiple rounds.
- When the server prints
picoCTF{...}, copy it.
$ nc challenge.picoctf.org 12345What is 2 + 2?> 4Correct! 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 filegrep '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
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 newlineecho '42' | nc challenge.picoctf.org 12345# Send a specific passwordecho '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 linecat payload.txt42yespicoCTF# Send the entire filecat payload.txt | nc challenge.picoctf.org 12345# Equivalent shorthand using input redirectionnc 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'42yespicoCTFEOF
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
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 sendingbanner = 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 '>' promptconn.recvuntil(b'> ')for _ in range(100):# Read the question lineline = conn.recvline().decode().strip()# Parse and compute the answer (example: eval a math expression)answer = str(eval(line))# Send the answerconn.sendline(answer.encode())# Read server feedback before the next questionresponse = conn.recvuntil(b'> ', timeout=5).decode()if 'picoCTF' in response:print(response)breakconn.close()
Key pwntools methods
| Method | What 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 |
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 answerecho 'the_answer' | nc -N challenge.picoctf.org 12345# If you need to see the question firstnc 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)breakanswer = compute_answer(prompt) # your logic hereconn.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 overflowconn.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.orgfor most challenges but some use a different host shown in the challenge description.
# Add a 10-second timeout to avoid indefinite hangingnc -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
- Connect with plain
nc host portfirst. Read the banner. If the flag is there, you are done. - If the server asks one question and you know the answer, pipe it:
echo 'answer' | nc -N host port. - If the server has multiple rounds with fixed answers, write them to a file and use
nc host port < payload.txt. - If the answer each round depends on the server's previous output, use pwntools with
recvuntilandsendline. - If you need to send raw bytes that cannot be typed, use pwntools or
python3 -c "..." | nc host port.