Skip to content

Unsafe deserialization in `load_config_with_no_duplicates` of `frigate/util/builtin.py` (GHSL-2023-190)

High
blakeblackshear published GHSA-qp3h-4q62-p428 Oct 28, 2023

Package

No package listed

Affected versions

<= v0.12.1, < v0.13.0 Beta 3

Patched versions

v0.13.0 Beta 3

Description

Summary

An unsafe deserialization vulnerability was identified in the endpoints used to save configurations for Frigate. This can lead to unauthenticated remote code execution. This can be performed through the UI at /config or through a direct call to /api/config/save.

Exploiting this vulnerability requires the attacker to both know very specific information about a user's Frigate server and requires an authenticated user to be tricked into clicking a specially crafted link to their Frigate instance.

This vulnerability could exploited by an attacker under the following circumstances:

  1. Frigate publicly exposed to the internet (even with authentication)
  2. Attacker knows the address of a user's Frigate instance
  3. Attacker crafts a specialized page which links to the user's Frigate instance
  4. Attacker finds a way to get an authenticated user to visit their specialized page and click the button/link

Details

Input is initially accepted through http.py at frigate/http.py:998:

@bp.route("/config/save", methods=["POST"])
def config_save():
    save_option = request.args.get("save_option")

    new_config = request.get_data().decode()

The user-provided input is then parsed and loaded by load_config_with_no_duplicates at frigate/config.py:1244:

@classmethod
def parse_raw(cls, raw_config):
    config = load_config_with_no_duplicates(raw_config)
    return cls.parse_obj(config)

However, load_config_with_no_duplicates does not sanitize this input by merit of using yaml.loader.Loader which can instantiate custom constructors. A provided payload will be executed directly at frigate/util/builtin.py:110:

PreserveDuplicatesLoader.add_constructor(
    yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, map_constructor
)
return yaml.load(raw_config, PreserveDuplicatesLoader)

This vulnerability was found using CodeQL’s Deserialization of user-controlled data query for Python.

Impact

This issue may lead to pre-authenticated Remote Code Execution.

Proof of Concept:

  1. Start Frigate in Docker for ease of setup.
  2. Navigate to localhost:5000/config.
  3. Enter the following content into the config, and save the configuration:
!!python/object/apply:os.popen
- touch /tmp/pwned
  1. Note that /tmp/pwned is created in the container. This access can also be extended to write to mounted filesystems if not mounted as read-only.

Severity

High

CVE ID

CVE-2023-45672

Weaknesses

Credits