SSH port forwarding, otherwise known as SSH tunneling, is a method for sending traffic from a client machine port to a server port, or vice versa, through a secured SSH tunnel. Almost all Linux systems have SSH clients and SSH servers installed by default making this an easily accessible tool.
Use Cases
SSH Tunneling can be used to add encryption to traffic that otherwise would not be encrypted. If your business had an old legacy application that used telnet to communicate information back to a server, you could secure that connection with an SSH tunnel.
It can also be used for testing applications without opening their ports to the rest of the network. For example, if you were building a web-based application, you could leave port 80 and 443 closed to the outside on your host firewall and use an SSH tunnel to connect to the web server from your workstation to test its functionality.
Employees often use it for back doors into their companies internal network. Most of the time for innocent reasons like convenience and allowing themselves access from home.
Often SSH tunneling is used for nefarious reasons. Malware and crackers use it to open access to the internal network of their targets from the internet or to mask data transmissions out to the internet.
Nomenclature
In the following examples we will be using 3 systems. Below is an outline of the system names, purpose and IP addresses.
- Putor - Main Workstation - 10.0.0.2
- Centos6 - MySQL Database Server - 192.168.122.91
- Fenrir - Web Server - 10.0.0.5
Different Kinds of SSH Forwarding
Local Forwarding
Local forwarding is used to send traffic destined for a local port to a port on a remote machine through the SSH tunnel. The SSH client will listen for connections to the local port, when it receives that connection it forwards it to the remote system on the specified port.
Local Forwarding - Example 1
For this first example we will connect our local machine named putor to a legacy MySQL database server named centos6 to encrypt the traffic.
We will forward local port 6603 (putor:6603) to the remote port (centos6:3306) and make the database connection.
Here are some configuration parameters of the server. You will see that we have MySQL running and listening on port 3306, BUT iptables (host firewall) DOES not have 3306 open. This means that normal communication to the database is blocked by the firewall. In this example, we are going to connect to the database through the SSH tunnel, so we do not need the port opened on the host system.
[root@centos6 ~]# ip addr | grep "inet 192"
inet 192.168.122.99/24 brd 192.168.122.255 scope global eth0
[root@centos6 ~]# service mysqld status
mysqld (pid 2794) is running…
[root@centos6 ~]# iptables -L -vn
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
984 86845 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
1 60 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
1 60 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT 576 packets, 71338 bytes)
pkts bytes target prot opt in out source destination
[root@centos6 ~]# netstat -anp | grep 3306
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 2794/mysqld
Now let's setup our SSH Forwarding to allow use to connect to the MySQL database on the remote server through the SSH connection.
[savona@putor ~]$ ssh -L 6033:127.0.0.1:3306 centos6
savona@centos6's password:
Last login: Sun Jan 27 18:32:11 2019 from 192.168.122.1
To reiterate, the command above forward port 6033 on the local system to port 3306 on the remote system.
Now we have the tunnel up, we can connect to the database from our workstation.
[savona@putor ~]$ mysql -s -h 127.0.0.1 -p --port 6033
Enter password:
MySQL [(none)]> show databases;
Database
information_schema
mysql
putorius
test
MySQL [(none)]>
Now my workstation (putor) is listening on port 6603 for incoming connections and it will forward those connections to the MySQL server at centos6:3306. This INCLUDES connections for another system. I can now make this database open to other systems the network, by allowing port 6603 on my firewall.
[savona@putor ~]$ netstat -anp | grep 6033
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 127.0.0.1:6033 0.0.0.0:* LISTEN 25479/ssh
tcp 0 0 127.0.0.1:39864 127.0.0.1:6033 TIME_WAIT -
tcp6 0 0 ::1:6033 :::* LISTEN 25479/ssh
To stop this behavior, we need to specify a BIND address. This mean we will tell SSH to only allows connections through this tunnel from the IP address we specify. Here is how that forwarding statement looks.
ssh -L putor:6033:127.0.0.1:3306 192.168.122.99
That is how local forwarding works. If you have any questions feel free to leave them in the comments.
Local Forwarding - Example 2
For this next example, we will use the the Centos6 system as a jump box.
We will open a connection to centos6, and forward all connections to port 8443 on the workstation to port 8443 on Fenrir, the web server.
ssh -L 8443:fenrir:8443 centos6
Now that we have the tunnel up, let's open our web browser and go to https://putor:8443.
In the above example, the request from our browser went to our local port 8443, which was sent through centos6 and off to Fenrir.
That's local forwarding in a nutshell. I hope I was able to explain it in a clear manner. If you have any questions leave them in the comments.
Remote Forwarding
Remote SSH forwarding works very similar to local forwarding, but in reverse. When you make the connection it forwards the port on the remote host back to the local host port.
Remote Forwarding - Example 1
So let's make a remote forwarding connection from centos6 MySQL server, back to my workstation and forward port 7777 to the database port 3306.
As you can see from the diagram above, we are initiating the connection from the database server (centos6) for this example. We will connect to my workstation (putor) and forward port 7777 on putor back to 3306 on centos6.
[savona@centos6 ~]$ ssh -R 7777:127.0.0.1:3306 putor
savona@putor's password:
Last login: Sun Jan 27 19:47:08 2019 from 192.168.122.99
Now let's test the database connection to port 7777 on putor.
[savona@putor ~]$ mysql -s -h 127.0.0.1 -p --port 7777
Enter password:
MySQL [(none)]>
Success. We were able to connect back through the tunnel using remote forwarding.
Remote Forwarding - Example 2
For this example, we will initial a remote forwarding tunnel from Fenrir:8443 to Putor:6556. This will allow putor to connect to localhost:6565 and open the web application on Fenrir:8443.
Just as with local forwarding, if you reverse forward a port from a server to a client, anybody who can access that port on the server will be forwarded to the client. This can be controlled with the GatewayPorts option in the SSH daemon configuration (see server configurations below).
NOTE: It is important to recognize that we are initiating the connect from the server.
Let's create the tunnel.
[savona@Fenrir ~]$ ssh -R 6565:localhost:8443 putor
savona@putor's password:
Last login: Sun Jan 27 20:00:11 2019 from 10.0.0.5
Now we should be able to open a browser on Putor and navigate to https://localhost:6565 and open the web application on Fenrir.
Success. We were able to connect to the web application from putor through the tunnel we initiated on the server.
Server Configurations
The SSH server must be configured to allow port forwarding. By default, port forwarding is allowed. You can control this behavior by using the AllowTCPForwarding option. To allow SSH Forwarding, open the SSH daemon configuration file (usually /etc/ssh/sshd_config) and add or modify the following line.
AllowTCPForwarding yes
To denied forwarding:
AllowTCPForwarding no
When reverse forwarding is enabled from a one system to another, anyone that has access to the port on that host server will be forwarded to the client. This can be controlled by using the GatewayPorts option in the SSH daemon configuration.
To prevent connecting to forwarded ports from outside the server, add or modify the following line in the configuration.
GatewayPorts no
To allow anyone to connect to the forwarding ports:
GatewayPorts yes
Conclusion
SSH Forwarding can be used local or remotely. It is a great tool for Linux System Administrators to have in their toolkit, but can easily be abused. Follow best practices and explicitly disable port forwarding if you are not using it.
Leave a Reply Cancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.
8 Comments
Join Our Newsletter
Categories
- Bash Scripting (17)
- Basic Commands (51)
- Featured (7)
- Just for Fun (5)
- Linux Quick Tips (98)
- Linux Tutorials (65)
- Miscellaneous (15)
- Network Tools (6)
- Reviews (2)
- Security (32)
Thanks for the article.
For LAN's connected to the internet via a GSM router, many/most? GSM ISP's block the ability of the router to port forward - so it is impossible to use ssh to connect to a server on the LAN from outside.
Is ssh a solution to this using a hosted server on the internet?
Connection 1: LAN Server -> Hosted Server
Connection 2: CLIENT SSH -> Hosted Server
The LAN server machine makes Connection 1. After that, the client ssh machine makes Connection 2 and then his ssh connection is forwarded to the LAN Server via Connection 1.
Can that work? If so I would like to know how?
Yes. this article explains exactly how to do what you ask.
I must study it more deeply. Thank you again.
Log into your hosted server, and forward a port back to your LAN server:
ssh -L 6666:127.0.0.1:22 LANServerIP
then SSH into your Hosted server, and connect with ssh to port 6666 and it will forward it to port 22 on your LAN server:
From your Hosted Server:
ssh -p 6666 127.0.0.1
Sorry, I read you issue again. You cannot create the tunnel because you cannot come through the firewall. In that case try this:
First, I would either change the port SSH is listening on, or add an additional port. For example, I added port 2222 to my sshd_config file to allow SSH to listen on both port 22 and 2222.
Then I forward the remote port on HostedServer to port 22 on my LanServer:
ssh -R 6666:LanServerIP:2222 HostedServerIP
Then you can log into your hosted server, and ssh to 127.0.0.1 on port 6666 and get to your LanServer like so:
ssh -p 6666 127.0.0.1
Let me know how it works out!
Good article with every possible step we getting at the time of configuration
There is still some (small) merit to disallowing root login. Virtually every unix-type system has a “root” account, so allowing root to log in means one less thing that an attacker has to guess (at the least).
Your article is very good