Merge pull request #391 from rsmudge/armitage

add color to armitage's presentation of the Metasploit console
This commit is contained in:
sinn3r 2012-05-16 21:57:43 -07:00
commit a88af1dd36
16 changed files with 344 additions and 71 deletions

Binary file not shown.

View File

@ -1,6 +1,18 @@
Armitage Changelog
==================
17 May 12
---------
- Fixed bug with loot/download viewer breaking with a font resize.
- Default console font color is now grey. I never noticed that I had
white text on a black background before. That's a lot of contrast.
This is adjustable too through Armitage -> Preferences.
- And... the Armitage console now displays pretty colors. If you don't
like colors, set the console.show_colors.boolean preference to false
through Armitage -> Preferences.
- Fixed a bug preventing input field from getting focus when popping a
console tab using Ctrl+W.
14 May 12
---------
- Oopserific--dynamic workspace shortcuts were not bound until you

View File

@ -3,7 +3,7 @@
<center><h1>Armitage 1.44-dev</h1></center>
<p>An attack management tool for Metasploit&reg;
<br />Release: 14 May 12</p>
<br />Release: 17 May 12</p>
<br />
<p>Developed by:</p>

View File

@ -16,7 +16,7 @@ console.page_up.shortcut=pressed PAGE_UP
console.highlight.color=\#0000cc
console.font_size_plus.shortcut=ctrl pressed EQUALS
console.font_size_minus.shortcut=ctrl pressed MINUS
console.foreground.color=\#ffffff
console.foreground.color=\#cccccc
console.background.color=\#000000
console.font.font=Monospaced-BOLD-14
graph.arrange_icons_hierarchical.shortcut=ctrl pressed H
@ -39,10 +39,20 @@ armitage.no_msf_banner.boolean=false
tab.highlight.color=#0000ff
armitage.show_all_commands.boolean=true
armitage.application_title.string=Armitage
console.color_0.color=#000000
console.color_1.color=#ffffff
console.color_2.color=#0000ff
console.color_3.color=#00ff00
console.color_4.color=#ff0000
console.color_5.color=#ffff00
console.color_6.color=#ff00ff
console.color_0.color=\#ffffff
console.color_1.color=\#000000
console.color_2.color=\#000080
console.color_3.color=\#009000
console.color_4.color=\#ff0000
console.color_5.color=\#800000
console.color_6.color=\#a000a0
console.color_7.color=\#ff8000
console.color_8.color=\#ffff00
console.color_9.color=\#00ff00
console.color_10.color=\#009090
console.color_11.color=\#00ffff
console.color_12.color=\#0000ff
console.color_13.color=\#ff00ff
console.color_14.color=\#808080
console.color_15.color=\#c0c0c0
console.show_colors.boolean=true

View File

@ -0,0 +1,4 @@
^(..:..:..) \[\*\] (.*) $1 \cA[*]\o $2
^\[\*\] (.*) \cA[*]\o $1
^(..:..:..) \* (.*) $1 \c7*\o $2
^(\w+)> \u$1\o>

View File

