Executing untrusted code

Discussion in 'Python' started by Emanuele D'Arrigo, Aug 7, 2009.

  1. Greetings everybody,

    I've been reading and mulling about python and security, specifically
    in terms of executing code that may or may not be trustworthy. I
    understand that libraries such as Rexec and Bastion are now deprecated
    because they have known vulnerabilities that may be exploited to
    circumvent the restrictions imposed.

    So, am I right in understanding that is not possible to execute a
    piece of code in a way that limits the objects and attributes that it
    can access or that limits its access to file system and sockets? Are
    there best practices to at least minimize some of the risks associated
    with untrusted code execution?

    And whatever happened to this:

    http://sayspy.blogspot.com/2007/05/i-have-finished-securing-python.html

    seemed to be a step forward in the right direction!

    Manu
     
    Emanuele D'Arrigo, Aug 7, 2009
    #1
    1. Advertising

  2. Emanuele D'Arrigo

    Nobody Guest

    On Fri, 07 Aug 2009 08:15:08 -0700, Emanuele D'Arrigo wrote:

    > Are
    > there best practices to at least minimize some of the risks associated
    > with untrusted code execution?


    Yes: don't execute it. Failing that, run the Python interpreter within a
    sandbox.

    If you want to support restricted execution within a language, it has to
    be built into the language from day one. Trying to bolt it on later is a
    fool's errand.
     
    Nobody, Aug 8, 2009
    #2
    1. Advertising

  3. Sorry for digging this back from the grave.
    I've had to chew on it for a little while.

    On Aug 8, 1:40 am, Nobody <> wrote:
    > If you want to support restricted execution within a language, it
    > has to be built into the language from day one. Trying to bolt it > on later is a fool's errand.


    Fair enough. In this context, let's say I do this:

    import __builtin__
    import imp
    originalBuiltins = imp.new_module("OriginalBuiltins")

    def readOnlyOpen(filename):
    return originalBuiltins.open(filename, "r")

    __builtin__.open = readOnlyOpen

    exec(anUntrustedString, {})

    In what ways would the untrusted string be able to obtain the
    original, built-in open function and open a file for writing?

    Manu
     
    Emanuele D'Arrigo, Aug 20, 2009
    #3
  4. They could, of course, use the file object constructor directly, e.g.:
    f = file("/etc/passwd", "w")

    On Thu, 20 Aug 2009 08:16:51 -0700, Emanuele D'Arrigo <>
    wrote:

    > Sorry for digging this back from the grave.
    > I've had to chew on it for a little while.
    >
    > On Aug 8, 1:40 am, Nobody <> wrote:
    >> If you want to support restricted execution within a language, it
    >> has to be built into the language from day one. Trying to bolt it > on
    >> later is a fool's errand.

    >
    > Fair enough. In this context, let's say I do this:
    >
    > import __builtin__
    > import imp
    > originalBuiltins = imp.new_module("OriginalBuiltins")
    >
    > def readOnlyOpen(filename):
    > return originalBuiltins.open(filename, "r")
    >
    > __builtin__.open = readOnlyOpen
    >
    > exec(anUntrustedString, {})
    >
    > In what ways would the untrusted string be able to obtain the
    > original, built-in open function and open a file for writing?
    >
    > Manu
    >




    --
    Rami Chowdhury
    "Never attribute to malice that which can be attributed to stupidity" --
    Hanlon's Razor
    408-597-7068 (US) / 07875-841-046 (UK) / 0189-245544 (BD)
     
    Rami Chowdhury, Aug 20, 2009
    #4
  5. On Thu, 20 Aug 2009 08:16:51 -0700, Emanuele D'Arrigo wrote:

    > Fair enough. In this context, let's say I do this:
    >
    > import __builtin__
    > import imp
    > originalBuiltins = imp.new_module("OriginalBuiltins")
    >
    > def readOnlyOpen(filename):
    > return originalBuiltins.open(filename, "r")
    >
    > __builtin__.open = readOnlyOpen



    Have you actually tested this? I don't think it works the way you think
    it does.

    >>> import __builtin__
    >>> import imp
    >>> originalBuiltins = imp.new_module("OriginalBuiltins")
    >>> originalBuiltins.open

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    AttributeError: 'module' object has no attribute 'open'


    So your strategy fails to provide read-only file access.

    But moving on...

    > In what ways would the untrusted string be able to obtain the original,
    > built-in open function and open a file for writing?


    That's hardly even a challenge.

    >>> __builtin__.open = readOnlyOpen
    >>> anUntrustedString = """import __builtin__

    .... reload(__builtin__)
    .... open('junk', 'w').write('a')
    .... """
    >>> exec(anUntrustedString, {})
    >>> open('junk').read()

    'a'


    Not only have I broken your "read only" open within the call to exec, but
    I've broken it outside as well. With a little bit more effort, I could
    probably save and restore the open, so that my untrusted string could
    write to files inside the exec(), but code outside of the exec() would
    still see the readOnlyOpen.




    --
    Steven
     
    Steven D'Aprano, Aug 20, 2009
    #5
  6. On Thu, 20 Aug 2009 08:16:51 -0700, Emanuele D'Arrigo wrote:

    > In what ways would the untrusted string be able to obtain the original,
    > built-in open function and open a file for writing?


    On a related topic, you should read this post here:

    http://tav.espians.com/a-challenge-to-break-python-security.html


    --
    Steven
     
    Steven D'Aprano, Aug 20, 2009
    #6
  7. Christian, Rami and Steven, thank you all for your help. It wasn't
    meant to be a challenge, I knew it ought to be easily breakable. I'm
    no hacker and it just helps to have some examples to better understand
    the issue.

    On Aug 20, 7:42 pm, Steven D'Aprano <st...@REMOVE-
    > On a related topic, you should read this post here:
    > http://tav.espians.com/a-challenge-to-break-python-security.html


    Indeed I did read the post and my minimalistic test was inspired by
    some of the code in it (I didn't know you could replace the
    builtins!). Tav's effort kinda of ended nowhere though. My
    understanding of it is that it hasn't been broken and that Tav has
    submitted a patch to secure some of python's innards. But

    Steven, you are perfectly right, I didn't test it and I missed the
    crucial part in which I store the __builtins__ dictionary in the
    dictionary of the new originalBuiltins module. My bad. Still, you did
    understand my intentions and did give me a simple example of how it
    could be broken. Thank you.

    -However- I would suggest that conceptually the "award" goes to
    Christian. ;)

    In the same way the open builtin function can be replaced or removed,
    also reload, file, __import__, exec, execfile and any other
    potentially "unsafe" builtin can be replaced with safer versions. Or
    not?

    Christian's solution though, seems to be much trickier to evade. Can
    the object class be replaced at runtime with a version that does not
    provide a way to reach its subclasses?

    Manu
     
    Emanuele D'Arrigo, Aug 20, 2009
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tomas Mikula
    Replies:
    8
    Views:
    662
    Teraposa Lunodas
    Nov 24, 2009
  2. Robin Krahl
    Replies:
    2
    Views:
    205
    Ramchandra Apte
    Oct 6, 2012
  3. Chris Angelico
    Replies:
    2
    Views:
    191
    Chris Angelico
    Oct 6, 2012
  4. Mark Lawrence
    Replies:
    0
    Views:
    170
    Mark Lawrence
    Oct 6, 2012
  5. Rodrick Brown
    Replies:
    0
    Views:
    171
    Rodrick Brown
    Oct 6, 2012
Loading...

Share This Page