diff --git a/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/CommandManager.java b/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/CommandManager.java index 60b3a0c7..100f1a43 100644 --- a/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/CommandManager.java +++ b/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/CommandManager.java @@ -30,20 +30,27 @@ public class CommandManager { try { Class.forName("java.lang.StrictMath"); apiVersion = ExtensionLoader.V1_3; + Class.forName("java.lang.CharSequence"); apiVersion = ExtensionLoader.V1_4; + Class.forName("java.net.Proxy"); apiVersion = ExtensionLoader.V1_5; + Class.forName("java.util.ServiceLoader"); apiVersion = ExtensionLoader.V1_6; + + Class.forName("java.util.Optional").getMethod("stream"); + apiVersion = ExtensionLoader.V1_9; + + Class protocolFamilyCls = Class.forName("java.net.ProtocolFamily"); + Class.forName("java.nio.channels.ServerSocketChannel").getMethod("open", protocolFamilyCls); + apiVersion = ExtensionLoader.V1_15; } catch (Throwable ignored) { } - String javaversion = System.getProperty("java.version"); - if (javaversion != null && javaversion.length() > 2) { - int vmVersion = javaversion.charAt(2) - '2' + ExtensionLoader.V1_2; - if (vmVersion >= ExtensionLoader.V1_2 && vmVersion < apiVersion) { - apiVersion = vmVersion; - } + int vmVersion = getVersion(); + if (vmVersion >= ExtensionLoader.V1_2 && vmVersion < apiVersion) { + apiVersion = vmVersion; } this.javaVersion = apiVersion; @@ -51,6 +58,21 @@ public class CommandManager { new com.metasploit.meterpreter.core.Loader().load(this); } + private static int getVersion() { + String version = System.getProperty("java.version"); + // Java version string changed at Java 9 from 1.x.y to just x.y + if (version.startsWith("1.")) { + version = version.substring(2, 3); + } else { + int dot = version.indexOf("."); + if (dot != -1) { + version = version.substring(0, dot); + } + } + + return Integer.parseInt(version) + ExtensionLoader.V1_base; + } + /** * Register a command that can be executed on all Java versions (from 1.2 onward) * @@ -95,7 +117,7 @@ public class CommandManager { } if (version != ExtensionLoader.V1_2) { - commandClass = commandClass.getClassLoader().loadClass(commandClass.getName() + "_V1_" + (version - 10)); + commandClass = commandClass.getClassLoader().loadClass(commandClass.getName() + "_V1_" + (version - ExtensionLoader.V1_base)); } Command cmd = (Command) commandClass.newInstance(); diff --git a/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/ExtensionLoader.java b/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/ExtensionLoader.java index 1d5def00..9233b3d4 100644 --- a/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/ExtensionLoader.java +++ b/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/ExtensionLoader.java @@ -7,12 +7,14 @@ package com.metasploit.meterpreter; */ public interface ExtensionLoader { + public static final int V1_base = 10; public static final int V1_2 = 12; public static final int V1_3 = 13; public static final int V1_4 = 14; public static final int V1_5 = 15; public static final int V1_6 = 16; public static final int V1_9 = 19; + public static final int V1_15 = 25; /** * Load this extension. diff --git a/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/Loader.java b/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/Loader.java index c5bc5129..44480c06 100644 --- a/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/Loader.java +++ b/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/Loader.java @@ -40,7 +40,7 @@ public class Loader implements ExtensionLoader { } public void load(CommandManager mgr) throws Exception { - mgr.registerCommand(CommandId.CORE_CHANNEL_OPEN, stdapi_channel_open.class); + mgr.registerCommand(CommandId.CORE_CHANNEL_OPEN, stdapi_channel_open.class, V1_2, V1_15); mgr.registerCommand(CommandId.STDAPI_FS_CHDIR, stdapi_fs_chdir.class); mgr.registerCommand(CommandId.STDAPI_FS_DELETE_DIR, stdapi_fs_delete_dir.class); mgr.registerCommand(CommandId.STDAPI_FS_DELETE_FILE, stdapi_fs_delete_file.class); diff --git a/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/stdapi_channel_open.java b/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/stdapi_channel_open.java index 59dd0c8c..be99ca19 100644 --- a/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/stdapi_channel_open.java +++ b/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/stdapi_channel_open.java @@ -1,20 +1,22 @@ package com.metasploit.meterpreter.stdapi; -import java.net.ConnectException; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; - import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; import com.metasploit.meterpreter.Channel; import com.metasploit.meterpreter.DatagramSocketChannel; +import com.metasploit.meterpreter.Meterpreter; import com.metasploit.meterpreter.ServerSocketChannel; import com.metasploit.meterpreter.SocketChannel; -import com.metasploit.meterpreter.Meterpreter; import com.metasploit.meterpreter.TLVPacket; import com.metasploit.meterpreter.TLVType; import com.metasploit.meterpreter.command.Command; @@ -81,20 +83,20 @@ public class stdapi_channel_open implements Command { return ERROR_SUCCESS; } - private int executeTcpServer(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception { + private int executeTcpServer(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws UnknownHostException, IOException { String localHost = request.getStringValue(TLVType.TLV_TYPE_LOCAL_HOST); int localPort = request.getIntValue(TLVType.TLV_TYPE_LOCAL_PORT); - ServerSocket ss; - if (localHost.equals("0.0.0.0")) { - ss = new ServerSocket(localPort); - } else { - ss = new ServerSocket(localPort, 50, InetAddress.getByName(localHost)); - } + ServerSocket ss = getSocket(localHost, localPort); Channel channel = new ServerSocketChannel(meterpreter, ss); response.add(TLVType.TLV_TYPE_CHANNEL_ID, channel.getID()); return ERROR_SUCCESS; } + protected ServerSocket getSocket(String localHost, int localPort) throws UnknownHostException, IOException { + return new ServerSocket(localPort, 50, InetAddress.getByName(localHost)); + } + + private int executeTcpClient(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception { String peerHost = request.getStringValue(TLVType.TLV_TYPE_PEER_HOST); int peerPort = request.getIntValue(TLVType.TLV_TYPE_PEER_PORT); diff --git a/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/stdapi_channel_open_V1_15.java b/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/stdapi_channel_open_V1_15.java new file mode 100755 index 00000000..e33037f7 --- /dev/null +++ b/java/meterpreter/stdapi/src/main/java/com/metasploit/meterpreter/stdapi/stdapi_channel_open_V1_15.java @@ -0,0 +1,46 @@ +package com.metasploit.meterpreter.stdapi; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.ConnectException; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.UnknownHostException; + +public class stdapi_channel_open_V1_15 extends stdapi_channel_open { + + // Constructing a ServerSocket directly for 0.0.0.0 will listen on both IPv4 and IPv6, which, if the operator has explicitly requested 0.0.0.0, + // may not be desirable. Java 15 and later support explicitly specifying IPv4 using ServerSocketChannel.open(StandardProtocolFamily.INET). + // To keep backwards-compatibility, we use reflection to call the newer version. + protected ServerSocket getSocket(String localHost, int localPort) throws UnknownHostException, IOException { + if (localHost.equals("0.0.0.0")) { + try { + Class standardProtocolFamilyCls = Class.forName("java.net.StandardProtocolFamily"); + Class protocolFamilyCls = Class.forName("java.net.ProtocolFamily"); + java.lang.reflect.Method getValueMethod = standardProtocolFamilyCls.getMethod("valueOf", String.class); + Object inet = getValueMethod.invoke(null, "INET"); + Class sscClazz = java.nio.channels.ServerSocketChannel.class; + java.lang.reflect.Method method = sscClazz.getMethod("open", protocolFamilyCls); + java.nio.channels.ServerSocketChannel server = (java.nio.channels.ServerSocketChannel)method.invoke(null, inet); + InetAddress addr = InetAddress.getByName(localHost); + InetSocketAddress sockAddr = new InetSocketAddress(addr, localPort); + java.lang.reflect.Method bindMethod = sscClazz.getMethod("bind", java.net.SocketAddress.class); + bindMethod.invoke(server, sockAddr); + ServerSocket ss = server.socket(); + return ss; + } + // If reflection failed for some reason, fall back to the original implementation + catch (IllegalAccessException e) {} + catch (ClassNotFoundException e) {} + catch (NoSuchMethodException e) {} + catch (InvocationTargetException e) {} + } + return super.getSocket(localHost, localPort); + + } +}