@ -0,0 +1,11 @@
^msf> \umsf\u>
^meterpreter > \umeterpreter\u >
^msf > \umsf\u >
^msf (.*?)\((.*?)\) > \umsf\u $1(\c4$2\o) >
^\[\*\] (.*) \cA[*]\o $1
^\[\+\] (.*) \c9[+]\o $1
^\[\-\] (.*) \c4[-]\o $1
^ =\[ (.*) =[\c7 $1
^(=[=\s]+) \cE$1
^(\s*-[-\s]+) \cE$1
^(.*?): (.*) $1\cE:\o $2

View File

@ -13,6 +13,7 @@ sub createEventLogTab {
if ($client is $null && $console is $null) {
$client = [new ConsoleClient: $null, $mclient, "armitage.poll", "armitage.push", $null, "", $null];
$console = [new ActivityConsole: $preferences];
setupEventStyle($console);
logCheck($console, "all", "events");
[$client setWindow: $console];
[$client setEcho: $null];

View File

@ -76,17 +76,16 @@ sub _postLoot {
local('$host $location $name $type $when');
($host, $location, $name, $type, $when) = $1;
[$2 append: "
[$2 append: "\c9
#
# $host $+ : $name
#
", "3", "#00ff00"];
#\n"];
if ("*binary*" iswm $type) {
[$2 append: "This is a binary file\n", "4", "#ff0000"];
[$2 append: "\c4This is a binary file\n"];
}
else {
[$2 append: getFileContent($location), $null, $null];
[$2 append: getFileContent($location)];
}
}

View File

@ -116,6 +116,7 @@ sub createMeterpreterTab {
# set up a meterpreter console window
$console = [new Console: $preferences];
setupConsoleStyle($console);
logCheck($console, sessionToHost($1), "meterpreter_ $+ $1");
[$console setPopupMenu: lambda(&meterpreterPopup, $session => sessionData($1), $sid => $1)];

View File

@ -69,10 +69,33 @@ sub cleanText {
return tr($1, "\x01\x02", "");
}
sub setupConsoleStyle {
this('$style');
if ($style is $null) {
local('$handle');
$handle = [SleepUtils getIOHandle: resource("resources/msfconsole.style"), $null];
$style = join("\n", readAll($handle));
closef($handle);
}
[$1 setStyle: $style];
}
sub setupEventStyle {
this('$style');
if ($style is $null) {
local('$handle');
$handle = [SleepUtils getIOHandle: resource("resources/eventlog.style"), $null];
$style = join("\n", readAll($handle));
closef($handle);
}
[$1 setStyle: $style];
}
sub createDisplayTab {
local('$console $host $queue $file');
$queue = [new ConsoleQueue: $client];
$console = [new Console: $preferences];
setupConsoleStyle($console);
[$queue setDisplay: $console];
[new QueueTabCompletion: $console, $queue];
logCheck($console, iff($host, $host, "all"), iff($file, $file, strrep($1, " ", "_")));
@ -84,6 +107,7 @@ sub createDisplayTab {
sub createConsolePanel {
local('$console $result $thread $1');
$console = [new Console: $preferences];
setupConsoleStyle($console);
$result = call($client, "console.create");
$thread = [new ConsoleClient: $console, $client, "console.read", "console.write", "console.destroy", $result['id'], $1];

View File

@ -165,19 +165,30 @@ public class ArmitageApplication extends JFrame {
i.remove();
/* pop goes the tab! */
JFrame r = new JFrame(t.title);
final JFrame r = new JFrame(t.title);
r.setIconImages(getIconImages());
r.setLayout(new BorderLayout());
r.add(t.component, BorderLayout.CENTER);
r.pack();
r.setVisible(true);
r.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent ev) {
if (t.removeListener != null)
t.removeListener.actionPerformed(new ActionEvent(ev.getSource(), 0, "close"));
}
public void windowOpened(WindowEvent ev) {
r.setState(JFrame.NORMAL);
t.component.requestFocusInWindow();
}
public void windowActivated(WindowEvent ev) {
t.component.requestFocusInWindow();
}
});
r.setState(JFrame.ICONIFIED);
r.setVisible(true);
}
}
}

View File

@ -6,6 +6,7 @@ import sleep.console.*;
import sleep.bridges.*;
import sleep.error.*;
import sleep.engine.*;
import sleep.parser.ParserConfig;
import java.util.*;
@ -79,6 +80,11 @@ public class ArmitageMain implements RuntimeWarningWatcher, Loadable, Function {
}
public ArmitageMain(String[] args) {
/* tweak the parser to recognize a few useful escapes */
ParserConfig.installEscapeConstant('c', console.Colors.color + "");
ParserConfig.installEscapeConstant('o', console.Colors.cancel + "");
/* setup a function or two */
Hashtable environment = new Hashtable();
environment.put("&resource", this);

View File

@ -0,0 +1,138 @@
package console;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
/* a class for managing and parsing colors */
public class Colors {
public static final char bold = (char)2;
public static final char underline = (char)31;
public static final char color = (char)3;
public static final char cancel = (char)15;
public static final char reverse = (char)22;
private static final class Fragment {
protected SimpleAttributeSet attr = new SimpleAttributeSet();
protected StringBuffer text = new StringBuffer(32);
protected Fragment next = null;
public void advance() {
next = new Fragment();
next.attr = (SimpleAttributeSet)attr.clone();
}
}
protected boolean showcolors = true;
public Colors(java.util.Properties prefs) {
colorTable = new Color[16];
colorTable[0] = Color.white;
colorTable[1] = new Color(0, 0, 0);
colorTable[2] = new Color(0, 0, 128);
colorTable[3] = new Color(0, 144, 0);
colorTable[4] = new Color(255, 0, 0);
colorTable[5] = new Color(128, 0, 0);
colorTable[6] = new Color(160, 0, 160);
colorTable[7] = new Color(255, 128, 0);
colorTable[8] = new Color(255, 255, 0);
colorTable[9] = new Color(0, 255, 0);
colorTable[10] = new Color(0, 144, 144);
colorTable[11] = new Color(0, 255, 255);
colorTable[12] = new Color(0, 0, 255);
colorTable[13] = new Color(255, 0, 255);
colorTable[14] = new Color(128, 128, 128);
colorTable[15] = Color.lightGray;
for (int x = 0; x < 16; x++) {
String temps = prefs.getProperty("console.color_" + x + ".color", null);
//System.err.println("console.color_" + x + ".color=\\#" + Integer.toHexString(colorTable[x].getRGB()).substring(2));
if (temps != null) {
colorTable[x] = Color.decode(temps);
}
}
/* do we want to show colors or automatically strip all of them? */
showcolors = "true".equals(prefs.getProperty("console.show_colors.boolean", "true"));
}
protected Color colorTable[];
/* strip format codes from the text */
public String strip(String text) {
StringBuffer buffer = new StringBuffer(text.length());
Fragment f = parse(text);
while (f != null) {
buffer.append(f.text);
f = f.next;
}
return buffer.toString();
}
public void append(JTextPane console, String text) {
StyledDocument doc = console.getStyledDocument();
Fragment f = parse(text);
while (f != null) {
try {
if (f.text.length() > 0)
doc.insertString(doc.getLength(), f.text.toString(), showcolors ? f.attr : null);
}
catch (Exception ex) {
ex.printStackTrace();
}
f = f.next;
}
}
public void set(JTextPane console, String text) {
console.setText("");
append(console, text);
}
private Fragment parse(String text) {
Fragment current = new Fragment();
Fragment first = current;
char[] data = text.toCharArray();
int fore, back;
for (int x = 0; x < data.length; x++) {
switch (data[x]) {
case bold:
current.advance();
StyleConstants.setBold(current.next.attr, !StyleConstants.isBold(current.attr));
current = current.next;
break;
case underline:
current.advance();
StyleConstants.setUnderline(current.next.attr, !StyleConstants.isUnderline(current.attr));
current = current.next;
break;
case color: /* look for 0-9a-f = 16 colors */
current.advance();
if ((x + 1) < data.length && ((data[x + 1] >= '0' && data[x + 1] <= '9') || (data[x + 1] >= 'A' && data[x + 1] <= 'F'))) {
int index = Integer.parseInt(data[x + 1] + "", 16);
StyleConstants.setForeground(current.next.attr, colorTable[index]);
x += 1;
}
current = current.next;
break;
case '\n':
current.advance();
current = current.next;
current.attr = new SimpleAttributeSet();
current.text.append(data[x]);
break;
case cancel:
current.advance();
current = current.next;
current.attr = new SimpleAttributeSet();
break;
default:
current.text.append(data[x]);
}
}
return first;
}
}

View File

@ -11,19 +11,21 @@ import java.awt.event.*;
import java.io.PrintStream;
import java.util.*;
import java.util.regex.*;
import armitage.Activity;
/** A generic multi-feature console for use in the Armitage network attack tool */
public class Console extends JPanel implements FocusListener {
protected JTextArea console;
protected JTextPane console;
protected JTextField input;
protected JLabel prompt;
protected JTextPane prompt;
protected PrintStream log = null;
protected Properties display;
protected Font consoleFont;
protected Colors colors;
protected ClickListener clickl;
@ -56,7 +58,7 @@ public class Console extends JPanel implements FocusListener {
public ClickListener(Console parent) {
this.parent = parent;
}
public void setPopup(ConsolePopup popup) {
this.popup = popup;
}
@ -120,7 +122,7 @@ public class Console extends JPanel implements FocusListener {
String temp = data.substring(start, end).trim();
int a = temp.indexOf("\n");
if (a > 0) {
return temp.substring(0, a);
return temp.substring(0, a);
}
return temp;
}
@ -139,6 +141,8 @@ public class Console extends JPanel implements FocusListener {
}
private void updateComponentLooks() {
colors = new Colors(display);
Color foreground = Color.decode(display.getProperty("console.foreground.color", "#ffffff"));
Color background = Color.decode(display.getProperty("console.background.color", "#000000"));
@ -146,7 +150,10 @@ public class Console extends JPanel implements FocusListener {
while (i.hasNext()) {
JComponent component = (JComponent)i.next();
component.setForeground(foreground);
component.setBackground(background);
if (component == console || component == prompt)
component.setOpaque(false);
else
component.setBackground(background);
component.setFont(consoleFont);
if (component == console || component == prompt) {
@ -173,11 +180,11 @@ public class Console extends JPanel implements FocusListener {
public void setPrompt(String text) {
String bad = "\ufffd\ufffd";
if (text.equals(bad) || text.equals("null")) {
prompt.setText(defaultPrompt);
colors.set(prompt, fixText(defaultPrompt));
}
else {
defaultPrompt = text;
prompt.setText(text);
colors.set(prompt, fixText(text));
}
}
@ -196,15 +203,64 @@ public class Console extends JPanel implements FocusListener {
}
}
protected void appendToConsole(String _text) {
if (_text.endsWith("\n") || _text.endsWith("\r")) {
if (!promptLock) {
console.append(_text);
if (log != null)
log.print(_text);
private static class Replacements {
public Pattern original;
public String replacer;
public Replacements(String o, String r) {
original = Pattern.compile(o);
replacer = r;
}
}
public void setStyle(String text) {
String lines[] = text.trim().split("\n");
colorme = new Replacements[lines.length];
for (int x = 0; x < lines.length; x++) {
String ab[] = lines[x].split("\\t+");
if (ab.length == 2) {
ab[1] = ab[1].replace("\\c", Colors.color + "");
ab[1] = ab[1].replace("\\o", Colors.cancel + "");
ab[1] = ab[1].replace("\\u", Colors.underline + "");
colorme[x] = new Replacements(ab[0], ab[1]);
}
else {
console.append(prompt.getText());
System.err.println(lines[x] + "<-- didn't split right:" + ab.length);
}
}
}
protected Replacements colorme[] = null;
protected String fixText(String text) {
if (colorme == null)
return text;
StringBuffer result = new StringBuffer();
String[] lines = text.split("(?<=\\n)");
for (int x = 0; x < lines.length; x++) {
String temp = lines[x];
for (int y = 0; y < colorme.length; y++) {
if (colorme[y] != null)
temp = colorme[y].original.matcher(temp).replaceFirst(colorme[y].replacer);
}
result.append(temp);
}
return result.toString();
}
protected void appendToConsole(String _text) {
_text = fixText(_text);
if (_text.endsWith("\n") || _text.endsWith("\r")) {
if (!promptLock) {
colors.append(console, _text);
if (log != null)
log.print(colors.strip(_text));
}
else {
colors.append(console, prompt.getText());
}
if (!_text.startsWith(prompt.getText()))
@ -214,18 +270,17 @@ public class Console extends JPanel implements FocusListener {
int breakp = _text.lastIndexOf("\n");
if (breakp != -1) {
console.append(_text.substring(0, breakp + 1));
prompt.setText(_text.substring(breakp + 1) + " ");
colors.append(console, _text.substring(0, breakp + 1));
colors.set(prompt, _text.substring(breakp + 1) + " ");
if (log != null)
log.print(_text.substring(0, breakp + 1));
log.print(colors.strip(_text.substring(0, breakp + 1)));
}
else {
prompt.setText(_text);
colors.set(prompt, _text);
}
promptLock = true;
}
if (console.getDocument().getLength() >= 1) {
console.setCaretPosition(console.getDocument().getLength() - 1);
}
@ -276,9 +331,9 @@ public class Console extends JPanel implements FocusListener {
/* init the console */
console = new JTextArea();
console = new JTextPane();
console.setEditable(false);
console.setLineWrap(true);
//console.setLineWrap(true);
console.addFocusListener(this);
JScrollPane scroll = new JScrollPane(
@ -290,7 +345,8 @@ public class Console extends JPanel implements FocusListener {
/* init the prompt */
prompt = new JLabel();
prompt = new JTextPane();
prompt.setEditable(false);
/* init the input */
@ -373,6 +429,13 @@ public class Console extends JPanel implements FocusListener {
/* setup our word click listener */
clickl = new ClickListener(this);
console.addMouseListener(clickl);
/* work-around for Nimbus L&F */
Color background = Color.decode(display.getProperty("console.background.color", "#000000"));
console.setBackground(new Color(0,0,0,0));
prompt.setBackground(new Color(0,0,0,0));
scroll.getViewport().setBackground(background);
console.setOpaque(false);
}
public JPopupMenu getPopupMenu(final JTextComponent _component) {

View File

@ -17,18 +17,24 @@ public class Display extends JPanel {
protected JTextPane console;
protected Properties display;
protected Font consoleFont;
protected Colors colors;
protected LinkedList components = new LinkedList();
private void updateComponentLooks() {
colors = new Colors(display);
Color foreground = Color.decode(display.getProperty("console.foreground.color", "#ffffff"));
Color background = Color.decode(display.getProperty("console.background.color", "#000000"));
Iterator i = components.iterator();
while (i.hasNext()) {
JComponent component = (JComponent)i.next();
if (component == console)
component.setOpaque(false);
else
component.setBackground(background);
component.setForeground(foreground);
component.setBackground(background);
component.setFont(consoleFont);
if (component == console) {
@ -45,48 +51,23 @@ public class Display extends JPanel {
}
}
private static Map colors = new HashMap();
public static AttributeSet getColor(String index, Properties preferences, String def) {
synchronized (colors) {
if (colors.get(index) == null) {
SimpleAttributeSet attrs = new SimpleAttributeSet();
Color temp = Color.decode(preferences.getProperty("console.color_" + index + ".color", def));
StyleConstants.setForeground(attrs, temp);
colors.put(index, attrs);
}
return (SimpleAttributeSet)colors.get(index);
}
}
public void append(final String text, final String index, final String fg) {
public void append(final String text) {
if (SwingUtilities.isEventDispatchThread()) {
_append(text, index, fg);
_append(text);
}
else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
_append(text, index, fg);
_append(text);
}
});
}
}
public void _append(String text, String index, String foreground) {
try {
Rectangle r = console.getVisibleRect();
StyledDocument doc = console.getStyledDocument();
if (foreground == null) {
doc.insertString(doc.getLength(), text, null);
}
else {
doc.insertString(doc.getLength(), text, getColor(index, display, foreground));
}
console.scrollRectToVisible(r);
}
catch(Exception e) {
System.out.println(e);
}
public void _append(String text) {
Rectangle r = console.getVisibleRect();
colors.append(console, text);
console.scrollRectToVisible(r);
}
public void setText(final String _text) {

View File

@ -1,6 +1,18 @@
Armitage Changelog
==================
17 May 12
---------
- Fixed bug with loot/download viewer breaking with a font resize.
- Default console font color is now grey. I never noticed that I had
white text on a black background before. That's a lot of contrast.
This is adjustable too through Armitage -> Preferences.
- And... the Armitage console now displays pretty colors. If you don't
like colors, set the console.show_colors.boolean preference to false
through Armitage -> Preferences.
- Fixed a bug preventing input field from getting focus when popping a
console tab using Ctrl+W.
14 May 12
---------
- Oopserific--dynamic workspace shortcuts were not bound until you