Add postgres acceptance tests
This commit is contained in:
parent
97ef5cf827
commit
e7bc17cab3
|
@ -155,7 +155,7 @@ jobs:
|
||||||
# Note: rspec retry is intentionally not used, as it can cause issues with allure's reporting
|
# Note: rspec retry is intentionally not used, as it can cause issues with allure's reporting
|
||||||
# Additionally - flakey tests should be fixed or marked as flakey instead of silently retried
|
# Additionally - flakey tests should be fixed or marked as flakey instead of silently retried
|
||||||
run: |
|
run: |
|
||||||
bundle exec rspec spec/acceptance/
|
bundle exec rspec spec/acceptance/meterpreter_spec.rb
|
||||||
|
|
||||||
- name: Archive results
|
- name: Archive results
|
||||||
if: always()
|
if: always()
|
||||||
|
@ -188,7 +188,7 @@ jobs:
|
||||||
BUNDLE_FORCE_RUBY_PLATFORM: true
|
BUNDLE_FORCE_RUBY_PLATFORM: true
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.0.2
|
ruby-version: '${{ matrix.ruby }}'
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
cache-version: 4
|
cache-version: 4
|
||||||
# Github actions with Ruby requires Bundler 2.2.18+
|
# Github actions with Ruby requires Bundler 2.2.18+
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
name: Acceptance
|
||||||
|
|
||||||
|
# Optional, enabling concurrency limits: https://docs.github.com/en/actions/using-jobs/using-concurrency
|
||||||
|
#concurrency:
|
||||||
|
# group: ${{ github.ref }}-${{ github.workflow }}
|
||||||
|
# cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||||
|
|
||||||
|
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||||
|
permissions:
|
||||||
|
actions: none
|
||||||
|
checks: none
|
||||||
|
contents: none
|
||||||
|
deployments: none
|
||||||
|
id-token: none
|
||||||
|
issues: none
|
||||||
|
discussions: none
|
||||||
|
packages: none
|
||||||
|
pages: none
|
||||||
|
pull-requests: none
|
||||||
|
repository-projects: none
|
||||||
|
security-events: none
|
||||||
|
statuses: none
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches-ignore:
|
||||||
|
- gh-pages
|
||||||
|
- metakitty
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
paths:
|
||||||
|
- 'metsploit-framework.gemspec'
|
||||||
|
- 'Gemfile.lock'
|
||||||
|
- '**/**postgres**'
|
||||||
|
- 'spec/acceptance/**'
|
||||||
|
- 'spec/support/acceptance/**'
|
||||||
|
- 'spec/acceptance_spec_helper.rb'
|
||||||
|
# Example of running as a cron, to weed out flaky tests
|
||||||
|
# schedule:
|
||||||
|
# - cron: '*/15 * * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
postgres:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 40
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: ${{ matrix.docker_image }}
|
||||||
|
ports: ["5432:5432"]
|
||||||
|
env:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: password
|
||||||
|
options: >-
|
||||||
|
--health-cmd pg_isready
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
ruby:
|
||||||
|
- '3.2'
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
docker_image:
|
||||||
|
- postgres:9.4
|
||||||
|
- postgres:16.2
|
||||||
|
|
||||||
|
env:
|
||||||
|
RAILS_ENV: test
|
||||||
|
|
||||||
|
name: ${{ matrix.docker_image }} - ${{ matrix.os }} - Ruby ${{ matrix.ruby }}
|
||||||
|
steps:
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: sudo apt-get install -y --no-install-recommends libpcap-dev graphviz
|
||||||
|
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Ruby
|
||||||
|
env:
|
||||||
|
BUNDLE_WITHOUT: "coverage development pcap"
|
||||||
|
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||||
|
BUNDLE_FORCE_RUBY_PLATFORM: "${{ contains(matrix.ruby, 'preview') && 'true' || 'false' }}"
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: '${{ matrix.ruby }}'
|
||||||
|
bundler-cache: true
|
||||||
|
|
||||||
|
- name: Extract runtime version
|
||||||
|
run: |
|
||||||
|
echo "RUNTIME_VERSION=$(echo $DOCKER_IMAGE | awk -F: '{ print $2 }')" >> $GITHUB_ENV
|
||||||
|
echo "DOCKER_IMAGE_FILENAME=$(echo $DOCKER_IMAGE | tr -d ':')" >> $GITHUB_ENV
|
||||||
|
env:
|
||||||
|
DOCKER_IMAGE: ${{ matrix.docker_image }}
|
||||||
|
OS: ${{ matrix.os }}
|
||||||
|
|
||||||
|
- name: acceptance
|
||||||
|
env:
|
||||||
|
SPEC_HELPER_LOAD_METASPLOIT: false
|
||||||
|
SPEC_OPTS: "--tag acceptance --require acceptance_spec_helper.rb --color --format documentation --format AllureRspec::RSpecFormatter"
|
||||||
|
RUNTIME_VERSION: ${{ env.RUNTIME_VERSION }}
|
||||||
|
# Unix run command:
|
||||||
|
# SPEC_HELPER_LOAD_METASPLOIT=false bundle exec ./spec/acceptance
|
||||||
|
# Windows cmd command:
|
||||||
|
# set SPEC_HELPER_LOAD_METASPLOIT=false
|
||||||
|
# bundle exec rspec .\spec\acceptance
|
||||||
|
# Note: rspec retry is intentionally not used, as it can cause issues with allure's reporting
|
||||||
|
# Additionally - flakey tests should be fixed or marked as flakey instead of silently retried
|
||||||
|
run: |
|
||||||
|
bundle exec rspec spec/acceptance/postgres_spec.rb
|
||||||
|
|
||||||
|
- name: Archive results
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
# Provide a unique artifact for each matrix os, otherwise race conditions can lead to corrupt zips
|
||||||
|
name: ${{ env.DOCKER_IMAGE_FILENAME }}-${{ matrix.os }}
|
||||||
|
path: tmp/allure-raw-data
|
||||||
|
|
||||||
|
# Generate a final report from the previous test results
|
||||||
|
report:
|
||||||
|
name: Generate report
|
||||||
|
needs:
|
||||||
|
- postgres
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: always()
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
if: always()
|
||||||
|
|
||||||
|
- name: Install system dependencies (Linux)
|
||||||
|
if: always()
|
||||||
|
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||||
|
|
||||||
|
- name: Setup Ruby
|
||||||
|
if: always()
|
||||||
|
env:
|
||||||
|
BUNDLE_WITHOUT: "coverage development"
|
||||||
|
BUNDLE_FORCE_RUBY_PLATFORM: true
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: '${{ matrix.ruby }}'
|
||||||
|
bundler-cache: true
|
||||||
|
cache-version: 4
|
||||||
|
# Github actions with Ruby requires Bundler 2.2.18+
|
||||||
|
# https://github.com/ruby/setup-ruby/tree/d2b39ad0b52eca07d23f3aa14fdf2a3fcc1f411c#windows
|
||||||
|
bundler: 2.2.33
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
id: download
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
# Note: Not specifying a name will download all artifacts from the previous workflow jobs
|
||||||
|
path: raw-data
|
||||||
|
|
||||||
|
- name: allure generate
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
export VERSION=2.22.1
|
||||||
|
|
||||||
|
curl -o allure-$VERSION.tgz -Ls https://github.com/allure-framework/allure2/releases/download/$VERSION/allure-$VERSION.tgz
|
||||||
|
tar -zxvf allure-$VERSION.tgz -C .
|
||||||
|
|
||||||
|
ls -la ${{steps.download.outputs.download-path}}
|
||||||
|
./allure-$VERSION/bin/allure generate ${{steps.download.outputs.download-path}}/* -o ./allure-report
|
||||||
|
|
||||||
|
find ${{steps.download.outputs.download-path}}
|
||||||
|
bundle exec ruby tools/dev/report_generation/support_matrix/generate.rb --allure-data ${{steps.download.outputs.download-path}} > ./allure-report/support_matrix.html
|
||||||
|
|
||||||
|
- name: archive results
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: final-report-${{ github.run_id }}
|
||||||
|
path: |
|
||||||
|
./allure-report
|
|
@ -212,7 +212,7 @@ module Msf
|
||||||
if s.platform.blank?
|
if s.platform.blank?
|
||||||
issues << "Unknown session platform. This module works with: #{platform.names.join(', ')}."
|
issues << "Unknown session platform. This module works with: #{platform.names.join(', ')}."
|
||||||
elsif !platform.supports?(Msf::Module::PlatformList.transform(s.platform))
|
elsif !platform.supports?(Msf::Module::PlatformList.transform(s.platform))
|
||||||
issues << "incompatible session platform: #{s.platform}. This module works with: #{platform.names.join(', ')}."
|
issues << "incompatible session platform: #{s.platform}. This module works with: #{platform ? platform.names.join(', ') : platform.inspect}."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ create handlers, etc.
|
||||||
The test suite runs on the current host, so the Meterpreter runtimes should be available.
|
The test suite runs on the current host, so the Meterpreter runtimes should be available.
|
||||||
There is no remote host support currently.
|
There is no remote host support currently.
|
||||||
|
|
||||||
### Examples
|
### Meterpreter
|
||||||
|
|
||||||
Useful environment variables:
|
Useful environment variables:
|
||||||
- `METERPRETER` - Filter the test suite for specific Meterpreter instances, example: `METERPRETER=java`
|
- `METERPRETER` - Filter the test suite for specific Meterpreter instances, example: `METERPRETER=java`
|
||||||
|
@ -33,6 +33,20 @@ SPEC_OPTS='--tag acceptance' METERPRETER=php METERPRETER_MODULE_TEST=test/unix b
|
||||||
$env:SPEC_OPTS='--tag acceptance'; $env:SPEC_HELPER_LOAD_METASPLOIT=$false; $env:METERPRETER = 'php'; bundle exec rspec './spec/acceptance/meterpreter_spec.rb'
|
$env:SPEC_OPTS='--tag acceptance'; $env:SPEC_HELPER_LOAD_METASPLOIT=$false; $env:METERPRETER = 'php'; bundle exec rspec './spec/acceptance/meterpreter_spec.rb'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Postgres
|
||||||
|
|
||||||
|
Run a target:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -it --rm --publish 127.0.0.1:9000:5432 -e POSTGRES_PASSWORD=password postgres:14
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the test suite:
|
||||||
|
|
||||||
|
```
|
||||||
|
POSTGRES_RPORT=9000 SPEC_HELPER_LOAD_METASPLOIT=false bundle exec rspec ./spec/acceptance/postgres_spec.rb
|
||||||
|
```
|
||||||
|
|
||||||
#### Allure reports
|
#### Allure reports
|
||||||
|
|
||||||
Generate allure reports locally:
|
Generate allure reports locally:
|
||||||
|
|
|
@ -0,0 +1,373 @@
|
||||||
|
require 'acceptance_spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Postgres sessions and postgres modules' do
|
||||||
|
include_context 'wait_for_expect'
|
||||||
|
|
||||||
|
TESTS = {
|
||||||
|
postgres: {
|
||||||
|
target: {
|
||||||
|
session_module: "auxiliary/scanner/postgres/postgres_login",
|
||||||
|
type: 'PostgreSQL',
|
||||||
|
platforms: [:linux, :osx, :windows],
|
||||||
|
datastore: {
|
||||||
|
global: {},
|
||||||
|
module: {
|
||||||
|
username: ENV.fetch('POSTGRES_USERNAME', 'postgres'),
|
||||||
|
password: ENV.fetch('POSTGRES_PASSWORD', 'password'),
|
||||||
|
rhost: ENV.fetch('POSTGRES_RHOST', '127.0.0.1'),
|
||||||
|
rport: ENV.fetch('POSTGRES_RPORT', '5432'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
module_tests: [
|
||||||
|
{
|
||||||
|
name: "post/test/postgres",
|
||||||
|
platforms: [:linux, :osx, :windows],
|
||||||
|
targets: [:session],
|
||||||
|
skipped: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "auxiliary/scanner/postgres/postgres_hashdump",
|
||||||
|
platforms: [:linux, :osx, :windows],
|
||||||
|
targets: [:session, :rhost],
|
||||||
|
skipped: false,
|
||||||
|
lines: {
|
||||||
|
all: {
|
||||||
|
required: [
|
||||||
|
" Username Hash",
|
||||||
|
" -------- ----",
|
||||||
|
# postgres SCRAM-SHA-256$4096:UfTJGaMUW+DtXay1UUD+zA==$0C01mPHaruGTqKJFt5qdITvM+nwLsCgxukO3MIbKugU=:iNBXVE5Vqnoa+dGhmEGMQ0cy+nNXDOzg0F3YNcrtRyE=
|
||||||
|
/ postgres \w+/
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "auxiliary/scanner/postgres/postgres_version",
|
||||||
|
platforms: [:linux, :osx, :windows],
|
||||||
|
targets: [:session, :rhost],
|
||||||
|
skipped: false,
|
||||||
|
lines: {
|
||||||
|
all: {
|
||||||
|
required: [
|
||||||
|
/Version PostgreSQL \d+.\d+/
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "auxiliary/admin/postgres/postgres_readfile",
|
||||||
|
platforms: [:linux],
|
||||||
|
targets: [:session, :rhost],
|
||||||
|
skipped: false,
|
||||||
|
lines: {
|
||||||
|
all: {
|
||||||
|
# Module reads /etc/passwd by default:
|
||||||
|
required: [
|
||||||
|
/root:x:\d+:\d+:root:/,
|
||||||
|
/postgres:x:\d+:\d+::/
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "auxiliary/admin/postgres/postgres_sql",
|
||||||
|
platforms: [:linux, :osx, :windows],
|
||||||
|
targets: [:session, :rhost],
|
||||||
|
skipped: false,
|
||||||
|
lines: {
|
||||||
|
all: {
|
||||||
|
required: [
|
||||||
|
# Default module query
|
||||||
|
"Query Text: 'select version()'",
|
||||||
|
# Result
|
||||||
|
/PostgreSQL \d+.\d+/,
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ENVIRONMENT = AllureRspec.configuration.environment_properties
|
||||||
|
|
||||||
|
let_it_be(:current_platform) { Acceptance::Meterpreter::current_platform }
|
||||||
|
|
||||||
|
# Driver instance, keeps track of all open processes/payloads/etc, so they can be closed cleanly
|
||||||
|
let_it_be(:driver) do
|
||||||
|
driver = Acceptance::ConsoleDriver.new
|
||||||
|
driver
|
||||||
|
end
|
||||||
|
|
||||||
|
# Opens a test console with the test loadpath specified
|
||||||
|
# @!attribute [r] console
|
||||||
|
# @return [Acceptance::Console]
|
||||||
|
let_it_be(:console) do
|
||||||
|
console = driver.open_console
|
||||||
|
|
||||||
|
# Load the test modules
|
||||||
|
console.sendline('loadpath test/modules')
|
||||||
|
console.recvuntil(/Loaded \d+ modules:[^\n]*\n/)
|
||||||
|
console.recvuntil(/\d+ auxiliary modules[^\n]*\n/)
|
||||||
|
console.recvuntil(/\d+ exploit modules[^\n]*\n/)
|
||||||
|
console.recvuntil(/\d+ post modules[^\n]*\n/)
|
||||||
|
console.recvuntil(Acceptance::Console.prompt)
|
||||||
|
|
||||||
|
# Read the remaining console
|
||||||
|
# console.sendline "quit -y"
|
||||||
|
# console.recv_available
|
||||||
|
|
||||||
|
features = %w[
|
||||||
|
postgresql_session_type
|
||||||
|
]
|
||||||
|
|
||||||
|
features.each do |feature|
|
||||||
|
console.sendline("features set #{feature} true")
|
||||||
|
console.recvuntil(Acceptance::Console.prompt)
|
||||||
|
end
|
||||||
|
|
||||||
|
console
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run the given block in a 'test harness' which will handle all of the boilerplate for asserting module results, cleanup, and artifact tracking
|
||||||
|
# This doesn't happen in a before/after block to ensure that allure's report generation is correctly attached to the correct test scope
|
||||||
|
def with_test_harness(module_test)
|
||||||
|
begin
|
||||||
|
replication_commands = []
|
||||||
|
|
||||||
|
known_failures = module_test.dig(:lines, :all, :known_failures) || []
|
||||||
|
known_failures += module_test.dig(:lines, current_platform, :known_failures) || []
|
||||||
|
known_failures = known_failures.flat_map { |value| Acceptance::LineValidation.new(*Array(value)).flatten }
|
||||||
|
|
||||||
|
required_lines = module_test.dig(:lines, :all, :required) || []
|
||||||
|
required_lines += module_test.dig(:lines, current_platform, :required) || []
|
||||||
|
required_lines = required_lines.flat_map { |value| Acceptance::LineValidation.new(*Array(value)).flatten }
|
||||||
|
|
||||||
|
yield replication_commands
|
||||||
|
|
||||||
|
# XXX: When debugging failed tests, you can enter into an interactive msfconsole prompt with:
|
||||||
|
# console.interact
|
||||||
|
|
||||||
|
# Expect the test module to complete
|
||||||
|
module_type = module_test[:name].split('/').first
|
||||||
|
test_result = console.recvuntil("#{module_type.capitalize} module execution completed")
|
||||||
|
|
||||||
|
# Ensure there are no failures, and assert tests are complete
|
||||||
|
aggregate_failures("#{target.type} target and passes the #{module_test[:name].inspect} tests") do
|
||||||
|
# Skip any ignored lines from the validation input
|
||||||
|
validated_lines = test_result.lines.reject do |line|
|
||||||
|
is_acceptable = known_failures.any? do |acceptable_failure|
|
||||||
|
is_matching_line = is_matching_line.value.is_a?(Regexp) ? line.match?(acceptable_failure.value) : line.include?(acceptable_failure.value)
|
||||||
|
is_matching_line &&
|
||||||
|
acceptable_failure.if?(test_environment)
|
||||||
|
end || line.match?(/Passed: \d+; Failed: \d+/)
|
||||||
|
|
||||||
|
is_acceptable
|
||||||
|
end
|
||||||
|
|
||||||
|
validated_lines.each do |test_line|
|
||||||
|
test_line = Acceptance::Meterpreter.uncolorize(test_line)
|
||||||
|
expect(test_line).to_not include('FAILED', '[-] FAILED', '[-] Exception', '[-] '), "Unexpected error: #{test_line}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Assert all expected lines are present
|
||||||
|
required_lines.each do |required|
|
||||||
|
next unless required.if?(test_environment)
|
||||||
|
if required.value.is_a?(Regexp)
|
||||||
|
expect(test_result).to match(required.value)
|
||||||
|
else
|
||||||
|
expect(test_result).to include(required.value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Assert all ignored lines are present, if they are not present - they should be removed from
|
||||||
|
# the calling config
|
||||||
|
known_failures.each do |acceptable_failure|
|
||||||
|
next if acceptable_failure.flaky?(test_environment)
|
||||||
|
next unless acceptable_failure.if?(test_environment)
|
||||||
|
|
||||||
|
expect(test_result).to include(acceptable_failure.value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue RSpec::Expectations::ExpectationNotMetError, StandardError => e
|
||||||
|
test_run_error = e
|
||||||
|
end
|
||||||
|
|
||||||
|
# Test cleanup. We intentionally omit cleanup from an `after(:each)` to ensure the allure attachments are
|
||||||
|
# still generated if the session dies in a weird way etc
|
||||||
|
|
||||||
|
console_reset_error = nil
|
||||||
|
current_console_data = console.all_data
|
||||||
|
begin
|
||||||
|
console.reset
|
||||||
|
rescue => e
|
||||||
|
console_reset_error = e
|
||||||
|
Allure.add_attachment(
|
||||||
|
name: 'console.reset failure information',
|
||||||
|
source: "Error: #{e.class} - #{e.message}\n#{(e.backtrace || []).join("\n")}",
|
||||||
|
type: Allure::ContentType::TXT
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
target_configuration_details = target.as_readable_text(
|
||||||
|
default_global_datastore: default_global_datastore,
|
||||||
|
default_module_datastore: default_module_datastore
|
||||||
|
)
|
||||||
|
|
||||||
|
replication_steps = <<~EOF
|
||||||
|
## Load test modules
|
||||||
|
loadpath test/modules
|
||||||
|
|
||||||
|
#{target_configuration_details}
|
||||||
|
|
||||||
|
## Replication commands
|
||||||
|
#{replication_commands.empty? ? 'no additional commands run' : replication_commands.join("\n")}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
Allure.add_attachment(
|
||||||
|
name: 'payload configuration and replication',
|
||||||
|
source: replication_steps,
|
||||||
|
type: Allure::ContentType::TXT
|
||||||
|
)
|
||||||
|
|
||||||
|
Allure.add_attachment(
|
||||||
|
name: 'console data',
|
||||||
|
source: current_console_data,
|
||||||
|
type: Allure::ContentType::TXT
|
||||||
|
)
|
||||||
|
|
||||||
|
test_assertions = JSON.pretty_generate(
|
||||||
|
{
|
||||||
|
required_lines: required_lines.map(&:to_h),
|
||||||
|
known_failures: known_failures.map(&:to_h),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Allure.add_attachment(
|
||||||
|
name: 'test assertions',
|
||||||
|
source: test_assertions,
|
||||||
|
type: Allure::ContentType::TXT
|
||||||
|
)
|
||||||
|
|
||||||
|
raise test_run_error if test_run_error
|
||||||
|
raise console_reset_error if console_reset_error
|
||||||
|
end
|
||||||
|
|
||||||
|
TESTS.each do |runtime_name, test_config|
|
||||||
|
runtime_name = "#{runtime_name}#{ENV.fetch('RUNTIME_VERSION', '')}"
|
||||||
|
|
||||||
|
describe "#{Acceptance::Meterpreter.current_platform}/#{runtime_name}", focus: test_config[:focus] do
|
||||||
|
test_config[:module_tests].each do |module_test|
|
||||||
|
describe(
|
||||||
|
module_test[:name],
|
||||||
|
if: (
|
||||||
|
Acceptance::Meterpreter.supported_platform?(module_test)
|
||||||
|
)
|
||||||
|
) do
|
||||||
|
let(:target) { Acceptance::Target.new(test_config[:target]) }
|
||||||
|
|
||||||
|
let(:default_global_datastore) do
|
||||||
|
{
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:test_environment) { TEST_ENVIRONMENT }
|
||||||
|
|
||||||
|
let(:default_module_datastore) do
|
||||||
|
{
|
||||||
|
lhost: '127.0.0.1'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# The shared session id that will be reused across the test run
|
||||||
|
let(:session_id) do
|
||||||
|
console.sendline "use #{target.session_module}"
|
||||||
|
console.recvuntil(Acceptance::Console.prompt)
|
||||||
|
|
||||||
|
# Set global options
|
||||||
|
console.sendline target.setg_commands(default_global_datastore: default_global_datastore)
|
||||||
|
console.recvuntil(Acceptance::Console.prompt)
|
||||||
|
|
||||||
|
console.sendline target.run_command(default_module_datastore: { PASS_FILE: nil, USER_FILE: nil, CreateSession: true })
|
||||||
|
|
||||||
|
session_id = nil
|
||||||
|
# Wait for the session to open, or break early if the payload is detected as dead
|
||||||
|
wait_for_expect do
|
||||||
|
session_opened_matcher = /#{target.type} session (\d+) opened[^\n]*\n/
|
||||||
|
session_message = ''
|
||||||
|
begin
|
||||||
|
session_message = console.recvuntil(session_opened_matcher, timeout: 1)
|
||||||
|
rescue Acceptance::ChildProcessRecvError
|
||||||
|
# noop
|
||||||
|
end
|
||||||
|
|
||||||
|
session_id = session_message[session_opened_matcher, 1]
|
||||||
|
expect(session_id).to_not be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
session_id
|
||||||
|
end
|
||||||
|
|
||||||
|
before :each do |example|
|
||||||
|
next unless example.respond_to?(:parameter)
|
||||||
|
|
||||||
|
# Add the test environment metadata to the rspec example instance - so it appears in the final allure report UI
|
||||||
|
test_environment.each do |key, value|
|
||||||
|
example.parameter(key, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
after :all do
|
||||||
|
driver.close_payloads
|
||||||
|
console.reset
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when targeting a session", if: module_test[:targets].include?(:session) do
|
||||||
|
it(
|
||||||
|
"#{Acceptance::Meterpreter.current_platform}/#{runtime_name} session opens and passes the #{module_test[:name].inspect} tests"
|
||||||
|
) do
|
||||||
|
with_test_harness(module_test) do |replication_commands|
|
||||||
|
# Ensure we have a valid session id; We intentionally omit this from a `before(:each)` to ensure the allure attachments are generated if the session dies
|
||||||
|
expect(session_id).to_not(be_nil, proc do
|
||||||
|
"There should be a session present"
|
||||||
|
end)
|
||||||
|
|
||||||
|
use_module = "use #{module_test[:name]}"
|
||||||
|
run_module = "run session=#{session_id} Verbose=true"
|
||||||
|
|
||||||
|
replication_commands << use_module
|
||||||
|
console.sendline(use_module)
|
||||||
|
console.recvuntil(Acceptance::Console.prompt)
|
||||||
|
|
||||||
|
replication_commands << run_module
|
||||||
|
console.sendline(run_module)
|
||||||
|
|
||||||
|
# Assertions will happen after this block ends
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when targeting an rhost", if: module_test[:targets].include?(:rhost) do
|
||||||
|
it(
|
||||||
|
"#{Acceptance::Meterpreter.current_platform}/#{runtime_name} rhost opens and passes the #{module_test[:name].inspect} tests"
|
||||||
|
) do
|
||||||
|
with_test_harness(module_test) do |replication_commands|
|
||||||
|
use_module = "use #{module_test[:name]}"
|
||||||
|
run_module = "run #{target.datastore_options(default_module_datastore: default_module_datastore)} Verbose=true"
|
||||||
|
|
||||||
|
replication_commands << use_module
|
||||||
|
console.sendline(use_module)
|
||||||
|
console.recvuntil(Acceptance::Console.prompt)
|
||||||
|
|
||||||
|
replication_commands << run_module
|
||||||
|
console.sendline(run_module)
|
||||||
|
|
||||||
|
# Assertions will happen after this block ends
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -21,6 +21,7 @@ AllureRspec.configure do |config|
|
||||||
environment_properties[:meterpreter_runtime_version] = "#{meterpreter_name}#{meterpreter_runtime_version}"
|
environment_properties[:meterpreter_runtime_version] = "#{meterpreter_name}#{meterpreter_runtime_version}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
environment_properties[:runtime_version] = ENV['RUNTIME_VERSION']
|
||||||
|
|
||||||
config.environment_properties = environment_properties.compact
|
config.environment_properties = environment_properties.compact
|
||||||
end
|
end
|
||||||
|
|
|
@ -499,7 +499,7 @@ module Acceptance
|
||||||
end
|
end
|
||||||
|
|
||||||
def close
|
def close
|
||||||
close_processes(@payload_processes + [console])
|
close_processes(@payload_processes + [@console])
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.finalizer_proc_for(instance)
|
def self.finalizer_proc_for(instance)
|
||||||
|
|
|
@ -19,7 +19,7 @@ module Acceptance::Meterpreter
|
||||||
],
|
],
|
||||||
module_tests: [
|
module_tests: [
|
||||||
{
|
{
|
||||||
name: "test/services",
|
name: "post/test/services",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -74,7 +74,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/cmd_exec",
|
name: "post/test/cmd_exec",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -90,7 +90,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/extapi",
|
name: "post/test/extapi",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -106,7 +106,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/file",
|
name: "post/test/file",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -124,7 +124,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/get_env",
|
name: "post/test/get_env",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -140,7 +140,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/meterpreter",
|
name: "post/test/meterpreter",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -156,7 +156,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun",
|
name: "post/test/railgun",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -172,7 +172,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun_reverse_lookups",
|
name: "post/test/railgun_reverse_lookups",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -188,7 +188,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/registry",
|
name: "post/test/registry",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -223,7 +223,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/search",
|
name: "post/test/search",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -239,7 +239,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/unix",
|
name: "post/test/unix",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
|
|
@ -38,7 +38,7 @@ module Acceptance::Meterpreter
|
||||||
],
|
],
|
||||||
module_tests: [
|
module_tests: [
|
||||||
{
|
{
|
||||||
name: "test/services",
|
name: "post/test/services",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -70,7 +70,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/cmd_exec",
|
name: "post/test/cmd_exec",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
@ -96,7 +96,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/extapi",
|
name: "post/test/extapi",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
@ -122,7 +122,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/file",
|
name: "post/test/file",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
@ -148,7 +148,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/get_env",
|
name: "post/test/get_env",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
@ -174,7 +174,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/meterpreter",
|
name: "post/test/meterpreter",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
@ -203,7 +203,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun",
|
name: "post/test/railgun",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
@ -229,7 +229,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun_reverse_lookups",
|
name: "post/test/railgun_reverse_lookups",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
@ -255,7 +255,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/registry",
|
name: "post/test/registry",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -287,7 +287,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/search",
|
name: "post/test/search",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
[
|
[
|
||||||
|
@ -319,7 +319,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/unix",
|
name: "post/test/unix",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
|
|
@ -19,7 +19,7 @@ module Acceptance::Meterpreter
|
||||||
],
|
],
|
||||||
module_tests: [
|
module_tests: [
|
||||||
{
|
{
|
||||||
name: "test/services",
|
name: "post/test/services",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -61,7 +61,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/cmd_exec",
|
name: "post/test/cmd_exec",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -79,7 +79,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/extapi",
|
name: "post/test/extapi",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -95,7 +95,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/file",
|
name: "post/test/file",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -119,7 +119,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/get_env",
|
name: "post/test/get_env",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -135,7 +135,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/meterpreter",
|
name: "post/test/meterpreter",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -153,7 +153,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun",
|
name: "post/test/railgun",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -169,7 +169,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun_reverse_lookups",
|
name: "post/test/railgun_reverse_lookups",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -185,7 +185,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/registry",
|
name: "post/test/registry",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -227,7 +227,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/search",
|
name: "post/test/search",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -243,7 +243,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/unix",
|
name: "post/test/unix",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
|
|
@ -20,7 +20,7 @@ module Acceptance::Meterpreter
|
||||||
],
|
],
|
||||||
module_tests: [
|
module_tests: [
|
||||||
{
|
{
|
||||||
name: "test/services",
|
name: "post/test/services",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -73,7 +73,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/cmd_exec",
|
name: "post/test/cmd_exec",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -89,7 +89,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/extapi",
|
name: "post/test/extapi",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -110,7 +110,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/file",
|
name: "post/test/file",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -126,7 +126,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/get_env",
|
name: "post/test/get_env",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -142,7 +142,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/meterpreter",
|
name: "post/test/meterpreter",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -160,7 +160,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun",
|
name: "post/test/railgun",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -176,7 +176,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun_reverse_lookups",
|
name: "post/test/railgun_reverse_lookups",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -192,7 +192,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/registry",
|
name: "post/test/registry",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -224,7 +224,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/search",
|
name: "post/test/search",
|
||||||
platforms: [:linux, :osx, :windows],
|
platforms: [:linux, :osx, :windows],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
lines: {
|
lines: {
|
||||||
|
@ -240,7 +240,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/unix",
|
name: "post/test/unix",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
|
|
@ -22,7 +22,7 @@ module Acceptance::Meterpreter
|
||||||
],
|
],
|
||||||
module_tests: [
|
module_tests: [
|
||||||
{
|
{
|
||||||
name: "test/services",
|
name: "post/test/services",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -54,7 +54,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/cmd_exec",
|
name: "post/test/cmd_exec",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -86,7 +86,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/extapi",
|
name: "post/test/extapi",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -118,7 +118,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/file",
|
name: "post/test/file",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -150,7 +150,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/get_env",
|
name: "post/test/get_env",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -182,7 +182,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/meterpreter",
|
name: "post/test/meterpreter",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -214,7 +214,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun",
|
name: "post/test/railgun",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -246,7 +246,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/railgun_reverse_lookups",
|
name: "post/test/railgun_reverse_lookups",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -278,7 +278,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/registry",
|
name: "post/test/registry",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -310,7 +310,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/search",
|
name: "post/test/search",
|
||||||
platforms: [
|
platforms: [
|
||||||
[
|
[
|
||||||
:linux,
|
:linux,
|
||||||
|
@ -342,7 +342,7 @@ module Acceptance::Meterpreter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "test/unix",
|
name: "post/test/unix",
|
||||||
platforms: [
|
platforms: [
|
||||||
:linux,
|
:linux,
|
||||||
:osx,
|
:osx,
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
module Acceptance
|
||||||
|
###
|
||||||
|
# Stores the data for a target. These credentials can be used to create a sesion, or run a module against
|
||||||
|
###
|
||||||
|
class Target
|
||||||
|
attr_reader :session_module, :type, :datastore
|
||||||
|
|
||||||
|
def initialize(options)
|
||||||
|
@type = options.fetch(:type)
|
||||||
|
@session_module = options.fetch(:session_module)
|
||||||
|
@datastore = options.fetch(:datastore)
|
||||||
|
end
|
||||||
|
|
||||||
|
def [](k)
|
||||||
|
options[k]
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param [Hash] default_global_datastore
|
||||||
|
# @return [String] The setg commands for setting the global datastore
|
||||||
|
def setg_commands(default_global_datastore: {})
|
||||||
|
commands = []
|
||||||
|
# Ensure the global framework datastore is always clear
|
||||||
|
commands << "irb -e '(self.respond_to?(:framework) ? framework : self).datastore.user_defined.clear'"
|
||||||
|
# Call setg
|
||||||
|
global_datastore = default_global_datastore.merge(@datastore[:global])
|
||||||
|
global_datastore.each do |key, value|
|
||||||
|
commands << "setg #{key} #{value}"
|
||||||
|
end
|
||||||
|
commands.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param [Hash] default_module_datastore
|
||||||
|
# @return [String] The datastore options string
|
||||||
|
def datastore_options(default_module_datastore: {})
|
||||||
|
module_datastore = default_module_datastore.merge(@datastore[:module])
|
||||||
|
module_options = module_datastore.map do |key, value|
|
||||||
|
"#{key}=#{value}"
|
||||||
|
end
|
||||||
|
|
||||||
|
module_options.join(' ')
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param [Hash] default_module_datastore
|
||||||
|
# @return [String] The command which can be used on msfconsole to generate the payload
|
||||||
|
def run_command(default_module_datastore: {})
|
||||||
|
"run #{datastore_options(default_module_datastore: default_module_datastore)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param [Hash] default_global_datastore
|
||||||
|
# @param [Hash] default_module_datastore
|
||||||
|
# @return [String] A human readable representation of the payload configuration object
|
||||||
|
def as_readable_text(default_global_datastore: {}, default_module_datastore: {})
|
||||||
|
<<~EOF
|
||||||
|
## Session module
|
||||||
|
use #{session_module}
|
||||||
|
|
||||||
|
## Set global datastore
|
||||||
|
#{setg_commands(default_global_datastore: default_global_datastore)}
|
||||||
|
|
||||||
|
## Run command
|
||||||
|
#{run_command(default_module_datastore: default_module_datastore)}
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -36,7 +36,7 @@ class MetasploitModule < Msf::Post
|
||||||
end
|
end
|
||||||
|
|
||||||
def select_available_modules
|
def select_available_modules
|
||||||
session_platform = Msf::Module::Platform.find_platform(session.platform)
|
session_platform = session.platform ? Msf::Module::Platform.find_platform(session.platform) : nil
|
||||||
session_type = session.type
|
session_type = session.type
|
||||||
|
|
||||||
module_results = []
|
module_results = []
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
require 'rex/post/meterpreter/extensions/stdapi/command_ids'
|
||||||
|
require 'rex'
|
||||||
|
|
||||||
|
lib = File.join(Msf::Config.install_root, "test", "lib")
|
||||||
|
$LOAD_PATH.push(lib) unless $LOAD_PATH.include?(lib)
|
||||||
|
require 'module_test'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Post
|
||||||
|
|
||||||
|
include Msf::ModuleTest::PostTest
|
||||||
|
include Msf::ModuleTest::PostTestFileSystem
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(
|
||||||
|
update_info(
|
||||||
|
info,
|
||||||
|
'Name' => 'Testing Postgres sessions work',
|
||||||
|
'Description' => %q{ This module will test the postgres sessions work },
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' => [ 'alanfoster'],
|
||||||
|
'Platform' => all_platforms,
|
||||||
|
'SessionTypes' => [ 'postgresql' ]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def cleanup
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_console_query
|
||||||
|
it "should return a version" do
|
||||||
|
stdout = with_mocked_console(session) { |console| console.run_single("query 'select version();'") }
|
||||||
|
ret = true
|
||||||
|
ret &&= stdout.buf.match?(/PostgreSQL \d+.\d+/)
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_console_help
|
||||||
|
it "should support the help command" do
|
||||||
|
stdout = with_mocked_console(session) { |console| console.run_single("help") }
|
||||||
|
ret = true
|
||||||
|
ret &&= stdout.buf.include?('Core Commands')
|
||||||
|
ret &&= stdout.buf.include?('PostgreSQL Client Commands')
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def all_platforms
|
||||||
|
Msf::Module::Platform.subclasses.collect { |c| c.realname.downcase }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Wrap the console with a mocked stdin/stdout for testing purposes. This ensures the console
|
||||||
|
# will not write the real stdout, and the contents can be verified in the test
|
||||||
|
# @param [Session] session
|
||||||
|
# @return [Rex::Ui::Text::Output::Buffer] the stdout buffer
|
||||||
|
def with_mocked_console(session)
|
||||||
|
old_input = session.console.input
|
||||||
|
old_output = session.console.output
|
||||||
|
|
||||||
|
mock_input = Rex::Ui::Text::Input.new
|
||||||
|
mock_output = Rex::Ui::Text::Output::Buffer.new
|
||||||
|
|
||||||
|
session.console.init_ui(mock_input, mock_output)
|
||||||
|
yield session.console
|
||||||
|
|
||||||
|
mock_output
|
||||||
|
ensure
|
||||||
|
session.console.init_ui(old_input, old_output)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue