# motionEye: LFI → pass‑the‑hash admin → unsafe restore → unauth action exec (RCE)

motionEye chain: absolute-path LFI leaks admin SHA1 hash, pass-the-hash grants admin, malicious tar restore plants executable, unauthenticated /action endpoint runs it for RCE.

- Payout: Research
- Severity: critical
- Program: motionEye
- Found by: C4spr0x1A
- Disclosed: 2026-06-23
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-qxvg-h7q2-hcxh
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-qxvg-h7q2-hcxh
- Tags: area:web domain:web impact:data-leak impact:privesc impact:rce kind:research platform:ghsa sev:critical technique:chained technique:source-review vuln:auth-bypass vuln:file-upload vuln:path-traversal vuln:rce

**Target:** motionEye web handlers (picture download, auth, config restore, action)
**Root cause:** get_media_content() only blocks '..' so absolute paths bypass the join and are read directly; signature verification also accepts keys derived from the admin password hash; restore extracts unsanitized tars into CONF_PATH; ActionHandler lacks an auth decorator.
**Steps:**
1. Ensure a local motion camera exists (netcam_url or videodevice) to get a camera id.
2. Request `/picture/1/download/%2Fetc%2Fhosts` to confirm arbitrary file read via absolute path.
3. Read `/etc/motioneye/motion.conf` to obtain `@admin_password <SHA1_HASH>`.
4. Compute a request signature for `/config/restore?_username=admin` using the leaked SHA1 hash as the key; server accepts it as admin.
5. Upload a tar containing an executable `lock_<id>` entry; restore writes it into CONF_PATH.
6. POST `/action/<id>/lock` unauthenticated; server runs the injected file via subprocess.Popen.
**How found:** Code review of handlers: noticed get_media_content() only filters '..' and joins paths (absolute path bypass), that signature verification accepts password-hash keys, that restore shells out to `tar zxC` on user data, and that ActionHandler.post lacks an auth decorator.
**Exploitation:** Attacker with reachability to picture download reads motion.conf for the admin SHA1 hash, forges admin signatures with the hash (pass-the-hash), restores a tar dropping an executable action file into CONF_PATH, then hits the unauthenticated /action/<id>/lock endpoint to execute it as the motionEye process account. Marker file /tmp/meye_rce_ok confirmed execution.
**Escalation:** Chained four separate flaws: LFI leaks hash → pass-the-hash yields admin → admin restore plants file → unauth action endpoint executes it, turning file read into RCE; unauthenticated entirely when normal_password is unset.
**Insight:** When a path filter only strips '..', test absolute paths — os.path.join discards the base dir for absolute inputs. Also check whether HMAC/signature verification accepts stored password hashes as keys, which converts any file-read into admin.

## Proof of concept (copied exactly from the original report)

**LFI request reading /etc/hosts via picture download**

```
/picture/1/download/%2Fetc%2Fhosts
```

**Unauth action trigger POST to execute injected file**

```
POST `/action/<id>/lock`
   - The server executes the injected file.
```

