본문 바로가기
프로...NetWork

[Reverse SSH] Behind NAT

by 크크다스 2019. 9. 3.
반응형

https://www.google.com/search?q=how+to+access+a+linux+server+behind+NAT&oq=how+to+access+a+linux+server+behind+NAT&aqs=chrome..69i57.11598j0j7&sourceid=chrome&ie=UTF-8

https://www.linux.com/tutorials/how-access-linux-server-behind-nat-reverse-ssh-tunnel/

http://xmodulo.com/access-linux-server-behind-nat-reverse-ssh-tunnel.html

OpenWRT Dropbear> https://techfindings.one/archives/219 

How to access a Linux server behind NAT via reverse SSH tunnel

Check "Configure Reverse SSH Tunneling"

SSH Server> ssh -fN -R 10022:localhost:22 relayserver_user@RelayServer_External_IP
- R : define reverse tunnel
  10022 : 임의의 포트(arbitrary port)
  localhost:22 : 로컬(127.0.0.1) SSH Port 지정
  => Local 22 <--> Relay 10022
- fN : Background job after 1st authentication is OK.


Ex>
ssh -fN -R 10022:localhost:8822 firstpw@192.168.88.222
/bin/setsid /usr/bin/ssh -fN 
-R 30017:127.0.0.1:22 
remote@122.129.111.11 -j sawwavessh 
-p 22222 
> /dev/null 2>&1 < /dev/null &

-R a:b:c
a> Relay 에서 Internal Server로 접근하기 위한 포트
참고 : Relay에 여러 Internal Server들이 터널링 되면 
그때 각  Internal Server에 개별적으로 접속하기 위한 
구분자로 사용된다고 생각하면 됨.

b> Internal Server의 SSH 데몬이 Listening 하는 IP
참고 : OpenWRT의 경우 외부 NIC에 할당된 IP상요

c> Internal Server의 SSH 데몬이 Listening 하는 PORT

id@host -j password
id> Relay의 SSH 데몬에 접속가능한 id

host> Relay의 SSH 데몬에 접속가능한 외부 IP

-j> password자동 입력 옵션

password> 앞에 명시한 id의 password

-P port
a> Relay 에서 SSH 데몬에 접속가능한 외부 IP가 Listen하는 port
참고> Relay가 공유기 내의 Port Forwarding 사용시 등 사용

참고> OpenWRT dropbear

config dropbear
        option GatewayPorts 'on'

Do NOT USE localhost -> Use External IP
Ex>
ssh -fN -R 10022:192.168.88.107:8822 firstpw@192.168.88.222

Ex> Shell Command

// Daemonize
snprintf(buff, sizeof(buff), "echo '/bin/setsid /usr/bin/ssh -fN -R %s:%s:%s %s@%s -j %s %s %s > /dev/null 2>&1 < /dev/null &' >>"
                                                                   SHELL_REMOTE_SSH,
pCli->remote_port ,
pCli->local_ip ,
pCli->local_port ,
pCli->username ,
pCli->remote_ip ,
pCli->password,
// -p remote_ssh_port
pCli->remote_ssh_port ? "-p":"",
pCli->remote_ssh_port ?:""
);

참고>
/config/.remote-ssh.sh   <== NAT내의 SSH 서버에서 수행
#!/bin/sh
killall ssh
/bin/setsid /usr/bin/ssh -fN -R 30015:127.0.0.1:22 id@1.2.3.4 -j passwd -p 22222 > /dev/null 2>&1 < /dev/null &

   -R 30015:127.0.0.1:22 >  Relay_Local_Port:SSH_Server_Listening_IP:SSH_Server_Listening_PORT 
   id@1.2.3.4 -j passwd -p 22222 > 아이디@Relay_SSH_IP -j 패스워드 -p Relay_SSH_PORT > /dev/null 2>&1 < /dev/null &


Ex> Trouble Shooting : 접속 이상시

// Check : 
[/home/firstpw] netstat -a | grep 30015
tcp        0      0 localhost:30015         *:*                     LISTEN
tcp6       0      0 localhost:30015         [::]:*                  LISTEN
tcp6      40      0 localhost:30015         localhost:55234         CLOSE_WAIT
tcp6      40      0 localhost:30015         localhost:55233         CLOSE_WAIT

[/home/firstpw] ps -ef|grep ssh
root       878   600  0 Oct01 ?        00:00:00 sshd: firstpw [priv]
firstpw    880   878  0 Oct01 ?        00:00:03 sshd: firstpw@pts/4

root     14312   600  0 08:20 ?        00:00:00 sshd: remote [priv]
remote   14317 14312  0 08:20 ?        00:00:00 sshd: remote   <=== No TTY (Ex> @pts/4)


[/home/firstpw] sudo kill -9 14312   


Check "SSH Server"
SSH Relay> netstat -napt | grep 300
tcp        0      0 127.0.0.1:30015         0.0.0.0:*               LISTEN      -
tcp6       0      0 ::1:30015               :::*                    LISTEN      -
tcp6       0      0 ::1:30015               ::1:54762               ESTABLISHED -
tcp6       0      0 ::1:54762               ::1:30015               ESTABLISHED 18069/ssh

Connect "SSH Server"
SSH Relay> ssh -p 30015 ssh_server_id@localhost

Ex> Relay 서버의 ID/PW가 아니라 접속하려는 NAT내의 SSH Server의 ID/PW 사용
ssh -p 30015 root@127.0.0.1


[전체 플로우]
"@" Relay 서버 : SSH 서버 Listening 

"#" NAT 내서버 ---> Reverse SSH Tunnel 요청 to "@" : Check "Configure Reverse SSH Tunneling"

터널링 설정 OK : Check "SSH Server"

"#" 연결 : Connect "SSH Server"



[원문]

How to access a Linux server behind NAT via reverse SSH tunnel

You are running a Linux server at home, which is behind a NAT router or restrictive firewall. Now you want to SSH to the home server while you are away from home. How would you set that up? SSH port forwarding will certainly be an option. However, port forwarding can become tricky if you are dealing with multiple nested NAT environment. Besides, it can be interfered with under various ISP-specific conditions, such as restrictive ISP firewalls which block forwarded ports, or carrier-grade NAT which shares IPv4 addresses among users.

What is Reverse SSH Tunneling?

One alternative to SSH port forwarding is reverse SSH tunneling. The concept of reverse SSH tunneling is simple. For this, you will need another host (so-called "relay host") outside your restrictive home network, which you can connect to via SSH from where you are. You could set up a relay host using a VPS instance with a public IP address. What you do then is to set up a persistent SSH tunnel from the server in your home network to the public relay host. With that, you can connect "back" to the home server from the relay host (which is why it's called a "reverse" tunnel). As long as the relay host is reachable to you, you can connect to your home server wherever you are, or however restrictive your NAT or firewall is in your home network.

Set up a Reverse SSH Tunnel on Linux

Let's see how we can create and use a reverse SSH tunnel. We assume the following. We will be setting up a reverse SSH tunnel from homeserver to relayserver, so that we can SSH to homeserver via relayserver from another computer called clientcomputer. The public IP address of relayserver is 1.1.1.1.

On homeserver, open an SSH connection to relayserver as follows.

homeserver~$ ssh -fN -R 10022:localhost:22 relayserver_user@1.1.1.1

Here the port 10022 is any arbitrary port number you can choose. Just make sure that this port is not used by other programs on relayserver.

The "-R 10022:localhost:22" option defines a reverse tunnel. It forwards traffic on port 10022 of relayserver to port 22 of homeserver.

With "-fN" option, SSH will go right into the background once you successfully authenticate with an SSH server. This option is useful when you do not want to execute any command on a remote SSH server, and just want to forward ports, like in our case.

After running the above command, you will be right back to the command prompt of homeserver.

Log in to relayserver, and verify that 127.0.0.1:10022 is bound to sshd. If so, that means a reverse tunnel is set up correctly.

relayserver~$ sudo netstat -nap | grep 10022
tcp      0    0 127.0.0.1:10022          0.0.0.0:*               LISTEN      8493/sshd           

Now from any other computer (e.g., clientcomputer), log in to relayserver. Then access homeserver as follows.

relayserver~$ ssh -p 10022 homeserver_user@localhost

One thing to take note is that the SSH login/password you type for localhost should be for homeserver, not for relayserver, since you are logging in to homeserver via the tunnel's local endpoint. So do not type login/password for relayserver. After successful login, you will be on homeserver.

Connect Directly to a NATed Server via a Reverse SSH Tunnel

While the above method allows you to reach homeserver behind NAT, you need to log in twice: first to relayserver, and then to homeserver. This is because the end point of an SSH tunnel on relayserver is binding to loopback address (127.0.0.1).

But in fact, there is a way to reach NATed homeserver directly with a single login to relayserver. For this, you will need to let sshd on relayserver forward a port not only from loopback address, but also from an external host. This is achieved by specifying GatewayPorts option in sshd running on relayserver.

Open /etc/ssh/sshd_conf of relayserver and add the following line.

relayserver~$ vi /etc/ssh/sshd_conf
GatewayPorts clientspecified

Restart sshd.

Debian-based system:

relayserver~$ sudo /etc/init.d/ssh restart

Red Hat-based system:

relayserver~$ sudo systemctl restart sshd

Now let's initiate a reverse SSH tunnel from homeserver as follows.

homeserver~$ ssh -fN -R 1.1.1.1:10022:localhost:22 relayserver_user@1.1.1.1

Log in to relayserver and confirm with netstat command that a reverse SSH tunnel is established successfully.

relayserver~$ sudo netstat -nap | grep 10022
tcp      0      0 1.1.1.1:10022     0.0.0.0:*           LISTEN      1538/sshd: dev  

Unlike a previous case, the end point of a tunnel is now at 1.1.1.1:10022 (relayserver's public IP address), not 127.0.0.1:10022. This means that the end point of the tunnel is reachable from an external host.

Now from any other computer (e.g., clientcomputer), type the following command to gain access to NATed homeserver.

clientcomputer~$ ssh -p 10022 homeserver_user@1.1.1.1

In the above command, while 1.1.1.1 is the public IP address of relayserverhomeserver_user must be the user account associated with homeserver. This is because the real host you are logging in to is homeserver, not relayserver. The latter simply relays your SSH traffic to homeserver.

Set up a Persistent Reverse SSH Tunnel on Linux

Now that you understand how to create a reverse SSH tunnel, let's make the tunnel "persistent", so that the tunnel is up and running all the time (regardless of temporary network congestion, SSH timeout, relay host rebooting, etc.). After all, if the tunnel is not always up, you won't be able to connect to your home server reliably.

For a persistent tunnel, I am going to use a tool called autossh. As the name implies, this program allows you to automatically restart an SSH session should it breaks for any reason. So it is useful to keep a reverse SSH tunnel active.

As the first step, let's set up passwordless SSH login from homeserver to relayserver. That way, autossh can restart a broken reverse SSH tunnel without user's involvement.

Next, install autossh on homeserver where a tunnel is initiated.

From homeserver, run autossh with the following arguments to create a persistent SSH tunnel destined to relayserver.

homeserver~$ autossh -M 10900 -fN -o "PubkeyAuthentication=yes" -o "StrictHostKeyChecking=false" -o "PasswordAuthentication=no" -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -R 1.1.1.1:10022:localhost:22 relayserver_user@1.1.1.1

The "-M 10900" option specifies a monitoring port on relayserver which will be used to exchange test data to monitor an SSH session. This port should not be used by any program on relayserver.

The "-fN" option is passed to ssh command, which will let the SSH tunnel run in the background.

The "-o XXXX" options tell ssh to:

  • Use key authentication, not password authentication.
  • Automatically accept (unknown) SSH host keys.
  • Exchange keep-alive messages every 60 seconds.
  • Send up to 3 keep-alive messages without receiving any response back.

The rest of reverse SSH tunneling related options remain the same as before.

If you want an SSH tunnel to be automatically up upon boot, you can add the above autossh command in /etc/rc.local.

Conclusion

In this post, I talked about how you can use a reverse SSH tunnel to access a Linux server behind a restrictive firewall or NAT gateway from outside world. While I demonstrated its use case for a home network via a public VPS, you must be careful when applying it for corporate networks. Such a tunnel can be considered as a breach of a corporate policy, as it circumvents corporate firewalls and can expose corporate networks to outside attacks. There is a great chance it can be misused or abused. So always remember its implication before setting it up.



SSH reverse tunnel to OpenWRT / dropbear

I have a little WRT54GL router that runs OpenWRT. It is very convenient to be able to SSH into the router, and even more convenient to make tunnels.

In opensshd, there is an option

GatewayPorts yes

that needs to be turned on. It allows the SSH server to listen to ports and forward them back to the client. Also it allows other machines to connect to that port on the SSH server, not just the SSH server.

Well, for dropbear (the SSH implementation of OpenWRT), things are a little different. First, you need to start the dropbear deamon with the flag -a. Preferably:

#/etc/config/dropbear
        option 'GatewayPorts' 'on'

Second, when you invoke ssh, you need to specifically tell dropbear to listen to the network interface (not to localhost). Example:

$ ssh -l root -R 1.2.3.4:7777:10.2.2.12:80 1.2.3.4

This assumes you are on a client, on the 10.2-network. Your OpenWRT is on the internet (IP=1.2.3.4). Connections made to 1.2.3.4, port 7777 will be tunneled through SSH back to the client. The client will in turn make a new connection to 10.2.2.12, port 80 and forward all traffic there. So, in this case, an internal webserver is exposed on the internet.

With other sshd servers, it may be enought to make the call

$ ssh -l root -R 7777:10.2.2.12:80 1.2.3.4

and sshd will listen to all interfaces.


반응형