This is the fifth post in the series of the blog posts about Secure Shell aka SSH. You can find the series index here. In this blog post, we’ll discuss about SSH tunneling and how to configure and use the same.
SSH port forwarding or SSH tunneling, is a mechanism in SSH for tunneling application ports from the client machine to the server machine or vice versa. It can be used for variety of purpose such as adding encryption to legacy applications, bypassing firewalls, opening backdoors into internal networks, etc. It is a double edged sword. It can be useful at the times but it can also be abused by hackers and malware to open access from the internet to the internal network.
Local Forwarding / Tunneling
Local forwarding is used to forward a port from the client machine to the server machine. A local connection is a way of accessing a network location from your local computer through your remote host. First, an SSH connection is established to your remote host. On the remote server, a connection is made to an external (or internal) network address provided by the user and traffic to this location is tunneled to your local computer on a specified port.
Typical uses for local port forwarding include:
- Tunneling sessions and file transfers through jump servers
- Connecting to a service on an internal network from the outside
- Connecting to a remote file share over the Internet
It is one of the common practices in the organizations to use jump servers. The servers may be standard Linux/Unix box, usually with some extra hardening, intrusion detection, and/or logging, or it may be a commercial jump server solution. Many jump servers allow incoming port forwarding, once the connection has been authenticated. Such port forwarding is convenient, because it allows tech-savvy users to use internal resources quite transparently.
To establish a local tunnel to your remote server, you need to use the
-L parameter when connecting and you must supply three pieces of additional information:
- The local port where you wish to access the tunneled connection.
- The host that you want your remote host to connect to.
- The port that you want your remote host to connect on.
ssh -L 80:intra.example.com:80 js.example.com
Now we can point our browser to listen on 127.0.0.1:80 and we should be able to see whatever content hosted on the intra.example.com:80. By default, anyone (even on different machines) can connect to the specified port on the SSH client machine. However, this can be restricted to programs on the same host by supplying a bind address:
ssh -L 127.0.0.1:80:intra.example.com:80 js.example.com
LocalForward option in the ssh client configuration file can be used to configure forwarding without having to specify it on command line.
Remote Forwarding / Tunneling
As the name indicates, this is the reverse of the Local tunneling. In this method, the traffic can be tunneled from ports on local host to ports on the remote host. This can be be useful for giving someone on the outside access to an internal web server. Or exposing an internal web application to the public Internet.
In a remote tunnel, a connection is made to a remote host. During the creation of the tunnel, a remote port is specified. This port, on the remote host, will then be tunneled to a host and port combination that is connected to from the local computer. This will allow the remote computer to access a host through your local computer.
To establish a remote tunnel to your remote server, you need to use the
-R option when connecting and you must supply three pieces of additional information:
- The port where the remote host can access the tunneled connection.
- The host that you want your local computer to connect to.
- The port that you want your local computer to connect to.
ssh -R 8080:localhost:80 js.example.com
This allows anyone on the remote server to connect to TCP port 8080 on the remote server. The connection will then be tunneled back to the client host, and the client then makes a TCP connection to port 80 on localhost. Any other host name or IP address could be used instead of localhost to specify the host to connect to.
By default, SSH only allows connecting to remote forwarded ports from the server host. However, the
GatewayPorts option in the server configuration file sshd_config can be used to control this. The following alternatives are possible:
This prevents connecting to forwarded ports from outside the server computer. Alternatively, setting it to yes allows anyone to connect to the forwarded ports. If the server is on the internet, anyone on the internet can connect to the port.
OpenSSH also allows the forwarded remote port to specified as 0. In this case, the server will dynamically allocate a port and report it to the client. When used with the
-O forward option, the client will print the allocated port number to standard output.
Opening Backdoors into the Enterprise
Remote SSH port forwarding is commonly used by employees to open backdoors into the enterprise. For example, the employee may set get a free-tier server from Amazon AWS, and log in from the office to that server, specifying remote forwarding from a port on the server to some server or application on the internal enterprise network. Multiple remote forwards may be specified to open access to more than one application.
The employee would also set
GatewayPorts yes on the server (most employees do not have fixed IP addresses at home, so they cannot restrict the IP address).
For example, the following command opens access to an internal Postgres database at port 5432:
ssh -R 5432:postgres3.nyc.example.com:5432 aws4.mydomain.net
AllowTcpForwarding option in the server configuration file must be enabled on the server to allow port forwarding. By default, forwarding is allowed. Possible values for this option are yes or all to allow all TCP forwarding, no to prevent all TCP forwarding, local to allow local forwardings, and remote to allow remote forwardings.
Another option of interest is
AllowStreamLocalForwarding, which can be used to forward Unix domain sockets. It allows the same values as
AllowTcpForwarding. The default is yes. For example:
AllowTcpForwarding remote AllowStreamLocalForwarding no
GatewayPorts configuration option as described above also affects remote port forwardings. Possible values were no (only local connections from server host allowed; default), yes (anyone on the internet can connect to remote forwarded ports), and clientspecified (client can specify an IP address that can connect, anyone can if not specified).
How to Prevent SSH Port Forwarding from Circumventing Firewalls
It is recommended that port forwarding be explicitly disabled when not needed. Leaving port forwarding enabled can expose the organization to security risks and backdoors. The problem is that port forwarding can in practice only be prevented by a server or firewall. An enterprise cannot control all servers on the Internet. Firewall-based control can also be tricky, as most organizations have servers in Amazon AWS, Azure and myriad of other cloud services, and those servers are usually accessed using SSH.