0

I have a Python project that dynamically loads Python scripts from a set of specified directories and executes an expected function off of them (the framework expects a function name that takes a certain number of parameters, but the implementation is unknown). To harden the security of this application, I would like to analyze the scripts to ensure that they are just pure math functions and, therefore, not interacting with any system components such as the HDD/SDD, the network, a database, etc. Is this even possible to do in Python?

2

I'm afraid this is not possible. After all, your problem boils down to asking "is this code malicious?", and it we could reliably answer this question then malware would no longer exist.

You could mitigate this issue by allowing users to build their script using a set of allowed functions which you consider as safe (even though nothing is totally safe and there may be bugs in those functions that allow to do evil stuff) and only allow certain arguments (integers and references to previously defined variables) to further complicate an attacker's task (they can't just pass a string to a vulnerable function, yet another thing they need to work around). Of course you'll need to do all this validation server side, don't rely on client-side Javascript to enforce this.

Another option would be to accept any code (with a reasonable size limit) and running it in a VM with no network access and that can only communicate with the host through an emulated serial port to get the data and return its result (you can provide helper functions in your environment like get_input and set_output that would internally use the serial port to communicate with the host. You could make that even safer by running the VMs on physically separate machines that are considered untrusted and themselves only have a serial port to talk to the outside world. That way even if they do get exploited the attacker will have a hard time making any use of them.

  • 2 Questions - 1st - could using Haskell add some security since anything performing impure interactions would need to return an appropriate type: if my framework is not expecting the type it receives, it will throw an exception. - 2nd - Could Docker be a potential alternative to a full-blown VM? – josiah Jul 28 '16 at 16:24
  • 2
    @josiah I'm not familiar with Haskell, no idea if it'll work. Docker isn't designed for security. And depending on what the attacker wants, breaking out of Docker isn't even necessary - a spam or DoS bot will happily run inside a container and still do tons of damage. – André Borie Jul 28 '16 at 16:27
1

Adding on from what André said, I think whitelisting would be your best bet.

Some resources that might help you out https://wiki.python.org/moin/SandboxedPython Or more specifically http://www.jython.org/ As it includes some whitelisting capabilities.

If you'd like to come up with your own solution, you could either find, or build (given that python is whitespaced it wouldn't be too hard) a python parser using some regex magic and what not, to only allow certain code in a given script.

  • This is what I initially thought - parse through the scripts and whitelist the libraries that are allowed to be imported (or don't allow imports at all and just inject the dependencies that are permitted from the framework into the scripts) - but it seemed sort-of hackish to my intuition. I may take a hybrid approach of using a VM plus whitelisting before loading. – josiah Jul 28 '16 at 16:34
1

Possible: maybe. Feasible: seems unlikely. Simply restricting the imports will not secure the system. You'll need to parse the script and look for things like exec()

The biggest roadblock is that it's really hard to know that you've succeeded at blocking all dangerous operations.

If you can't trust the scripts, I think the safer way to go is to use a language specifically built for what you want to do or build your own. Trying to restrict the use of a general purpose language to what is known to be safe seems like a Sisyphean task. What you really want is a mathematical expression language, right?

Here's some code to give you an idea of what you are up against:

e = eval

g = e("glo" + "bals")

f = chr(101)
f += chr(120)
f += chr(101)
f += chr(99)
f += chr(102)
f += chr(105)
f += chr(108)
f += chr(101)

b = getattr(g()["__" + "builtins" + "__"], f)

print b

b("badstuff.py")

If you can't be bothered to run it, the print b displays:

<built-in function execfile> 

This is just what I came up with in a few minutes. Clearly you need to restrict use of globals, eval, exec, execfile but I make no claim that this list is comprehensive.

  • "You can't simply restrict the imports" - Yes you can, to an extent – Ella Rose Jul 28 '16 at 18:02
  • @EllaRose Sorry, I'm not seeing how that restricts access to exec() or execFile() or open(), etc. – JimmyJames Jul 28 '16 at 18:06
  • exec, execFile, open, etc are methods, not modules, and you do not "import" methods, you "import" modules in python. Modules are collections of methods (and objects). You can whitelist what modules can be imported. – Ella Rose Jul 28 '16 at 18:09
  • 1
    @josiah People problems are harder than technical ones. It's really going to come down to how much you trust them. If they aren't python masters and just like the simplicity of python, you might be able to create a python-esgue language that does what they need. That could take a while, of course. – JimmyJames Jul 28 '16 at 18:56
  • 1
    @josiah I know this is kind of crazy talk but if you created a parser that was a subset of the python language (say minus imports) you could, in theory, use that to build actual python. The problem with Python is that a lot useful stuff is mixed in with the dangerous stuff. Things like callbacks are going to be tough to support without creating holes. – JimmyJames Jul 28 '16 at 19:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.