Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/command_shell_acceptance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ jobs:
# Linux
- { command_shell: { name: linux }, ruby: '3.4', os: ubuntu-latest }

# Python
- { command_shell: { name: python }, ruby: '3.4', os: ubuntu-latest }

# CMD
- { command_shell: { name: cmd }, ruby: '3.4', os: windows-2022 }

Expand Down Expand Up @@ -153,7 +156,7 @@ jobs:

- name: Pull pyenv container image
if: startsWith(matrix.command_shell.name, 'python_ssl')
run: docker pull public.ecr.aws/n5b4u6h0/zerosteiner/pyenv@sha256:e686265001ee43333f14c896d8362970e816c5a7c661a6fa7e37a90770c9108a
run: docker pull rapid7/msf-pyenv@sha256:596c78595c69847661a135890bfb7ed09b7cd3b39fb66699e075f7eea5dc0f09
working-directory: metasploit-framework

- name: Acceptance
Expand Down
54 changes: 0 additions & 54 deletions .github/workflows/pyenv_image_publish.yml

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced this workflow with internal jenkins and dockerhub

This file was deleted.

33 changes: 33 additions & 0 deletions spec/acceptance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,39 @@ $env:SPEC_OPTS='--tag acceptance'; $env:SPEC_HELPER_LOAD_METASPLOIT=$false; $env
Session types can be specified via the `SESSION` argument. Meterpreter and command shell are support and use the following notation:
- SESSION=meterpreter/php
- SESSION=command_shell/php
- SESSION=command_shell/python (non-SSL Python shell payloads: `python/shell_reverse_tcp`, `python/shell_bind_tcp`, `cmd/unix/reverse_python`)

Run just one payload flavor within a `SESSION` by filtering on a substring of its example description with rspec's `-e` flag, example:

```
SPEC_OPTS='--tag acceptance' SPEC_HELPER_LOAD_METASPLOIT=false SESSION=command_shell/python bundle exec rspec spec/acceptance/command_shell_spec.rb -e "shell_bind_tcp"
```

### Python SSL (pyenv container)

