Is it possible to get the erroneous variable when getting a NameError exception?

Michael Fötsch foetsch at yahoo.com
Sat Dec 26 07:34:18 EST 2009


Stephen Hansen wrote:
>             Dotan Barak wrote:
> 
> <snip>
>             ...         eval("my_number < 10", {"__builtins__":None}, {})
> <snip>
> 
> Hm, is this true, though? Is there anything subtle or dangerous possible 
> here? He's using eval-- so no statements, its only an expression. He's 
> passing in a 'globals' which has __builtins__ set to None, so this 
> environment has access to -- basically nothing. Then the locals 
> dictionary is empty as well, though I assume he'll fill it with things 
> like my_number.

A simple expression is enough to write to files, for example.

Try this expression in Python 3.0:

    [x for x in ().__class__.__base__.__subclasses__() if x.__name__ == 
'_FileIO'][0]('hello.txt', 'w').write('Hello, World!')


To explain, "().__class__.__base__.__subclasses__()" gives you a list of 
all object-derived classes, i.e., of *all* classes that exist in the 
surrounding program. If you can find just one class that allows you to 
do something subtle or dangerous, you're done.

See also:
- "Controlling Access to Resources Within The Python Interpreter" 
(http://people.cs.ubc.ca/~drifty/papers/python_security.pdf)
- http://evoque.gizmojo.org/usage/restricted/



To write your own restricted expression parser, the standard module 
"ast" is quite useful. For example, ast.parse("my_number < 10") gives 
you a syntax tree similar to this:

   ast.Expr(ast.Compare(ops=[ast.Lt], left=ast.Name(id="my_number"), 
comparators=[ast.Num(n=10)]))

 From there, you can implement your own logic to traverse the tree, 
which gives you very fine-grained control over the kinds of expressions 
to allow, where to look up variable names, how to react to errors, etc.


Kind Regards,
M.F.



More information about the Python-list mailing list