MessagePack support for GUI. Woohoo! Still backend errors though; see #5309

git-svn-id: file:///home/svn/framework3/trunk@13616 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Matt Weeks 2011-08-24 01:06:53 +00:00
parent 32eb5d05ba
commit 7a933bdf2c
16 changed files with 492 additions and 237 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -25,10 +25,12 @@ dist.jar=${dist.dir}/msfgui.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
file.reference.msgpack-0.5.1-devel.jar=msgpack-0.5.1-devel.jar
includes=**
jar.compress=false
javac.classpath=\
${libs.swing-app-framework.classpath}
${libs.swing-app-framework.classpath}:\
${file.reference.msgpack-0.5.1-devel.jar}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false

View File

@ -144,7 +144,7 @@ public class InteractWindow extends MsfFrame implements ClipboardOwner {
time = System.currentTimeMillis() - start;
if (!received.get("encoding").equals("base64"))
throw new MsfException("Uhoh. Unknown encoding. Time to update?");
byte[] decodedBytes = Base64.decode(received.get("data").toString());
byte[] decodedBytes = RpcConnection.getData(received);
if (decodedBytes.length > 0) {
outputArea.append(new String(decodedBytes));
if(decodedBytes[decodedBytes.length-1] != '\n')
@ -153,8 +153,7 @@ public class InteractWindow extends MsfFrame implements ClipboardOwner {
}
publish(received);
} catch (MsfException ex) {
if(!ex.getMessage().contains("unknown session"))
MsfguiApp.showMessage(null, ex);
MsfguiApp.showMessage(null, ex);
if(!ex.getMessage().contains("timed out")) // on timeout, just retry
timerCommand.setCharAt(0, STOP_POLLING);
}

View File

@ -224,7 +224,7 @@ public class MeterpFileBrowser extends MsfFrame {
MsfguiApp.showMessage(null, "uhoh. encoding changed. Time to update msfgui?");
return;
}
byte[] decodedBytes = Base64.decode(received.get("data").toString());
byte[] decodedBytes = RpcConnection.getData(received);
if (decodedBytes.length == 0)
return;
String[] lines = new String(decodedBytes).split("\n");

View File

@ -53,7 +53,12 @@ public abstract class ModuleInfoWindow extends MsfFrame {
Map info = (Map) rpcConn.execute("module.info", moduleType, fullName);
//Basic info
setTitle(info.get("name") + " " + fullName);
try{
titleLabel.setText("<html><h2>"+info.get("name")+ "</h2> <b>Rank:</b> "+Rank.toString(info.get("rank"))+"</html>");
}
catch(Exception ex){
System.out.println(info);
}
Object references = info.get("references");
StringBuilder referenceString = new StringBuilder();
if(references != null){

View File

@ -73,7 +73,7 @@ public class MsfguiApp extends SingleFrameApplication {
//get saved properties file
Map props;
try{
props = (Map)RpcConnection.parseVal(DocumentBuilderFactory.newInstance().newDocumentBuilder()
props = (Map)XmlRpc.parseVal(DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new FileInputStream(confFilename)).getDocumentElement());
} catch (Exception ex) { //if anything goes wrong, make new (IOException, SAXException, ParserConfigurationException, NullPointerException
props = new HashMap();//ensure existence
@ -90,7 +90,8 @@ public class MsfguiApp extends SingleFrameApplication {
});
}
public static void showMessage(java.awt.Component parent, Object message){
if(!shuttingDown)
String msg = message.toString();
if(!shuttingDown && !msg.contains("unknown session"))
JOptionPane.showMessageDialog(parent, message);
}
@ -100,7 +101,7 @@ public class MsfguiApp extends SingleFrameApplication {
public static void savePreferences(){
try {
Document docElement = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
docElement.appendChild(RpcConnection.objectToNode(docElement, propRoot));
docElement.appendChild(XmlRpc.objectToNode(docElement, propRoot));
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(docElement), new StreamResult(new FileOutputStream(confFilename)));
} catch (Exception ex) {
//fail

View File

@ -100,11 +100,9 @@ public class MsfguiLog {
}
//New data on existing sessions
} else if (methodName.equals("console.read")) {
String resString = new String(Base64.decode(((Map) result).get("data").toString()));
logConsole("Console " + params[0], resString, false);
logConsole("Console " + params[0], new String(RpcConnection.getData((Map)result)), false);
} else if (methodName.startsWith("session.") && methodName.endsWith("_read")) {
String resString = new String(Base64.decode(((Map) result).get("data").toString()));
logConsole(params[0].toString(), resString, false);
logConsole(params[0].toString(), new String(RpcConnection.getData((Map)result)), false);
}
} catch (MsfException mex) {
}

View File

@ -0,0 +1,95 @@
package msfgui;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.msgpack.MessagePack;
import org.msgpack.MessagePackObject;
import org.msgpack.Packer;
import org.msgpack.object.*;
/**
* Implements an RPC backend using the MessagePack interface
* @author scriptjunkie
*/
public class MsgRpc extends RpcConnection {
private URL u;
private URLConnection huc; // new for each call
protected int timeout = 5000;
/**
* Creates a new URL to use as the basis of a connection.
*/
protected void connect() throws MalformedURLException{
u = new URL("http",host,port,"/api");
}
/**
* Decodes a response recursively from MessagePackObject to a normal Java object
* @param src MessagePack response
* @return decoded object
*/
private static Object unMsg(Object src){
Object out = src;
if(src instanceof ArrayType){
List l = ((ArrayType)src).asList();
List outList = new ArrayList(l.size());
out = outList;
for(Object o : l)
outList.add(unMsg(o));
}else if(src instanceof BooleanType){
out = ((BooleanType)src).asBoolean();
}else if(src instanceof FloatType){
out = ((FloatType)src).asFloat();
}else if(src instanceof IntegerType){
out = ((IntegerType)src).asInt();
}else if(src instanceof MapType){
Set ents = ((MapType)src).asMap().entrySet();
out = new HashMap();
for (Object ento : ents){
Map.Entry ent = (Map.Entry)ento;
((Map)out).put(unMsg(ent.getKey()), unMsg(ent.getValue()));
}
if(((Map)out).containsKey("error") && ((Map)out).containsKey("error_class")){
System.out.println(((Map)out).get("error_backtrace"));
throw new MsfException(((Map)out).get("error_message").toString());
}
}else if(src instanceof NilType){
out = null;
}else if(src instanceof RawType){
out = ((RawType)src).asString();
}
return out;
}
/** Creates an XMLRPC call from the given method name and parameters and sends it */
protected void writeCall(String methodName, Object[] args) throws Exception{
huc = u.openConnection();
huc.setDoOutput(true);
huc.setDoInput(true);
huc.setUseCaches(false);
huc.setRequestProperty("Content-Type", "binary/message-pack");
huc.setReadTimeout(timeout);
OutputStream os = huc.getOutputStream();
Packer pk = new Packer(os);
pk.packArray(args.length+1);
pk.pack(methodName);
for(Object o : args)
pk.pack(o);
os.close();
}
/** Receives an RPC response and converts to an object */
protected Object readResp() throws Exception{
InputStream is = huc.getInputStream();
MessagePackObject mpo = MessagePack.unpack(is);
return unMsg(mpo);
}
}

View File

@ -1,6 +1,10 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<NonVisualComponents>
<Component class="javax.swing.ButtonGroup" name="buttonGroup1">
</Component>
</NonVisualComponents>
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" resourceKey="Form.title"/>
@ -44,7 +48,13 @@
<Component id="hostField" alignment="0" pref="427" max="32767" attributes="0"/>
<Component id="passwordField" alignment="0" pref="427" max="32767" attributes="0"/>
<Component id="portField" alignment="0" pref="427" max="32767" attributes="0"/>
<Component id="sslBox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="sslBox" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="250" max="32767" attributes="0"/>
<Component id="xmlButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="msgpackButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
@ -87,14 +97,22 @@
<Component id="portLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="sslBox" alignment="0" min="0" pref="0" max="32767" attributes="1"/>
<Component id="sslLabel" alignment="0" max="32767" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="disableDbLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="disableDbButton" alignment="3" min="-2" pref="18" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="sslBox" alignment="0" min="0" pref="0" max="32767" attributes="1"/>
<Component id="sslLabel" alignment="0" max="32767" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="disableDbLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="disableDbButton" alignment="3" min="-2" pref="18" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
<Component id="msgpackButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="xmlButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
@ -250,5 +268,24 @@
<Property name="name" type="java.lang.String" value="disableDbButton" noResource="true"/>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="xmlButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup1"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" resourceKey="xmlButton.text"/>
<Property name="name" type="java.lang.String" value="xmlButton" noResource="true"/>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="msgpackButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup1"/>
</Property>
<Property name="text" type="java.lang.String" resourceKey="msgpackButton.text"/>
<Property name="name" type="java.lang.String" value="msgpackButton" noResource="true"/>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -103,7 +103,8 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
String host = info.get("host").toString();
int port = Integer.parseInt(info.get("port").toString());
boolean ssl = Boolean.parseBoolean(info.get("ssl").toString());
RpcConnection rpc = new RpcConnection(username, password.toCharArray(), host, port, ssl);
String type = info.get("type").toString();
RpcConnection rpc = RpcConnection.getConn(type, username, password.toCharArray(), host, port, ssl);
if(javax.swing.JOptionPane.showConfirmDialog(null, "Connect to last remembered rpcd?") == javax.swing.JOptionPane.YES_OPTION)
return rpc;
rpc.execute("auth.logout");
@ -118,6 +119,7 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
mainframe.statusAnimationLabel.setText("Timeout; is the SSL option correct?"
+ " Is msfrpcd running on the right port?");
} catch (NullPointerException nex) {//generated when attributes dont exist.
} catch (Exception ex) { //for weird msg exceptions
}
//Darn. open the gui anyway
OpenConnectionDialog diag = new OpenConnectionDialog(true, mainframe);
@ -134,6 +136,7 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
buttonGroup1 = new javax.swing.ButtonGroup();
titleLabel = new javax.swing.JLabel();
usernameLabel = new javax.swing.JLabel();
passwordLabel = new javax.swing.JLabel();
@ -151,6 +154,8 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
sslLabel = new javax.swing.JLabel();
disableDbLabel = new javax.swing.JLabel();
disableDbButton = new javax.swing.JCheckBox();
xmlButton = new javax.swing.JRadioButton();
msgpackButton = new javax.swing.JRadioButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(msfgui.MsfguiApp.class).getContext().getResourceMap(OpenConnectionDialog.class);
@ -250,6 +255,15 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
disableDbButton.setText(resourceMap.getString("disableDbButton.text")); // NOI18N
disableDbButton.setName("disableDbButton"); // NOI18N
buttonGroup1.add(xmlButton);
xmlButton.setSelected(true);
xmlButton.setText(resourceMap.getString("xmlButton.text")); // NOI18N
xmlButton.setName("xmlButton"); // NOI18N
buttonGroup1.add(msgpackButton);
msgpackButton.setText(resourceMap.getString("msgpackButton.text")); // NOI18N
msgpackButton.setName("msgpackButton"); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
@ -274,7 +288,12 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
.addComponent(hostField, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
.addComponent(passwordField, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
.addComponent(portField, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
.addComponent(sslBox)))
.addGroup(layout.createSequentialGroup()
.addComponent(sslBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 250, Short.MAX_VALUE)
.addComponent(xmlButton)
.addGap(18, 18, 18)
.addComponent(msgpackButton))))
.addGroup(layout.createSequentialGroup()
.addComponent(startNewButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -307,13 +326,18 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
.addComponent(portField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(portLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(sslBox, javax.swing.GroupLayout.Alignment.LEADING, 0, 0, Short.MAX_VALUE)
.addComponent(sslLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(disableDbLabel)
.addComponent(disableDbButton, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(sslBox, javax.swing.GroupLayout.Alignment.LEADING, 0, 0, Short.MAX_VALUE)
.addComponent(sslLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(disableDbLabel)
.addComponent(disableDbButton, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(msgpackButton)
.addComponent(xmlButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(connectButton, javax.swing.GroupLayout.DEFAULT_SIZE, 37, Short.MAX_VALUE)
@ -332,8 +356,15 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
String host = hostField.getText();
int port = Integer.parseInt(portField.getText());
boolean ssl = checkCrypto(sslBox.isSelected());
String type = "xml";
if(msgpackButton.isSelected()){
if(JOptionPane.showConfirmDialog(this, "MsgPack RPC is not currently supported. Continue anyway?",
"Warning",JOptionPane.YES_NO_CANCEL_OPTION,JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION)
return;
type = "msg";
}
try {
rpcConn = new RpcConnection(username, password, host, port, ssl);
rpcConn = RpcConnection.getConn(type, username, password, host, port, ssl);
} catch (MsfException mex) {
rpcConn = null;
}
@ -363,6 +394,14 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
private void startNewButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startNewButtonActionPerformed
//Setup defaults
if(msgpackButton.isSelected()){
if(JOptionPane.showConfirmDialog(this, "MsgPack RPC is not currently supported. Continue anyway?",
"Warning",JOptionPane.YES_NO_CANCEL_OPTION,JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION)
return;
RpcConnection.defaultType = "msg";
}else{
RpcConnection.defaultType = "xml";
}
RpcConnection.defaultUser = usernameField.getText();
if(passwordField.getPassword().length > 0)
RpcConnection.defaultPass = new String(passwordField.getPassword());
@ -396,12 +435,14 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
}//GEN-LAST:event_pathButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JButton cancelButton;
private javax.swing.JButton connectButton;
private javax.swing.JCheckBox disableDbButton;
private javax.swing.JLabel disableDbLabel;
private javax.swing.JTextField hostField;
private javax.swing.JLabel hostLabel;
private javax.swing.JRadioButton msgpackButton;
private javax.swing.JPasswordField passwordField;
private javax.swing.JLabel passwordLabel;
private javax.swing.JButton pathButton;
@ -413,5 +454,6 @@ public class OpenConnectionDialog extends javax.swing.JDialog {
private javax.swing.JLabel titleLabel;
private javax.swing.JTextField usernameField;
private javax.swing.JLabel usernameLabel;
private javax.swing.JRadioButton xmlButton;
// End of variables declaration//GEN-END:variables
}

View File

@ -83,7 +83,7 @@ public class ProcessList extends MsfFrame {
MsfguiApp.showMessage(null, "uhoh. encoding changed. Time to update msfgui?");
return;
}
byte[] decodedBytes = Base64.decode(received.get("data").toString());
byte[] decodedBytes = RpcConnection.getData(received);
if (decodedBytes.length == 0)
return; //no data
String[] lines = new String(decodedBytes).split("\n");

View File

@ -1,7 +1,5 @@
package msfgui;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -10,54 +8,78 @@ import java.net.SocketException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.jdesktop.application.Task;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* RpcConnection handles connection details to a msfrpcd and automatically sends
* activity to be logged. It also caches some method calls to more quickly
* retrieve results later.
*
* Implements a minimal XMLRPC client for our purposes. Reinventing the wheel is
* usually a bad idea, but CVE/description searching takes a long time and this
* implementation runs a CVE search twice as fast as the apache libs. It also
* results in a more responsive console.
* Connection implementation is left to child classes, which must implemtent
* writeCall() and readResp() and may implement connect.
*
* @author scriptjunkie
*/
public class RpcConnection {
private String rpcToken;
private Map callCache = new HashMap();
public static String defaultUser = "msf",defaultPass = null, defaultHost = "127.0.0.1";
public abstract class RpcConnection {
public String type = "msg";
protected String rpcToken;
protected Map callCache = new HashMap();
public static String defaultUser = "msf",defaultPass = null, defaultHost = "127.0.0.1", defaultType = "msg";
public static int defaultPort = 55553;
public static boolean defaultSsl = false;
public static boolean disableDb = false;
private Socket connection;
private OutputStream sout; //socket output/input
private InputStream sin;
private final Object lockObject = new Object();//to synchronize one request at a time
private String username, password, host;
private int port;
private boolean ssl;
protected Socket connection;
protected OutputStream sout; //socket output/input
protected InputStream sin;
protected final Object lockObject = new Object();//to synchronize one request at a time
protected String username, password, host;
protected int port;
protected boolean ssl;
/** Constructor sets up a connection and authenticates. */
RpcConnection(String username, char[] password, String host, int port, boolean ssl) throws MsfException {
protected abstract void writeCall(String methname, Object[] params) throws Exception;
protected abstract Object readResp() throws Exception;
/**
* Creates an RPC connection of the appropriate type and connection details
* @param type RPC type
* @param username
* @param password
* @param host IP address or hostname of RPC server
* @param port Port RPC server is operating on
* @param ssl Whether SSL is to be used
* @return A new RPC connection
* @throws MsfException
*/
public static RpcConnection getConn(String type, String username, char[] password, String host, int port, boolean ssl) throws MsfException{
RpcConnection conn;
if(type.toLowerCase().equals("xml"))
conn = new XmlRpc();
else
conn = new MsgRpc();
conn.setup(username, password, host, port, ssl);
return conn;
}
/**
* Gets the unencoded data returned from a something.read call
* @param ret The return from the read call
* @return the
*/
public static byte[] getData(Map received){
if(received.get("encoding").equals("base64"))
return Base64.decode(received.get("data").toString());
else
return received.get("data").toString().getBytes();
}
/** Setup sets up a connection and authenticates. */
public void setup(String username, char[] password, String host, int port, boolean ssl) throws MsfException {
boolean haveRpcd=false;
this.username = username;
this.password = new String(password);
@ -87,9 +109,20 @@ public class RpcConnection {
root.put("port", port);
root.put("ssl", ssl);
root.put("disableDb", disableDb);
root.put("type", type);
MsfguiApp.savePreferences();
}
/**
* Disconnects this connection
*
* @throws SocketException
* @throws IOException
*/
protected void disconnect() throws SocketException, IOException{
connection.close();
}
/**
* Disconnects then reconnects.
*
@ -98,20 +131,20 @@ public class RpcConnection {
* @throws IOException
* @throws NoSuchAlgorithmException
*/
private void reconnect() throws SocketException, KeyManagementException, IOException, NoSuchAlgorithmException {
connection.close();
protected void reconnect() throws SocketException, KeyManagementException, IOException, NoSuchAlgorithmException {
disconnect();
connect();
}
/**
* Connects the TCP stream, setting up SSL if necessary.
* Default connect method connects the TCP stream, setting up SSL if necessary.
*
* @throws SocketException
* @throws KeyManagementException
* @throws IOException
* @throws NoSuchAlgorithmException
*/
private void connect() throws SocketException, KeyManagementException, IOException, NoSuchAlgorithmException {
protected void connect() throws SocketException, KeyManagementException, IOException, NoSuchAlgorithmException {
if (ssl) {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
@ -136,6 +169,7 @@ public class RpcConnection {
public String toString(){
return "RPC connection "
+ "\ntype: "+type
+ "\nusername: "+username
+ "\npassword: " + password
+ "\nhost: " + host
@ -207,174 +241,6 @@ public class RpcConnection {
}
}
/** Creates an XMLRPC call from the given method name and parameters and sends it */
protected void writeCall(String methname, Object[] params) throws Exception{
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element methodCall = doc.createElement("methodCall");
doc.appendChild(methodCall);
Element methodName = doc.createElement("methodName");
methodName.appendChild(doc.createTextNode(methname));
methodCall.appendChild(methodName);
Element paramsEl = doc.createElement("params");
methodCall.appendChild(paramsEl);
//Add each parameter by type. Usually just the maps are difficult
for(Object param : params){
Element paramEl = doc.createElement("param");
paramEl.appendChild(objectToNode(doc,param));
paramsEl.appendChild(paramEl);
}
ByteArrayOutputStream bout = new ByteArrayOutputStream();
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc), new StreamResult(bout));
sout.write(bout.toByteArray());
sout.write(0);
}
/**
* Takes the object provided and recursively creates a node out of it suitable
* for xmlrpc transmission.
* @param doc
* @param param
* @return
*/
public static Node objectToNode(Document doc, Object param){
Node valEl = doc.createElement("value");
if(param instanceof Map){ //Reverse of the parseVal() struct-to-HashMap code
Element structEl = doc.createElement("struct");
for(Object entryObj : ((Map)param).entrySet()){
Map.Entry ent = (Map.Entry)entryObj;
Element membEl = doc.createElement("member");
Element nameEl = doc.createElement("name");
nameEl.appendChild(doc.createTextNode(ent.getKey().toString()));
membEl.appendChild(nameEl);
membEl.appendChild(objectToNode(doc,ent.getValue()));
structEl.appendChild(membEl);
}
valEl.appendChild(structEl);
}else if(param instanceof List || param instanceof Object[]){ //Reverse of the parseVal() array-to-HashMap code
Element arrayEl = doc.createElement("array");
Element dataEl = doc.createElement("data");
if(param instanceof Object[])
for(Object obj : (Object[])param)
dataEl.appendChild(objectToNode(doc,obj));
else
for(Object obj : (List)param)
dataEl.appendChild(objectToNode(doc,obj));
arrayEl.appendChild(dataEl);
valEl.appendChild(arrayEl);
}else if(param instanceof Integer){ //not sure I even need this
Element i4El = doc.createElement("i4");
i4El.appendChild(doc.createTextNode(param.toString()));
valEl.appendChild(i4El);
}else if(param instanceof Boolean){ //not sure I even need this
Element boolEl = doc.createElement("boolean");
boolEl.appendChild(doc.createTextNode(param.toString()));
valEl.appendChild(boolEl);
}else{
Element strEl = doc.createElement("string");
strEl.appendChild(doc.createTextNode(param.toString()));
valEl.appendChild(strEl);
}
return valEl;
}
/** Receives an XMLRPC response and converts to an object */
protected Object readResp() throws Exception{
//Will store our response
StringBuilder sb = new StringBuilder();
int len;
do{
//read bytes
ByteArrayOutputStream cache = new ByteArrayOutputStream();
int val;
while((val = sin.read()) != 0){
if(val == -1)
throw new MsfException("Stream died.");
cache.write(val);
}
//parse the response: <methodResponse><params><param><value>...
ByteArrayInputStream is = new ByteArrayInputStream(cache.toByteArray());
int a = is.read();
while(a != -1){
if(!Character.isISOControl(a) || a == '\t')
sb.append((char)a);
//else
// sb.append("&#x").append(Integer.toHexString(a)).append(';');
a = is.read();
}
len = sb.length();//Check to make sure we aren't stopping on an embedded null
} while (sb.lastIndexOf("</methodResponse>") < len - 20 || len < 30);
Document root = DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new ByteArrayInputStream(sb.toString().getBytes()));
if(!root.getFirstChild().getNodeName().equals("methodResponse"))
throw new MsfException("Error reading response: not a response.");
Node methResp = root.getFirstChild();
if(methResp.getFirstChild().getNodeName().equals("fault")){
throw new MsfException(methResp.getFirstChild()//fault
.getFirstChild() // value
.getFirstChild() // struct
.getLastChild() // member
.getLastChild() // value
.getTextContent());
}
Node params = methResp.getFirstChild();
if(!params.getNodeName().equals("params"))
throw new MsfException("Error reading response: no params.");
Node param = params.getFirstChild();
if(!param.getNodeName().equals("param"))
throw new MsfException("Error reading response: no param.");
Node value = param.getFirstChild();
if(!value.getNodeName().equals("value"))
throw new MsfException("Error reading response: no value.");
return parseVal(value);
}
/** Takes an XMLRPC DOM value node and creates a java object out of it recursively */
public static Object parseVal(Node submemb) throws MsfException {
Node type = submemb.getFirstChild();
String typeName = type.getNodeName();
if(typeName.equals("string")){//<struct><member><name>jobs</name><value><struct/></value></member></struct>
return type.getTextContent(); //String returns java string
}else if (typeName.equals("array")){ //Array returns List
ArrayList arrgh = new ArrayList();
Node data = type.getFirstChild();
if(!data.getNodeName().equals("data"))
throw new MsfException("Error reading array: no data.");
for(Node val = data.getFirstChild(); val != null; val = val.getNextSibling())
arrgh.add(parseVal(val));
return arrgh;
}else if (typeName.equals("struct")){ //Struct returns a HashMap of name->value member pairs
HashMap structmembs = new HashMap();
for(Node member = type.getFirstChild(); member != null; member = member.getNextSibling()){
if(!member.getNodeName().equals("member"))
throw new MsfException("Error reading response: non struct member.");
Object name = null, membValue = null;
//get each member and put into output map
for(Node submember = member.getFirstChild(); submember != null; submember = submember.getNextSibling()){
if(submember.getNodeName().equals("name"))
name = submember.getTextContent();
else if (submember.getNodeName().equals("value"))
membValue = parseVal(submember); //Value can be arbitrarily complex
}
structmembs.put(name, membValue);
}
return structmembs;
}else if (typeName.equals("i4")){
return new Integer(type.getTextContent());
}else if (typeName.equals("boolean")){
return type.getTextContent().equals("1") || Boolean.valueOf(type.getTextContent());
}else if (typeName.equals("dateTime.iso8601")) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
try{
return sdf.parse(type.getTextContent());
}catch(ParseException pex){
return type.getTextContent();
}
} else {
throw new MsfException("Error reading val: unknown type " + typeName);
}
}
/** Attempts to start msfrpcd and connect to it.*/
public static Task startRpcConn(final MainFrame mainFrame){
if(mainFrame.rpcConn != null){
@ -397,8 +263,11 @@ public class RpcConnection {
}
// Don't fork cause we'll check if it dies
String rpcType = "Basic";
if(defaultType.toLowerCase().equals("msg"))
rpcType = "Msg";
java.util.List args = new java.util.ArrayList(java.util.Arrays.asList(new String[]{
"msfrpcd","-f","-P",defaultPass,"-t","Basic","-U",defaultUser,"-a","127.0.0.1"}));
"msfrpcd","-f","-P",defaultPass,"-t",rpcType,"-U",defaultUser,"-a","127.0.0.1"}));
if(!defaultSsl)
args.add("-S");
if(disableDb)
@ -426,7 +295,7 @@ public class RpcConnection {
} //Nope. We're good.
try {
myRpcConn = new RpcConnection(defaultUser, defaultPass.toCharArray(), "127.0.0.1", defaultPort, defaultSsl);
myRpcConn = RpcConnection.getConn(defaultType, defaultUser, defaultPass.toCharArray(), "127.0.0.1", defaultPort, defaultSsl);
connected = true;
break;
} catch (MsfException mex) {

View File

@ -0,0 +1,205 @@
package msfgui;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* XMLRPC implementation of an RpcConnection.
*
* Implements a minimal XMLRPC client for our purposes. Reinventing the wheel is
* usually a bad idea, but CVE/description searching takes a long time and this
* implementation runs a CVE search twice as fast as the apache libs. It also
* results in a more responsive console.
*
* @author scriptjunkie
*/
public class XmlRpc extends RpcConnection {
/**
* We're an XML RPC
*/
public XmlRpc(){
super();
type = "XML";
}
/** Creates an XMLRPC call from the given method name and parameters and sends it */
protected void writeCall(String methname, Object[] params) throws Exception{
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element methodCall = doc.createElement("methodCall");
doc.appendChild(methodCall);
Element methodName = doc.createElement("methodName");
methodName.appendChild(doc.createTextNode(methname));
methodCall.appendChild(methodName);
Element paramsEl = doc.createElement("params");
methodCall.appendChild(paramsEl);
//Add each parameter by type. Usually just the maps are difficult
for(Object param : params){
Element paramEl = doc.createElement("param");
paramEl.appendChild(objectToNode(doc,param));
paramsEl.appendChild(paramEl);
}
ByteArrayOutputStream bout = new ByteArrayOutputStream();
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc), new StreamResult(bout));
sout.write(bout.toByteArray());
sout.write(0);
}
/**
* Takes the object provided and recursively creates a node out of it suitable
* for xmlrpc transmission.
* @param doc
* @param param
* @return
*/
public static Node objectToNode(Document doc, Object param){
Node valEl = doc.createElement("value");
if(param instanceof Map){ //Reverse of the parseVal() struct-to-HashMap code
Element structEl = doc.createElement("struct");
for(Object entryObj : ((Map)param).entrySet()){
Map.Entry ent = (Map.Entry)entryObj;
Element membEl = doc.createElement("member");
Element nameEl = doc.createElement("name");
nameEl.appendChild(doc.createTextNode(ent.getKey().toString()));
membEl.appendChild(nameEl);
membEl.appendChild(objectToNode(doc,ent.getValue()));
structEl.appendChild(membEl);
}
valEl.appendChild(structEl);
}else if(param instanceof List || param instanceof Object[]){ //Reverse of the parseVal() array-to-HashMap code
Element arrayEl = doc.createElement("array");
Element dataEl = doc.createElement("data");
if(param instanceof Object[])
for(Object obj : (Object[])param)
dataEl.appendChild(objectToNode(doc,obj));
else
for(Object obj : (List)param)
dataEl.appendChild(objectToNode(doc,obj));
arrayEl.appendChild(dataEl);
valEl.appendChild(arrayEl);
}else if(param instanceof Integer){ //not sure I even need this
Element i4El = doc.createElement("i4");
i4El.appendChild(doc.createTextNode(param.toString()));
valEl.appendChild(i4El);
}else if(param instanceof Boolean){ //not sure I even need this
Element boolEl = doc.createElement("boolean");
boolEl.appendChild(doc.createTextNode(param.toString()));
valEl.appendChild(boolEl);
}else{
Element strEl = doc.createElement("string");
strEl.appendChild(doc.createTextNode(param.toString()));
valEl.appendChild(strEl);
}
return valEl;
}
/** Receives an XMLRPC response and converts to an object */
protected Object readResp() throws Exception{
//Will store our response
StringBuilder sb = new StringBuilder();
int len;
do{
//read bytes
ByteArrayOutputStream cache = new ByteArrayOutputStream();
int val;
while((val = sin.read()) != 0){
if(val == -1)
throw new MsfException("Stream died.");
cache.write(val);
}
//parse the response: <methodResponse><params><param><value>...
ByteArrayInputStream is = new ByteArrayInputStream(cache.toByteArray());
int a = is.read();
while(a != -1){
if(!Character.isISOControl(a) || a == '\t')
sb.append((char)a);
//else
// sb.append("&#x").append(Integer.toHexString(a)).append(';');
a = is.read();
}
len = sb.length();//Check to make sure we aren't stopping on an embedded null
} while (sb.lastIndexOf("</methodResponse>") < len - 20 || len < 30);
Document root = DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new ByteArrayInputStream(sb.toString().getBytes()));
if(!root.getFirstChild().getNodeName().equals("methodResponse"))
throw new MsfException("Error reading response: not a response.");
Node methResp = root.getFirstChild();
if(methResp.getFirstChild().getNodeName().equals("fault")){
throw new MsfException(methResp.getFirstChild()//fault
.getFirstChild() // value
.getFirstChild() // struct
.getLastChild() // member
.getLastChild() // value
.getTextContent());
}
Node params = methResp.getFirstChild();
if(!params.getNodeName().equals("params"))
throw new MsfException("Error reading response: no params.");
Node param = params.getFirstChild();
if(!param.getNodeName().equals("param"))
throw new MsfException("Error reading response: no param.");
Node value = param.getFirstChild();
if(!value.getNodeName().equals("value"))
throw new MsfException("Error reading response: no value.");
return parseVal(value);
}
/** Takes an XMLRPC DOM value node and creates a java object out of it recursively */
public static Object parseVal(Node submemb) throws MsfException {
Node type = submemb.getFirstChild();
String typeName = type.getNodeName();
if(typeName.equals("string")){//<struct><member><name>jobs</name><value><struct/></value></member></struct>
return type.getTextContent(); //String returns java string
}else if (typeName.equals("array")){ //Array returns List
ArrayList arrgh = new ArrayList();
Node data = type.getFirstChild();
if(!data.getNodeName().equals("data"))
throw new MsfException("Error reading array: no data.");
for(Node val = data.getFirstChild(); val != null; val = val.getNextSibling())
arrgh.add(parseVal(val));
return arrgh;
}else if (typeName.equals("struct")){ //Struct returns a HashMap of name->value member pairs
HashMap structmembs = new HashMap();
for(Node member = type.getFirstChild(); member != null; member = member.getNextSibling()){
if(!member.getNodeName().equals("member"))
throw new MsfException("Error reading response: non struct member.");
Object name = null, membValue = null;
//get each member and put into output map
for(Node submember = member.getFirstChild(); submember != null; submember = submember.getNextSibling()){
if(submember.getNodeName().equals("name"))
name = submember.getTextContent();
else if (submember.getNodeName().equals("value"))
membValue = parseVal(submember); //Value can be arbitrarily complex
}
structmembs.put(name, membValue);
}
return structmembs;
}else if (typeName.equals("i4")){
return new Integer(type.getTextContent());
}else if (typeName.equals("boolean")){
return type.getTextContent().equals("1") || Boolean.valueOf(type.getTextContent());
}else if (typeName.equals("dateTime.iso8601")) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
try{
return sdf.parse(type.getTextContent());
}catch(ParseException pex){
return type.getTextContent();
}
} else {
throw new MsfException("Error reading val: unknown type " + typeName);
}
}
}

View File

@ -17,3 +17,5 @@ sslBox.text=
sslLabel.text=SSL
disableDbButton.text=
disableDbLabel.text=Disable DB
xmlButton.text=XML
msgpackButton.text=MsgPack