Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

java.rb 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # -*- coding: binary -*-
  2. ###
  3. #
  4. # This mixin provides methods for interacting with a JDK installation to perform
  5. # functions such as dynamic compilation and jar signing.
  6. #
  7. # Dependencies:
  8. # - JDK6
  9. # - rjb (rjb.rubyforge.org)
  10. # - the $JAVA_HOME variable must point to the JDK
  11. #
  12. # Nathan Keltner <natron@metasploit.com>
  13. #
  14. ###
  15. require 'msf/core'
  16. require 'msf/core/exploit/java/rmi/util'
  17. require 'msf/core/exploit/java/rmi/client'
  18. module Msf
  19. module Exploit::Java
  20. def initialize(info = {})
  21. super
  22. register_advanced_options(
  23. [
  24. OptString.new( 'JavaCache', [true, 'Java cache location',
  25. File.join(Msf::Config.config_directory, "javacache")]),
  26. OptString.new( 'AddClassPath', [false, 'Additional java classpath', nil]),
  27. ], self.class)
  28. begin
  29. require 'rjb'
  30. @rjb_loaded = true
  31. init_jvm
  32. rescue ::Exception => e
  33. @rjb_loaded = false
  34. @jvm_init = false
  35. @java_error = e
  36. end
  37. end
  38. def init_jvm(jvmoptions = nil)
  39. if (not ENV['JAVA_HOME'])
  40. raise RuntimeError, 'JAVA_HOME is not set'
  41. end
  42. toolsjar = File.join(ENV['JAVA_HOME'], "lib", "tools.jar")
  43. if (not File.exist? toolsjar)
  44. raise RuntimeError, 'JAVA_HOME does not point to a valid JDK installation.'
  45. end
  46. # Instantiate the JVM with a classpath pointing to the JDK tools.jar
  47. # and our javatoolkit jar.
  48. classpath = File.join(Msf::Config.data_directory, "exploits", "msfJavaToolkit.jar")
  49. classpath += ":" + toolsjar
  50. classpath += ":" + datastore['ADDCLASSPATH'] if datastore['ADDCLASSPATH']
  51. Rjb::load(classpath, jvmargs=[])
  52. @jvm_init = true
  53. end
  54. def query_jvm
  55. return @jvmInit
  56. end
  57. def save_to_file(classnames, codez, location)
  58. path = File.join( Msf::Config.install_root, "external", "source", location )
  59. if not File.exist? path
  60. Dir.mkdir(path)
  61. end
  62. i = 0
  63. classnames.each { |fil|
  64. file = File.join( path, fil + ".java")
  65. fp = File.open( file, "wb" )
  66. print_status "Writing #{fil} to " + file
  67. fp.puts codez[i]
  68. i += 1
  69. fp.close
  70. }
  71. end
  72. def compile(classnames, codez, compile_options=nil)
  73. if !@rjb_loaded or !@jvm_init
  74. raise RuntimeError, "Could not load rjb and/or the JVM: " + @java_error.to_s
  75. end
  76. if !compile_options.is_a?(Array) && compile_options
  77. raise RuntimeError, "Compiler options must be of type Array."
  78. end
  79. compile_options = [] if compile_options.nil?
  80. # Create the directory if it doesn't exist
  81. Dir.mkdir(datastore['JavaCache']) if !File.exist? datastore['JavaCache']
  82. # For compatibility, some exploits need to have the target and source version
  83. # set to a previous JRE version.
  84. std_compiler_opts = [ "-target", "1.3", "-source", "1.3", "-d", datastore['JavaCache'] ]
  85. compile_options += std_compiler_opts
  86. java_compiler_klass = Rjb::import('javaCompile.CompileSourceInMemory')
  87. # If we were passed arrays
  88. if classnames.class == [].class && codez.class == [].class
  89. # default compile class
  90. begin
  91. # Same as java_compiler_klass.CompileFromMemory( String[] classnames,
  92. # String[] codez, String[] compilerOptions)
  93. success = java_compiler_klass._invoke('CompileFromMemory',
  94. # Signature explained: [ means array, Lpath.to.object; means object
  95. # Thus, this reads as call the method with 3 String[] args.
  96. '[Ljava.lang.String;[Ljava.lang.String;[Ljava.lang.String;',
  97. classnames, codez, compile_options)
  98. rescue Exception => e
  99. print_error "Received unknown error: " + e
  100. end
  101. else
  102. raise RuntimeError, "The Java mixin received unknown argument-type combinations and cannot continue."
  103. end
  104. if !success
  105. raise RuntimeError, "Compile failed."
  106. end
  107. end
  108. def build_jar(output_jar, in_files)
  109. if output_jar.class != "".class || in_files.class != [].class
  110. raise RuntimeError, "Building a jar requires an output_jar and an Array of in_files."
  111. end
  112. # Add paths
  113. in_files = in_files.map { |file| File.join(datastore['JavaCache'], file) }
  114. create_jar_klass = Rjb::import('javaCompile.CreateJarFile')
  115. file_class = Rjb::import('java.io.File')
  116. file_out_jar = file_class.new_with_sig('Ljava.lang.String;', File.join(datastore['JavaCache'], output_jar) )
  117. files_in = Array.new
  118. in_files.each { |file| files_in << file_class.new_with_sig('Ljava.lang.String;', file) }
  119. create_jar_klass._invoke('createJarArchive', 'Ljava.io.File;[Ljava.io.File;', file_out_jar, files_in)
  120. end
  121. #
  122. # http://www.defcon.org/images/defcon-17/dc-17-presentations/defcon-17-valsmith-metaphish.pdf
  123. #
  124. def sign_jar(cert_cn, unsiged_jar, signed_jar, cert_alias="signFiles", msf_keystore="msfkeystore",
  125. msf_store_pass="msfstorepass", msf_key_pass="msfkeypass")
  126. # Dependent on $JAVA_HOME/lib/tools.jar that comes with the JDK.
  127. signer_klass = Rjb::import('javaCompile.SignJar')
  128. # Check if the keystore exists from previous run. If it does, delete it.
  129. msf_keystore = File.join(datastore['JavaCache'], msf_keystore)
  130. File.delete msf_keystore if File.exist? msf_keystore
  131. # Rjb pukes on a CN with a comma in it so bad that it crashes to shell
  132. # and turns input echoing off. Simple fix for this ugly bug is
  133. # just to get rid of commas which kinda sucks but whatever. See #1543.
  134. keytool_opts = [
  135. "-genkey", "-alias", cert_alias, "-keystore", msf_keystore,
  136. "-storepass", msf_store_pass, "-dname", "CN=#{cert_cn.gsub(",",'')}",
  137. "-keypass", "msfkeypass"
  138. ]
  139. # Build the cert keystore
  140. signer_klass._invoke('KeyToolMSF','[Ljava.lang.String;',keytool_opts)
  141. jarsigner_opts = [
  142. "-keystore", msf_keystore, "-storepass", msf_store_pass,
  143. "-keypass", msf_key_pass, "-signedJar",
  144. File.join(datastore['JavaCache'], signed_jar), # Signed Jar
  145. File.join(datastore['JavaCache'], unsiged_jar), # Input Jar we're signing
  146. cert_alias # The cert we're using
  147. ]
  148. signer_klass._invoke('JarSignerMSF','[Ljava.lang.String;',jarsigner_opts)
  149. # There are warnings in the source for KeyTool/JarSigner warning that security providers
  150. # are not released, and if you are calling .main(foo) from another app, you need to release
  151. # them manually. This is not done here, and should Rjb be used for anything in the future,
  152. # this may need to be cleaned up.
  153. end
  154. end
  155. end