Ozgur's Blog

Random ramblings of personal nature

Remote Code Execution


Remote Code Execution is considered as one of the worst ways to compromise a system. With this method an attacker can (and in most cases will) execute arbitrary code within a web application. As you can imagine, in some scenarios, this can escalate to sending commands to the host operating system.

Let me try to explain this via an analogy from biology. This is akin to Zombie ant fungus. A spore first infects an ant then after its incubation period of 3-9 days it manipulates the infected ant to plod away from the safety, like a zombie - hence Zombie ant fungus. Its final act is spectacular, a scene you may be familiar if you have watched the first Alien movie - it bursts its stalk from the dead chest of the hapless ant like a chestburster.

If we return to our subject with this method an attacker can gain persistence in the system with the use of a reverse shell. This is an insidious way of attacking - and most of the Metasploit exploits work in this way - for with a reverse shell, the infected machine tries to establish a connection with your machine, not vice versa. Usually we expect the attacker the connect to the machine and most sysadmins check incoming connections but this is an outbound - and usually done via a commonly used port - connection, hence making it quite invisible to most sysadmins.

Let us reiterate, with this method the attacker can run system commands. So in addition to gaining persistence, the attacker can use this to pivot in the network which the victim machine is connected. Here is a summary graphic of what an attacker can do via RCE.

rci-summary

Old Times - Perl

To give an example about how it was done back in the day let me give you an example with Perl. Because it is not used that widely I believe this won't trigger an attack on systems used in our modern times. After that I'll illustrate two mild attacks with PHP and Python's Flask framework.

Let us imagine we have built a web application with Perl and passing parameters to it without checking. So when a user is trying to list a product from a store that's near to him he'd see something like this in the address bar:

https://example.com/stockquery?product_id=12&store_id=3

To present this data to user the application passes this information to its systems. In that age this meant calling out a shell command with the product id and store id as arguments:

stockquery.pl 12 3

The command executes and pipelines the result to the web app which presents it to the user. But this enabled an attacker to run commands like:

stockquery.pl & echo myname & 3

by changing the first parameter after the question mark. This often generated a result like this:

Error - product_id was not provided
myname
3: command not found

By this data the attacker knew three things:

  • A command to generate the data, in our case it is stockquery.pl, was executed without arguments it expected
  • Injected echo command was run and its result is pipelined
  • The argument 3 is understood as a command and hence resulting an error.

The attacker, then, could execute commands like whoami, ifconfig and ps -ef (or their Windows equivalents if the server is running it) and get its results.

But most often the resulting error wouldn't be shown to the end user. But if the attacker knew something was running s/he could execute a blind OS command injection with passing something like

ifconfig > /var/www/static/ifconfig.txt &

Then s/he could access to this newly generated txt file via a simple get request:

example.com/ifconfig.txt

Now let us discuss two mild examples of Remote Code Execution. As I have said that those attacks are mild, as in they don't escalate to full system access but showing how can we execute commands valid in the programming language the web application is written.

Example with PHP

Even though I am a Python programmer nowadays I dabbled in PHP and read/fixed a lot of code in it. Within this language when you want to dynamically generate pages with some data people often use eval() function.

Let us imagine we are trying to list the birth date of an user within his profile page. Inevitably we will use something like this:

eval("\$$user = '$dobdate');

Because the username is generally controlled by user an attacker can create a name like this:

x = 'y';phpinfo();

When this information is passed the php will interpret it like:

$x = 'y'; phpinfo(); // = '1983';

Or more clearly:

    $x = 'y';
    phpinfo(); // = '1983';

The doubleslashes will render the rest as comment. So php will assign a new variable called x, assign it to the value 'y' and then executes the phpinfo() function disregarding the rest. This will print out the phpinfo() to the page.

Possible Fixes

To prevent this we need to avoid using user input inside any evaluated code. Assume that a user inevitably will try to pull something like that. Best way? Do NOT use the eval() function. Secondly never NEVER give a user free reign on the content of files that will be parsed by the server. Filenames and extensions should and must be limited.

Python - Flask

Flask is one of the most popular web frameworks built with Python. It uses a templating system called Jinja2. If unchecked this system may allow attackers to exploit Server-Side Template injection vulnerabilities. In short, this vulnerability enables a hacker to inject language/syntax into templates - hence executing the code within the server context.

Local File Inclusion - LFI

Although usually template files residing in their own folder, we can provide template formatting within the code for the ease of reading here.

This is a valid flask code:

from flask import Flask, request, render_template, render_template_string
app = Flask(__name__)

@app.route('/introducing-rce')
def vulnerable_func():
    person = {'firstname':"Ozgur", "sekrit":"MySecret"}
    if request.args.get('firstname'):
        person['firstname'] = request.args.get('firstname')
    template = """<h1> Hello {} </h1>""".format(person['firstname'])
    return render_template_string(template, person=person)

if __name__ == "__main__":
    app.run()

The usual execution is pretty much working. I send a get request to my web app via

http://localhost:5000/introducing-rce

And get a screen like this:

normal-flask

But when I change my request to this:

http://localhost:5000/introducing-rce?firstname=Ahmet-{{person.sekrit}}

And the result is:

secret-flask

Oh yes... our secret is out in the open! But we are not done yet. What if this system is able to list a user's files via function:

def get_user_files(f_name):
    with open(f_name) as f:
        return f.readlines()

app.jinja_env.globals["get_user_files"] = get_user_files  # This enables us to use this function within a template context

And let's say I know the user stores a pass.txt file within his home directory. This is what happens when a request like this is passed:

http://localhost:5000/introducing-rce?firstname=Ahmet.{{get_user_files("/home/f4stjack/pass.txt")}}

The result of this request:

filereader-flask

Goodness gracious me! This is my actual path by the way.

The Fix

This happens because we use string formatting or substitution. To prevent this we need to use the actual variable name in the template changing the code to:

template = "<h1> Hello {{person.firstname}}!</h1>

When this happens we translate the entered data into full string and pass it to the template - hence rendering it harmless.

Cross Side Scripting - XSS

What about XSS or Cross Side Scripting. Does our fix protect us against this widely used attack method? Sadly... no.

When we pass a request like this:

http://localhost:5000/introducing-rce?firstname=Ahmet<script>alert("I run happily!")</script>

And we have this:

xss-flask

Omagad! No. To mitigate this we need to add a manual escape filter to our template code making it thus:

template = "<h1> Hello {{person.firstname | e}}!</h1>

But not every app uses this kind of internal templating done on the code. As I've stated before, most of the templates reside in a templates folder for ease of developing and of course enabling use to reuse code with base templates. To mitigate this attack within the templates we need to use the |e fix within the template:

<a href='{{url_for('function_name')}}?firstname={{firstname |e}}'>Click me</a>

Conclusion

Basically Remote Code Execution is something like this. In the recent years Shellshock vulnerability and a Java exploit behind the Equifax breach are most noteworthy examples of executing this method of attack.

Thank you for reading!