Skip to content

Commit

Permalink
Land #685, Fix Java TCP server socket binding
Browse files Browse the repository at this point in the history
Don't listen on IPv6 when 0.0.0.0 srvhost is requested
  • Loading branch information
smcintyre-r7 committed Nov 22, 2023
2 parents 2b3e70c + e12217d commit 9f8a20c
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,49 @@ protected CommandManager() throws Exception {
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;

// load core commands
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)
*
Expand Down Expand Up @@ -95,7 +117,7 @@ public void registerCommand(int commandId, Class commandClass, int version, int
}

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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
*/
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static void setCWD(File newCWD) {
}

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);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package com.metasploit.meterpreter.stdapi;

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.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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;
Expand Down Expand Up @@ -81,20 +83,20 @@ private int executeUdpClient(Meterpreter meterpreter, TLVPacket request, TLVPack
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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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);

}
}

0 comments on commit 9f8a20c

Please sign in to comment.