Matimus wrote:
On Jun 11, 9:16 pm, George Sakkis <[EMAIL PROTECTED]> wrote:
On Jun 11, 8:15 pm, bvdp <[EMAIL PROTECTED]> wrote:



Matimus wrote:
The solution I posted should work and is safe. It may not seem very
readable, but it is using Pythons internal parser to parse the passed
in string into an abstract symbol tree (rather than code). Normally
Python would just use the ast internally to create code. Instead I've
written the code to do that. By avoiding anything but simple operators
and literals it is guaranteed safe.
Just wondering ... how safe would:
         eval(s, {"__builtins__":None}, {} )
be? From my testing it seems that it parses out numbers properly (int
and float) and does simple math like +, -, **, etc. It doesn't do
functions like int(), sin(), etc ... but that is fine for my puposes.
Just playing a bit, it seems to give the same results as your code using
ast does. I may be missing something!
Probably you do; within a couple of minutes I came up with this:

s = """
... (t for t in 42 .__class__.__base__.__subclasses__()
...  if t.__name__ == 'file').next()('/etc/passwd')
... """>>> eval(s, {"__builtins__":None}, {} )

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 3, in <module>
IOError: file() constructor not accessible in restricted mode

Not an exploit yet but I wouldn't be surprised if there is one. Unless
you fully trust your users, an ast-based approach is your best bet.

George

You can get access to any new-style class that has been loaded. This
exploit works on my machine (Windows XP).

[code]
# This assumes that ctypes was loaded, but keep in mind any classes
# that have been loaded are potentially accessible.

import ctypes

s = """
(
    t for t in 42 .__class__.__base__.__subclasses__()
        if t.__name__ == 'LibraryLoader'
    ).next()(
        (
            t for t in 42 .__class__.__base__.__subclasses__()
                if t.__name__ == 'CDLL'
            ).next()
        ).msvcrt.system('dir') # replace 'dir' with something nasty
"""

eval(s, {"__builtins__":None}, {})
[/code]

Matt

Yes, this is probably a good point. But, I don't see this as an exploit in my program. Again, I could be wrong ... certainly not the first time that has happened :)

In my case, the only way a user can use eval() is via my own parsing which restricts this to a limited usage. So, the code setting up the eval() exploit has to be entered via the "safe" eval to start with. So, IF the code you present can be installed from within my program's scripts ... then yes there can be a problem. But for the life of me I don't see how this is possible. In my program we're just looking at single lines in a script and doing commands based on the text. Setting/evaluating macros is one "command" and I just want a method to do something like "Set X 25 * 2" and passing the "25 * 2" string to python works. If the user creates a script with "Set X os.system('rm *')" and I used a clean eval() then we could have a meltdown ... but if we stick with the eval(s, {"__builtins__":None}, {}) I don't see how the malicious script could do the class modifications you suggest.

I suppose that someone could modify my program code and then cause my eval() to fail (be unsafe). But, if we count on program modifications to be doorways to exploits then we might as well just pull the plug.

Bob.
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to