Skip to content

Remote Code Execution via sys.path Pollution and Dynamic Import of Remote Code #1175

@Doria77486

Description

@Doria77486

Description

After receiving class metadata from a remote client, the worker dynamically modifies sys.path using client-controlled paths and then loads Python modules via __import__. Since both the import path and module contents are influenced by remote input, this behavior enables arbitrary code execution and import hijacking.

def load_remote_class(remote_class_info):
    """load a class given related info dumped in the client.

    Args:
      remote_class_info: [in_notebook, dumped_class_info]
                         - in_notebook: whether the remote class is implemented in the environments like notebook (e.g., ipython, notebook).
                         - dumped_class_info: information of dumped remote class (decided by `in_notebook`).

    Return:
      cls: the class to load
    """

    in_notebook, dumped_class_info = cloudpickle.loads(remote_class_info)

    if in_notebook:
        cls = dumped_class_info
    else:
        file_name, class_name, end_of_file, in_sys_path, client_sys_path = dumped_class_info

        file_name = file_name.split(os.sep)
        prefix = os.sep.join(file_name[:-1])
        if prefix == "":
            prefix = '.'

        new_file_name = 'xparl_{}'.format(os.getpid()) + file_name[-1]
        module_name = prefix + os.sep + new_file_name
        tmp_file_name = module_name + '.py'
        with open(tmp_file_name, 'w') as t_file:
            for line in code:
                t_file.write(line)

        if in_sys_path:
            # dangerous!!
            sys.path.extend(client_sys_path)

            # the path of the remote class is in the sys.path, we can import it directly.
            mod = __import__(new_file_name)
        else:
            module_name = module_name.lstrip('.' + os.sep).replace(os.sep, '.')
            mod = __import__(module_name, globals(), locals(), [class_name], 0)

        cls = getattr(mod, class_name)

        os.remove(tmp_file_name)
    return cls

Modifying sys.path based on untrusted input violates Python’s import safety assumptions and allows attackers to inject malicious modules that are executed automatically during import.

Attack Scenario

An attacker can craft remote class metadata containing a malicious client_sys_path that points to an attacker-controlled directory. When the worker extends sys.path, subsequent imports may resolve to attacker-provided modules instead of trusted standard library or third-party packages.
Additionally, the dynamically written temporary module is imported immediately, causing any top-level malicious code to be executed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions