To connect to the RIPT Server we need to have it establish reverse SSH tunnels on the RIPT Relay.
First we need to upload our RIPT Server’s public key to the RIPT Relay. Since we can’t access the relay directly – it requires key authentication – you can copy the file to a USB and move it over to the RIPT Client which does have access to the RIPT Server, or since you’re probably setting up the RIPT Server on the same network as your RIPT Client just ncat it…
On the RIPT Client
ncat -l > ript-01.id_rsa.pub
On the RIPT Server
ncat --send-only <IP ADDRESS OF RIPT CLIENT> < /root/.ssh/ript-01.id_rsa.pub
Now paste the key up to the RIPT Relay.
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYLth9fKJYB9NU79L3OasBUOTVrnIRBgJH4VwVPhXs23xnpG4sYmDel3xoChglPvM50wgkWxm/JFcrW5DHi4ndkZBR8Wp6bSvEVkijIYejDdeJVfmmpChnJopGgPO5w+vDTgP5I1fjDQvocXscjPJdAqFEQKtWOoGd+SzpCfwG4wD/egHMZIchLjpkexuJpG9k2Q5cgqRd/CEAJ0QL8+4lqbYCqapw6zIBZiOHnv3WR3QXhSY1gvX1Isri1D7Oh8ZFI7jqv0cYteX2f1iDbfwN6YYqkkIA6BrkMBincC/FSZ/mpo8hlRRnIrcCHfYrSVc3bsuocesz/b/UJngVzCjV root@ript-01
Do this for each RIPT Server you have, e.g. ript-02.id_rsa.pub, ript-03.id_rsa.pub, ript-04.id_rsa.pub…
Let’s start simple and work our way up.
Can we SSH from the RIPT Server to the RIPT Relay as the ript-relay user with our RIPT Server private key?
ssh -i /root/.ssh/ript-01.id_rsa -p 22 ript-relay@<FQDN of RIPT Relay>
You should be prompted to add the server’s fingerprint to the known_hosts file and then see a command prompt for the RIPT Relay. Remember you won’t be asked to enter the passphrase for the key because we didn’t set one.
Okay, can we do the same thing, but over an SSL/TLS tunnel?
ssh -i /root/.ssh/ript-01.id_rsa -o ProxyCommand="/usr/bin/ncat --ssl <FQDN of RIPT Relay> 443" -p 22 ript-relay@localhost
And, now let’s verify the certificate to add an additional layer of security against MitM attacks.
ssh -i /root/.ssh/ript-01.id_rsa -o ProxyCommand="/usr/bin/ncat --ssl-verify <FQDN of RIPT Relay> 443" -p 22 ript-relay@localhost
Running all the above from the command line also populated the known_hosts file, which is a requirement since we’re going to be implementing strict host checking.
Do this on each RIPT Server you will be connecting to the RIPT Relay. There’s no point in proceeding until the above works.
Finally we need to build an SSH configuration file on the RIPT Server that will support the following:
- Key authentication to the RIPT Relay server
- Strict host checking (only allow automated authentication to the RIPT Relay)
- Tunnel SSH over SSL/TLS
- Tunnel VNC over an SSL/TLS encapsulated SSH session
- Tunnel HTTP(S) proxied traffic over an SSL/TLS encapsulated SSH session
- Tunnel SOCKS proxied traffic over an SSL/TLS encapsulated SSH session
- Support client outbound proxies with Basic or NTLM authentication
Here’s what we’re going to start with, assuming RIPT Server 01 (modify for 02, 03, 04…by changing the IdentityFile and RemoteForward ports accordingly). This will be replaced on every boot at a later step so if you make any modifications make sure to back the file up!
Host ript* HostName localhost AddressFamily inet User ript-relay Port 22 IdentityFile /root/.ssh/ript-01.id_rsa ProxyCommand /usr/bin/ncat --ssl-verify <FQDN of RIPT Relay> 443 ServerAliveInterval 10 ServerAliveCountMax 3 ExitOnForwardFailure yes StrictHostKeyChecking yes UserKnownHostsFile /root/.ssh/known_hosts Host ript-ssh-tunnel RemoteForward 11095 localhost:22 Host ript-vnc-tunnel RemoteForward 11096 localhost:5901 Host ript-squid-tunnel RemoteForward 11097 localhost:3128 Host ript-socks-tunnel RemoteForward 11098 localhost:9999 Host client HostName localhost AddressFamily inet User root Port 22 IdentityFile /root/.ssh/ript-01.id_rsa LocalForward 9999 192.168.1.69:3306 ServerAliveInterval 10 ServerAliveCountMax 3 ExitOnForwardFailure yes NoHostAuthenticationForLocalhost yes
The more than help, but less than man explanation of the above…
Host ript* – All entries under this apply to any entry that starts with ‘ript’, so basically all entries other than ‘client’ in this case.
HostName – In this case localhost is localhost on the RIPT Relay. We establish an SSL/TLS connection with ncat to the HAProxy listening on the RIPT Relay. It sees that we have encapsulated SSH and routes to the local SSH server so at that point we are localhost.
User – Same reasoning as above. We’re authenticating to the SSH server on the RIPT Relay.
Port – This is the port the RIPT Relay SSH Server is listening on. We’ll see later that it is bound to all interfaces, but we’ll firewall it so it can only be accessed via the HAProxy over port 443.
IdentityFile – This is the private key we will be using to authenticate to the RIPT Relay. We uploaded the corresponding public key previously.
ProxyCommand – This is what we are using to encapsulate our SSH traffic in. In later examples where the client requires going through an outbound proxy we’ll replace ncat with proxytunnels.
ServerAliveInterval and ServerAliveCountMax – These settings can be higher for pure SSH connections, but to keep SSL/TLS alive seems to require a bit more consistent traffic.
ExitOnForwardFailure – If a connection dies ungracefully the RIPT Relay won’t necessarily know and will keep the remote ports open. The auto-restart services we define later on the RIPT Server will notice the dead service and reanimate it. If this setting is not set to yes then the service will assume everything is OK even though it was not able to create the remote ports (because they already exist). With this set to yes it will fail until the RIPT Relay times out and releases the orphaned tunnels. This ensures new good tunnels because the service will keep trying until it succeeds.
StrictHostKeyChecking – This is an added measure of security as we will only accept fingerprints of servers in the known_hosts file. It can also cause problems if servers change. If problems do occur, though, we can always comment it out and send the client a new config to place on the USB.
UserKnownHostsFile – The file we store all those fingerprints in. Can be customized.
Host ript-ssh-tunnel – All the ript* apply to this entry plus we create a reverse SSH tunnel on port 11095 of the RIPT Relay and forward all traffic that connects to it to our local port 22 (SSH). Note 11095 is arbitrary, but needs to be unused.
Host ript-vnc-tunnel – All the ript* apply to this entry plus we create a reverse SSH tunnel on port 11096 of the RIPT Relay and forward all traffic that connects to it to our local port 5901 (VNC). Note 11096 is arbitrary, but needs to be unused.
Host ript-squid-tunnel – All the ript* apply to this entry plus we create a reverse SSH tunnel on port 11097 of the RIPT Relay and forward all traffic that connects to it to our local port 3128 (Squid). Note 11097 is arbitrary, but needs to be unused.
Host ript-socks-tunnel – All the ript* apply to this entry plus we create a reverse SSH tunnel on port 11098 of the RIPT Relay and forward all traffic that connects to it to our local port 9999. Note 11098 is arbitrary, but needs to be unused.
Note: Each RIPT Server needs a unique set of ports on the RIPT Relay. I’ve gone with quadruplets of 11095/11096/11097/11098,12095/12096/12097/12098, 13095/13096/13097/13098, 14095/14096/14097/14098, etc. Use whatever you like and whatever is easy for you to remember. None of these are exposed to the client or the Internet so it doesn’t really matter.
Host Client – This can really be thought of as SOCKS proxy Part 2. All of the other services will be autostarted for us, but this we will only define and start manually as needed since it requires specific client information. For example we will always want to SSH and VNC to our RIPT Server or even use it as a proxy for running Burp Suite against client applications, but if we’re going to have it act as a SOCKS proxy to test a client’s MySQL server (as shown in the example config above) we need to know specific IP address and port information.
There are a few Host Client configuration settings that deserve special attention.
HostName – This time localhost means our localhost, which is why we can’t do StrictHostKeyChecking here because we already have an entry for localhost and that’s for the RIPT Relay, which won’t match. Not really an issue, though, since if an attacker can MitM our local connection it’s already game over.
LocalForward – Now we’re forwarding everything that’s coming over the already forwarded, forwarded port 9999 to the client’s MySQL database on port 3306.
NoHostAuthenticationForLocalhost – As described above RIPT Server localhost will conflict with RIPT Relay localhost in known_hosts. Setting this to yes alleviates that issue.
You should now be able to manually test your tunnels!
First lets look at what the current connections on the RIPT Relay look like.
From the RIPT Relay type the following.
You should see something like this.
Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 968/sshd tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 20979/haproxy tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN 1062/dnsmasq tcp6 0 0 :::22 :::* LISTEN 968/sshd tcp6 0 0 :::80 :::* LISTEN 20900/apache2 tcp6 0 0 :::53 :::* LISTEN 1062/dnsmasq
Now let’s try establishing some tunnels from the RIPT Server.
This should log you into the RIPT Relay. From this terminal checkout the current active connections.
There’s port 11095 waiting for our RIPT Client to connect!
Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:11095 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN - tcp6 0 0 :::22 :::* LISTEN - tcp6 0 0 :::11095 :::* LISTEN - tcp6 0 0 :::80 :::* LISTEN - tcp6 0 0 :::53 :::* LISTEN -
Verify this for ript-vnc-tunnel, ript-squid-tunnel, and ript-socks-tunnel in the same manner.