The `python_ssl_*` command shell flavors (`SESSION=command_shell/python_ssl_2_6`, `python_ssl_2_7`,
`python_ssl_3_4`, `python_ssl_3_13`) exercise Python's SSL support across several CPython/OpenSSL
combinations. They run each payload inside the `test/pyenv/` container image (built via
[pyenv](https://github.com/pyenv/pyenv)) instead of the host's `python3`, so old interpreter/OpenSSL pairings
can be tested without installing them locally.

Build the image locally:

```
docker build -f test/pyenv/Containerfile -t pyenv:local test/pyenv
```

The published image is built and pushed to [`rapid7/msf-pyenv`](https://hub.docker.com/r/rapid7/msf-pyenv) on Docker Hub by the
`framework_pyenv_image_publish` Jenkins pipeline. Any maintainer can trigger it manually to
rebuild/republish it. After a new image is published, update the
digest pinned in `PYTHON_SSL_IMAGE` (`spec/support/acceptance/command_shell/python.rb`) and the
`docker pull` line in `command_shell_acceptance.yml` to match.

Run the test suite:

```
SPEC_OPTS='--tag acceptance' SPEC_HELPER_LOAD_METASPLOIT=false SESSION=command_shell/python_ssl_3_13 bundle exec rspec spec/acceptance/command_shell_spec.rb
```

### Postgres

Expand Down
3 changes: 2 additions & 1 deletion spec/acceptance/command_shell_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
powershell: Acceptance::Session::POWERSHELL,
cmd: Acceptance::Session::CMD,
linux: Acceptance::Session::LINUX,
python: Acceptance::Session::PYTHON,
python_ssl_2_6: Acceptance::Session::PYTHON_SSL_2_6,
python_ssl_2_7: Acceptance::Session::PYTHON_SSL_2_7,
python_ssl_3_4: Acceptance::Session::PYTHON_SSL_3_4,
Expand Down Expand Up @@ -137,7 +138,7 @@ def initialize(path)
end

console.sendline payload.handler_command(default_module_datastore: default_module_datastore)
console.recvuntil(/Started reverse (?:TCP|SSL) handler[^\n]*\n/)
console.recvuntil(/Started (?:reverse|bind) (?:TCP|SSL|UDP) handler[^\n]*\n/)
payload_process = executed_payload
session_id = nil

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# frozen_string_literal: true

module Acceptance::Session
PYTHON_SSL_IMAGE = 'public.ecr.aws/n5b4u6h0/zerosteiner/pyenv@sha256:e686265001ee43333f14c896d8362970e816c5a7c661a6fa7e37a90770c9108a'
PYTHON_SSL_IMAGE = 'rapid7/msf-pyenv@sha256:596c78595c69847661a135890bfb7ed09b7cd3b39fb66699e075f7eea5dc0f09'
PYTHON_SSL_CONTAINER_CMD = '$(command -v podman || command -v docker)'

PYTHON_SSL_MODULE_TESTS = [
PYTHON_MODULE_TESTS = [
{
name: 'post/test/unix',
platforms: [
Expand Down Expand Up @@ -66,12 +66,59 @@ def self.python_ssl_config(pyenv_version)
}
}
],
module_tests: PYTHON_SSL_MODULE_TESTS
module_tests: PYTHON_MODULE_TESTS
}
end

PYTHON_SSL_2_6 = python_ssl_config('2.6.9-no-pip')
PYTHON_SSL_2_7 = python_ssl_config('2.7.18')
PYTHON_SSL_3_4 = python_ssl_config('3.4.10')
PYTHON_SSL_3_13 = python_ssl_config('3.13.7')
PYTHON_SSL_3_13 = python_ssl_config('3.13.13')

PYTHON = {
payloads: [
{
name: 'python/shell_reverse_tcp',
extension: '.py',
platforms: [:linux],
execute_cmd: ['python', '${payload_path}'],
generate_options: {
'-f': 'raw'
},
datastore: {
global: {},
module: {}
}
},
{
name: 'cmd/unix/reverse_python',
extension: '.sh',
platforms: [:linux],
execute_cmd: ['sh ${payload_path}'],
generate_options: {
'-f': 'raw'
},
datastore: {
global: {},
module: {}
}
},
{
name: 'python/shell_bind_tcp',
extension: '.py',
platforms: [:linux],
execute_cmd: ['python', '${payload_path}'],
generate_options: {
'-f': 'raw'
},
datastore: {
global: {},
module: {
RHOST: '127.0.0.1'
}
}
},
],
module_tests: PYTHON_MODULE_TESTS
}
end
8 changes: 4 additions & 4 deletions test/pyenv/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ CPython interpreter versions (installed via [pyenv](https://github.com/pyenv/pye
very old releases that need a custom-built OpenSSL to compile) so that payloads exercising Python's SSL
support can be tested against the interpreter/OpenSSL combinations they actually target.

This image is published to `ghcr.io/rapid7/metasploit-framework/pyenv` by the
`.github/workflows/pyenv_image_publish.yml` workflow, which any maintainer can trigger via
`workflow_dispatch` to rebuild/republish it.
This image is published to [`rapid7/msf-pyenv`](https://hub.docker.com/r/rapid7/msf-pyenv) on Docker Hub
by the `framework_pyenv_image_publish` Jenkins pipeline, which any maintainer can trigger manually to
rebuild/republish it.

## Running

Expand All @@ -18,7 +18,7 @@ docker build -f Containerfile -t pyenv:local .

- Run a specific interpreter version by setting `PYENV_VERSION`:
```shell
docker run --rm -e PYENV_VERSION=3.13.7 pyenv:local python --version
docker run --rm -e PYENV_VERSION=3.13.13 pyenv:local python --version
```

There's no `docker-compose.yml` for this fixture — unlike the long-running service fixtures (SMB, SSH,
Expand Down
Loading