updating with r7-msf

unstable
Royce Davis 2013-03-10 14:19:20 -05:00
commit 907983db4a
420 changed files with 2970 additions and 1136 deletions

7
.yardopts Normal file
View File

@ -0,0 +1,7 @@
--protected
--exclude samples/
--exclude \.ut\.rb/
--exclude \.ts\.rb/
--files CONTRIBUTING.md,COPYING,HACKING,LICENSE
lib/msf/**/*.rb
lib/rex/**/*.rb

View File

@ -7,7 +7,7 @@ gem 'activerecord'
# Needed for some admin modules (scrutinizer_add_user.rb)
gem 'json'
# Database models shared between framework and Pro.
gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.6.0'
gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.6.2'
# Needed by msfgui and other rpc components
gem 'msgpack'
# Needed by anemone crawler

View File

@ -1,9 +1,9 @@
GIT
remote: git://github.com/rapid7/metasploit_data_models.git
revision: 0285d6e199f125b33214100dcb0f4eeb12ee765f
tag: 0.6.0
revision: 67d78f9ce59a74ad9d6e8d3f9e68760ff4d2ec55
tag: 0.6.2
specs:
metasploit_data_models (0.6.0)
metasploit_data_models (0.6.2)
activerecord (>= 3.2.10)
activesupport
pg

View File

@ -1,52 +1,49 @@
require 'bundler/setup'
require 'rspec/core/rake_task'
require 'yard'
require 'metasploit_data_models'
print_without = false
begin
require 'rspec/core/rake_task'
rescue LoadError
puts "rspec not in bundle, so can't set up spec tasks. " \
"To run specs ensure to install the development and test groups."
print_without = true
else
RSpec::Core::RakeTask.new(:spec)
task :default => :spec
namespace :yard do
yard_files = [
# Ruby source files first
'lib/msf/**/*.rb',
'lib/rex/**/*.rb',
# Anything after '-' is a normal documentation, not source
'-',
'COPYING',
'HACKING',
'LICENSE',
'CONTRIBUTING.md',
]
yard_options = [
# include documentation for protected methods for developers extending the code.
'--protected',
# Don't bother with files meant to be examples
'--exclude', 'samples/',
'--exclude', '\.ut\.rb/',
'--exclude', '\.ts\.rb/',
]
YARD::Rake::YardocTask.new(:doc) do |t|
t.files = yard_files
# --no-stats here as 'stats' task called after will print fuller stats
t.options = yard_options + ['--no-stats']
t.after = Proc.new {
Rake::Task['yard:stats'].execute
}
end
desc "Shows stats for YARD Documentation including listing undocumented modules, classes, constants, and methods"
task :stats => :environment do
stats = YARD::CLI::Stats.new
yard_arguments = yard_options + ['--compact', '--list-undoc'] + yard_files
stats.run(*yard_arguments)
end
begin
require 'yard'
rescue LoadError
puts "yard not in bundle, so can't set up yard tasks. " \
"To generate documentation ensure to install the development group."
print_without = true
end
# @todo Figure out how to just clone description from yard:doc
desc "Generate YARD documentation"
# allow calling namespace to as a task that goes to default task for namespace
task :yard => ['yard:doc']
metasploit_data_models_task_glob = MetasploitDataModels.root.join(
'lib',
'tasks',
'**',
'*.rake'
).to_s
# include tasks from metasplioit_data_models, such as `rake yard`.
# metasploit-framework specific yard options are in .yardopts
Dir.glob(metasploit_data_models_task_glob) do |path|
load path
end
if print_without
puts "Bundle currently installed " \
"'--without #{Bundler.settings.without.join(' ')}'."
puts "To clear the without option do `bundle install --without ''` " \
"(the --without flag with an empty string) or " \
"`rm -rf .bundle` to remove the .bundle/config manually and " \
"then `bundle install`"
end

Binary file not shown.

Binary file not shown.

View File

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

View File

@ -1,12 +0,0 @@
source 'http://rubygems.org'
gem 'rails', '3.2.2'
gem 'authlogic'
gem 'prototype_legacy_helper', '0.0.0', :git => 'git://github.com/jvennix-r7/prototype_legacy_helper.git'
gem 'state_machine', '1.1.2'
gem 'liquid', '2.3.0'
gem 'ice_cube'
gem 'acts_as_list'
gem 'mime-types', '1.18', :git => "git://github.com/rapid7/mime-types.git"
gem 'metasploit_data_models', '0.0.2', :git => "git://github.com/rapid7/metasploit_data_models.git"
gem 'robots', '0.10.1'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,34 +0,0 @@
#!/usr/bin/env rake
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
load 'rails/tasks/engine.rake'
Bundler::GemHelper.install_tasks
#
# load rake files like a normal rails app
# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl
#
pathname = Pathname.new(__FILE__)
root = pathname.parent
rakefile_glob = root.join('lib', 'tasks', '**', '*.rake').to_path
Dir.glob(rakefile_glob) do |rakefile|
load rakefile
end
require 'rspec/core'
require 'rspec/core/rake_task'
# Depend on app:db:test:prepare so that test database is recreated just like in a full rails app
# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
task :default => :spec

View File

@ -1,14 +0,0 @@
require 'rails'
module MetasploitDataModels
class Engine < Rails::Engine
# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl
config.generators do |g|
g.assets false
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
g.helper false
g.test_framework :rspec, :fixture => false
end
end
end

View File

@ -1,27 +0,0 @@
# @note All options not specific to any given rake task should go in the .yardopts file so they are available to both
# the below rake tasks and when invoking `yard` from the command line
require 'yard'
require 'yard/rake/yardoc_task'
namespace :yard do
YARD::Rake::YardocTask.new(:doc) do |t|
# --no-stats here as 'stats' task called after will print fuller stats
t.options = ['--no-stats']
t.after = Proc.new {
Rake::Task['yard:stats'].execute
}
end
desc "Shows stats for YARD Documentation including listing undocumented modules, classes, constants, and methods"
task :stats => :environment do
stats = YARD::CLI::Stats.new
stats.run('--compact', '--list-undoc')
end
end
# @todo Figure out how to just clone description from yard:doc
desc "Generate YARD documentation"
# allow calling namespace to as a task that goes to default task for namespace
task :yard => ['yard:doc']

View File

@ -0,0 +1,53 @@
#!/usr/bin/env rake
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
print_without = false
APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
begin
load 'rails/tasks/engine.rake'
rescue LoadError
puts "railties not in bundle, so can't load engine tasks."
print_without = true
end
Bundler::GemHelper.install_tasks
#
# load rake files like a normal rails app
# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl
#
pathname = Pathname.new(__FILE__)
root = pathname.parent
rakefile_glob = root.join('lib', 'tasks', '**', '*.rake').to_path
Dir.glob(rakefile_glob) do |rakefile|
load rakefile
end
begin
require 'rspec/core'
rescue LoadError
puts "rspec not in bundle, so can't set up spec tasks. " \
"To run specs ensure to install the development and test groups."
print_without = true
else
require 'rspec/core/rake_task'
# Depend on app:db:test:prepare so that test database is recreated just like in a full rails app
# @see http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
task :default => :spec
end
if print_without
puts "Bundle currently installed '--without #{Bundler.settings.without.join(' ')}'."
puts "To clear the without option do `bundle install --without ''` (the --without flag with an empty string) or " \
"`rm -rf .bundle` to remove the .bundle/config manually and then `bundle install`"
end

View File

@ -15,9 +15,8 @@ class Mdm::WebVuln < ActiveRecord::Base
# CONSTANTS
#
# A percentage {#confidence} that the vulnerability is real and not a false positive. 0 is not allowed because there
# shouldn't be an {Mdm::WebVuln} record if there is 0% {#confidence} in the the finding.
CONFIDENCE_RANGE = 1 .. 100
# A percentage {#confidence} that the vulnerability is real and not a false positive.
CONFIDENCE_RANGE = 0 .. 100
# Default value for {#params}
DEFAULT_PARAMS = []

Some files were not shown because too many files have changed in this diff Show More