One of the things that I really like about ssh-agent is its ability to forward itself to remotes. By sending the agent instead of setting keys on each box, I’m locking down access to a few machines that I know and trust. It’s amazingly convenient and has saved me so much headache.
As I was doing research for a previous post, I kept seeing hints that maybe forwarding the agent isn’t actually a very good idea. man ssh quite explicitly cautions users against forwarding. man ssh_config repeats the same warning. man ssh-agent goes so far as to say it “is easily abused.”
The Vulnerability
In order to forward authentication requests, ssh creates a UNIX-domain socket between the machines. This is not an open port governed by network protocols, but rather a pathname managed by the kernel. On either end, access to the socket is limited by file and directory permissions. On the remote, this means only the owning user has access to it.
Also root. It’s easy to forget that root has access to everything. By extension, this means anyone with root access has access to private sockets. If root can get there, anyone that can act as root can get there too.
The socket is fairly easy to discover once you know what you’re looking for.
| $ find /tmp -path '*ssh*' -type s | 
By setting your environment’s SSH_AUTH_SOCK, you can gain access to the agent. There’s not much information you can gain from the socket itself.
| $ sudo SSH_AUTH_SOCK=/tmp/ssh-20mMR4ptdrVJ/agent.2283 ssh-add -l | 
You can, however, authenticate as the compromised user anywhere the compromised agent can take you. That’s the danger. The current machine might be safe (barring some situations) but everything connected to it is not.
Example
I really struggled to wrap my head around this initially. I mean, I understand root can get anywhere. I just didn’t see the implications. To grok the issue, I put together a demo. It’s slightly contrived, but it gets the job done. The final steps especially will probably take more time in the real world. They were easier with full knowledge of the network.
Setup
miller and holden are two users on a network.
- Both have simple access to mars
- millerhas- sudoon- cereswhile- holdenconnects via a service account
- holdenhas- sudoon- earthwhile- millerconnects via a service account
| $ vagrant ssh-config | 
Forward an Agent
To begin, holden loads credentials in ssh-agent and connects to ceres, forwarding the agent.
| $ vagrant ssh earth | 
Exploit the Socket
With the exposed agent on ceres, miller abuses superuser privileges to access the socket and subsequently connects to mars as holden.
| $ vagrant ssh ceres | 
I’ll leave the rest up to your imagination.
Alternative
ProxyCommand is the generally accepted alternative. Rather than leave a trail of open sockets, you tunnel your way to the desired machine via direct connections. You can, in theory, chain as many as you’d like.
| ~/.ssh/config | |
| 1 2 3 4 5 6 | Host start | 
start is straightforward. It just defines an easy way to get to start.fqdn. end does a bit more with ProxyCommand. Instead of connecting directly, it forwards client I/O to %host on %port via start.
Depending on where you double-check this post, you might run into nc/netcat usage. It’s still presented as a current solution in many places (including the man pages for OpenSSH 7.6!). However, it was superceded by -W %h:%p in OpenSSH 5.4, released almost ten years ago. -W is OpenSSH’s netcat mode.
Depending on how new your version of OpenSSH is, you might notice ProxyJump while poking around the documentation. OpenSSH 7.3 introduced the option, which simplifies the chaining process. ProxyJump and ProxyCommand are mutually exclusive (I believe it’s first-come-first-served), so you can’t use both. For this situation, where we’re just trying to maintain an encrypted connection between us and a far-flung remote, ProxyJump is perfect. It can be chained in a single line, making lengthy proxy chains more manageable.
| ~/.ssh/config | |
| 1 2 3 4 5 6 7 8 9 10 | Host start | 
Recap
Forwarding ssh-agents, like many things in life, trades security for convenience. With minimal time investment, forwarding can be replaced by Proxy(Command|Jump). Proxying is not as simple as forwarding but does not, at first blush, expose as much of your network.
Full Scripts
These are in the repo but I also wanted to lay out everything here.
keygen
| keygen | |
| 1 2 3 4 | #!/bin/bash | 
Vagrantfile
| Vagrantfile | |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | # -*- mode: ruby -*- | 
Legal
The OpenSSH logo was pulled directly from its website and was not altered. I couldn’t find a license but I’m assuming the logo is covered by a BSD license of some sort. I’m not affiliated with OpenSSH at all.

