A couple of lessons ago you saw how you can use the
.__setstate__() method to reinitialize things that can’t be saved in a pickled object. This was a cool workaround, but remember how you executed that
print() statement that had little to do with the object itself? In this lesson, you’re going to see how
pickle is not secure and why you should never unpickle untrusted data.
00:23 Let’s take a look at an example where you’ll be an attacker going after a service that transfers data in a pickled format. In this scenario, imagine that the client is sending a pickled stream of data to the server.
00:35 What the service is probably expecting is that users have some sort of Python application on their machines which is collecting data, pickling it, and then sending it over the network to the service, which could be a Flask web application that’s storing that data in a database.
Unfortunately for the service, you’ve realized this process by monitoring network traffic out of your machine. You decide to make your own custom class that will compromise the service running the application using
Define a constructor
.__init__() method that will take in
self, and it can just be
pass. And now, to work with the
.__setstate__() methods, go ahead and define
.__getstate__(), which will take in
self, and will return
self and then the
Because this example is going to take place on my Mac and would also work on a Linux machine, the attack is going to come from
localhost, and you will also expect the attack is listening on port
How this works is well beyond the scope of this lesson, but it’s a cool example to see how
pickle can be used in less-than-expected ways. Because we’re only going to be working inside of one script, go ahead and make an instance of
And then here is what the server would do, where it would take that pickled data stream, unpickle it, which would then call this
.__setstate__() method, which unfortunately for the server, instead of returning what the properties of the expected object should be it’s actually going to run this code here, which it does not want to do.
So, save this script, open up a terminal, and this is going to happen in two steps. I’m opening up a second terminal, and this is what would be the attacker’s machine—so that
localhost at port
nc command for Ncat, and then you’re going to listen with a
-l at port
8080. So by running this, it looks like nothing’s happening, and that’s because this terminal is now listening on port
8080 for some type of communication to come back through.
So now let’s see what we can do. We can print the working directory, and this is the working directory that I ran the script from. You can do all sorts of stuff, like run a
whoami and see, “Oh, well there’s the user account that’s running that script.” So obviously, this is not intended behavior and you definitely don’t want to expose any services that you have to somebody to be able to run a reverse shell this easily. I mean, looking at the actual exploit itself, it’s just a couple of lines of code and really just one significant line.
The biggest takeaway from here is that if you’re going to pickle data and then unpickle the data, make sure you trust where that unpickled data is coming from because it can be very easy for an attacker to execute code on your machine that you’re not intending to run. And with that, you should be pretty comfortable using
pickle and knowing some of its limitations and how to get around those limitations. In the next video, we’re going to take a few minutes to wrap up and cover everything that you learned.
Become a Member to join the conversation.