@@ -13,7 +13,7 @@ An attacker can execute arbitrary system commands in the context of the user run
1313## Exploit Workflow
1414
15151 . Adds a new camera in MotionEye Frontend.
16- 2 . Injects the payload into the image_file_name field (used for naming camera screenshots).
16+ 2 . Injects the payload into the ` image_file_name ` field (used for naming camera screenshots).
17173 . Captures a screenshot ("snapshot" in the terminology of MotionEye), triggering the payload.
1818
1919## Testing
@@ -104,102 +104,9 @@ BUG_REPORT_URL="https://bugs.debian.org/"
104104
105105## Script for signing requests
106106
107- The application verifies request signatures, so I wrote a small script to sign requests manually.
108-
109- You won't need it if you use the exploit, but it can be useful for debugging.
110-
111- ```
112- import hashlib
113- import re
114- import argparse
115- import sys
116- from urllib.parse import urlsplit, parse_qs, unquote, quote
117- from typing import Dict, List, Tuple
118-
119- _SIGNATURE_REGEX = re.compile(r'[^A-Za-z0-9/?_.=&{}\[\]":, -]')
120-
121- def compute_signature(method: str, path: str, body: str = '', key: str = '') -> str:
122- if not method or not path:
123- raise ValueError("Method and path must be provided.")
124-
125- url_parts = urlsplit(path)
126- base_path = url_parts.path
127-
128- if not base_path.startswith('/'):
129- base_path = '/' + base_path
130-
131- raw_query_params: Dict[str, List[str]] = parse_qs(
132- url_parts.query, keep_blank_values=True, strict_parsing=False
133- )
134-
135- canonical_query: List[Tuple[str, str]] = []
136- for k, v_list in raw_query_params.items():
137- if k == '_signature':
138- continue
139-
140- value = unquote(v_list[0]) if v_list else ''
141- canonical_query.append((k, value))
142-
143- canonical_query.sort(key=lambda item: item[0])
144-
145- query_string = '&'.join(f"{k}={quote(v)}" for k, v in canonical_query)
146-
147- if query_string:
148- canonical_path = f"{base_path}?{query_string}"
149- else:
150- canonical_path = base_path
151-
152- canonical_path = re.sub(_SIGNATURE_REGEX, '-', canonical_path)
153-
154- body_for_signing = re.sub(_SIGNATURE_REGEX, '-', body)
155-
156- if not key:
157- password_hash = "da39a3ee5e6b4b0d3255bfef95601890afd80709"
158- else:
159- password_hash = hashlib.sha1(key.encode('utf-8')).hexdigest().lower()
160-
161- data = f"{method.upper()}:{canonical_path}:{body_for_signing}:{password_hash}"
162-
163- return hashlib.sha1(data.encode('utf-8')).hexdigest().lower()
164-
165- def main():
166- parser = argparse.ArgumentParser(description="Computes a SHA1 signature for an HTTP request.")
167-
168- parser.add_argument('--method', type=str, required=True,
169- choices=['GET', 'POST', 'PUT', 'DELETE'],
170- help="The HTTP method (e.g., GET).")
171- parser.add_argument('--path', type=str, required=True,
172- help="The canonical path (e.g., /api/resource?param=value).")
173- parser.add_argument('--key', type=str, default='',
174- help="The secret key. Defaults to an empty string.")
175- parser.add_argument('--body', type=str, default='',
176- help="The request body as a string. Defaults to an empty string.")
177-
178- try:
179- args = parser.parse_args()
180-
181- signature = compute_signature(
182- method=args.method,
183- path=args.path,
184- body=args.body,
185- key=args.key
186- )
187-
188- print(f"Computed Signature: {signature}")
189-
190- except ValueError as e:
191- sys.stderr.write(f"Error: {e}\n")
192- sys.exit(1)
193- except Exception as e:
194- sys.stderr.write(f"An unexpected error occurred: {e}\n")
195- sys.exit(1)
196-
197-
198- if __name__ == '__main__':
199- main()
200- ```
107+ A script for manually signing requests is available in data/exploits/CVE-2025 -60787/sign_request.py and can be used for debugging purposes.
201108
202109Example of usage:
203110```
204- python3 ./main .py --method "GET" --path "/config/1/get/?force=true&_=1759747431350&_username=admin" --body "" --key ""
111+ python3 ./sign_request .py --method "GET" --path "/config/1/get/?force=true&_=1759747431350&_username=admin" --body "" --key ""
205112```
0 commit comments