SSH Port Forwarding Tutorial

By XiaoXin
A Bit Randomly

To remove untracked files or directories from the current Git repository, you can use the git clean command. This command will delete any files or directories that are not being tracked by Git, without deleting any tracked... Read Git remove untracked files or directories

Main Contents

SSH Port Forwarding Tutorial

What is SSH port forwarding?

SSH port forwarding is also called SSH tunneling. We know that SSH is an encrypted communication, so the content transmitted through the tunnel established by SSH is safe. It is usually used to bypass firewalls and other devices to penetrate into the intranet, or to protect TCP connections, etc.

There are three types of SSH port forwarding:

  1. local forwarding
  2. remote forwarding
  3. dynamic forwarding

When should I use SSH port forwarding?

Let us consider the following situation, when we use WorkStation SSH to connect to SQL Server, the data we send through SSH is encrypted, but when we connect to SQL Server through Mysql, its connection will not be encrypted, if This is a connection across the public network, which will be very dangerous. 

But if we forward the SSH port, we can encrypt it through SSH in the process, which can protect the security of our data. 

So what kind of SSH port forwarding should we use? 

local forwarding

Local forwarding—means that the data communication of a local port will be forwarded to a specific port of the target host. Note that we call the device that executes the local forwarding command the local host.

In the case mentioned above, we can use the local forwarding method. After setting the local forwarding method, we can transmit data through the SSH tunnel established between the local and the target host, so that the data we transmit can be encrypted.

Let's look at the following example:

We access the web server through the curl command line tool.

bash

[[email protected] ~]# curl -I 192.168.222.128
HTTP/1.1 403 Forbidden
Date: Wed, 23 Nov 2022 20:04:36 GMT
Server: Apache/2.4.37 (centos)
Content-Location: index.html.en-us
Vary: negotiate,accept-language
TCN: choice
Last-Modified: Fri, 14 Jun 2019 03:37:43 GMT
ETag: "fa6-58b405e7d6fc0;5ee25c70d2749"
Accept-Ranges: bytes
Content-Length: 4006
Content-Type: text/html; charset=UTF-8
Content-Language: en-us

Through the above content, we can capture the plaintext HTTP packet through WireShark. 

So let's set up SSH port forwarding next.

bash

[[email protected] ~]# ssh -L 80:192.168.222.128:80 192.168.222.128
The authenticity of host '192.168.222.128 (192.168.222.128)' can't be established.
ECDSA key fingerprint is SHA256:gfElOdquMLiDDsfg0TQG//KU+uahlfzSjb23pQlbSxk.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.222.128' (ECDSA) to the list of known hosts.
[email protected]'s password: 
Last login: Thu Nov 24 04:01:51 2022 from 192.168.222.1

It is worth noting that here we have set up SSH port forwarding. After entering the corresponding password, we will generate a new SSH session to connect to the remote host.

Regarding the specific parameters of setting up the tunnel, we will mention it at the end.

bash

[[email protected] ~]# netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:80            0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp6       0      0 ::1:80                  :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN   
   

It can be seen from the above that we have listened to a port 80 locally (at this time, we are using the machine that just executed the port forwarding command). We try to access the web server again.

bash

[[email protected] ~]# curl -I localhost
HTTP/1.1 403 Forbidden
Date: Wed, 23 Nov 2022 20:12:06 GMT
Server: Apache/2.4.37 (centos)
Content-Location: index.html.en-us
Vary: negotiate,accept-language
TCN: choice
Last-Modified: Fri, 14 Jun 2019 03:37:43 GMT
ETag: "fa6-58b405e7d6fc0;5ee25c70d2749"
Accept-Ranges: bytes
Content-Length: 4006
Content-Type: text/html; charset=UTF-8
Content-Language: en-us

Let's look at the generated traffic again. 

Then the traffic at this time is the traffic encrypted by SSH.

So how to establish an SSH tunnel separately without creating a new SSH session? We can use -N parameter, this option will help us to establish SSH tunnel only without opening a remote shell connection to the host.

But just using the -N parameter is not enough (you can try it out for yourself), we also need to use the -f parameter to make the tunnel run in the background.

Then our current command is ssh -f -N -L 80:192.168.222.128:80 192.168.222.128

