On Tue, 29 Nov 2016 09:35 am, Gregory Ewing wrote: > Steve D'Aprano wrote: >> I daresay you are right that a sufficiently clever adversary may have >> found an exploit. But there's no sign that anyone actually did find an >> exploit, until f-strings made exploiting this trivial. > > The person who wrote the bug report found at least one > way of exploiting it that doesn't require f-strings.
Oops, of course you are right. The bug report says: 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. http://bugs.python.org/issue28563 And later on: 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: [...] This will successfully spawn a shell in Python 2.7.11. Which I had forgotten about. (And by the way: the exploit could have been avoided by refusing any string which contains an underscore. If you can't avoid vulnerable code, at least make attackers work hard to exploit it.) The point I was making was this comment: 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 [emphasis added] f-strings are *not* "just a string", as this shows -- they're actually equivalent to a call to eval. And *that* is my point: we've picked a syntax which looks like a static literal string for something which is not only a function call but equivalent to the second most powerful (and hence dangerous) built-in function call available in the language. Normally I think Guido's instinct for syntax and language features is pretty good, but here I think he's made a blunder. The original proposal on the Python-Ideas mailing list was for syntax to automatically perform *only* name lookups so that f"{x}" was syntactic sugar for "{x}".format(x=x) and from that simple request it has grown in scope to the point that we can now write: f"{os.system('sh')}" as syntactic sugar for: str(eval("os.system('sh')")) Yay for progress! > I agree that f-strings are not to blame here. I've already said that. Certainly the *vulnerability* comes from the use of eval by gettext.c2py, but the TRIVIAL *exploit* comes from f-strings. > If we really > want to avoid breaking anyone's ill-conceived attempts at > sandboxing eval, we'd better not add anything more to the > language, ever, because nobody can foresee all the possible > consequences. Now you're just being silly, this isn't "anything", it is a specific design decision: something which looks like, and is treated by the tokeniser, as a string but is actually a hidden call to eval. And in fact I did foresee the consequences. I never predicted this *exact* vulnerability, of course, but I did say that disguising a call to eval inside something which looks like a string would lead to trouble. I was poo-pooed for that idea, so please excuse me if I gloat a little when the first "trouble" is discovered before the feature is even available in a production release. I don't say this as if it were an amazing feat of prediction. I'm astonished that apparently others can't, or won't, see it. Its like when people store weed killer or some other poison in a soft-drink bottle, complete with the label still on, and then are surprised when someone gets poisoned. http://www.dailymail.co.uk/news/article-1337101/Father-Phillip-Ward-dies-accidentally-drinking-weedkiller-Lucozade-bottle.html (Not the first, or last, case of accidental poisoning from herbicide or pesticide stored inappropriately.) -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list