Jollyfrogs' pedantic guide to pivoting - part 1: SSH local port forwarding

 

"Pivoting is the act of tunneling traffic between two networks, through a computer under our control"

In part one of the SSH pivoting guide, I'll provide a detailed (pedantic) guide of the easiest form of pivoting which is depicted by the green arrow in the diagram above. If you would like to reproduce this pivoting guide in your local lab, click on the following links for installation guides:
Installing kali

Installing pivot-host-1

Installing target-1

Preparation tasks

All commands are run from the attacker machine "kali" unless explicitly stated

Pivoting is the act of tunneling traffic between two networks, through a computer under our control. Generally, pivoting is used to bypass a lack of routing between the networks, or to bypass a firewall which prevents routing between the two networks. There are various tools that can be used to pivot, including ssh, sshuttle, meterpreter, iptables, python, a custom tool etc.

Due to the proliferation of secure shell (SSH) it makes sense to first detail how ssh can be used to pivot.
The two commands to pivot through 10.123.1.210 to 10.2.1.22:2222 using SSH local port forwarding are:

We will go into detail of what exactly happens 'under the hood' when we enter those two commands on your Kali Linux machine.

The best place to learn about the SSH protocol is the RFC document that describes it. There are a few RFCs that make up the description of the complete SSH protocol and the RFC that describes the SSH connection protocol is available at https://www.ietf.org/rfc/rfc4254.txt

Section "7. TCP/IP Port Forwarding" describes the component we will use to pivot, specifically:

We can demonstrate with an example how SSH local port forwarding works.

The following command creates a locally forwarded TCP/IP port on "kali" with some useful options.

The command above can be broken down as follows:

When we enter the command above, the following happens:

  • the ssh client starts up and sends itself to the background - it's still running, just not on the foreground
  • the ssh client on "kali" connects to "pivot-host-1" via a new session we'll refer to as process-1
  • the ssh server on "pivot-host-1" accepts the connection from "kali"
  • the ssh client on "kali" authenticates with user "frog" and matching private key "id_rsa"
  • the ssh server on "pivot-host-1" logs in user "frog" by matching the key to an entry in /home/frog/.ssh/authorized_keys
  • the ssh client on "kali" creates a listener on port 9922 and waits for new connections

This is the relevant netstat output on "kali" after connecting to the remote host "pivot-host-1":

And this is the relevant netstat output on "pivot-host-1" after connecting:

process-1 can be visually represented as follows:

Now that we have created a local ssh port-forwarding session on "kali", we can connect to the listening port 9922 on "kali" to see what happens. The following command connects to port 9922 on "kali" which we just created via an ssh local port-forward:

When we enter the command above, the following happens:

  • the ssh client on "kali" connects to its own port tcp/9922 as new process we'll refer to as process-2
  • backgrounded port-forward process process-1 accepts the connection to port 9922
  • process-1 sends a "direct-tcpip" request to remote ssh server "pivot-host-1" with following contents
    • ssh request: "direct-tcpip"
    • host to connect: 10.2.1.22
    • port to connect: 2222
    • originator IP address: 127.0.0.1 (process-2 connection source IP)
    • originator port: 51210 (process-2 connection source port - a random src port)
  • ssh server on "pivot-host-1" reads the "direct-tcpip" request
  • "pivot-host-1" looks up the routing table for destination IP 10.2.1.22 and confirms it can connect via interface 10.2.1.1
  • ssh server on "pivot-host-1" creates a new connection to 10.2.1.22:2222 from interface 10.2.1.1 port 33000 (a random src port)
  • ssh server on "pivot-host-1" maps ssh connection from "kali" process-2 to the new connection to 10.2.1.22:2222
  • Since host 10.2.1.22 port 2222 runs an SSH server, we will be asked to login to the ssh server on "target-1"

This is the relevant netstat on "kali" after connecting to port 9922 on "kali":

And this is the relevant netstat on "pivot-host-1" after connecting to port 9922 on "kali":

process-2 can be visually represented as follows:

When process-2 connects to port 9922 on "kali", process-1 on "kali" tunnels the request via its existing ssh (port-forward) connection with "pivot-host-1". Host "pivot-host-1" connects the new connection to 10.2.1.22:2222 via its interface "10.2.1.1".

Pivoting into an unreachable network via SSH local port-forwarding can be useful when there are known ports on known hosts in the remote network. When hosts or ports are not known, or there are a very large number of hosts or ports in the remote network, creation of a large number of single port forwards is often not practical. This is where ProxyChains takes over, and it will be covered in Part 2 of the pedantic guide to pivoting.