But this also has disadvantages, this command only listens on the local loopback address of 127.0.0.1. If we want to listen on a local address, we can write it in the following form.

ssh -f -N -L 192.168.222.129:80:192.168.222.128:80 192.168.222.128 In this way, we can monitor port 80 on the address we need.

If we need to set the port to listen on all addresses, we can use the -g parameter to enable gateway mode so that it can listen on all addresses.

remote forwarding

After introducing local forwarding, let's think about remote forwarding again. For the convenience of understanding, let's describe a scenario. 

In the above scenario, the web server cannot be accessed through the outside due to the firewall. We can control the internal web server and the external server, but we do not have the operation authority of the firewall.

At this point, we can use remote forwarding to bypass the firewall restrictions and penetrate to the intranet to access intranet resources.

Let's introduce remote forwarding through practical experiments.

Remote & Dynamic Forwarding Experiment lab environment

We use CentOS 8 as the server and firewall, build the network environment by setting up three hosts, and divide the network by simulating the firewall. The specific topology is as shown in the figure below.

Environment deployment FW

First of all, we need to set the global forwarding function of Linux, so that Linux can forward data between different network segments.

bash

[[email protected] ~]# vim /etc/sysctl.conf    

Add the following content in it.

bash

net.ipv4.ip_forward = 1

Then execute the command.

bash

[[email protected] ~]# sysctl -p
net.ipv4.ip_forward = 1

Secondly, to set the Firewalld that comes with CentOS 8, we need to set the network card of the network segment where the FW is connected to the OutSide device to the external area (the masquerade function is automatically enabled in the external area).

The default NICs are in the Public area, we should delete the NICs from the Public area first, and then add the NICs to the external area.

bash

[[email protected] ~]# firewall-cmd --remove-interface=ens160 --zone=public
success
[[email protected] ~]# firewall-cmd --add-interface=ens160 --zone=external
success

The following content is to operate the Inside host.

Inside

Then Ping the OutSide host on the Web server, theoretically it can communicate.

bash

[[email protected] ~]# ping outside
PING outside (192.168.244.130) 56(84) bytes of data.
64 bytes from outside (192.168.244.130): icmp_seq=1 ttl=63 time=2.49 ms
64 bytes from outside (192.168.244.130): icmp_seq=2 ttl=63 time=0.890 ms
64 bytes from outside (192.168.244.130): icmp_seq=3 ttl=63 time=0.854 ms
64 bytes from outside (192.168.244.130): icmp_seq=4 ttl=63 time=1.02 ms

Then the basic network has been built. We install the Web function for the Inside server, and set up the firewall to allow designated services.

bash

[[email protected] ~]# yum install -y httpd
[[email protected] ~]# systemctl start httpd && systemctl enable httpd
[[email protected] ~]# firewall-cmd --add-service=http --per && firewall-cmd --reload
[[email protected] ~]# curl -I localhost
HTTP/1.1 403 Forbidden
Date: Fri, 25 Nov 2022 20:57:20 GMT
Server: Apache/2.4.37 (centos)
Content-Location: index.html.en-us
Vary: negotiate,accept-language
TCN: choice
Last-Modified: Fri, 14 Jun 2019 03:37:43 GMT
ETag: "fa6-58b405e7d6fc0;5ee25c70d2749"
Accept-Ranges: bytes
Content-Length: 4006
Content-Type: text/html; charset=UTF-8
Content-Language: en-us

The above is the configuration of the basic environment, and the configuration of remote forwarding begins below.

Remote forwarding experiment

We can know from the topology that the FW separates two network segments. Due to the FW's masquerade function, the Inside can access the OutSide, but the OutSide cannot access the Inside. If Inside wants OutSide to access its own Web service at this time, it can use the remote forwarding function.

bash

[[email protected] ~]# ssh -f -N -R 80:192.168.222.128:80 192.168.244.130 
[email protected]'s password:  

At this point we can see the establishment of the corresponding port on the OutSide machine.

bash

[[email protected] ~]# netstat -tnl    
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:80            0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp6       0      0 ::1:80                  :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN    
  

We access local port 80 on the OutSide machine.

bash

