It all started with an seemingly inocent ssh command :

ssh -o "ProxyCommand ssh -o 'ForwardAgent yes' B 'ssh-add && nc %h %p'" C

Understanding what that command actually did took me a whole day.

Primer on SSH protocol

SSH is protocol has 3 components :

Network_SSH_components.svg

Simple tunneling

The following demonstrates how to tunnel both ways using SSH.

### local_host ###
ssh -R 8888:localhost:8888 -L 8889:localhost:8889 -T -N remote_host &
nc -l localhost 8888 &
nc localhost 8889

### remote_host ###
nc -l localhost 8889 &
nc localhost 8888

Network_SSH_tunneling.svg

Be careful it is a trap ! IPv6

X11 server

The Xserver running on ssh client side must be invoked without -nolisten. Otherwise it will only accept connections on unix sockets.

This basically works using reverse tunneling. However, SSH must understand the X protocol to a certain degree.

ProxyCommand

Instead of using a TCP connection below SSH transport layer, the stdin/stdout of any program can be used. This is used to proxy ssh connections through a bastion host (or jump host) running on a different machine. 3 different ways to achieve the same technique :

Network_SSH_proxycmd.svg

Security characteristics

Authentication with ssh-agent

SSH private keys should be encrypted with a passphrase. This way they are stored encrypted on disk. ssh-agent is a convinience program to keep the unencrypted keys in memory for a given duration. The keys can later be used for several ssh sessions without user interaction. The ssh client can contact the ssh-agent daemon via environment vars :

ssh-agent never transmits unencrypted keys to ssh clients. Instead it answers authentication challenges for them.

ForwardAgent

ssh-agent traffic can be forwarded via reverse tunneling. This allows to keep all private keys on local_host even when using several interactive ssh sessions to jump across machines.

Network_SSH_forwardagent.svg

This is NOT the same setup as for ProxyCommand.

Forward agent vulnerability

An attaquer with root access on remote_host_1 can use the unix socket to contact the local_host agent. This will allow him to impersonate any user connected to remote_host_1 using agent forwading.

Mixing ForwardAgent, ssh-add and ProxyCommand

What does this command do ? ssh -o "ProxyCommand ssh -A remote_host_1 'ssh-add && nc %h %p'" remote_host_2

Network_SSH_forward_add_proxy.svg

This can only work if keys are NOT passphrase protected. Otherwise ssh protocol wire data will contain garbage.

SOCKS proxying

SSH can act as a SOCKS proxy (-D option). A SOCKS proxy acts as an OSI layer 5 gateway. It can forward any protocol above TCP (ex: HTTP).

Aside from the SOCKS headers that indicate where the connection should be forwarded to, the upper layers are opaque to the proxy. For example, a SOCKS proxy will only see encrypted HTTPS traffic flow by.

Example with HTTP

curl ifconfig.me
# output: 83.87.183.152
ssh -v -D 1080 -T -N remote_host
curl --socks5 localhost ifconfig.me
# output: 144.37.93.213

Network_SSH_socks_proxy.svg

Note that the client application (here curl) MUST understand SOCKS. It needs to prepend the relevant SOCKS headers.