diff --git a/cSploit/res/layout/target_list_item.xml b/cSploit/res/layout/target_list_item.xml
index 6c28880202..f5ff9f8e78 100644
--- a/cSploit/res/layout/target_list_item.xml
+++ b/cSploit/res/layout/target_list_item.xml
@@ -23,16 +23,33 @@
android:layout_toRightOf="@id/itemIcon"
android:textColor="@color/app_color"
android:fontFamily="sans-serif-light"
- android:textSize="16sp" />
+ android:textSize="16sp"
+ android:layout_toLeftOf="@+id/portCount"
+ android:layout_toStartOf="@+id/portCount" />
+ android:textSize="14sp"
+ android:layout_toRightOf="@+id/itemIcon"
+ android:layout_toLeftOf="@+id/portCount"
+ android:layout_toStartOf="@+id/portCount"
+ android:layout_below="@+id/itemTitle" />
+
\ No newline at end of file
diff --git a/cSploit/src/org/csploit/android/MainActivity.java b/cSploit/src/org/csploit/android/MainActivity.java
index 52ad38b668..7e38ff9911 100644
--- a/cSploit/src/org/csploit/android/MainActivity.java
+++ b/cSploit/src/org/csploit/android/MainActivity.java
@@ -27,6 +27,7 @@
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.text.Html;
@@ -48,6 +49,7 @@
import android.widget.Toast;
import org.csploit.android.core.Child;
+import org.csploit.android.core.ChildManager;
import org.csploit.android.core.Client;
import org.csploit.android.core.CrashReporter;
import org.csploit.android.core.Logger;
@@ -83,6 +85,7 @@
import org.csploit.android.services.UpdateService;
import org.csploit.android.services.receivers.MsfRpcdServiceReceiver;
import org.csploit.android.services.receivers.NetworkRadarReceiver;
+import org.csploit.android.tools.NMap;
import org.csploit.android.update.CoreUpdate;
import org.csploit.android.update.MsfUpdate;
import org.csploit.android.update.RubyUpdate;
@@ -132,6 +135,7 @@ private void createUpdateStatusText() {
layout.addView(mUpdateStatus);
}
+
private void createUpdateLayout() {
lv.setVisibility(View.GONE);
@@ -841,13 +845,14 @@ public View getView(int position, View convertView, ViewGroup parent) {
.findViewById(R.id.itemTitle) : null);
holder.itemDescription = (TextView) (row != null ? row
.findViewById(R.id.itemDescription) : null);
-
+ holder.portCount = (TextView) (row != null ? row
+ .findViewById(R.id.portCount) : null);
if (row != null)
row.setTag(holder);
} else
holder = (TargetHolder) row.getTag();
- Target target = System.getTarget(position);
+ final Target target = System.getTarget(position);
if (target.hasAlias())
holder.itemTitle.setText(Html.fromHtml(""
@@ -856,8 +861,7 @@ public View getView(int position, View convertView, ViewGroup parent) {
else
holder.itemTitle.setText(target.toString());
-
- holder.itemTitle.setTextColor(getResources().getColor((target.isConnected() ? R.color.app_color : R.color.gray_text)));
+ holder.itemTitle.setTextColor(ContextCompat.getColor(getContext(), (target.isConnected() ? R.color.app_color : R.color.gray_text)));
if (row != null && (getSharedPreferences("THEME", 0).getBoolean("isDark", false)))
row.setBackgroundResource(R.drawable.card_background_dark);
@@ -865,6 +869,23 @@ public View getView(int position, View convertView, ViewGroup parent) {
holder.itemImage.setImageResource(target.getDrawableResourceId());
holder.itemDescription.setText(target.getDescription());
+ // only do a portscan if/when target rolls into view and ports haven't been found...
+ if (target.getType() != Target.Type.NETWORK && target.getOpenPorts().size() == 0) {
+ final Receiver r = new Receiver(position, convertView);
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ System.getTools().nmap
+ .synScan(target, r, null);
+ } catch (ChildManager.ChildNotStartedException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ thread.run();
+ }
+
return row;
}
@@ -918,6 +939,7 @@ class TargetHolder {
ImageView itemImage;
TextView itemTitle;
TextView itemDescription;
+ TextView portCount;
}
}
@@ -1093,4 +1115,41 @@ public void onReceive(Context context, Intent intent) {
}
}
}
+
+ private class Receiver extends NMap.SynScanReceiver {
+ int position;
+ final View cv;
+
+ public Receiver(int position, View cv) {
+ this.position = position;
+ this.cv = cv;
+ }
+
+ @Override
+ public void onEnd(int exitCode) {
+ MainActivity.this.runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ System.setCurrentTarget(position);
+ // new items may have snuck in so the order can change. Double check this
+ if (cv != null) {
+ TextView tv = (TextView) cv.findViewById(R.id.portCount);
+ if (tv != null) {
+ tv.setText(String.format("%d", System.getCurrentTarget().getOpenPorts().size()));
+ tv.setVisibility(System.getCurrentTarget().getOpenPorts().size() < 1 ? View.GONE : View.VISIBLE);
+ }
+ }
+ }
+ }
+ );
+ super.onEnd(exitCode);
+ }
+
+ @Override
+ public void onPortFound(int port, String protocol) {
+ System.setCurrentTarget(position);
+ System.addOpenPort(port, null);
+ }
+ }
}
\ No newline at end of file
diff --git a/msf/.gitignore b/msf/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/msf/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/msf/build.gradle b/msf/build.gradle
new file mode 100644
index 0000000000..5b04692e32
--- /dev/null
+++ b/msf/build.gradle
@@ -0,0 +1,8 @@
+apply plugin: 'java'
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile 'junit:junit:4.12'
+ compile 'commons-io:commons-io:2.4'
+ compile 'org.apache.commons:commons-lang3:3.4'
+}
\ No newline at end of file
diff --git a/msf/src/main/java/org/csploit/msf/Author.java b/msf/src/main/java/org/csploit/msf/Author.java
new file mode 100644
index 0000000000..7e3b3bd062
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/Author.java
@@ -0,0 +1,37 @@
+package org.csploit.msf;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Represent an author
+ */
+public class Author {
+ private static Pattern MAIL = Pattern.compile("<(.+)>");
+
+ private String name;
+ private String email;
+
+ public Author(String name, String email) {
+ this.name = name;
+ this.email = email;
+ }
+
+ @Override
+ public String toString() {
+ if(email != null) {
+ return name + " <" + email + ">";
+ } else {
+ return name;
+ }
+ }
+
+ public static Author fromString(String s) {
+ Matcher matcher = MAIL.matcher(s);
+ if(matcher.matches()) {
+ return new Author(s.substring(0, matcher.start()), matcher.group(1));
+ } else {
+ return new Author(s, null);
+ }
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/DataHolder.java b/msf/src/main/java/org/csploit/msf/DataHolder.java
new file mode 100644
index 0000000000..e6acb5b292
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/DataHolder.java
@@ -0,0 +1,8 @@
+package org.csploit.msf;
+
+/**
+ * A class that hold a DataStore instance
+ */
+public interface DataHolder {
+ DataStore getDataStore();
+}
diff --git a/msf/src/main/java/org/csploit/msf/DataStore.java b/msf/src/main/java/org/csploit/msf/DataStore.java
new file mode 100644
index 0000000000..7709c71692
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/DataStore.java
@@ -0,0 +1,113 @@
+package org.csploit.msf;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The data store is just a bitbucket that holds keyed values. It is used
+ * by various classes to hold option values and other state information.
+ */
+public class DataStore extends HashMap {
+ protected Set imported = new HashSet<>();
+ protected Set defaults = new HashSet<>();
+
+ @Override
+ public String put(String key, String value) {
+ key = findKeyCase(key);
+
+ defaults.remove(key);
+ imported.remove(key);
+
+ return super.put(key, value);
+ }
+
+ @Override
+ public String get(Object key) {
+ String k = (key instanceof String) ? (String) key : key.toString();
+ return super.get(findKeyCase(k));
+ }
+
+ public void updateValue(String key, String value) {
+ super.put(key, value);
+ }
+
+ /**
+ * This method is a helper method that imports the default value for
+ * all of the supplied options
+ */
+ public void importOptions(OptionContainer options, boolean isDefault, boolean overwrite) {
+ for(Option opt : options.values()) {
+ String name = opt.getName();
+ if(containsKey(name) && !overwrite) {
+ continue;
+ }
+ if(opt.haveDefaultValue() && (overwrite || get(name) == null)) {
+ String val = opt.display(opt.defaultValue);
+ importOption(name, val, true, isDefault);
+ }
+ }
+ }
+
+ public void importOptions(OptionContainer options, boolean isDefault) {
+ importOptions(options, isDefault, false);
+ }
+
+ public void importOptions(OptionContainer options) {
+ importOptions(options, false, false);
+ }
+
+ public void importOption(String name, String val, boolean imported, boolean isDefault) {
+ if(imported) {
+ this.imported.add(name);
+ }
+
+ if(isDefault) {
+ defaults.add(name);
+ }
+
+ super.put(name, val);
+ }
+
+ public void importOption(String name, String val, boolean imported) {
+ importOption(name, val, imported, false);
+ }
+
+ public void importOption(String name, String val) {
+ importOption(name, val, true, false);
+ }
+
+ public synchronized Map userDefined() {
+ Map res = new HashMap<>();
+
+ for (String key : keySet()) {
+ if (!imported.contains(key)) {
+ res.put(key, super.get(key));
+ }
+ }
+
+ return res;
+ }
+
+ public void clearNotUserDefined() {
+ for(String key : imported) {
+ if(defaults.remove(key)) {
+ remove(key);
+ }
+ }
+ }
+
+ protected String findKeyCase(String k) {
+
+ if(k == null)
+ return null;
+
+ for(String key : keySet()) {
+ if(key.toLowerCase().equals(k.toLowerCase()))
+ return key;
+ }
+
+ return k;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/Exploit.java b/msf/src/main/java/org/csploit/msf/Exploit.java
new file mode 100644
index 0000000000..151793a01f
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/Exploit.java
@@ -0,0 +1,67 @@
+package org.csploit.msf;
+
+import org.csploit.msf.module.ArchSet;
+import org.csploit.msf.module.PlatformList;
+import org.csploit.msf.module.Reference;
+import org.csploit.msf.module.Target;
+
+/**
+ * Represent an exploit module
+ */
+public class Exploit extends Module {
+ private Target[] targets;
+ private int defaultTarget = -1;
+
+ public Exploit() {
+ super();
+ }
+
+ // we may should use a Builder
+ public Exploit(String name,
+ String description,
+ String version,
+ Author[] authors,
+ ArchSet arch,
+ PlatformList platform,
+ Reference[] references,
+ boolean privileged,
+ License license,
+ Target[] targets,
+ int defaultTarget
+ ) {
+ super(name, description, version, authors, arch, platform, references, privileged, license);
+ this.targets = targets;
+ this.defaultTarget = defaultTarget;
+ }
+
+ @Override
+ public String getType() {
+ return "exploit";
+ }
+
+ protected void setTargets(Target[] targets) {
+ this.targets = targets;
+ }
+
+ public Target[] getTargets() {
+ return targets;
+ }
+
+ public Target getTarget() {
+ String val = datastore.get("TARGET");
+
+ if(val != null) {
+ try {
+ return targets[Integer.parseInt(val)];
+ } catch (NumberFormatException | IndexOutOfBoundsException e) {
+ // ignore
+ }
+ }
+
+ if(defaultTarget >= 0 && defaultTarget < targets.length) {
+ return targets[defaultTarget];
+ }
+
+ return null;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/Framework.java b/msf/src/main/java/org/csploit/msf/Framework.java
new file mode 100644
index 0000000000..10ed7e57b1
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/Framework.java
@@ -0,0 +1,24 @@
+package org.csploit.msf;
+
+/**
+ * Represent a MetaSploit Framework instance
+ */
+public class Framework implements DataHolder {
+
+ private DataStore dataStore;
+ private ModuleManager moduleManager;
+
+ public Framework() {
+ dataStore = new DataStore();
+ moduleManager = new ModuleManager(this, "all");
+ }
+
+ @Override
+ public DataStore getDataStore() {
+ return dataStore;
+ }
+
+ public ModuleManager getModuleManager() {
+ return moduleManager;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/License.java b/msf/src/main/java/org/csploit/msf/License.java
new file mode 100644
index 0000000000..4672e34dd3
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/License.java
@@ -0,0 +1,32 @@
+package org.csploit.msf;
+
+/**
+ * A license
+ */
+public enum License {
+ MSF("Metasploit Framework License (BSD)"),
+ GPL("GNU Public License v2.0"),
+ BSD("BSD License"),
+ ARTISTIC("Perl Artistic License"),
+ UNKNOWN("Unknown License");
+
+ String name;
+
+ License(String name) {
+ this.name = name;
+ }
+
+ public String toString() {
+ return name;
+ }
+
+ public static License fromString(String value) {
+ if(value != null) {
+ for (License l : values()) {
+ if (l.name.toLowerCase().startsWith(value.toLowerCase()))
+ return l;
+ }
+ }
+ return UNKNOWN;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/Module.java b/msf/src/main/java/org/csploit/msf/Module.java
new file mode 100644
index 0000000000..5b41db0404
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/Module.java
@@ -0,0 +1,98 @@
+package org.csploit.msf;
+
+import org.csploit.msf.module.ArchSet;
+import org.csploit.msf.module.ModuleDataStore;
+import org.csploit.msf.module.PlatformList;
+import org.csploit.msf.module.Reference;
+
+import java.util.Collection;
+
+/**
+ * Represent a module of the MSF
+ */
+public abstract class Module implements Offspring, DataHolder {
+ protected Author[] authors;
+ protected ArchSet arch;
+ protected PlatformList platform;
+ protected Reference[] references;
+ protected OptionContainer options;
+ protected Framework framework;
+ protected ModuleDataStore datastore;
+ protected boolean privileged;
+ protected License license;
+
+ protected String name;
+ protected String refname;
+ protected String description;
+ protected String version;
+
+ public Module(String name, String description, String version, Author[] authors, ArchSet arch, PlatformList platform, Reference[] references, boolean privileged, License license ) {
+ this.name = name;
+ this.description = description;
+ this.version = version;
+ this.authors = authors;
+ this.arch = arch;
+ this.platform = platform;
+ this.references = references;
+ this.privileged = privileged;
+ this.license = license;
+ this.options = new OptionContainer();
+ this.datastore = new ModuleDataStore(this);
+ }
+
+ public Module() {
+ this("No module name", "No module description", "0", null, new ArchSet(), new PlatformList(), null, false, License.MSF);
+ }
+
+ @Override
+ public boolean haveFramework() {
+ return framework != null;
+ }
+
+ @Override
+ public Framework getFramework() {
+ return framework;
+ }
+
+ @Override
+ public void setFramework(Framework framework) {
+ this.framework = framework;
+ }
+
+ @Override
+ public DataStore getDataStore() {
+ return datastore;
+ }
+
+ public String getRefname() {
+ return refname;
+ }
+
+ public void setRefname(String refname) {
+ this.refname = refname;
+ }
+
+ public abstract String getType();
+
+ public String getFullName() {
+ return getType() + "/" + getRefname();
+ }
+
+ public String getShortName() {
+ String[] parts = getRefname().split("/");
+ return parts[parts.length - 1];
+ }
+
+ public void registerOption(String name, Option option, boolean advanced, boolean evasion) {
+ options.addOption(name, option, advanced, evasion);
+ }
+
+ public Collection getinvalidOptions() {
+ return options.getInvalidOptions(getDataStore());
+ }
+
+ @Override
+ public int hashCode() {
+ return refname != null ? refname.hashCode() : 0;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/ModuleManager.java b/msf/src/main/java/org/csploit/msf/ModuleManager.java
new file mode 100644
index 0000000000..a87a532e93
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/ModuleManager.java
@@ -0,0 +1,101 @@
+package org.csploit.msf;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Manage all framework modules
+ */
+public class ModuleManager implements Offspring {
+
+ private final static String[] validModuleTypes = {
+ "encoder",
+ "exploit",
+ "nop",
+ "auxiliary",
+ "payload",
+ "post"
+ };
+
+ private Map sets = new HashMap<>();
+ private Framework framework;
+
+ public ModuleManager(Framework framework, String types) {
+ this(framework, types.equals("all") ? validModuleTypes : types.split(","));
+ }
+
+ public ModuleManager(Framework framework, String[] types) {
+ setFramework(framework);
+ for(String type : types) {
+ type = type.trim();
+ if(isValidType(type))
+ initSet(type);
+ }
+ }
+
+ private void initSet(String type) {
+ if(sets.containsKey(type))
+ return;
+
+ ModuleSet set = ModuleSet.forType(type);
+ set.setFramework(getFramework());
+ sets.put(type, set);
+ }
+
+ private static boolean isValidType(String type) {
+ for(String t : validModuleTypes) {
+ if(t.equals(type))
+ return true;
+ }
+ return false;
+ }
+
+ public Module get(String name) {
+ String[] parts = name.split("/");
+ String refname;
+
+ if(!sets.containsKey(parts[0])) {
+ if(!isValidType(parts[0])) {
+ return worldSearch(name);
+ } else {
+ return null;
+ }
+ }
+
+ refname = name.substring(parts[0].length() + 1);
+
+ return sets.get(parts[0]).get(refname);
+ }
+
+ private Module worldSearch(String name) {
+ for(ModuleSet set : sets.values()) {
+ Module m = set.get(name);
+ if(m != null)
+ return m;
+ }
+ return null;
+ }
+
+ public void put(Module module) {
+ String type = module.getType();
+ if(!sets.containsKey(type)) {
+ return;
+ }
+ sets.get(type).add(module);
+ }
+
+ @Override
+ public boolean haveFramework() {
+ return framework != null;
+ }
+
+ @Override
+ public Framework getFramework() {
+ return framework;
+ }
+
+ @Override
+ public void setFramework(Framework framework) {
+ this.framework = framework;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/ModuleSet.java b/msf/src/main/java/org/csploit/msf/ModuleSet.java
new file mode 100644
index 0000000000..d4d1a5f49c
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/ModuleSet.java
@@ -0,0 +1,68 @@
+package org.csploit.msf;
+
+import org.csploit.msf.module.ArchSet;
+import org.csploit.msf.module.PlatformList;
+
+import java.util.HashMap;
+
+/**
+ * A module set contains zero or more named module classes of an arbitrary
+ * type.
+ */
+public class ModuleSet extends HashMap implements Offspring {
+ protected String type;
+ private Framework framework;
+
+ public ModuleSet(String type) {
+ this.type = type;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public boolean haveFramework() {
+ return framework != null;
+ }
+
+ @Override
+ public Framework getFramework() {
+ return framework;
+ }
+
+ @Override
+ public void setFramework(Framework framework) {
+ this.framework = framework;
+ }
+
+ public void add(Module module) {
+ module.setFramework(framework);
+ put(module.getRefname(), module);
+ }
+
+ public ModuleSet filter(ArchSet architectures, PlatformList platforms) {
+ ModuleSet res = new ModuleSet(getType());
+ res.setFramework(framework);
+ for(Module m : values()) {
+
+ if(architectures != null && m.arch.intersect(architectures).isEmpty()) {
+ continue;
+ }
+
+ if(platforms != null && m.platform.intersect(platforms).isEmpty()) {
+ continue;
+ }
+
+ //TODO: custom filter
+
+ res.add(m);
+ }
+ return res;
+ }
+
+ public static ModuleSet forType(String type) {
+ //TODO: PayloadSet
+ return new ModuleSet(type);
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/Offspring.java b/msf/src/main/java/org/csploit/msf/Offspring.java
new file mode 100644
index 0000000000..fb2015cf85
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/Offspring.java
@@ -0,0 +1,10 @@
+package org.csploit.msf;
+
+/**
+ * CLasses that ave a reference to the framework
+ */
+public interface Offspring {
+ boolean haveFramework();
+ Framework getFramework();
+ void setFramework(Framework framework);
+}
diff --git a/msf/src/main/java/org/csploit/msf/Option.java b/msf/src/main/java/org/csploit/msf/Option.java
new file mode 100644
index 0000000000..c246ce3159
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/Option.java
@@ -0,0 +1,88 @@
+package org.csploit.msf;
+
+import org.csploit.msf.options.StringOption;
+
+/**
+ * Represent an option
+ */
+public abstract class Option {
+ protected boolean advanced;
+ protected T defaultValue;
+ protected String description;
+ protected boolean evasion;
+ protected String name;
+ protected Module owner;
+ protected boolean required;
+
+ public Option(String name, boolean required, String description, T defaultValue) {
+ this.name = name;
+ this.required = required;
+ this.description = description;
+ this.defaultValue = defaultValue;
+ }
+
+ public Option(String name, String description, T defaultValue) {
+ this(name, false, description, defaultValue);
+ }
+
+ public boolean isAdvanced() {
+ return advanced;
+ }
+
+ public void setAdvanced(boolean advanced) {
+ this.advanced = advanced;
+ }
+
+ public T getDefaultValue() {
+ return defaultValue;
+ }
+
+ public boolean haveDefaultValue() {
+ return defaultValue != null;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public boolean isEvasion() {
+ return evasion;
+ }
+
+ public void setEvasion(boolean evasion) {
+ this.evasion = evasion;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Module getOwner() {
+ return owner;
+ }
+
+ public void setOwner(Module owner) {
+ this.owner = owner;
+ }
+
+ public boolean isRequired() {
+ return required;
+ }
+
+ protected abstract T normalize(String input);
+
+ protected String display(T value) {
+ return value.toString();
+ }
+
+ protected boolean isValid(T input) {
+ if(isRequired() && (input == null || input.toString().isEmpty())) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/OptionContainer.java b/msf/src/main/java/org/csploit/msf/OptionContainer.java
new file mode 100644
index 0000000000..68de7115fa
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/OptionContainer.java
@@ -0,0 +1,50 @@
+package org.csploit.msf;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A container of options
+ */
+class OptionContainer extends HashMap {
+
+ public void addAdvancedOption(String name, Option option) {
+ addOption(name, option, true, false);
+ }
+
+ public void addEvasionOption(String name, Option option) {
+ addOption(name, option, false, true);
+ }
+
+ public void addOption(String name, Option option, boolean advanced, boolean evasion) {
+ option.setEvasion(evasion);
+ option.setAdvanced(advanced);
+ put(name, option);
+ }
+
+ /**
+ * this should be the validate method in the MSF.
+ * I decided to change it because updating dataStore
+ * within modules will write global values into it.
+ */
+ @SuppressWarnings("unchecked")
+ public Collection getInvalidOptions(DataStore dataStore) {
+ ArrayList errors = new ArrayList<>();
+
+ for(Map.Entry entry : entrySet()) {
+ String name = entry.getKey();
+ Option option = entry.getValue();
+
+ String val = dataStore.get(name);
+ Object normalized = option.normalize(val);
+
+ if(!option.isValid(normalized)) {
+ errors.add(name);
+ }
+ }
+
+ return errors;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/arch/Arch.java b/msf/src/main/java/org/csploit/msf/arch/Arch.java
new file mode 100644
index 0000000000..54e5137ad8
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/arch/Arch.java
@@ -0,0 +1,32 @@
+package org.csploit.msf.arch;
+
+/**
+ * Machines architectures
+ *
+ * source: lib/rex/constants.rb
+ */
+public enum Arch {
+ ANY,
+ X86,
+ X86_64,
+ X64,
+ MIPS,
+ MIPSLE,
+ MIPSBE,
+ PPC,
+ PPC64,
+ CBEA,
+ CBEA64,
+ SPARC,
+ CMD,
+ PHP,
+ TTY,
+ ARMLE,
+ ARMBE,
+ JAVA,
+ RUBY,
+ DALVIK,
+ PYTHON,
+ NODEJS,
+ FIREFOX;
+}
\ No newline at end of file
diff --git a/msf/src/main/java/org/csploit/msf/module/ArchSet.java b/msf/src/main/java/org/csploit/msf/module/ArchSet.java
new file mode 100644
index 0000000000..36c407f490
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/module/ArchSet.java
@@ -0,0 +1,57 @@
+package org.csploit.msf.module;
+
+import java.util.Collection;
+import java.util.HashSet;
+import org.csploit.msf.arch.Arch;
+
+/**
+ * A container for architectures supported by a module
+ */
+public class ArchSet extends HashSet {
+
+ public ArchSet() {
+ super();
+ }
+
+ public ArchSet(String s) {
+ this(s.split(","));
+ }
+
+ public ArchSet(String[] a) {
+ super(a.length);
+
+ for(String arch : a) {
+ add(Arch.valueOf(arch.trim().toUpperCase()));
+ }
+ }
+
+ private ArchSet(Collection extends Arch> other) {
+ super(other);
+ }
+
+ public boolean isSupported(Arch arch) {
+ return arch == Arch.ANY || contains(arch);
+ }
+
+ public ArchSet intersect(ArchSet other) {
+ ArchSet res = new ArchSet(this);
+ res.retainAll(other);
+ return res;
+ }
+
+ @Override
+ public String toString() {
+ if(isEmpty())
+ return "";
+ StringBuilder sb = new StringBuilder();
+
+ for (Arch a : this) {
+ if(sb.length() > 0) {
+ sb.append(", ");
+ }
+ sb.append(a.toString());
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/module/ModuleDataStore.java b/msf/src/main/java/org/csploit/msf/module/ModuleDataStore.java
new file mode 100644
index 0000000000..931a4750de
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/module/ModuleDataStore.java
@@ -0,0 +1,37 @@
+package org.csploit.msf.module;
+
+import org.csploit.msf.Module;
+
+/**
+ * DataStore wrapper for modules that will attempt to back values against the
+ * framework's datastore if they aren't found in the module's datastore. This
+ * is done to simulate global data store values.
+ */
+public class ModuleDataStore extends org.csploit.msf.DataStore {
+ private Module module;
+
+ public ModuleDataStore(Module module) {
+ this.module = module;
+ }
+
+ public boolean isDefault(String key) {
+ return defaults.contains(key);
+ }
+
+ @Override
+ public String get(Object key) {
+ String k, res;
+
+ k = key != null ? key.toString() : null;
+ k = findKeyCase(k);
+ res = null;
+ if(!isDefault(k))
+ res = super.get(key);
+
+ if(res == null && module != null && module.haveFramework()) {
+ res = module.getFramework().getDataStore().get(k);
+ }
+
+ return res != null ? res : super.get(k);
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/module/Platform.java b/msf/src/main/java/org/csploit/msf/module/Platform.java
new file mode 100644
index 0000000000..083a0893cf
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/module/Platform.java
@@ -0,0 +1,118 @@
+package org.csploit.msf.module;
+
+/**
+ * A platform
+ */
+public enum Platform {
+ WINDOWS("Windows", 1, 0, 0),
+ WINDOWS_95("Windows 95", 1, 1, 0),
+ WINDOWS_98("Windows 98", 1, 2, 0),
+ WINDOWS_98_FE("Windows 98 FE", 1, 2, 1),
+ WINDOWS_98_SE("Windows 98 SE", 1, 2, 2),
+ WINDOWS_ME("Windows ME", 1, 3, 0),
+ WINDOWS_NT("Windows NT", 1, 4, 0),
+ WINDOWS_NT_SP0("Windows NT SP0", 1, 4, 1),
+ WINDOWS_NT_SP1("Windows NT SP1", 1, 4, 2),
+ WINDOWS_NT_SP2("Windows NT SP2", 1, 4, 3),
+ WINDOWS_NT_SP3("Windows NT SP3", 1, 4, 4),
+ WINDOWS_NT_SP4("Windows NT SP4", 1, 4, 5),
+ WINDOWS_NT_SP5("Windows NT SP5", 1, 4, 6),
+ WINDOWS_NT_SP6("Windows NT SP6", 1, 4, 7),
+ WINDOWS_NT_SP6A("Windows NT SP6a", 1, 4, 8),
+ WINDOWS_2000("Windows 2000", 1, 5, 0),
+ WINDOWS_2000_SP0("Windows 2000 SP0", 1, 5, 1),
+ WINDOWS_2000_SP1("Windows 2000 SP1", 1, 5, 2),
+ WINDOWS_2000_SP2("Windows 2000 SP2", 1, 5, 3),
+ WINDOWS_2000_SP3("Windows 2000 SP3", 1, 5, 4),
+ WINDOWS_2000_SP4("Windows 2000 SP4", 1, 5, 5),
+ WINDOWS_XP("Windows XP", 1, 6, 0),
+ WINDOWS_XP_SP0("Windows XP SP0", 1, 6, 1),
+ WINDOWS_XP_SP1("Windows XP SP1", 1, 6, 2),
+ WINDOWS_XP_SP2("Windows XP SP2", 1, 6, 3),
+ WINDOWS_XP_SP3("Windows XP SP3", 1, 6, 4),
+ WINDOWS_2003("Windows 2003", 1, 7, 0),
+ WINDOWS_2003_SP0("Windows 2003 SP0", 1, 7, 1),
+ WINDOWS_2003_SP1("Windows 2003 SP1", 1, 7, 2),
+ WINDOWS_VISTA("Windows Vista", 1, 8, 0),
+ WINDOWS_VISTA_SP0("Windows Vista SP0", 1, 8, 1),
+ WINDOWS_VISTA_SP1("Windows Vista SP1", 1, 8, 2),
+ WINDOWS_7("Windows 7", 1, 9, 0),
+ WINDOWS_8("Windows 8", 1, 10, 0),
+ NETWARE("Netware", 2, 0, 0),
+ ANDROID("Android", 3, 0, 0),
+ JAVA("Java", 4, 0, 0),
+ RUBY("Ruby", 5, 0, 0),
+ LINUX("Linux", 6, 0, 0),
+ CISCO("Cisco", 7, 0, 0),
+ SOLARIS("Solaris", 8, 0, 0),
+ SOLARIS_V4("Solaris V4", 8, 1, 0),
+ SOLARIS_V5("Solaris V5", 8, 2, 0),
+ SOLARIS_V6("Solaris V6", 8, 3, 0),
+ SOLARIS_V7("Solaris V7", 8, 4, 0),
+ SOLARIS_V8("Solaris V8", 8, 5, 0),
+ SOLARIS_V9("Solaris V9", 8, 6, 0),
+ SOLARIS_V10("Solaris V10", 8, 7, 0),
+ OSX("OSX", 9, 0, 0),
+ BSD("BSD", 10, 0, 0),
+ OPENBSD("OpenBSD", 11, 0, 0),
+ BSDI("BSDi", 12, 0, 0),
+ NETBSD("NetBSD", 13, 0, 0),
+ FREEBSD("FreeBSD", 14, 0, 0),
+ AIX("AIX", 15, 0, 0),
+ HPUX("HPUX", 16, 0, 0),
+ IRIX("Irix", 17, 0, 0),
+ UNIX("Unix", 18, 0, 0),
+ PHP("PHP", 19, 0, 0),
+ JAVASCRIPT("JavaScript", 20, 0, 0),
+ PYTHON("Python", 21, 0, 0),
+ NODEJS("NodeJS", 22, 0, 0),
+ FIREFOX("Firefox", 23, 0, 0),
+ MAINFRAME("Mainframe", 24, 0, 0);
+
+ protected String realName;
+ protected int major;
+ protected int minor;
+ protected int patch;
+
+ Platform(String realName, int major, int minor, int patch) {
+ this.realName = realName;
+ this.major = major;
+ this.minor = minor;
+ this.patch = patch;
+ }
+
+ public String getRealName() {
+ return realName;
+ }
+
+ /**
+ * is a platform a subset of another ?
+ * @param other possible ancestor to test
+ * @return true if {@code other} is a platform that contains {@code this}
+ */
+ public boolean subsetOf(Platform other) {
+ if(other.major != major)
+ return false;
+ if(other.minor == 0)
+ return true;
+ if(other.minor != minor)
+ return false;
+ if(other.patch == 0)
+ return true;
+ if(other.patch != patch)
+ return false;
+ return true;
+ }
+
+ public static Platform fromString(String s) {
+ if(s != null) {
+ s = s.trim();
+ for (Platform pl : values()) {
+ if (pl.getRealName().equals(s))
+ return pl;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/msf/src/main/java/org/csploit/msf/module/PlatformList.java b/msf/src/main/java/org/csploit/msf/module/PlatformList.java
new file mode 100644
index 0000000000..a4f5cdc464
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/module/PlatformList.java
@@ -0,0 +1,43 @@
+package org.csploit.msf.module;
+
+import java.util.HashSet;
+
+/**
+ * A list of platforms
+ */
+public class PlatformList extends HashSet {
+
+ public PlatformList() {
+ super();
+ }
+
+ public PlatformList(String s) {
+ this(s.split(","));
+ }
+
+ public PlatformList(String[] plats) {
+ super(plats.length);
+ for(String s : plats) {
+ Platform platform = Platform.fromString(s);
+ if(platform != null) {
+ add(platform);
+ }
+ }
+ }
+
+ public PlatformList intersect(PlatformList other) {
+ PlatformList res = new PlatformList();
+
+ for(Platform pl1 : this) {
+ for(Platform pl2 : other) {
+ if(pl1.subsetOf(pl2)) {
+ res.add(pl1);
+ } else if(pl2.subsetOf(pl1)) {
+ res.add(pl2);
+ }
+ }
+ }
+
+ return res;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/module/Rank.java b/msf/src/main/java/org/csploit/msf/module/Rank.java
new file mode 100644
index 0000000000..b74854255b
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/module/Rank.java
@@ -0,0 +1,43 @@
+package org.csploit.msf.module;
+
+/**
+ * A module rank
+ */
+public enum Rank {
+ MANUAL(0, "manual"),
+ LOW(100, "low"),
+ AVERAGE(200, "average"),
+ NORMAL(300, "normal"),
+ GOOD(400, "good"),
+ GREAT(500, "great"),
+ EXCELLENT(600, "excellent")
+ ;
+
+ private String name;
+ private int value;
+
+ Rank(int value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ public static Rank fromName(String name) {
+ name = name.trim();
+ name = name.toLowerCase();
+ for (Rank r : values()) {
+ if (r.name.toLowerCase().equals(name)) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ public static Rank fromValue(int value) {
+ for (Rank r : values()) {
+ if (r.value <= value) {
+ return r;
+ }
+ }
+ return null;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/module/Reference.java b/msf/src/main/java/org/csploit/msf/module/Reference.java
new file mode 100644
index 0000000000..8ad1c18a23
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/module/Reference.java
@@ -0,0 +1,37 @@
+package org.csploit.msf.module;
+
+/**
+ * A reference to some sort of information. This is typically a URL, but could
+ * be any type of referential value that people could use to research a topic.
+ */
+public class Reference {
+ protected String str;
+
+ public Reference(String str) {
+ this.str = "" + str;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Reference reference = (Reference) o;
+
+ return str.equals(reference.str);
+ }
+
+ @Override
+ public int hashCode() {
+ return str.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return str;
+ }
+
+ public static Reference fromString(String s) {
+ return new Reference(s);
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/module/SiteReference.java b/msf/src/main/java/org/csploit/msf/module/SiteReference.java
new file mode 100644
index 0000000000..8b012171a1
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/module/SiteReference.java
@@ -0,0 +1,51 @@
+package org.csploit.msf.module;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * A reference to a website.
+ */
+public class SiteReference extends Reference {
+ protected String ctx_id;
+ protected String ctx_val;
+
+ private final static Pattern SIMPLE_URL_PATTERN = Pattern.compile("(http://|https://|ftp://)");
+
+ private final static Map formats = new HashMap() {{
+ put("OSVDB", "http://www.osvdb.org/%s");
+ put("CVE", "http://cvedetails.com/cve/%s/");
+ put("CWE", "https://cwe.mitre.org/data/definitions/%s.html");
+ put("BID", "http://www.securityfocus.com/bid/%s");
+ put("MSB", "http://technet.microsoft.com/en-us/security/bulletin/%s");
+ put("EDB", "https://www.exploit-db.com/exploits/%s");
+ put("US-CERT-VU", "http://www.kb.cert.org/vuls/id/%s");
+ put("ZDI", "http://www.zerodayinitiative.com/advisories/ZDI-%s");
+ put("WPVDB", "https://wpvulndb.com/vulnerabilities/%s");
+ put("PACKETSTORM", "https://packetstormsecurity.com/files/%s");
+ put("URL", "%s");
+ }};
+
+ public SiteReference(String ctx_id, String ctx_val) {
+ super("");
+ this.ctx_id = ctx_id;
+ this.ctx_val = ctx_val;
+
+ if(formats.containsKey(ctx_id)) {
+ str = String.format(formats.get(ctx_id), ctx_val);
+ } else {
+ str = ctx_id;
+ if(ctx_val != null) {
+ str += " (" + ctx_val + ")";
+ }
+ }
+ }
+
+ public static SiteReference fromString(String str) {
+ if(!SIMPLE_URL_PATTERN.matcher(str).matches()) {
+ return null;
+ }
+ return new SiteReference("URL", str);
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/module/Target.java b/msf/src/main/java/org/csploit/msf/module/Target.java
new file mode 100644
index 0000000000..9262f7d25f
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/module/Target.java
@@ -0,0 +1,32 @@
+package org.csploit.msf.module;
+
+/**
+ * Represent a target
+ */
+public class Target {
+ private String name;
+ private PlatformList platform;
+ private ArchSet arch;
+
+ public Target(String name, PlatformList platform, ArchSet arch) {
+ this.name = name;
+ this.platform = platform;
+ this.arch = arch;
+ }
+
+ public Target(String name) {
+ this(name, new PlatformList(), new ArchSet());
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public PlatformList getPlatform() {
+ return platform;
+ }
+
+ public ArchSet getArch() {
+ return arch;
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/AddressOption.java b/msf/src/main/java/org/csploit/msf/options/AddressOption.java
new file mode 100644
index 0000000000..2c0d502217
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/AddressOption.java
@@ -0,0 +1,37 @@
+package org.csploit.msf.options;
+
+import org.csploit.msf.Option;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Network address option.
+ */
+public class AddressOption extends Option {
+
+ public AddressOption(String name, boolean required, String description, InetAddress defaultValue) {
+ super(name, required, description, defaultValue);
+ }
+
+ public AddressOption(String name, boolean required, String description, String defaultValue) {
+ super(name, required, description, sNormalize(defaultValue));
+ }
+
+ public AddressOption(String name, String description, InetAddress defaultValue) {
+ super(name, description, defaultValue);
+ }
+
+ @Override
+ protected InetAddress normalize(String input) {
+ return sNormalize(input);
+ }
+
+ private static InetAddress sNormalize(String input) {
+ try {
+ return input != null ? InetAddress.getByName(input) : null;
+ } catch (UnknownHostException e) {
+ return null;
+ }
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/AddressRangeOption.java b/msf/src/main/java/org/csploit/msf/options/AddressRangeOption.java
new file mode 100644
index 0000000000..422830b518
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/AddressRangeOption.java
@@ -0,0 +1,81 @@
+package org.csploit.msf.options;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.csploit.msf.Option;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Network address range option.
+ */
+public class AddressRangeOption extends Option {
+
+ public AddressRangeOption(String name, boolean required, String description, InetAddress[] defaultValue) {
+ super(name, required, description, defaultValue);
+ }
+
+ public AddressRangeOption(String name, String description, InetAddress[] defaultValue) {
+ super(name, description, defaultValue);
+ }
+
+ @Override
+ protected InetAddress[] normalize(String input) {
+ if(input == null)
+ return null;
+
+ if(input.startsWith("file:")) {
+ InputStream is = null;
+ try {
+ input = input.substring(5).trim();
+ is = new FileInputStream(new File(input));
+ List lines = IOUtils.readLines(is);
+ ArrayList result = new ArrayList<>();
+
+ for(String line : lines) {
+ try {
+ result.add(InetAddress.getByName(line.trim()));
+ } catch (UnknownHostException e) {
+ // ignore
+ }
+ }
+
+ return result.toArray(new InetAddress[result.size()]);
+ } catch (IOException e) {
+ // ignore
+ } finally {
+ IOUtils.closeQuietly(is);
+ }
+ } else if ( input.startsWith("rand:")) {
+ throw new UnsupportedOperationException("random address ranges not supported");
+ } else {
+ String[] parts = input.split(" ");
+ ArrayList result = new ArrayList<>();
+
+ for(String part : parts) {
+ try {
+ result.add(InetAddress.getByName(part));
+ } catch (UnknownHostException e) {
+ // ignore
+ }
+ }
+
+ return result.toArray(new InetAddress[result.size()]);
+ }
+ return null;
+ }
+
+ @Override
+ protected String display(InetAddress[] value) {
+ return StringUtils.join(value, " ");
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/BooleanOption.java b/msf/src/main/java/org/csploit/msf/options/BooleanOption.java
new file mode 100644
index 0000000000..768553640f
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/BooleanOption.java
@@ -0,0 +1,26 @@
+package org.csploit.msf.options;
+
+import org.csploit.msf.Option;
+
+import java.util.regex.Pattern;
+
+/**
+ * Boolean option.
+ */
+public class BooleanOption extends Option {
+ private static final Pattern TRUE = Pattern.compile("^(y|yes|t|1|true)$", Pattern.CASE_INSENSITIVE);
+ private static final Pattern BOOLEAN = Pattern.compile("^(y|yes|n|no|t|f|0|1|true|false)$", Pattern.CASE_INSENSITIVE);
+
+ public BooleanOption(String name, boolean required, String description, Boolean defaultValue) {
+ super(name, required, description, defaultValue);
+ }
+
+ public BooleanOption(String name, String description, Boolean defaultValue) {
+ super(name, description, defaultValue);
+ }
+
+ @Override
+ protected Boolean normalize(String input) {
+ return input != null && TRUE.matcher(input).matches();
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/EnumOption.java b/msf/src/main/java/org/csploit/msf/options/EnumOption.java
new file mode 100644
index 0000000000..d7a276710b
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/EnumOption.java
@@ -0,0 +1,36 @@
+package org.csploit.msf.options;
+
+import org.csploit.msf.Option;
+
+/**
+ * Enum option.
+ */
+public class EnumOption extends Option {
+
+ private String[] enums;
+
+ public EnumOption(String name, boolean required, String description, String defaultValue, String[] enums) {
+ super(name, required, description, defaultValue);
+ this.enums = enums;
+ }
+
+ public EnumOption(String name, String description, String defaultValue, String[] enums) {
+ super(name, description, defaultValue);
+ this.enums = enums;
+ }
+
+ @Override
+ protected String normalize(String input) {
+ for(String s : enums) {
+ if(s.equals(input)) {
+ return s;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean isValid(String input) {
+ return super.isValid(input) && (input == null || normalize(input) != null);
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/IntegerOption.java b/msf/src/main/java/org/csploit/msf/options/IntegerOption.java
new file mode 100644
index 0000000000..72bec85aa3
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/IntegerOption.java
@@ -0,0 +1,29 @@
+package org.csploit.msf.options;
+
+import org.csploit.msf.Option;
+
+/**
+ * Integer option.
+ */
+public class IntegerOption extends Option {
+ public IntegerOption(String name, boolean required, String description, Integer defaultValue) {
+ super(name, required, description, defaultValue);
+ }
+
+ public IntegerOption(String name, String description, Integer defaultValue) {
+ super(name, description, defaultValue);
+ }
+
+ @Override
+ protected Integer normalize(String input) {
+ try {
+ if (input.startsWith("0x")) {
+ return Integer.parseInt(input.substring(2), 16);
+ } else {
+ return Integer.parseInt(input);
+ }
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/PathOption.java b/msf/src/main/java/org/csploit/msf/options/PathOption.java
new file mode 100644
index 0000000000..1443fc09f7
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/PathOption.java
@@ -0,0 +1,35 @@
+package org.csploit.msf.options;
+
+import org.csploit.msf.Option;
+
+import java.io.File;
+
+/**
+ * File system path option.
+ */
+public class PathOption extends Option {
+
+ public PathOption(String name, boolean required, String description, File defaultValue) {
+ super(name, required, description, defaultValue);
+ }
+
+ public PathOption(String name, String description, File defaultValue) {
+ super(name, description, defaultValue);
+ }
+
+ @Override
+ protected File normalize(String input) {
+ File res = new File(input);
+ return res.exists() ? res : null;
+ }
+
+ @Override
+ protected boolean isValid(File input) {
+ return super.isValid(input) && (input == null || input.exists());
+ }
+
+ @Override
+ protected String display(File value) {
+ return value.getAbsolutePath();
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/PortOption.java b/msf/src/main/java/org/csploit/msf/options/PortOption.java
new file mode 100644
index 0000000000..8094bb719f
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/PortOption.java
@@ -0,0 +1,33 @@
+package org.csploit.msf.options;
+
+import org.csploit.msf.Option;
+
+/**
+ * Network port option.
+ */
+public class PortOption extends Option {
+
+ public PortOption(String name, boolean required, String description, Integer defaultValue) {
+ super(name, required, description, defaultValue);
+ }
+
+ public PortOption(String name, String description, Integer defaultValue) {
+ super(name, description, defaultValue);
+ }
+
+ @Override
+ protected Integer normalize(String input) {
+ try {
+ int val = Integer.parseInt(input);
+ return isValid(val) ? val : null;
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean isValid(Integer input) {
+ return super.isValid(input) && (input == null || input >= 0 && input <= 65535);
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/RawOption.java b/msf/src/main/java/org/csploit/msf/options/RawOption.java
new file mode 100644
index 0000000000..d6868ba70a
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/RawOption.java
@@ -0,0 +1,42 @@
+package org.csploit.msf.options;
+
+import org.apache.commons.io.IOUtils;
+import org.csploit.msf.Option;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+
+/**
+ * Raw, arbitrary data option.
+ */
+public class RawOption extends Option {
+
+ public RawOption(String name, boolean required, String description, byte[] defaultValue) {
+ super(name, required, description, defaultValue);
+ }
+
+ public RawOption(String name, String description, byte[] defaultValue) {
+ super(name, description, defaultValue);
+ }
+
+ @Override
+ protected byte[] normalize(String input) {
+ if(input.startsWith("file:")) {
+ try {
+ IOUtils.toByteArray(new URI(input));
+ } catch (IOException | URISyntaxException e) {
+ //ignore
+ }
+ return null;
+ }
+ return input.getBytes();
+ }
+
+ @Override
+ protected String display(byte[] value) {
+ return Arrays.toString(value);
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/RegexpOption.java b/msf/src/main/java/org/csploit/msf/options/RegexpOption.java
new file mode 100644
index 0000000000..74d57cde35
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/RegexpOption.java
@@ -0,0 +1,29 @@
+package org.csploit.msf.options;
+
+import org.csploit.msf.Option;
+
+import java.util.regex.Pattern;
+
+/**
+ * A regex option
+ */
+public class RegexpOption extends Option {
+
+ public RegexpOption(String name, boolean required, String description, Pattern defaultValue) {
+ super(name, required, description, defaultValue);
+ }
+
+ public RegexpOption(String name, String description, Pattern defaultValue) {
+ super(name, description, defaultValue);
+ }
+
+ @Override
+ protected Pattern normalize(String input) {
+ return Pattern.compile(input);
+ }
+
+ @Override
+ protected String display(Pattern value) {
+ return value.pattern();
+ }
+}
diff --git a/msf/src/main/java/org/csploit/msf/options/StringOption.java b/msf/src/main/java/org/csploit/msf/options/StringOption.java
new file mode 100644
index 0000000000..449f99da13
--- /dev/null
+++ b/msf/src/main/java/org/csploit/msf/options/StringOption.java
@@ -0,0 +1,38 @@
+package org.csploit.msf.options;
+
+import org.apache.commons.io.IOUtils;
+import org.csploit.msf.Option;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Option string
+ */
+public class StringOption extends Option {
+
+ public StringOption(String name, boolean required, String description, String defaultValue) {
+ super(name, required, description, defaultValue);
+ }
+
+ public StringOption(String name, String description, String defaultValue) {
+ super(name, description, defaultValue);
+ }
+
+ @Override
+ protected String normalize(String input) {
+ if(input.startsWith("file:")) {
+ try {
+ return IOUtils.toString(new URI(input));
+ } catch (IOException | URISyntaxException e) {
+ //ignore
+ }
+ return null;
+ }
+ return input;
+ }
+}
diff --git a/msf/src/test/java/org/csploit/msf/DataStoreTest.java b/msf/src/test/java/org/csploit/msf/DataStoreTest.java
new file mode 100644
index 0000000000..737ccfe511
--- /dev/null
+++ b/msf/src/test/java/org/csploit/msf/DataStoreTest.java
@@ -0,0 +1,59 @@
+package org.csploit.msf;
+
+import org.csploit.msf.options.StringOption;
+import org.junit.Test;
+
+import java.util.Set;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+/**
+ * Test the DataStore class
+ */
+public class DataStoreTest {
+
+ private DataStore buildDataStoreWithDefaultOption() {
+ DataStore store = new DataStore();
+ OptionContainer options = new OptionContainer();
+
+ options.addOption("A",
+ new StringOption("A", "description", "default value"), false, false);
+
+ store.importOptions(options, true);
+
+ return store;
+ }
+
+ @Test
+ public void testImportOptions() throws Exception {
+ DataStore store = buildDataStoreWithDefaultOption();
+
+ assertThat(store.get("A"), is("default value"));
+ }
+
+ @Test
+ public void testUserDefined() throws Exception {
+ DataStore store = buildDataStoreWithDefaultOption();
+
+ assertThat(store.userDefined().isEmpty(), is(true));
+
+ store.put("A", "user-defined value");
+
+ assertThat(store.userDefined().isEmpty(), is(false));
+ }
+
+ @Test
+ public void testClearNotUserDefined() throws Exception {
+ DataStore store = buildDataStoreWithDefaultOption();
+
+ store.put("B", "user-defined value");
+
+ store.clearNotUserDefined();
+
+ Set keys = store.keySet();
+
+ assertThat(keys.contains("B"), is(true));
+ assertThat(keys.contains("A"), is(false));
+ }
+}
\ No newline at end of file
diff --git a/msf/src/test/java/org/csploit/msf/RpcSampleTest.java b/msf/src/test/java/org/csploit/msf/RpcSampleTest.java
new file mode 100644
index 0000000000..3c0c414b1c
--- /dev/null
+++ b/msf/src/test/java/org/csploit/msf/RpcSampleTest.java
@@ -0,0 +1,196 @@
+package org.csploit.msf;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.CoreMatchers.*;
+
+import org.csploit.msf.module.ArchSet;
+import org.csploit.msf.module.PlatformList;
+import org.csploit.msf.module.Reference;
+import org.csploit.msf.module.SiteReference;
+import org.csploit.msf.module.Target;
+import org.csploit.msf.options.AddressOption;
+import org.csploit.msf.options.BooleanOption;
+import org.csploit.msf.options.EnumOption;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Test msf library usage for rpc usage
+ */
+public class RpcSampleTest {
+
+ private class ModuleInfoBase {
+ public String name,description,license,filepath;
+ public int rank;
+ public String[][] references;
+ public String[] authors;
+ }
+
+ private class ExploitInfo extends ModuleInfoBase {
+ public String[] targets;
+ public int defaultTarget;
+ }
+
+ private class AuxInfo extends ModuleInfoBase {
+ public String[] actions;
+ public int defaultAction;
+ }
+
+ private class ModuleOptionInfo {
+ public String type, description;
+ public boolean required, advanced, evasion;
+ public T defaultValue;
+ public String[] enums;
+
+ public ModuleOptionInfo(String type, String description, boolean required, boolean advanced, boolean evasion, T defaultValue, String[] enums) {
+ this.type = type;
+ this.description = description;
+ this.required = required;
+ this.advanced = advanced;
+ this.evasion = evasion;
+ this.defaultValue = defaultValue;
+ this.enums = enums;
+ }
+
+ public ModuleOptionInfo(String type, String description, boolean required, boolean advanced, boolean evasion, T defaultValue) {
+ this(type, description, required, advanced, evasion, defaultValue, null);
+ }
+
+ public ModuleOptionInfo(String type, String description, boolean required, boolean advanced, boolean evasion) {
+ this(type, description, required, advanced, evasion, null, null);
+ }
+ }
+
+ @Test
+ public void putExploitTest() {
+
+ ExploitInfo info = new ExploitInfo();
+
+ info.name = "A funny exploit";
+ info.description = "a very long description";
+ info.license = License.GPL.toString();
+ info.filepath = "whocares";
+ info.rank = 300;
+ info.references = new String[][] {
+ {"URL", "http://nowhere.com/index.html"},
+ {"OSVDB", "12345"}
+ };
+ info.authors = new String[] {
+ "Someone "
+ };
+ info.targets = new String[] {
+ "IE / RealOne Player 2",
+ "IE / RealOne Player 3"
+ };
+ info.defaultTarget = 0;
+
+
+ Framework framework = new Framework();
+
+ ModuleManager mgr = framework.getModuleManager();
+
+ // deserialize rpc stuff
+
+ Target[] targets = new Target[info.targets.length];
+ Author[] authors = new Author[info.authors.length];
+ Reference[] references = new Reference[info.references.length];
+ License license = License.fromString(info.license);
+
+ for(int i = 0; i < info.targets.length; i++) {
+ targets[i] = new Target(info.targets[i]);
+ }
+
+ for(int i = 0; i < info.authors.length; i++) {
+ authors[i] = Author.fromString(info.authors[i]);
+ }
+
+ for(int i = 0; i < info.references.length; i++) {
+ String[] pair = info.references[i];
+ String id = pair[0];
+ String val = pair[1];
+ references[i] = new SiteReference(id, val);
+ }
+
+ Exploit exploit = new Exploit(
+ info.name, info.description, "0", authors,
+ new ArchSet(), new PlatformList(), references,
+ false, license, targets, 0);
+
+ mgr.put(exploit);
+
+ assertThat(exploit.getFramework(), is(framework));
+ assertThat(exploit.license, is(License.GPL));
+ assertThat(exploit.getTarget(), is(exploit.getTargets()[0]));
+
+ // receive exploit options
+ Map options = new HashMap<>();
+
+ options.put("NTLM::SendNTLM",
+ new ModuleOptionInfo<>(
+ "bool", "A", true, true, false, true
+ ));
+ options.put("HTTP::uri_encode_mode",
+ new ModuleOptionInfo<>(
+ "enum", "B", false, false, true, "hex-normal", new String[] {
+ "none", "hex-normal", "hex-noslashes", "hex-random",
+ "hex-all", "u-normal", "u-all", "u-random"
+ }
+ ));
+ options.put("RHOST",
+ new ModuleOptionInfo<>(
+ "address", "C", true, false, false
+ ));
+
+ // put them into the exploit
+
+ for (Map.Entry entry : options.entrySet()) {
+ ModuleOptionInfo info1 = entry.getValue();
+ String name = entry.getKey();
+
+ exploit.registerOption(name, getOptionForInfo(name, info1), info1.advanced, info1.evasion);
+ }
+
+ // let's now try to edit an option
+
+ // first in the local datastore
+ exploit.getDataStore().put("TARGET", "1");
+ assertThat(exploit.getTarget(), is(exploit.getTargets()[1]));
+ exploit.getDataStore().remove("TARGET");
+ assertThat(exploit.getTarget(), is(exploit.getTargets()[0]));
+
+ // from global datastore
+ framework.getDataStore().put("TARGET", "1");
+ assertThat(exploit.getTarget(), is(exploit.getTargets()[1]));
+ framework.getDataStore().remove("TARGET");
+ assertThat(exploit.getTarget(), is(exploit.getTargets()[0]));
+
+ // exploit settings should not be valid without the required RHOST options
+
+ assertThat(exploit.getinvalidOptions().isEmpty(), is(false));
+
+ framework.getDataStore().put("RHOST", "invalid address");
+
+ assertThat(exploit.getinvalidOptions().isEmpty(), is(false));
+
+ framework.getDataStore().put("RHOST", "127.0.0.1");
+
+ assertThat(exploit.getinvalidOptions().isEmpty(), is(true));
+ }
+
+ private static Option getOptionForInfo(String name, ModuleOptionInfo info) {
+ switch (info.type) {
+ case "bool":
+ return new BooleanOption(name, info.required, info.description,
+ ((ModuleOptionInfo)info).defaultValue);
+ case "enum":
+ return new EnumOption(name, info.required, info.description,
+ ((ModuleOptionInfo)info).defaultValue, info.enums);
+ case "address":
+ return new AddressOption(name, info.required, info.description,
+ ((ModuleOptionInfo)info).defaultValue);
+ }
+ return null;
+ }
+}
diff --git a/msf/src/test/java/org/csploit/msf/module/PlatformListTest.java b/msf/src/test/java/org/csploit/msf/module/PlatformListTest.java
new file mode 100644
index 0000000000..b9bbec1d2d
--- /dev/null
+++ b/msf/src/test/java/org/csploit/msf/module/PlatformListTest.java
@@ -0,0 +1,24 @@
+package org.csploit.msf.module;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+/**
+ * Test unit for PlatformList class
+ */
+public class PlatformListTest {
+
+ @Test
+ public void testIntersect() throws Exception {
+ PlatformList l1, l2, ex;
+
+ l1 = new PlatformList("Windows 98, Solaris V4");
+ l2 = new PlatformList("Windows 98 FE, Solaris");
+ ex = new PlatformList("Windows 98 FE, Solaris V4");
+
+ assertThat(l1.intersect(l2), is(ex));
+ assertThat(l2.intersect(l1), is(ex));
+ }
+}
\ No newline at end of file
diff --git a/msf/src/test/java/org/csploit/msf/module/PlatformTest.java b/msf/src/test/java/org/csploit/msf/module/PlatformTest.java
new file mode 100644
index 0000000000..0735e860e4
--- /dev/null
+++ b/msf/src/test/java/org/csploit/msf/module/PlatformTest.java
@@ -0,0 +1,33 @@
+package org.csploit.msf.module;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.CoreMatchers.*;
+import org.junit.Test;
+
+/**
+ * Test unit for Platform enum
+ */
+public class PlatformTest {
+
+ @Test
+ public void testFromString() throws Exception {
+ assertThat(Platform.fromString("Windows"), is(Platform.WINDOWS));
+ assertThat(Platform.fromString("Windows NT SP3"), is(Platform.WINDOWS_NT_SP3));
+ assertThat(Platform.fromString(null), nullValue());
+ assertThat(Platform.fromString("Unknown"), nullValue());
+ assertThat(Platform.fromString("Unix"), is(Platform.UNIX));
+ }
+
+ @Test
+ public void testSubsetOf() throws Exception {
+ assertThat(Platform.WINDOWS_2000_SP0.subsetOf(Platform.WINDOWS), is(true));
+ assertThat(Platform.WINDOWS.subsetOf(Platform.WINDOWS_2000), is(false));
+ assertThat(Platform.WINDOWS_VISTA_SP0.subsetOf(Platform.WINDOWS_NT_SP0), is(false));
+ assertThat(Platform.UNIX.subsetOf(Platform.AIX), is(false));
+ assertThat(Platform.SOLARIS_V10.subsetOf(Platform.SOLARIS), is(true));
+
+ for(Platform platform : Platform.values()) {
+ assertThat(platform.subsetOf(platform), is(true));
+ }
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 47bb48eb2b..d07762bec5 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':cSploit'
+include ':cSploit', ':msf'