[[email protected] ~]# curl -I localhost
HTTP/1.1 403 Forbidden
Date: Fri, 25 Nov 2022 22:01:18 GMT
Server: Apache/2.4.37 (centos)
Content-Location: index.html.en-us
Vary: negotiate,accept-language
TCN: choice
Last-Modified: Fri, 14 Jun 2019 03:37:43 GMT
ETag: "fa6-58b405e7d6fc0;5ee25c70d2749"
Accept-Ranges: bytes
Content-Length: 4006
Content-Type: text/html; charset=UTF-8
Content-Language: en-us

So far, our remote port forwarding has also been successfully built.

The specific traffic will still pass through the FW, but the FW allows the SSH port, and the data encrypted by SSH will pass through the FW to the intranet, so that you can access the Inside.

Dynamic Forwarding & Experimentation

So we all have remote forwarding and local forwarding, why do we need dynamic forwarding?

Then we think about such a problem. If the destination port of our local forwarding is 443, and the peer end is an HTTPS service, when we access it through a browser, because the local listening address is localhost, there will be a problem that the certificate cannot be verified. Also suppose that this web server redirects us to another URL, which will most likely fail the connection, for example when using single sign-on (SSO), this situation is likely to cause problems.

Using dynamic forwarding can solve this problem. The realization of dynamic forwarding is that SSH establishes a Socks proxy locally, and then forwards to the remote host through SSH, and then the remote host forwards the data packets in SSH to the intranet host. 

In the above topology environment, OutSide will first listen to the local port as a Socks proxy, and the data transmitted to the Socks proxy will be encrypted by SSH and transmitted to the FW, and then the FW will forward it to the internal Web server again.

We operate on OutSide hosts.

bash

[[email protected] ~]# ssh -f -N -D 1080 192.168.244.129
[email protected]'s password: 
[[email protected] ~]# netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:1080          0.0.0.0:*               LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
tcp6       0      0 ::1:1080                :::*                    LISTEN   

Generally, the Socks proxy will listen on TCP/1080, but in the above command line command, you can specify it arbitrarily, but the port used must match the set one.

After we enter the correct remote host SSH password, we can establish an SSH tunnel. Then we use Curl's command-line tool for testing.

bash

[[email protected] ~]# curl -I --socks5 127.0.0.1:1080 192.168.222.128
HTTP/1.1 403 Forbidden
Date: Sat, 26 Nov 2022 00:08:51 GMT
Server: Apache/2.4.37 (centos)
Content-Location: index.html.en-us
Vary: negotiate,accept-language
TCN: choice
Last-Modified: Fri, 14 Jun 2019 03:37:43 GMT
ETag: "fa6-58b405e7d6fc0;5ee25c70d2749"
Accept-Ranges: bytes
Content-Length: 4006
Content-Type: text/html; charset=UTF-8
Content-Language: en-us

It can be seen that although we specified the intranet address, we can still successfully access the web server through the Socks proxy.

Next we use WireShark to see the actual situation. First, let's analyze the data packets when the tunnel is established. 

This is similar to the process established by SSH to open a shell. Next, let's look at the situation of forwarding HTTP requests through the Socks proxy. 

As can be seen from the figure above, since the Socks address monitoring does not generate data on the virtual network card locally, we can only capture the HTTP request data transmitted through the tunnel. So how do we grab the Socks package on the local network card?

We monitor the data through the tcpdump tool.

bash

[[email protected] ~]# tcpdump -i lo dst port 1080 -vv > test.pcap

We pass the test.pcap file to the host and open it with WireShark for analysis. We can see that the content displayed here proves that SSH dynamic forwarding is implemented through Socks, and the data packets are in plain text. 

Next, focus on the transmission from the FW to the Inside server. 

It can be seen that the FW assumes the role of a proxy, forwarding traffic between the internal network and the external network, and only uses the ports required by SSH.

Please Share This Article Thank You!

Biometric System Using Blockchain Based

Blockchain technology, which came into our lives along with Bitcoin, has been tried to be used in many fields by developers and entrepreneurs. While some attempts failed, others gained a lot of attention and were embraced ...

Kernel mode vs User mode on Linux Interview

The service code we develop is based on the functional interface provided by the operating system abstraction and then operates the corresponding hardware resources. However, hardware resources have very high requirements ...