Catching shells from the internet!
Background information
So for this post you'll need a bit of background information to understand what we're talking about.
The first thing you'll want to understand is what an IP address is. You can think of it as kindof like a street address for a house. It tells computers where other computers live so they can send information to them. If you open up your terminal application on your computer and type ipconfig if you're on windows, and ip addr if you're on Mac or linux you'll see some output that includes your private IP address. Wait private? Don't worry we'll get to that. It will likely start with a 192.168, 172.16, or 10.
Everything that wants to talk over a network needs an IP address, including very large networks like the Internet. "But wait", I hear you say, "I don't type ip addresses into my browser to go to websites!". Right you are my dear reader. You probably type the domain name of the website you want to go to. For example FRSecure.com. Domain names are human readable addresses that point to IP addresses that computers like to use. Your computer basically sees you type the domain name, and asks a source of dns information (a dns server) what the current IP address is for that domain name. It then uses that IP address for the communications between your computer and the web server you're connecting to! Cool Right!
This actually gives us some interesting options when it comes to DNS like a post I'm going to make soon about how to block ads at the DNS level... keep your eyes peeled for that, its super cool!
Ok so everything has an IP address even on the internet... so what. Well when the internet was young we didn't know how much it would explode. We figured that there was no way we'd need more then 4.2 billion addresses right? wrong! we ran out. Hence the invention of IPv6 which has alot more address space, but almost no one uses that... so we'll ignore it for now. Another solution came into existence. Private IP space. Private IP addresses are IP addresses that are not allowed to be on the internet, but are allowed on local networks. These IP addresses will start with either 192.168, 172.16, or 10.
Ok cool, but then if they can't be on the internet why can you still connect online? Great question tiny reader voice in my head! See your Router has a public IP address, to see what it is simply type "Whats my ip" into google. All devices on your network share that public IP address for internet communication, and then use the private addresses we saw earlier for local communication. Cool Right! This is made possible by a technology called NAT or Network Address Translation. Basically it dictates how routers can keep track of out going connections to make sure that the replies to those are sent to the right local device. You may notice a problem here if you want to catch a reverse shell over the internet. Outgoing connections are tracked and used to make sure replies are sent correctly... but what about if a connection starts from the outside? These connections will be dropped. Making NAT the worlds most simple firewall that just blocks everything.
Solutions
This is too long... whats the easiet way?
b.... but I wrote all this up for you.... Fine....
Set up a VPS on linode or digital ocean and then skip to the SSH Tunneling section below.... I'm not mad... just dissapointed.
Portforwarding on your router
But I want to receive a connection from the internet. Me too dear reader, me too. Luckily we CAN! see most NAT implementations allow a procedure called Portforwarding. Basically it tells the router, "hey any connections originating from the internet connecting to us on this specific port, forward that connection to this specific device." Setting it up varies from router to router, but you can generally google your router model and portforwarding to figure it out.
That's all fine and dandy but what if you have an ISP router that you don't have admin access to, or your ISP doesn't actually give you a public IP on your router's WAN interface (double natted)? Well lucky for you we have other options!
Using a service to expose a port
One such option is to use a service to expose a port on your local machine to the internet. One such service is ngrok. I have not personally used ngrok, but it apparently works pretty well.
A service I have used is Tailscale. Tailscale isn't a service to expose a port to the internet persay, but is a mesh VPN service that allows your devices to make direct connections to eachother even acrossed the internet! Pretty sick right! They have a function called Funnel that lets you set up a domain name that will connect to a specific machine on your tailnet. Of course one option with tailscale is to include the agent in your payload for getting the reverse shell, and just making the connection through the tailscale vpn... but that's.... a bit out of scope here (I haven't done that yet, but I do intend to!)
Who needs a service?
Another option that I have used to quite good success is to spin up a small VPS on a hosting provider like linode or digital ocean, install a VPN server on it like wireguard or openvpn, then connect your computer to that VPN and portforward through the VPN connection. This sounds complicated, but its actually pretty easy. Below are the instructions to do this on linode, but it will be pretty similiar on other hosting providers. I like wireguard for its speed and security, but the setup with OpenVPN might be easier.
Here are the instructions for Wireguard and Linode!
First you'll need to create a linode account. Then you'll create a new linode, luckily there are ready to deploy images with VPN servers to make it easier!
click on the create a linode button, then instead of filling out the information look at the top for a tab that says "Market Place".
in the search bar go a head and type "wireguard" that should bring up the Wireguard image. Click on it, and scroll down until you see region and select the region that makes the most sense to you.
scroll down a bit more until you see the sizing options. click on the shared CPU tab and select the smallest one you can.
Once you hit go it'll take a few minutes to fully build and deploy it self, so go grab a coffee, or a beer... or a whisky..... or some weed what ever coats your scrote.
Once the build process is done you can copy the ssh command and ssh into the server, using the root password you set during creation.
Now that the linode is built we need to configure the server!
Go a head and copy the ssh command out of the linode web console and paste it into your terminal, use the root password you set up during linode creation.
Once you're logged in we'll first create a key pair for the server to use (it already has one, but we want a new one just incase!).
Do this by running the following commands:
wg genkey | tee /etc/wireguard/server_private_key
cat /etc/wireguard/server_private_key | wg pubkey | tee /etc/wireguard/server_public_key
The first command creates a new private key for the server to use, the second generates a public key based on this private key.
Now lets add those keys to our server's config file. Edit the file /etc/wireguard/wg0.conf and where it says PrivateKey = (stuff) replace the stuff with the private key we just generated.
Now we need to make a client for us to use! let's create a directory to store the client configuration files. This will be useful if you want to create new clients at a later time, after all this is a fully functional VPN server, so if you want to keep your ISP from snooping, or be better protected on public wifi you can use this for that too!!
mkdir /etc/wireguard/clients/
now lets make a client for our attacking linux machine so we can catch a shell!
nano /etc/wireguard/clients/attack_linux.conf
you can use this template to set up the bare bones
[Interface]
Address = 10.0.1.2/24
ListenPort = 51820
PrivateKey = <CLIENT_PRIVATE_KEY>
[Peer]
PublicKey = <SERVER_PUBIC_KEY>
PresharedKey = <CLIENT_PRESHARED_KEY>
AllowedIPs = 0.0.0.0/0
Endpoint = <SERVER_PUBLIC_IP>:51820
cool, but now we need to generate a key pair for this client! we can do that in a very similiar fashion to how we generated the key pair for the server.
wg genkey
then copy the string it prints out and do
echo 'the string you copied' | wg pubkey
then we can add that to the client configuration file under the Interface section.
Keep the public key somewhere, we'll need it when we add the client to the server as a peer.
[Interface]
Address = 10.0.1.2/24
ListenPort = 51820
PrivateKey = the genkey thing you copied
PublicKey = the public key you generated
[Peer]
PublicKey = <SERVER_PUBIC_KEY>
PresharedKey = <CLIENT_PRESHARED_KEY>
AllowedIPs = 0.0.0.0/0
Endpoint = <SERVER_PUBLIC_IP>:51820
Also add the server's public key to the Peer section where indicated, you can read it by running
cat /etc/wireguard/server_public_key
cool so we have our public private keys for both the server and the client to encrypt their communication, but what about authentication? that's important right? SURE IS!
We can simply generate a pre-shared key to use for authentication using the same wg genkey command!
wg genkey
Then copy the string and add it to the preshared key section of the client configuration!
The final thing we need to do for the client is add the server's public IP address to the Peer section of our client configuration. You can get this by looking at the linode web console, or by running ip addr in your ssh session.
Cool, now all we need to do is add the client to our server as a peer. Open up the wg0.conf file
nano /etc/wireguard/wg0.conf
Add the following to the end of the configuration file:
[Peer]
PublicKey = {your attack_linux_public_key}
PresharedKey = {the preshared key you generated}
AllowedIPs = 10.0.1.2/32
replace the public key with your client's public key, and the presharedkey with the preshared key you generated, and its configured!
now we just need to start the server. Run the following
wg-quick up wg0
If there are no errors we can go a head and shut it down for now, because we will be enabling it to run at boot.
wg-quick down wg0
cool now to enable it to run at boot we can use systemd!
systemctl enable --now wg-quick@wg0
Wireguard should now be running! If you need to stop if for any reason you can run.
systemctl stop wg-quick@wg0
you can also manually start it with
systemctl start wg-quick@wg0
And if you need to just restart it you can run
systemctl restart wg-quick@wg0
Cool, we have a VPN server now... but so what, how do we catch shells?
Easy, we portforward, through the VPN! See a VPN is basically just a fancy router. Did you notice those iptables commands in the post start and post stop sections of the configuration files? If not here they are:
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6
tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; i
p6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Understanding what these are specifically doesn't really matter for this post, but it does illustrate how iptables works on Linux, they make IP routing rules!
So we can use IP tables to make a routing rule to port forward through the VPN tunnel!
First run the following command to make sure that proper routing of the responses for any port forwarded ports.
iptables -t nat -A POSTROUTING -j MASQUERADE
Now for any port you want to forward you can run do the following:
iptables -t nat -A PREROUTING -p tcp --dport (port you want to forward) -j DNAT --to-destination (your client IP):(port you want to forward)
iptables -A FORWARD -p tcp -d (your client IP) --dport (port you want to forward -j ACCEPT
For example if we want to catch a shell that will connect back on port 31337 with the example client we just created we would run:
iptables -t nat -A PREROUTING -p tcp --dport 31337 -j DNAT --to-destination 10.0.1.2:31337
iptables -A FORWARD -p tcp -d 10.0.1.2 --dport 31337 -j ACCEPT
Now just save the client configuration on your attacking machine and use it to connect! There are a few ways to connect to the Wireguard VPN on linux, you can install the wireguard-tools package (at least that's what its called on arch linux) and just use wg-quick to start it, or you can add it to your network manager application, for example KDE Plasma allows you to import wireguard configuration files directly!
Now just point your shell at the public IP of the VPS and start the listener on your attacking Linux machine!
there has to be an easier way!
Well there are a couple. The easiest would be to spin up a normal linux VPS on Linode, then install tailscale. Since tailscale already creates the mesh VPN you can add those same iptables rules mentioned above, just adjust the destination IP address to point to the tailscale IP address of your attacking linux host!
BUUUUT

SSH Tunneling
SSH can be used as a psuedo VPN itself! Crazy right! To do this we'll need to adjust the configuration of the ssh server already installed on our linode!
nano /etc/ssh/sshd.conf
find the line that reads:
#GatwayPorts no
and change it to
GatewayPorts yes
now we need to restart the ssh service
systemctl restart sshd
once that's done we can just spin up our shell listener on the attacking machine
nc -nlvp 31337
then use ssh remote port forwarding to forward the correct port!
ssh -R 0.0.0.0:31337:localhost:31337 root@your_linode_public_ip
if this doesn't work, you may have UFW running on your linode. You can disable that with
systemctl stop ufw
you can make sure it doesn't run at boot with
systemctl disable ufw
Conclusion:
Thank you for reading through this alcohol, nicotine, and caffeine fueled rant on portforwarding. Hope you learned something, and as always, get out there and hack something!