
Adding detailed documentation, with examples, on why things are bad and the correct way to fix the warnings. Right now, this is just a knowledge base, but eventually it would be nice to have these docs tied into the report via a URL. Change-Id: I05d0f07624425e8505fcd97d94ce8a966c86bc0c
2.4 KiB
yaml.load()
The PyYaml docs have
details on why using yaml.load()
with untrusted user data is very scary.
yaml.load()
can lead to remote code execution - yaml.safe_load()
should be used whenever parsing untrusted YAML.
Incorrect
We'll use Paul McMillan's
gist to demonstrate
why yaml.load()
is scary. We start by defining a few things for our
exploit, starting with exploit.py
will look like:
print 'WINNA WINNA'
In order to get yaml.load()
to properly execute our Python, we have to do
some careful encoding.
encoded = ("eval(compile('%s'.decode('base64'), '<string>', 'exec'))" % exploit.encode('base64').replace('\n', ''))
After executing the above, our encoded
variable looks like:
"eval(compile('cHJpbnQgIldJTk5BIFdJTk5BIgo='.decode('base64'), '<string>', 'exec'))"
Next, we build the actual YAML object:
yaml_object = ('\nupgrade_helper: !!python/object/apply:eval ["%s",]\n' % encoded)
This results in yaml_object
looking like:
'\nupgrade_helper: !!python/object/apply:eval ["eval(compile(\'cHJpbnQgIldJTk5BIFdJTk5BIgo=\'.decode(\'base64\'), \'<string>\', \'exec\'))",]\n'
We then take that yaml_object
and print it to a file exploit.yaml
, it will look like:
upgrade_helper: !!python/object/apply:eval ["eval(compile('cHJpbnQgIldJTk5BIFdJTk5BIgo='.decode('base64'), '<string>', 'exec'))",]
Ok, all the setup is done. All we need to do now is
yaml.load(open("exploit.yaml").read())
. We can see from the output that
our print
was executed and WINNA WINNA
was printed to STDOUT:
>>> yaml.load(open("exploit.yaml"))
WINNA WINNA
Correct
Use yaml.safe_load()
instead of yaml.load()
. In the PoC above, if we
try to load exploit.yaml
via safe_load()
we get the following error:
>>> yaml.safe_load(open("exploit.yaml"))
Traceback (most recent call last):
...
yaml.constructor.ConstructorError: could not determine a constructor for the tag 'tag:yaml.org,2002:python/object/apply:eval'
in "exploit.yaml", line 1, column 17
Consequences
- Remote code execution