Use eval() safely?

W

W. Martin Borgert

Hi,

I know that this issue has been discussed before, but most of
the time using only one argument to eval().

Is it possible to use the following code, e.g. run as part of a
web application, to break in and if so, how?

import math

def myeval(untrustedinput):
return eval(untrustedinput, {"__builtins__": None},
{ "abs": abs, "sin": math.sin })

Is it possible to define functions or import modules from the
untrusted input string?

Which Python built-ins and math functions would I have to add to
the functions dictionary to make it unsafe?

TIA! (Please cc me, thanks.)
 
S

Steven D'Aprano

Hi,

I know that this issue has been discussed before, but most of the time
using only one argument to eval().

Is it possible to use the following code, e.g. run as part of a web
application, to break in and if so, how?

import math

def myeval(untrustedinput):
return eval(untrustedinput, {"__builtins__": None},
{ "abs": abs, "sin": math.sin })

Is it possible to define functions or import modules from the untrusted
input string?

Which Python built-ins and math functions would I have to add to the
functions dictionary to make it unsafe?

You've got the right idea, but the task is difficult.

Please read this thread:

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

Gregory Ewing

W. Martin Borgert said:
def myeval(untrustedinput):
return eval(untrustedinput, {"__builtins__": None},
{ "abs": abs, "sin": math.sin })

Is it possible to define functions or import modules from the
untrusted input string?

This is NOT safe as it stands. It still isn't safe even if
you put nothing in the globals dict at all.

A couple of ways someone can do nasty things to you:

# Wipe out any file writable by the calling process
eval("[c for c in (0).__class__.__bases__[0].__subclasses__() if c.__name__ ==
'file'][0]('/my/precious/file', 'w')")

# Use up large amounts of memory and CPU time
eval("100000**100000")
 
S

Steven D'Aprano

This is NOT safe as it stands. It still isn't safe even if you put
nothing in the globals dict at all.

It's *especially* not safe if you put nothing in the globals dict,
because Python kindly rectifies that by putting the builtins into it:
['IndexError', 'all', 'help', 'vars', ... 'OverflowError']

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'globals' is not defined

So {'__builtins__': None} is safer than {}. Still not safe, exactly, but
safer. Or at least you make the Black Hats work harder before they own
your server :)
 
D

Dieter Maurer

Steven D'Aprano said:
...
It's *especially* not safe if you put nothing in the globals dict,
because Python kindly rectifies that by putting the builtins into it:
['IndexError', 'all', 'help', 'vars', ... 'OverflowError']

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'globals' is not defined

So {'__builtins__': None} is safer than {}. Still not safe, exactly, but
safer. Or at least you make the Black Hats work harder before they own
your server :)

Using functionality introduced with the class/type homogenization,
it is quite easy to get access to the "file" type (even when "__builtins__"
is disabled). Having "file", arbitrary files can be read, written, destroyed...


Dieter
 
S

Steven D'Aprano

Using functionality introduced with the class/type homogenization, it is
quite easy to get access to the "file" type (even when "__builtins__" is
disabled). Having "file", arbitrary files can be read, written,
destroyed...

Not that I don't believe you (I do!) but could you demonstrate for the
record?
 
G

Gregory Ewing

Steven said:
Not that I don't believe you (I do!) but could you demonstrate for the
record?

I posted a demonstration of this earlier in this thread. The
key thing is the __subclasses__() method of a class. You can
start with any object, work your way up the base class chain
to object, and then use __subclasses__() to get to any builtin
class in the system, including file.

There was a sandboxing scheme put forward a while back which
involves vetting the code and disallowing the use of any
double-underscore attribute names. With a suitably censored
set of builtin functions, this prevents the use of the
__subclasses__ hack, as well as some other potential lines
of attack. As far as I know, nobody managed to break it at
the time, but it probably hasn't been tested much in
the real world, if at all, so I probably wouldn't recommend
using it for anything critical.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,169
Latest member
ArturoOlne
Top