Skip to content

Commit

Permalink
Added an eval method to the constants module, to evaluate constants i…
Browse files Browse the repository at this point in the history
…n the current context
  • Loading branch information
Mathias Svensson committed Jan 11, 2015
1 parent 4a8e822 commit 93d2f57
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 18 deletions.
22 changes: 21 additions & 1 deletion pwnlib/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from types import ModuleType
import importlib, sys
from ..context import context
from ..util import safeeval

class module(ModuleType):
def __init__(self, submodules):
Expand Down Expand Up @@ -65,9 +66,28 @@ def __dir__(self):
if context.os in self.__all__:
result.extend(dir(getattr(self, context.os)))


return result

def eval(self, string):
"""eval(string) -> value
Evaluates a string in the context of values of this module.
Example:
>>> with context.local(arch = 'i386', os = 'linux'):
... print constants.eval('SYS_execve + PROT_WRITE')
13
>>> with context.local(arch = 'amd64', os = 'linux'):
... print constants.eval('SYS_execve + PROT_WRITE')
61
>>> with context.local(arch = 'amd64', os = 'linux'):
... print constants.eval('SYS_execve + PROT_WRITE')
61
"""
env = {key: getattr(self, key) for key in dir(self) if not key.endswith('__')}
return safeeval.values(string, env)

# To prevent garbage collection
tether = sys.modules[__name__]

Expand Down
76 changes: 59 additions & 17 deletions pwnlib/util/safeeval.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
'BINARY_OR',
]

_values_codes = _expr_codes + ['LOAD_NAME']

def _get_opcodes(codeobj):
"""_get_opcodes(codeobj) -> [opcodes]
Extract the actual opcodes as a list from a code object
>>> c = compile("[1 + 2, (1,2)]", "", "eval")
>>> _get_opcodes(c)
[100, 100, 23, 100, 100, 102, 103, 83]
[100, 100, 103, 83]
"""
import dis
i = 0
Expand Down Expand Up @@ -63,14 +65,16 @@ def const(expr):
a Python constant. Strings that are not valid Python expressions
or that contain other code besides the constant raise ValueError.
>>> const("10")
10
>>> const("[1,2, (3,4), {'foo':'bar'}]")
[1, 2, (3, 4), {'foo': 'bar'}]
>>> const("[1]+[2]")
Traceback (most recent call last):
...
ValueError: opcode BINARY_ADD not allowed
Examples:
>>> const("10")
10
>>> const("[1,2, (3,4), {'foo':'bar'}]")
[1, 2, (3, 4), {'foo': 'bar'}]
>>> const("[1]+[2]")
Traceback (most recent call last):
...
ValueError: opcode BINARY_ADD not allowed
"""

c = test_expr(expr, _const_codes)
Expand All @@ -85,15 +89,53 @@ def expr(expr):
uses Python constants. This can be used to e.g. evaluate
a numerical expression from an untrusted source.
>>> expr("1+2")
3
>>> expr("[1,2]*2")
[1, 2, 1, 2]
>>> expr("__import__('sys').modules")
Traceback (most recent call last):
...
ValueError: opcode LOAD_NAME not allowed
Examples:
>>> expr("1+2")
3
>>> expr("[1,2]*2")
[1, 2, 1, 2]
>>> expr("__import__('sys').modules")
Traceback (most recent call last):
...
ValueError: opcode LOAD_NAME not allowed
"""

c = test_expr(expr, _expr_codes)
return eval(c)

def values(expr, env):
"""values(expression, dict) -> value
Safe Python expression evaluation
Evaluates a string that contains an expression that only
uses Python constants and values from a supplied dictionary.
This can be used to e.g. evaluate e.g. an argument to a syscall.
Note: This is potentially unsafe if e.g. the __add__ method has side
effects.
Examples:
>>> values("A + 4", {'A': 6})
10
>>> class Foo:
... def __add__(self, other):
... print "Firing the missiles"
>>> values("A + 1", {'A': Foo()})
Firing the missiles
>>> values("A.x", {'A': Foo()})
Traceback (most recent call last):
...
ValueError: opcode LOAD_ATTR not allowed
"""

# The caller might need his dictionary again
env = dict(env)

# We do not want to have built-ins set
env['__builtins__'] = {}

c = test_expr(expr, _values_codes)
return eval(c, env)

0 comments on commit 93d2f57

Please sign in to comment.