If an attacker can control the value of attacker_controlled_nasty_variable
, is this segment of code vulnerable?
dic={"one":1,
"nasty":attacker_controlled_nasty_variable,
}
store=str(dict)
...
dic=eval(store)
If an attacker can control the value of attacker_controlled_nasty_variable
, is this segment of code vulnerable?
dic={"one":1,
"nasty":attacker_controlled_nasty_variable,
}
store=str(dict)
...
dic=eval(store)
Use ast.literal_eval()
instead of eval()
.
Yes. It could be replaced with an object that has a __repr__()
method that either has a payload itself, or returns a string that could be unsafe when passed to eval()
.
Proof of Concept:
class MyClass(object):
def __repr__(self):
return 'os.system("format c:")'
bad = [MyClass()]
print str(bad)
It is safe as long as you can be sure that attacker_controlled_nasty_variable
is never an object where the attacker can control __repr__
(or __str__
) as he could otherwise inject python code.
However, better use repr(dic)
instead of str(dic)
since only repr
is expected to return valid python code.
Additionally - as mentioned by @payne - use the safer ast.literal_eval()
instead of eval()
.
Let's try it:
>>> attacker_controlled_nasty_variable="`cat /etc/passwd`"
>>> dic={"one":1,
... "nasty":attacker_controlled_nasty_variable,
... }
>>> store = repr(dic)
>>> store
"{'nasty': '`cat /etc/passwd`', 'one': 1}"
>>> dic=eval(store)
>>> dic
{'nasty': '`cat /etc/passwd`', 'one': 1}
>>> attacker_controlled_nasty_variable="'hello',}"
>>> dic={"one":1,
... "nasty":attacker_controlled_nasty_variable,
... }
>>> repr(dic)
'{\'nasty\': "\'hello\',}", \'one\': 1}'
>>> eval(repr(dic))
{'nasty': "'hello',}", 'one': 1}
You may want to try more cases, but empirically it looks like __repr__
is quoting the contents correctly.