├── .docker ├── Dockerfile └── entrypoint.sh ├── .dockerignore ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── auto-merge.yml │ ├── changelog.yml │ ├── ci-python.yml │ ├── codeql-analysis-python.yml │ ├── container.yml │ ├── conventional-commits.yml │ ├── dependency-review.yml │ ├── deploy-pypi.yml │ ├── github-pages.yml │ ├── release.yml │ └── sbom-upload.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── Makefile ├── _static │ ├── custom.css │ ├── greenbone.png │ └── logo.svg ├── conf.py ├── config.md ├── connectiontypes.md ├── favicon.png ├── glossary.md ├── index.md ├── install.md ├── requirements.txt ├── scripting.md └── tools.md ├── gvmtools ├── __init__.py ├── __version__.py ├── cli.py ├── config.py ├── helper.py ├── parser.py ├── pyshell.py └── script.py ├── poetry.lock ├── pyproject.toml ├── scripts ├── .pylintrc ├── README.md ├── application-detection.gmp.py ├── bulk-modify-schedules.gmp.py ├── certbund-report.gmp.py ├── cfg-gen-for-certs.gmp.py ├── check-gmp-gos22.04.gmp.py ├── check-gmp-gos24.10.gmp.py ├── clean-sensor.gmp.py ├── combine-reports.gmp.py ├── create-alerts-from-csv.gmp.py ├── create-consolidated-report.gmp.py ├── create-credentials-from-csv.gmp.py ├── create-cve-report-from-json.gmp.py ├── create-dummy-data.gmp.py ├── create-filters-from-csv.gmp.py ├── create-report-format-from-csv.gmp.py ├── create-schedules-from-csv.gmp.py ├── create-tags-from-csv.gmp.py ├── create-targets-from-csv.gmp.py ├── create-targets-from-host-list.gmp.py ├── create-tasks-from-csv.gmp.py ├── default_report_data.json ├── delete-overrides-by-filter.gmp.py ├── empty-trash.gmp.py ├── export-certificates.gmp.py ├── export-csv-report.gmp.py ├── export-hosts-csv.gmp.py ├── export-operatingsystems-csv.gmp.py ├── export-pdf-report.gmp.py ├── export-xml-report.gmp.py ├── generate-random-reports.gmp.py ├── generate-random-targets.gmp.py ├── list-alerts.gmp.py ├── list-credentials.gmp.py ├── list-feeds.gmp.py ├── list-filters.gmp.py ├── list-groups.gmp.py ├── list-hosts.gmp.py ├── list-policies.gmp.py ├── list-portlists.gmp.py ├── list-report-formats.gmp.py ├── list-reports.gmp.py ├── list-roles.gmp.py ├── list-scan-configs.gmp.py ├── list-scanners.gmp.py ├── list-schedules.gmp.py ├── list-tags.gmp.py ├── list-targets.gmp.py ├── list-tasks.gmp.py ├── list-tickets.gmp.py ├── list-users.gmp.py ├── monthly-report-gos24.10.gmp.py ├── monthly-report-gos3.gmp.py ├── monthly-report-gos4.gmp.py ├── nvt-scan.gmp.py ├── requirements.txt ├── ruff.toml ├── scan-new-system.gmp.py ├── send-delta-emails.gmp.py ├── send-schedules.gmp.py ├── send-targets.gmp.py ├── send-tasks.gmp.py ├── ssv_csv.py ├── start-alert-scan.gmp.py ├── start-multiple-alerts-scan.gmp.py ├── start-nvt-scan.gmp.py ├── start-scans-from-csv.py ├── stop-all-scans.gmp.py ├── stop-scans-from-csv.py ├── sync-hosts.gmp.py ├── update-task-target.gmp.py └── verify-scanners.gmp.py └── tests ├── __init__.py ├── root_help.3.10.snap ├── root_help.snap ├── scripts ├── __init__.py ├── example_schedules.xml ├── example_target.xml ├── example_task.xml ├── get_alerts.xml ├── get_scan_configs.xml ├── invalid_xml.xml ├── test_combine_reports.py ├── test_create_consolidated_report.py ├── test_list_tasks.py ├── test_send_schedules.py ├── test_send_targets.py ├── test_send_tasks.py └── test_start_alert_scan.py ├── socket_help.3.10.snap ├── socket_help.snap ├── ssh_help.3.10.snap ├── ssh_help.snap ├── test.cfg ├── test_auth.cfg ├── test_config.py ├── test_helper.py ├── test_parser.py ├── tls_help.3.10.snap └── tls_help.snap /.docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stable-slim AS builder 2 | 3 | COPY . /source 4 | 5 | WORKDIR /source 6 | 7 | RUN apt-get update && \ 8 | apt-get install --no-install-recommends --no-install-suggests -y \ 9 | gosu \ 10 | python3 \ 11 | python-is-python3 \ 12 | pipx && \ 13 | apt-get remove --purge --auto-remove -y && \ 14 | rm -rf /var/lib/apt/lists/* 15 | 16 | RUN pipx install poetry 17 | 18 | RUN rm -rf dist && /root/.local/bin/poetry build -f wheel 19 | 20 | FROM debian:stable-slim 21 | 22 | ENV PYTHONDONTWRITEBYTECODE=1 23 | ENV PYTHONUNBUFFERED=1 24 | ENV PIP_NO_CACHE_DIR=off 25 | 26 | WORKDIR /gvm-tools 27 | 28 | RUN apt-get update && \ 29 | apt-get install --no-install-recommends --no-install-suggests -y \ 30 | gosu \ 31 | python3 \ 32 | python3-pip && \ 33 | apt-get remove --purge --auto-remove -y && \ 34 | rm -rf /var/lib/apt/lists/* 35 | 36 | RUN addgroup --gid 1001 --system gvm && \ 37 | adduser --no-create-home --shell /bin/false --disabled-password --uid 1001 --system --group gvm 38 | 39 | COPY --from=builder /source/dist/* /gvm-tools/ 40 | COPY .docker/entrypoint.sh /usr/local/bin/entrypoint 41 | 42 | RUN python3 -m pip install --break-system-packages /gvm-tools/* 43 | 44 | RUN chown -R gvm:gvm /gvm-tools && \ 45 | chmod 755 /usr/local/bin/entrypoint 46 | 47 | ENTRYPOINT [ "/usr/local/bin/entrypoint" ] 48 | 49 | CMD ["/bin/bash"] 50 | -------------------------------------------------------------------------------- /.docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec gosu gvm "$@" 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .github/ 3 | .vscode/ 4 | .venv/ 5 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # default reviewers 2 | * @greenbone/gea 3 | 4 | # dev ops 5 | .github/ @greenbone/devops @greenbone/gea 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 12 | 13 | ### Expected behavior 14 | 15 | ### Current behavior 16 | 17 | ### Steps to reproduce 18 | 1. 19 | 2. 20 | 3. 21 | 22 | ### GVM versions 23 | **gsa:** (gsad --version) 24 | 25 | **gvm:** (gvmd --version) 26 | 27 | **openvas-scanner:** (openvassd --version) 28 | 29 | **gvm-libs:** 30 | 31 | **gvm-tools:** (gvm-cli --version) 32 | 33 | ### Environment 34 | **Operating system:** 35 | 36 | **Installation method / source:** (packages, source installation) 37 | 38 | ### Logfiles 39 | 40 | 41 | 42 | ``` 43 | 44 | ``` -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | time: "04:00" 8 | allow: 9 | - dependency-type: direct 10 | - dependency-type: indirect 11 | commit-message: 12 | prefix: "Deps" 13 | groups: 14 | python-packages: 15 | patterns: 16 | - "*" 17 | 18 | - package-ecosystem: "github-actions" 19 | directory: "/" 20 | schedule: 21 | interval: "weekly" 22 | commit-message: 23 | prefix: "Deps" 24 | groups: 25 | github-actions: 26 | patterns: 27 | - "*" 28 | -------------------------------------------------------------------------------- /.github/workflows/auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: Auto-merge squash 2 | on: pull_request_target 3 | 4 | permissions: 5 | contents: write 6 | pull-requests: write 7 | 8 | jobs: 9 | auto-merge: 10 | uses: greenbone/workflows/.github/workflows/auto-merge.yml@main 11 | secrets: inherit 12 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | name: Show changelog since last release 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | changelog: 8 | name: Show changelog since last release 9 | runs-on: 'ubuntu-latest' 10 | steps: 11 | - name: Checkout code 12 | uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 0 # for conventional commits and getting all git tags 15 | persist-credentials: false 16 | - name: Install git-cliff 17 | uses: greenbone/actions/uv@v3 18 | with: 19 | install: git-cliff 20 | - name: Determine changelog 21 | env: 22 | GITHUB_REPO: ${{ github.repository }} 23 | GITHUB_TOKEN: ${{ github.token }} 24 | run: | 25 | git-cliff -v --strip header --unreleased -o /tmp/changelog.md 26 | - name: Show changelog 27 | run: | 28 | cat /tmp/changelog.md 29 | cat /tmp/changelog.md >> $GITHUB_STEP_SUMMARY 30 | -------------------------------------------------------------------------------- /.github/workflows/ci-python.yml: -------------------------------------------------------------------------------- 1 | name: Build and test Python package 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | linting: 11 | name: Linting 12 | strategy: 13 | matrix: 14 | python-version: 15 | - "3.9" 16 | - "3.10" 17 | - "3.11" 18 | - "3.12" 19 | uses: greenbone/workflows/.github/workflows/lint-python.yml@main 20 | with: 21 | linter: ruff check 22 | lint-packages: gvmtools tests 23 | python-version: ${{ matrix.python-version }} 24 | 25 | lint-scripts: 26 | name: Lint all scripts 27 | runs-on: "ubuntu-latest" 28 | strategy: 29 | matrix: 30 | python-version: 31 | - "3.9" 32 | - "3.10" 33 | - "3.11" 34 | - "3.12" 35 | steps: 36 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 37 | - name: Set up Python ${{ matrix.python-version }} 38 | uses: greenbone/actions/poetry@v3 39 | with: 40 | python-version: ${{ matrix.python-version }} 41 | - name: Install additional script dependencies 42 | run: poetry run pip install -r scripts/requirements.txt 43 | - name: Check with black 44 | run: poetry run black --check scripts/*.gmp.py 45 | - name: Lint scripts 46 | run: | 47 | poetry run ruff check --config scripts/ruff.toml scripts/*.py 48 | 49 | test: 50 | name: Unit tests 51 | strategy: 52 | matrix: 53 | python-version: 54 | - "3.9" 55 | - "3.10" 56 | - "3.11" 57 | - "3.12" 58 | uses: greenbone/workflows/.github/workflows/test-python.yml@main 59 | with: 60 | python-version: ${{ matrix.python-version }} 61 | 62 | codecov: 63 | name: Upload coverage to codecov.io 64 | needs: test 65 | runs-on: "ubuntu-latest" 66 | steps: 67 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 68 | - name: Calculate and upload coverage to codecov.io 69 | uses: greenbone/actions/coverage-python@v3 70 | with: 71 | token: ${{ secrets.CODECOV_TOKEN }} 72 | 73 | build-docs: 74 | name: Build the documentation 75 | runs-on: "ubuntu-latest" 76 | steps: 77 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 78 | - name: Install poetry and dependencies 79 | uses: greenbone/actions/poetry@v3 80 | - name: Build docs 81 | run: | 82 | cd docs 83 | poetry run make html 84 | 85 | versioning: 86 | name: Check versioning 87 | uses: greenbone/workflows/.github/workflows/check-version.yml@main 88 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis-python.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | paths-ignore: 9 | - '**/*.md' 10 | - '**/*.txt' 11 | schedule: 12 | - cron: '30 5 * * 0' # 5:30h on Sundays 13 | 14 | jobs: 15 | analyze: 16 | name: Analyze 17 | runs-on: ubuntu-latest 18 | permissions: 19 | actions: read 20 | contents: read 21 | security-events: write 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | language: [ 'python' ] 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 31 | 32 | - name: Initialize CodeQL 33 | uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 34 | with: 35 | languages: ${{ matrix.language }} 36 | 37 | - name: Perform CodeQL Analysis 38 | uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 39 | -------------------------------------------------------------------------------- /.github/workflows/container.yml: -------------------------------------------------------------------------------- 1 | name: Build & Push Container Images 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - "v*" 9 | pull_request: 10 | branches: 11 | - main 12 | workflow_dispatch: 13 | inputs: 14 | ref-name: 15 | type: string 16 | description: "The ref to build a container image from. For example a tag v23.0.0." 17 | required: true 18 | 19 | jobs: 20 | build: 21 | name: Build and Push to Greenbone Registry 22 | uses: greenbone/workflows/.github/workflows/container-build-push-2nd-gen.yml@main 23 | with: 24 | build-docker-file: .docker/Dockerfile 25 | image-url: community/gvm-tools 26 | image-labels: | 27 | org.opencontainers.image.vendor=Greenbone 28 | org.opencontainers.image.documentation=https://greenbone.github.io/gvm-tools/ 29 | org.opencontainers.image.base.name=debian/stable-slim 30 | ref-name: ${{ inputs.ref-name }} 31 | secrets: inherit 32 | -------------------------------------------------------------------------------- /.github/workflows/conventional-commits.yml: -------------------------------------------------------------------------------- 1 | name: Conventional Commits 2 | 3 | on: 4 | pull_request_target: 5 | 6 | permissions: 7 | pull-requests: write 8 | contents: read 9 | 10 | jobs: 11 | conventional-commits: 12 | name: Conventional Commits 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Report Conventional Commits 16 | uses: greenbone/actions/conventional-commits@v3 17 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: "Dependency Review" 2 | 3 | on: pull_request 4 | 5 | permissions: 6 | contents: read 7 | pull-requests: write 8 | 9 | jobs: 10 | dependency-review: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: "Dependency Review" 14 | uses: greenbone/actions/dependency-review@v3 15 | -------------------------------------------------------------------------------- /.github/workflows/deploy-pypi.yml: -------------------------------------------------------------------------------- 1 | name: Deploy on PyPI 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | deploy: 9 | permissions: 10 | id-token: write 11 | runs-on: ubuntu-latest 12 | environment: 13 | name: pypi 14 | url: https://pypi.org/project/gvm-tools/ 15 | steps: 16 | - name: Build and publish to PyPI 17 | uses: greenbone/actions/pypi-upload@v3 18 | -------------------------------------------------------------------------------- /.github/workflows/github-pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy docs to GitHub Pages 2 | 3 | on: 4 | # Runs on pushes targeting the default branch 5 | push: 6 | branches: [main] 7 | 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 12 | permissions: 13 | contents: read 14 | pages: write 15 | id-token: write 16 | 17 | # Allow one concurrent deployment 18 | concurrency: 19 | group: "pages" 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | deploy: 24 | uses: greenbone/workflows/.github/workflows/docs-python.yml@main 25 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release gvm-tools 2 | 3 | on: 4 | pull_request: 5 | types: [closed] 6 | workflow_dispatch: 7 | inputs: 8 | release-type: 9 | type: choice 10 | description: "Release type. One of patch, minor or major" 11 | options: 12 | - patch 13 | - minor 14 | - major 15 | release-version: 16 | description: "Set an explicit version, that will overwrite release-type. Fails if version is not compliant." 17 | type: string 18 | 19 | jobs: 20 | build-and-release: 21 | name: Create a new release 22 | # If the event is a workflow_dispatch or on of the labels 'pre release', 23 | # 'patch release', 'minor release' or 'major release' is set and PR is 24 | # closed because of a merge 25 | # NOTE: priority of set labels will be alpha > release-candidate > patch > minor > major, 26 | # so if 'major' and 'patch' labels are set, it will create a patch release. 27 | if: | 28 | ( github.event_name == 'workflow_dispatch') || ( 29 | ( contains(github.event.pull_request.labels.*.name, 'alpha release') || 30 | contains(github.event.pull_request.labels.*.name, 'rc release') || 31 | contains(github.event.pull_request.labels.*.name, 'patch release') || 32 | contains(github.event.pull_request.labels.*.name, 'minor release') || 33 | contains(github.event.pull_request.labels.*.name, 'major release')) && 34 | github.event.pull_request.merged == true ) 35 | runs-on: "ubuntu-latest" 36 | steps: 37 | - name: Selecting the Release type 38 | id: release-type 39 | uses: greenbone/actions/release-type@v3 40 | with: 41 | release-type-input: ${{ inputs.release-type }} 42 | - name: Checkout code 43 | uses: actions/checkout@v4 44 | with: 45 | fetch-depth: 0 # for conventional commits and getting all git tags 46 | persist-credentials: false 47 | ref: ${{ steps.release-type.outputs.release-ref }} 48 | - name: Determine release version 49 | id: release-version 50 | uses: greenbone/actions/release-version@v3 51 | with: 52 | release-type: ${{ steps.release-type.outputs.release-type }} 53 | release-version: ${{ inputs.release-version }} 54 | versioning-scheme: "semver" 55 | - name: Install git-cliff 56 | uses: greenbone/actions/uv@v3 57 | with: 58 | install: git-cliff 59 | - name: Determine changelog 60 | env: 61 | GITHUB_REPO: ${{ github.repository }} 62 | GITHUB_TOKEN: ${{ github.token }} 63 | run: | 64 | git-cliff -v --strip header -o /tmp/changelog.md --unreleased --tag ${{ steps.release-version.outputs.release-version }} ${{ steps.release-version.outputs.last-release-version }}..HEAD 65 | - name: Release with release action 66 | id: release 67 | uses: greenbone/actions/release@v3 68 | with: 69 | github-user: ${{ secrets.GREENBONE_BOT }} 70 | github-user-mail: ${{ secrets.GREENBONE_BOT_MAIL }} 71 | github-user-token: ${{ secrets.GREENBONE_BOT_TOKEN }} 72 | gpg-key: ${{ secrets.GPG_KEY }} 73 | gpg-fingerprint: ${{ secrets.GPG_FINGERPRINT }} 74 | gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} 75 | release-version: ${{ steps.release-version.outputs.release-version }} 76 | changelog: /tmp/changelog.md 77 | ref: ${{ steps.release-type.outputs.release-ref }} 78 | versioning-scheme: "semver" 79 | -------------------------------------------------------------------------------- /.github/workflows/sbom-upload.yml: -------------------------------------------------------------------------------- 1 | name: SBOM upload 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: ["main"] 6 | jobs: 7 | SBOM-upload: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | id-token: write 11 | contents: write 12 | steps: 13 | - name: "SBOM upload" 14 | uses: greenbone/actions/sbom-upload@v3 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.pyc 3 | *.log 4 | .egg 5 | *.egg-info 6 | dist 7 | build 8 | .idea 9 | .vscode 10 | .coverage 11 | .venv 12 | 13 | # ruff 14 | .ruff_cache/ 15 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | livehtml: 15 | sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 16 | 17 | .PHONY: help Makefile livehtml 18 | 19 | # Catch-all target: route all unknown targets to Sphinx using the new 20 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 21 | %: Makefile 22 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 23 | -------------------------------------------------------------------------------- /docs/_static/greenbone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenbone/gvm-tools/4dc8520aaa89a630b946fbce678c75d699162256/docs/_static/greenbone.png -------------------------------------------------------------------------------- /docs/config.md: -------------------------------------------------------------------------------- 1 | (config)= 2 | 3 | # Configuration 4 | 5 | ```{versionchanged} 2.0 6 | ``` 7 | 8 | By default, {program}`gvm-tools` {ref}`programs ` are evaluating the 9 | {file}`~/.config/gvm-tools.conf` 10 | [ini style](https://docs.python.org/3/library/configparser.html#supported-ini-file-structure) 11 | config file since version 2.0. The name of the used config file can be set using the 12 | {command}`-c/--config` command line switch. 13 | 14 | ## Settings 15 | 16 | The configuration file consists of sections, each led by a {code}`[section]` 17 | header, followed by key/value entries separated by a {code}`=` character. 18 | Whitespaces between key and value are ignored, i.e., {code}`key = value` is the 19 | same as {code}`key=value`. 20 | 21 | Currently five sections are evaluated: 22 | 23 | - {ref}`Main section ` 24 | - {ref}`GMP section ` 25 | - {ref}`Socket section ` 26 | - {ref}`TLS section ` 27 | - {ref}`SSH section ` 28 | 29 | (main-section)= 30 | 31 | ```{rubric} Main Section 32 | ``` 33 | 34 | The main section allows changing the default connection timeout besides 35 | defining variables for {ref}`interpolation`. 36 | 37 | ```ini 38 | [main] 39 | timeout = 60 40 | ``` 41 | 42 | (gmp-section)= 43 | 44 | ```{rubric} GMP Section 45 | ``` 46 | 47 | The GMP section allows setting the default user name and password for 48 | [Greenbone Management Protocol (GMP)](https://community.greenbone.net/t/about-the-greenbone-management-protocol-gmp-category/83) 49 | based communication. 50 | 51 | ```ini 52 | [gmp] 53 | username=gmpuser 54 | password=gmppassword 55 | ``` 56 | 57 | (socket-config-section)= 58 | 59 | ```{rubric} Socket Section 60 | ``` 61 | 62 | This section is only relevant if the {ref}`socket connection type 63 | ` is used. 64 | 65 | The socket section allows setting the default path to the Unix Domain socket of 66 | {term}`gvmd`. It must not be confused with the socket path to the redis server 67 | used by {term}`openvas`. 68 | 69 | ```ini 70 | [unixsocket] 71 | socketpath=/run/gvmd/gvmd.sock 72 | ``` 73 | 74 | (tls-config-section)= 75 | 76 | ```{rubric} TLS Section 77 | ``` 78 | 79 | This section is only relevant if the {ref}`TLS connection type 80 | ` is used. 81 | 82 | The TLS section allows setting the default port, TLS certificate file, TLS key 83 | file and TLS certificate authority file. 84 | 85 | ```ini 86 | [tls] 87 | port=1234 88 | certfile=/path/to/tls.cert 89 | keyfile=/path/to/tls.key 90 | cafile=/path/to/tls.ca 91 | ``` 92 | 93 | (ssh-config-section)= 94 | 95 | ```{rubric} SSH Section 96 | ``` 97 | 98 | This section is only relevant if the {ref}`SSH connection type ` 99 | is used. 100 | 101 | The SSH section allows setting the default SSH port, SSH user name and SSH 102 | password. 103 | 104 | ```ini 105 | [ssh] 106 | username=sshuser 107 | password=sshpassword 108 | port=2222 109 | ``` 110 | 111 | ```{rubric} Comments 112 | ``` 113 | 114 | Configuration files may also contain comments by using the special character 115 | {code}`#`. A comment should be placed on a separate line above or below the 116 | setting. 117 | 118 | ```ini 119 | [main] 120 | # connection timeout of 120 seconds 121 | timeout=120 122 | ``` 123 | 124 | (interpolation)= 125 | 126 | ```{rubric} Interpolation 127 | ``` 128 | 129 | The configuration file also supports the [interpolation of values](https://docs.python.org/3/library/configparser.html#interpolation-of-values). 130 | It is possible to define values in the {code}`[main]` section and reference 131 | them via a {code}`%()s` syntax. Additionally, values of the 132 | same section can be referenced. 133 | 134 | ```ini 135 | [main] 136 | my_first_name=John 137 | 138 | [gmp] 139 | my_last_name=Smith 140 | username=%(my_first_name)s%(my_last_name)s 141 | ``` 142 | 143 | Using this syntax will set the gmp user name setting to `JohnSmith`. 144 | 145 | ## Example 146 | 147 | Full example configuration: 148 | 149 | ```ini 150 | [main] 151 | # increased timeout to 5 minutes 152 | timeout = 300 153 | tls_path=/data/tls 154 | default_user=johnsmith 155 | 156 | [gmp] 157 | username=%(default_user)s 158 | password=choo4Gahdi2e 159 | 160 | [unixsocket] 161 | socketpath=/run/gvmd/gvmd.sock 162 | 163 | [tls] 164 | port=1234 165 | certfile=%(tls_path)s/tls.cert 166 | keyfile=%(tls_path)s/tls.key 167 | cafile=%(tls_path)s/tls.ca 168 | 169 | [ssh] 170 | username=%(default_user)s 171 | password=Poa8Ies1iJee 172 | ``` 173 | -------------------------------------------------------------------------------- /docs/connectiontypes.md: -------------------------------------------------------------------------------- 1 | (connection-types)= 2 | 3 | # Connection Types 4 | 5 | Before being able to talk to a remote {term}`GMP` or {term}`OSP` server using 6 | one of the {ref}`provided command line clients `, the user 7 | has to choose a connection type for establishing a communication channel. 8 | Currently three different connection types are supported for being used as 9 | transport protocol: 10 | 11 | > - {ref}`TLS – tls ` 12 | > - {ref}`SSH – ssh ` 13 | > - {ref}`Unix Domain Socket – socket ` 14 | 15 | For the most common use case (querying {term}`gvmd` via 16 | {term}`GMP` on the same host) the {ref}`socket connection 17 | ` should be chosen. The other connection types require 18 | some setup and possible adjustments at the server side, if no {term}`Greenbone OS ` 19 | based system is used. 20 | 21 | (socket-connection-type)= 22 | 23 | ## Using a Unix Domain Socket 24 | 25 | The Unix Domain Socket is the default connection type of {term}`gvmd` in the 26 | {term}`Greenbone Community Edition`. It is only usable when running the 27 | client tool on the same host as the daemon. 28 | 29 | The location and name of the Unix Domain Socket provided by {term}`gvmd` highly 30 | depends on the environment and {term}`Greenbone Community Edition` installation. 31 | 32 | For current releases of the Greenbone Community Edition 21.4 and 22.4 the 33 | socket should be found at {file}`/run/gvmd/gvmd.sock`. 34 | 35 | For {term}`GOS 4 ` the path is either {file}`/run/openvas/openvasmd.sock` or 36 | {file}`/usr/share/openvas/gsa/classic/openvasmd.sock` and for 37 | {term}`GOS 5 ` and later the path is either {file}`/run/gvm/gvmd.sock` or 38 | {file}`/usr/share/gvm/gsad/web/gvmd.sock`. 39 | 40 | {term}`OSPd based scanners ` may be accessed via Unix Domain Sockets as well. 41 | The location and name of these sockets is configurable and depends on the used 42 | OSPd scanner implementation. 43 | 44 | (don-t-use-sudo)= 45 | 46 | ```{warning} 47 | Accessing a Unix Domain Socket requires sufficient Unix file permissions for 48 | the user running the {ref}`command line interface tool `. 49 | 50 | Please do not start a tool as **root** user via {command}`sudo` or {command}`su` only to 51 | be able to access the socket path. Instead, adjust the 52 | socket file permissions, e.g. by setting the {command}`--listen-owner`, 53 | {command}`--listen-group` or {command}`--listen-mode` arguments of 54 | {term}`gvmd`. 55 | ``` 56 | 57 | (tls-connection-type)= 58 | 59 | ## Using TLS 60 | 61 | The TLS connection type was the default connection type for remote and local 62 | communication in {term}`GOS 3.1 ` and before. It is used to secure the 63 | transport protocol connection of {term}`GMP` or {term}`OSP`. It requires to 64 | provide a TLS certificate file, TLS key file and TLS certificate authority file. 65 | 66 | (ssh-connection-type)= 67 | 68 | ## Using SSH 69 | 70 | Since {term}`GOS 4 `, SSH is the default connection type for secure remote 71 | communication with the manager daemon via {term}`GMP`. The {term}`Greenbone 72 | Management Protocol ` is tunneled through SSH and forwarded to 73 | {term}`gvmd`. 74 | -------------------------------------------------------------------------------- /docs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenbone/gvm-tools/4dc8520aaa89a630b946fbce678c75d699162256/docs/favicon.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # gvm-tools: Remote Control of Your Greenbone Vulnerability Manager (GVM) 2 | 3 | The Greenbone Vulnerability Management Tools, or {program}`gvm-tools` in short, 4 | are a collection of tools that help with controlling a [Greenbone 5 | Enterprise Appliance](https://www.greenbone.net/en/product-comparison/) 6 | and Greenbone Community Edition installations remotely. 7 | 8 | Essentially, the tools aid accessing the communication protocols 9 | {term}`Greenbone Management Protocol (GMP) ` 10 | and {term}`Open Scanner Protocol (OSP) `. 11 | 12 | ```{note} 13 | {program}`gvm-tools` requires at least Python 3.9. 14 | ``` 15 | 16 | ```{toctree} 17 | install 18 | connectiontypes 19 | tools 20 | config 21 | scripting 22 | glossary 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/install.md: -------------------------------------------------------------------------------- 1 | (installation)= 2 | 3 | # Installation of gvm-tools 4 | 5 | ```{note} 6 | The current universally applicable installation process for Python is using 7 | the [pipx] installer tool in conjunction with the [pypi] package repository. 8 | ``` 9 | 10 | ## Installing the Latest Stable Release of gvm-tools 11 | 12 | For installing the latest stable release of {program}`gvm-tools` from the 13 | [Python Package Index](https://pypi.org/), [pipx], [pip] or [poetry] can be 14 | used. 15 | 16 | (using-pipx)= 17 | 18 | ### Using pipx 19 | 20 | You can install the latest release of **gvm-tools** using [pipx]. 21 | 22 | ```shell 23 | python3 -m pipx install gvm-tools 24 | ``` 25 | 26 | On Debian based Distributions like Ubuntu and Kali [pipx] itself can be 27 | installed via 28 | 29 | ```shell 30 | sudo apt install pipx 31 | ``` 32 | 33 | ### Using pip 34 | 35 | ```{note} 36 | The {command}`pip install` command does no longer work out-of-the-box in newer 37 | distributions like Ubuntu 23.04 or Debian 12 because of [PEP 668](https://peps.python.org/pep-0668). 38 | Please use the {ref}`installation via pipx ` instead. 39 | ``` 40 | 41 | The following command installs {program}`gvm-tools` system wide: 42 | 43 | ```shell 44 | python3 -m pip install gvm-tools 45 | ``` 46 | 47 | A system wide installation usually requires admin permissions. Therefore, 48 | {program}`gvm-tools` may only be installed for the 49 | [current user](https://docs.python.org/3/library/site.html#site.USER_BASE) 50 | via: 51 | 52 | ```shell 53 | python3 -m pip install --user gvm-tools 54 | ``` 55 | 56 | For further details and additional installation options, please take a look at 57 | the documentation of [pip]. 58 | 59 | ### Using poetry 60 | 61 | To avoid polluting the system and user namespaces with Python packages and to 62 | allow installing different versions of the same package at the same time, 63 | [python virtual environments](https://docs.python.org/3/library/venv.html) 64 | have been introduced. 65 | 66 | [poetry] is a tool combining the use of virtual environments and handling 67 | dependencies elegantly. 68 | 69 | Please follow the [poetry documentation](https://python-poetry.org/docs/#installation) 70 | to install the tool. 71 | 72 | To install {program}`gvm-tools` into a virtual environment, defaulting into 73 | the folder `.venv`, the following command need to be executed: 74 | 75 | ```shell 76 | poetry install 77 | ``` 78 | 79 | Afterwards, the environment containing the installed {program}`gvm-tools` can be 80 | activated by running: 81 | 82 | ```shell 83 | poetry shell 84 | ``` 85 | 86 | It is also possible to run single commands within the virtual environment: 87 | 88 | ```shell 89 | poetry run gvm-cli -h 90 | ``` 91 | 92 | ## Getting the Source 93 | 94 | The source code of **python-gvm** can be found at 95 | [GitHub](https://github.com/greenbone/python-gvm). 96 | 97 | To clone this public repository and install from source for the current user run 98 | the following commands: 99 | 100 | ```shell 101 | git clone git://github.com/greenbone/gvm-tools.git && cd gvm-tools 102 | python3 -m pip install -e . 103 | ``` 104 | 105 | [pip]: https://pip.pypa.io/en/stable/ 106 | [pipx]: https://pypa.github.io/pipx/ 107 | [poetry]: https://python-poetry.org/ 108 | [pypi]: https://pypi.org/ 109 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | furo 3 | -------------------------------------------------------------------------------- /gvmtools/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2018-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | """ 19 | Main module of gvm-tools. 20 | """ 21 | 22 | 23 | def get_version() -> str: 24 | """Returns the version of gvm-tools as a string in `PEP440`_ compliant 25 | format. 26 | 27 | Returns: 28 | str: Current version of gvm-tools 29 | 30 | .. _PEP440: 31 | https://www.python.org/dev/peps/pep-0440 32 | """ 33 | # pylint: disable=import-outside-toplevel 34 | from .__version__ import __version__ 35 | 36 | return __version__ 37 | -------------------------------------------------------------------------------- /gvmtools/__version__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=invalid-name 2 | 3 | # THIS IS AN AUTOGENERATED FILE. DO NOT TOUCH! 4 | 5 | __version__ = "25.3.1.dev1" 6 | -------------------------------------------------------------------------------- /gvmtools/cli.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2018-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import logging 20 | import sys 21 | import time 22 | 23 | from gvm.errors import GvmError 24 | from gvm.protocols.gmp import Gmp 25 | from gvm.protocols.latest import Osp 26 | from gvm.transforms import CheckCommandTransform 27 | from gvm.xml import parse_xml, pretty_print 28 | 29 | from gvmtools.helper import authenticate, do_not_run_as_root 30 | from gvmtools.parser import ( 31 | PROTOCOL_GMP, 32 | PROTOCOL_OSP, 33 | create_connection, 34 | create_parser, 35 | ) 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | HELP_TEXT = """ 40 | Command line tool to access services via GMP (Greenbone Management Protocol) and OSP (Open Scanner Protocol) 41 | 42 | Examples: 43 | gvm-cli socket --help 44 | gvm-cli tls --help 45 | gvm-cli ssh --help 46 | 47 | gvm-cli socket --xml "" 48 | gvm-cli socket --xml "myusermypass" 49 | gvm-cli socket --gmp-username foo --gmp-password foo myfile.xml 50 | 51 | The protocol specifications for GMP and OSP are available at: 52 | https://docs.greenbone.net/index.html#api_documentation""" # noqa: E501 53 | 54 | 55 | def _load_infile(filename=None): 56 | if not filename: 57 | return None 58 | 59 | with open(filename, encoding="utf-8") as f: 60 | return f.read() 61 | 62 | 63 | def main(): 64 | do_not_run_as_root() 65 | 66 | parser = create_parser(description=HELP_TEXT, logfilename="gvm-cli.log") 67 | 68 | parser.add_protocol_argument() 69 | 70 | parser.add_argument("-X", "--xml", help="XML request to send") 71 | parser.add_argument( 72 | "-r", "--raw", help="Return raw XML", action="store_true", default=False 73 | ) 74 | parser.add_argument( 75 | "--pretty", 76 | help="Pretty format the returned xml", 77 | action="store_true", 78 | default=False, 79 | ) 80 | parser.add_argument( 81 | "--duration", action="store_true", help="Measure command execution time" 82 | ) 83 | parser.add_argument( 84 | "infile", nargs="?", help="File to read XML commands from." 85 | ) 86 | 87 | args = parser.parse_args() 88 | 89 | # If timeout value is -1, then the socket has no timeout for this session 90 | if args.timeout == -1: 91 | args.timeout = None 92 | 93 | if args.xml is not None: 94 | xml = args.xml 95 | else: 96 | try: 97 | xml = _load_infile(args.infile) 98 | except IOError as e: 99 | print(e, file=sys.stderr) 100 | sys.exit(1) 101 | 102 | # If no command was given, program asks for one 103 | if len(xml) == 0: 104 | xml = input() 105 | 106 | try: 107 | parse_xml(xml) 108 | except GvmError as e: 109 | print(e, file=sys.stderr) 110 | sys.exit(1) 111 | 112 | connection = create_connection(**vars(args)) 113 | 114 | if args.raw: 115 | transform = None 116 | else: 117 | transform = CheckCommandTransform() 118 | 119 | if args.protocol == PROTOCOL_OSP: 120 | protocol_class = Osp 121 | else: 122 | protocol_class = Gmp 123 | 124 | try: 125 | with protocol_class(connection, transform=transform) as protocol: 126 | if args.protocol == PROTOCOL_GMP: 127 | # Ask for password if none are given 128 | authenticate(protocol, args.gmp_username, args.gmp_password) 129 | 130 | if args.duration: 131 | starttime = time.time() 132 | 133 | result = protocol.send_command(xml) 134 | 135 | if args.duration: 136 | duration = time.time() - starttime 137 | print(f"Elapsed time: {duration} seconds") 138 | elif args.pretty: 139 | pretty_print(result) 140 | else: 141 | print(result) 142 | 143 | except Exception as e: # pylint: disable=broad-except 144 | logger.error(e) 145 | sys.exit(1) 146 | sys.exit(0) 147 | 148 | 149 | if __name__ == "__main__": 150 | main() 151 | -------------------------------------------------------------------------------- /gvmtools/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2019-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | """ 19 | Module to store gvm-tools configuration settings 20 | """ 21 | 22 | import configparser 23 | import logging 24 | 25 | from gvm.connections import ( 26 | DEFAULT_GVM_PORT, 27 | DEFAULT_HOSTNAME, 28 | DEFAULT_SSH_PORT, 29 | DEFAULT_UNIX_SOCKET_PATH, 30 | ) 31 | 32 | logger = logging.getLogger(__name__) 33 | 34 | 35 | class Config: 36 | def __init__(self): 37 | self._config = configparser.ConfigParser(default_section="main") 38 | 39 | self._config = {} 40 | 41 | self._config["gmp"] = dict(username="", password="") 42 | self._config["ssh"] = dict( 43 | username="gmp", 44 | password="gmp", 45 | port=DEFAULT_SSH_PORT, 46 | hostname=DEFAULT_HOSTNAME, 47 | ) 48 | self._config["unixsocket"] = dict(socketpath=DEFAULT_UNIX_SOCKET_PATH) 49 | self._config["tls"] = dict( 50 | port=DEFAULT_GVM_PORT, hostname=DEFAULT_HOSTNAME 51 | ) 52 | 53 | self._defaults = dict() 54 | 55 | def load(self, filepath): 56 | path = filepath.expanduser() 57 | 58 | config = configparser.ConfigParser(default_section="main") 59 | 60 | with path.open() as f: 61 | config.read_file(f) 62 | 63 | if "Auth" in config: 64 | logger.warning( 65 | "Warning: Loaded config file %s contains deprecated 'Auth' " 66 | "section. This section will be ignored in future.", 67 | str(filepath), 68 | ) 69 | gmp_username = config.get("Auth", "gmp_username", fallback="") 70 | gmp_password = config.get("Auth", "gmp_password", fallback="") 71 | self._config["gmp"]["username"] = gmp_username 72 | self._config["gmp"]["password"] = gmp_password 73 | 74 | self._defaults.update(config.defaults()) 75 | 76 | for section in config.sections(): 77 | if section == "Auth": 78 | continue 79 | 80 | for key, value in config.items(section): 81 | self._config.setdefault(section, dict())[key] = value 82 | 83 | def defaults(self): 84 | return self._defaults 85 | 86 | def get(self, section, name): 87 | if section not in self._config: 88 | return None 89 | 90 | return self._config[section].get(name) 91 | -------------------------------------------------------------------------------- /gvmtools/script.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2018-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | import sys 21 | import traceback 22 | from argparse import Namespace 23 | 24 | from gvm import get_version as get_gvm_version 25 | from gvm.protocols.gmp import Gmp 26 | from gvm.protocols.latest import Osp 27 | from gvm.transforms import EtreeCheckCommandTransform 28 | 29 | from gvmtools import get_version 30 | from gvmtools.helper import authenticate, do_not_run_as_root, run_script 31 | from gvmtools.parser import ( 32 | PROTOCOL_GMP, 33 | PROTOCOL_OSP, 34 | create_connection, 35 | create_parser, 36 | ) 37 | 38 | HELP_TEXT = """ 39 | Command line tool to execute custom GMP (Greenbone Management 40 | Protocol) and OSP (Open Scanner Protocol) scripts. 41 | 42 | The protocol specifications for GMP and OSP are available at: 43 | https://docs.greenbone.net/index.html#api_documentation 44 | """ 45 | 46 | __version__ = get_version() 47 | __api_version__ = get_gvm_version() 48 | 49 | 50 | def main(): 51 | do_not_run_as_root() 52 | 53 | parser = create_parser(description=HELP_TEXT, logfilename="gvm-script.log") 54 | 55 | parser.add_protocol_argument() 56 | 57 | parser.add_argument( 58 | "scriptname", 59 | metavar="SCRIPT", 60 | help="Path to script to be executed (example: myscript.gmp.py)", 61 | ) 62 | parser.add_argument( 63 | "scriptargs", nargs="*", metavar="ARG", help="Arguments for the script" 64 | ) 65 | args, script_args = parser.parse_known_args() 66 | 67 | connection = create_connection(**vars(args)) 68 | 69 | transform = EtreeCheckCommandTransform() 70 | 71 | global_vars = { 72 | "__version__": __version__, 73 | "__api_version__": __api_version__, 74 | } 75 | 76 | username = None 77 | password = None 78 | 79 | if args.protocol == PROTOCOL_OSP: 80 | protocol_class = Osp 81 | name = "osp" 82 | else: 83 | protocol_class = Gmp 84 | name = "gmp" 85 | 86 | try: 87 | with protocol_class(connection, transform=transform) as protocol: 88 | global_vars[name] = protocol 89 | global_vars["__name__"] = f"__{name}__" 90 | 91 | if args.protocol == PROTOCOL_GMP: 92 | if args.gmp_username: 93 | (username, password) = authenticate( 94 | protocol, 95 | username=args.gmp_username, 96 | password=args.gmp_password, 97 | ) 98 | 99 | argv = [os.path.abspath(args.scriptname), *args.scriptargs] 100 | 101 | shell_args = Namespace( 102 | username=username, 103 | password=password, 104 | argv=argv, 105 | # for backwards compatibility we add script here 106 | script=argv, 107 | # the unknown args, which are owned by the script. 108 | script_args=script_args, 109 | ) 110 | 111 | global_vars["args"] = shell_args 112 | 113 | run_script(args.scriptname, global_vars) 114 | 115 | except Exception: # pylint: disable=broad-except 116 | print(traceback.format_exc()) 117 | sys.exit(1) 118 | 119 | sys.exit(0) 120 | 121 | 122 | if __name__ == "__main__": 123 | main() 124 | -------------------------------------------------------------------------------- /scripts/application-detection.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | 8 | from gvm.protocols.gmp import Gmp 9 | 10 | 11 | def check_args(args): 12 | len_args = len(args.script) - 1 13 | if len_args != 1: 14 | message = """ 15 | This script will display all hosts with the searched applications! 16 | 17 | 1. -- Name of the application 18 | 19 | Example: 20 | $ gvm-script --gmp-username name --gmp-password pass \ 21 | ssh --hostname scripts/application-detection.gmp.py 22 | """ 23 | print(message) 24 | sys.exit() 25 | 26 | 27 | def print_assets(gmp, appname): 28 | res = gmp.get_reports(details=False) 29 | 30 | reports = res.xpath("/get_reports_response/report") 31 | for report in reports: 32 | report_id = report.attrib["id"] 33 | print_assets_for_host(gmp, appname, report_id) 34 | 35 | 36 | def print_assets_for_host(gmp, appname, report_id): 37 | res = gmp.get_report( 38 | report_id, details=True, filter_string="rows=1 result_hosts_only=0" 39 | ) 40 | 41 | hosts = res.xpath("/get_reports_response/report/report/host") 42 | 43 | for host in hosts: 44 | ip = host.xpath("ip/text()") 45 | if len(ip) == 0: 46 | continue 47 | else: 48 | ip = ip[0] 49 | 50 | hostname = host.xpath('detail/name[text()="hostname"]/../value/text()') 51 | if len(hostname) == 0: 52 | hostname = "" 53 | else: 54 | hostname = hostname[0] 55 | 56 | apps = host.xpath( 57 | 'detail/name[text() = "App"]/../value[' 58 | f'contains(text(), "{appname}")]/text()' 59 | ) 60 | if len(apps) == 0: 61 | continue 62 | 63 | print(f"{ip} ({hostname})") 64 | for app in apps: 65 | print("\t" + app) 66 | print("\n") 67 | 68 | 69 | def main(gmp: Gmp, args: Namespace) -> None: 70 | # pylint: disable=undefined-variable 71 | 72 | check_args(args) 73 | 74 | print_assets(gmp, args.script[1]) 75 | 76 | 77 | if __name__ == "__gmp__": 78 | main(gmp, args) 79 | -------------------------------------------------------------------------------- /scripts/bulk-modify-schedules.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | 8 | from gvm.protocols.gmp import Gmp 9 | 10 | 11 | def check_args(args): 12 | len_args = len(args.script) - 1 13 | 14 | if len_args != 3: 15 | message = """ 16 | This script modifies the timezone and/or icalendar of all schedules 17 | in a filter selection. 18 | 19 | -- the filter text used to filter the schedules. 20 | -- the new timezone to set or empty to keep existing one. 21 | -- the new icalendar to set or empty to keep existing one. 22 | 23 | Example: 24 | $ gvm-script --gmp-username name --gmp-password pass \\ 25 | ssh --hostname scripts/bulk-modify-schedules.gmp.py \\ 26 | 27 | """ 28 | print(message) 29 | sys.exit() 30 | 31 | 32 | def bulk_modify_schedules(gmp, filter_term, new_timezone, new_icalendar): 33 | get_response = gmp.get_schedules(filter=filter_term) 34 | schedules = get_response.findall("schedule") 35 | 36 | for schedule in schedules: 37 | uuid = schedule.attrib["id"] 38 | name = schedule.find("name").text 39 | comment = schedule.find("comment").text 40 | 41 | if new_timezone: 42 | timezone = new_timezone 43 | else: 44 | timezone = schedule.find("timezone").text 45 | 46 | if new_icalendar: 47 | icalendar = new_icalendar 48 | else: 49 | icalendar = schedule.find("icalendar").text 50 | 51 | print(f"- Modifying {name} ({uuid})") 52 | 53 | gmp.modify_schedule( 54 | uuid, 55 | name=name, 56 | comment=comment, 57 | timezone=timezone, 58 | icalendar=icalendar, 59 | ) 60 | 61 | 62 | def main(gmp: Gmp, args: Namespace) -> None: 63 | # pylint: disable=unused-argument 64 | 65 | check_args(args) 66 | 67 | filter_term = args.script[1] 68 | new_timezone = args.script[2] 69 | new_icalendar = args.script[3] 70 | 71 | bulk_modify_schedules(gmp, filter_term, new_timezone, new_icalendar) 72 | 73 | 74 | if __name__ == "__gmp__": 75 | main(gmp, args) 76 | -------------------------------------------------------------------------------- /scripts/cfg-gen-for-certs.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | 8 | from gvm.errors import GvmError 9 | from gvm.protocols.gmp import Gmp 10 | 11 | 12 | def check_args(args): 13 | len_args = len(args.script) - 1 14 | if len_args != 1: 15 | message = """ 16 | This script creates a new scan config with nvts from a given CERT-Bund! 17 | It needs one parameter after the script name. 18 | 19 | 1. -- Name or ID of the CERT-Bund 20 | 21 | Example: 22 | $ gvm-script --gmp-username name --gmp-password pass \ 23 | ssh --hostname scripts/cfg-gen-for-certs.gmp.py CB-K16/0943 24 | """ 25 | print(message) 26 | sys.exit() 27 | 28 | 29 | def create_scan_config(gmp, cert_bund_name): 30 | cert_bund_details = gmp.get_info( 31 | info_id=cert_bund_name, info_type=gmp.types.InfoType.CERT_BUND_ADV 32 | ) 33 | 34 | list_cves = cert_bund_details.xpath( 35 | "info/cert_bund_adv/raw_data/Advisory/CVEList/CVE/text()" 36 | ) 37 | 38 | nvt_dict = dict() 39 | counter = 0 40 | 41 | for cve in list_cves: 42 | # Get all nvts of this cve 43 | cve_info = gmp.get_info(info_id=cve, info_type=gmp.types.InfoType.CVE) 44 | nvts = cve_info.xpath("info/cve/nvts/nvt") 45 | 46 | for nvt in nvts: 47 | counter += 1 48 | oid = nvt.xpath("@oid")[0] 49 | 50 | # We need the nvt family to modify scan config 51 | nvt_data = gmp.get_scan_config_nvt(oid) 52 | family = nvt_data.xpath("nvt/family/text()")[0] 53 | 54 | # Create key value map 55 | if family in nvt_dict and oid not in nvt_dict[family]: 56 | nvt_dict[family].append(oid) 57 | else: 58 | nvt_dict[family] = [oid] 59 | 60 | # Create new config 61 | copy_id = "085569ce-73ed-11df-83c3-002264764cea" 62 | config_name = f"scanconfig_for_{cert_bund_name}" 63 | config_id = "" 64 | 65 | try: 66 | res = gmp.create_scan_config(copy_id, config_name) 67 | config_id = res.xpath("@id")[0] 68 | 69 | # Modify the config with the nvts oid 70 | for family, nvt_oid in nvt_dict.items(): 71 | try: 72 | gmp.modify_scan_config_set_nvt_selection( 73 | config_id=config_id, nvt_oids=nvt_oid, family=family 74 | ) 75 | except GvmError as gvmerr: 76 | print(f"{gvmerr=}") 77 | 78 | # This nvts must be present to work 79 | family = "Port scanners" 80 | nvts = ["1.3.6.1.4.1.25623.1.0.14259", "1.3.6.1.4.1.25623.1.0.100315"] 81 | gmp.modify_scan_config_set_nvt_selection( 82 | config_id=config_id, nvt_oids=nvts, family=family 83 | ) 84 | 85 | except GvmError: 86 | print("Config exist") 87 | 88 | 89 | def main(gmp: Gmp, args: Namespace) -> None: 90 | # pylint: disable=undefined-variable 91 | 92 | check_args(args) 93 | 94 | cert_bund_name = args.script[1] 95 | 96 | print(f"Creating scan config for {cert_bund_name}") 97 | 98 | create_scan_config(gmp, cert_bund_name) 99 | 100 | 101 | if __name__ == "__gmp__": 102 | main(gmp, args) 103 | -------------------------------------------------------------------------------- /scripts/clean-sensor.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.errors import GvmResponseError 8 | from gvm.protocols.gmp import Gmp 9 | 10 | 11 | def clean_sensor(gmp: Gmp) -> None: 12 | tasks = gmp.get_tasks( 13 | filter_string="rows=-1 not status=Running and " 14 | "not status=Requested and not " 15 | "status="Stop Requested"" 16 | ) 17 | 18 | try: 19 | for task_id in tasks.xpath("task/@id"): 20 | print(f"Removing task {task_id} ... ") 21 | status_text = gmp.delete_task(task_id, ultimate=True).xpath( 22 | "@status_text" 23 | )[0] 24 | print(status_text) 25 | except GvmResponseError as gvmerr: 26 | print(f"{gvmerr=}") 27 | pass 28 | 29 | targets = gmp.get_targets(filter_string="rows=-1 not _owner=""") 30 | try: 31 | for target_id in targets.xpath("target/@id"): 32 | print(f"Removing target {target_id} ... ") 33 | status_text = gmp.delete_target(target_id, ultimate=True).xpath( 34 | "@status_text" 35 | )[0] 36 | print(status_text) 37 | except GvmResponseError as gvmerr: 38 | print(f"{gvmerr=}") 39 | pass 40 | 41 | configs = gmp.get_scan_configs( 42 | filter_string="rows=-1 not _owner=""" 43 | ) 44 | try: 45 | for config_id in configs.xpath("config/@id"): 46 | print(f"Removing config {config_id} ... ") 47 | status_text = gmp.delete_scan_config( 48 | config_id, ultimate=True 49 | ).xpath("@status_text")[0] 50 | print(status_text) 51 | except GvmResponseError as gvmerr: 52 | print(f"{gvmerr=}") 53 | pass 54 | 55 | port_lists = gmp.get_port_lists( 56 | filter_string="rows=-1 not _owner=""" 57 | ) 58 | try: 59 | for port_list_id in port_lists.xpath("port_list/@id"): 60 | print(f"Removing port_list {port_list_id} ... ") 61 | status_text = gmp.delete_port_list( 62 | port_list_id, ultimate=True 63 | ).xpath("@status_text")[0] 64 | print(status_text) 65 | except GvmResponseError as gvmerr: 66 | print(f"{gvmerr=}") 67 | pass 68 | 69 | alerts = gmp.get_alerts(filter_string="rows=-1 not _owner=""") 70 | try: 71 | for alert_id in alerts.xpath("alert/@id"): 72 | print(f"Removing alert {alert_id} ... ") 73 | status_text = gmp.delete_alert(alert_id, ultimate=True).xpath( 74 | "@status_text" 75 | )[0] 76 | print(status_text) 77 | except GvmResponseError as gvmerr: 78 | print(f"{gvmerr=}") 79 | pass 80 | 81 | schedules = gmp.get_schedules( 82 | filter_string="rows=-1 not _owner=""" 83 | ) 84 | try: 85 | for schedule_id in schedules.xpath("schedule/@id"): 86 | print(f"Removing schedule {schedule_id} ... ") 87 | status_text = gmp.delete_schedule(schedule_id, ultimate=True).xpath( 88 | "@status_text" 89 | )[0] 90 | print(status_text) 91 | except GvmResponseError as gvmerr: 92 | print(f"{gvmerr=}") 93 | pass 94 | 95 | tags = gmp.get_tags(filter_string="rows=-1 not _owner=""") 96 | try: 97 | for tag_id in tags.xpath("tag/@id"): 98 | print(f"Removing tag {tag_id} ... ") 99 | status_text = gmp.delete_tag(tag_id, ultimate=True).xpath( 100 | "@status_text" 101 | )[0] 102 | print(status_text) 103 | except GvmResponseError as gvmerr: 104 | print(f"{gvmerr=}") 105 | pass 106 | 107 | filters = gmp.get_filters(filter_string="rows=-1 not _owner=""") 108 | try: 109 | for filter_id in filters.xpath("filter/@id"): 110 | print(f"Removing filter {filter_id} ... ") 111 | status_text = gmp.delete_filter(filter_id, ultimate=True).xpath( 112 | "@status_text" 113 | )[0] 114 | print(status_text) 115 | except GvmResponseError as gvmerr: 116 | print(f"{gvmerr=}") 117 | pass 118 | 119 | credentials = gmp.get_credentials( 120 | filter_string="rows=-1 not _owner=""" 121 | ) 122 | try: 123 | for config_id in credentials.xpath("credential/@id"): 124 | print(f"Removing credential {config_id} ... ") 125 | status_text = gmp.delete_credential(config_id, ultimate=True).xpath( 126 | "@status_text" 127 | )[0] 128 | print(status_text) 129 | except GvmResponseError as gvmerr: 130 | print(f"{gvmerr=}") 131 | pass 132 | 133 | print("Emptying trash... ") 134 | try: 135 | status_text = gmp.empty_trashcan().xpath("@status_text")[0] 136 | print(status_text) 137 | except GvmResponseError as gvmerr: 138 | print(f"{gvmerr=}") 139 | pass 140 | 141 | 142 | def main(gmp: Gmp, args: Namespace) -> None: 143 | # pylint: disable=unused-argument 144 | 145 | print( 146 | "This script removes all resources from a sensor, except active tasks.\n" 147 | ) 148 | 149 | clean_sensor(gmp) 150 | 151 | 152 | if __name__ == "__gmp__": 153 | main(gmp, args) 154 | -------------------------------------------------------------------------------- /scripts/combine-reports.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | # ruff: noqa: E501 6 | 7 | import sys 8 | import time 9 | from argparse import Namespace 10 | 11 | from gvm.protocols.gmp import Gmp 12 | from gvmtools.helper import generate_uuid 13 | from lxml import etree as e 14 | 15 | 16 | def check_args(args: Namespace) -> None: 17 | len_args = len(args.script) - 1 18 | if len_args < 2: 19 | message = """ 20 | This script will combine desired reports into a single report. \ 21 | The combined report will then be sent to a desired container task. \ 22 | This script will create a container task for the combined report to\ 23 | be sent to, however, if you would like the report to be sent to an \ 24 | existing task, place the report of the desired task first and add \ 25 | the argument 'first_task'. 26 | 27 | 1. --uuid of report to be combined 28 | 2. --uuid of report to be combined 29 | ... 30 | n. --uuid of report to be combined 31 | 32 | Example for starting up the routine: 33 | $ gvm-script --gmp-username=namessh --gmp-password=pass ssh --hostname=hostname \ 34 | scripts/combine-reports.gmp.py \ 35 | "d15a337c-56f3-4208-a462-afeb79eb03b7" \ 36 | "303fa0a6-aa9b-43c4-bac0-66ae0b2d1698" 'first_task' 37 | 38 | """ 39 | print(message) 40 | sys.exit() 41 | 42 | 43 | def combine_reports(gmp: Gmp, args: Namespace) -> e.Element: 44 | new_uuid = generate_uuid() 45 | combined_report = e.Element( 46 | "report", 47 | { 48 | "id": new_uuid, 49 | "format_id": "d5da9f67-8551-4e51-807b-b6a873d70e34", 50 | "extension": "xml", 51 | "content_type": "text/xml", 52 | }, 53 | ) 54 | report_elem = e.Element("report", {"id": new_uuid}) 55 | ports_elem = e.Element("ports", {"start": "1", "max": "-1"}) 56 | results_elem = e.Element("results", {"start": "1", "max": "-1"}) 57 | combined_report.append(report_elem) 58 | report_elem.append(results_elem) 59 | 60 | if "first_task" in args.script: 61 | arg_len = args.script[1:-1] 62 | else: 63 | arg_len = args.script[1:] 64 | 65 | for argument in arg_len: 66 | current_report = gmp.get_report( 67 | argument, details=True, ignore_pagination=True 68 | )[0] 69 | for port in current_report.xpath("report/ports/port"): 70 | ports_elem.append(port) 71 | for result in current_report.xpath("report/results/result"): 72 | results_elem.append(result) 73 | for host in current_report.xpath("report/host"): 74 | report_elem.append(host) 75 | 76 | return combined_report 77 | 78 | 79 | def send_report(gmp: Gmp, args: Namespace, combined_report: e.Element) -> str: 80 | if "first_task" in args.script: 81 | main_report = gmp.get_report(args.script[1])[0] 82 | task_id = main_report.xpath("//task/@id")[0] 83 | else: 84 | the_time = time.strftime("%Y/%m/%d-%H:%M:%S") 85 | task_id = "" 86 | task_name = f"Combined_Report_{the_time}" 87 | 88 | res = gmp.create_container_task( 89 | name=task_name, comment="Created with gvm-tools." 90 | ) 91 | 92 | task_id = res.xpath("//@id")[0] 93 | 94 | combined_report = e.tostring(combined_report) 95 | 96 | res = gmp.import_report(combined_report, task_id=task_id, in_assets=True) 97 | 98 | return res.xpath("//@id")[0] 99 | 100 | 101 | def main(gmp: Gmp, args: Namespace) -> None: 102 | # pylint: disable=undefined-variable 103 | 104 | check_args(args) 105 | 106 | combined_report = combine_reports(gmp, args) 107 | send_report(gmp, args, combined_report) 108 | 109 | 110 | if __name__ == "__gmp__": 111 | main(gmp, args) 112 | -------------------------------------------------------------------------------- /scripts/create-dummy-data.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | from random import choice 8 | 9 | from gvm.protocols.gmp import Gmp 10 | from gvmtools.helper import generate_id 11 | 12 | 13 | def check_args(args): 14 | len_args = len(args.script) - 1 15 | if len_args != 1: 16 | message = """ 17 | This script will create random data in the given GVM database 18 | 19 | 1. -- Number of datasets to create 20 | 21 | Example: 22 | $ gvm-script --gmp-username name --gmp-password pass \ 23 | ssh --hostname scripts/create-dummy-data.gmp.py 24 | """ 25 | print(message) 26 | sys.exit() 27 | 28 | 29 | def create_data(gmp, count): 30 | config_ids = [] 31 | target_ids = [] 32 | 33 | for _ in range(0, count): 34 | name = generate_id() 35 | gmp.create_credential( 36 | name, 37 | login=name, 38 | password=name, 39 | credential_type=gmp.types.CredentialType.PASSWORD_ONLY, 40 | ) 41 | print(str(count) + " random credentials generated.") 42 | 43 | for _ in range(0, count): 44 | name = generate_id() 45 | gmp.create_port_list(name, port_range="T:1-42") 46 | print(str(count) + " random port lists generated.") 47 | 48 | for _ in range(0, count): 49 | name = generate_id() 50 | res = gmp.create_scan_config( 51 | "085569ce-73ed-11df-83c3-002264764cea", name 52 | ) 53 | config_ids.append(res.xpath("@id")[0]) 54 | print(str(count) + " random scan configs generated.") 55 | 56 | for _ in range(0, count): 57 | name = generate_id() 58 | res = gmp.create_target(name, hosts=["127.0.0.1"]) 59 | 60 | target_ids.append(res.xpath("@id")[0]) 61 | print(str(count) + " random targets generated.") 62 | 63 | for _ in range(0, count): 64 | name = generate_id() 65 | config_id = choice(config_ids) 66 | target_id = choice(target_ids) 67 | gmp.create_task( 68 | name, config_id, target_id, "08b69003-5fc2-4037-a479-93b440211c73" 69 | ) 70 | print(str(count) + " random tasks generated.") 71 | 72 | 73 | def main(gmp: Gmp, args: Namespace) -> None: 74 | # pylint: disable=undefined-variable 75 | 76 | check_args(args) 77 | 78 | create_data(gmp, int(args.script[1])) 79 | 80 | 81 | if __name__ == "__gmp__": 82 | main(gmp, args) 83 | -------------------------------------------------------------------------------- /scripts/create-schedules-from-csv.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # 5 | 6 | # Run with gvm-script --gmp-username admin-user --gmp-password password socket create-schedules-from-csv.gmp.py schedules.csv 7 | 8 | import csv 9 | import sys 10 | import time 11 | from argparse import ArgumentParser, Namespace, RawTextHelpFormatter 12 | from pathlib import Path 13 | 14 | from gvm.errors import GvmResponseError 15 | from gvm.protocols.gmp import Gmp 16 | from gvmtools.helper import error_and_exit 17 | 18 | HELP_TEXT = ( 19 | "This script pulls schedule information " 20 | "from a csv file and creates a schedule for each row. \n" 21 | "use the same schedule names when creating tasks! \n\n" 22 | "csv file may contain Name of schedule, Timezone, Icalendar entry \n" 23 | "Use example schedules.csv as a template \n\n" 24 | "It should be rather self explanatory." 25 | ) 26 | 27 | 28 | def check_args(args): 29 | len_args = len(args.script) - 1 30 | if len_args != 2: 31 | message = """ 32 | This script pulls schedules from a csv file and creates a \ 33 | schedule for each row in the csv file. 34 | One parameter after the script name is required. 35 | 36 | 1. -- csv file containing names and secrets required for scan schedules 37 | 38 | Example: 39 | $ gvm-script --gmp-username name --gmp-password pass \ 40 | ssh --hostname scripts/create_schedules_from_csv.gmp.py \ 41 | 42 | """ 43 | print(message) 44 | sys.exit() 45 | 46 | 47 | def parse_args(args: Namespace) -> Namespace: # pylint: disable=unused-argument 48 | """Parsing args ...""" 49 | 50 | parser = ArgumentParser( 51 | prefix_chars="+", 52 | add_help=False, 53 | formatter_class=RawTextHelpFormatter, 54 | description=HELP_TEXT, 55 | ) 56 | 57 | parser.add_argument( 58 | "+h", 59 | "++help", 60 | action="help", 61 | help="Show this help message and exit.", 62 | ) 63 | 64 | parser.add_argument( 65 | "sched_file", 66 | type=str, 67 | help=("CSV File containing schedules"), 68 | ) 69 | script_args, _ = parser.parse_known_args(args) 70 | return script_args 71 | 72 | 73 | def schedule_id( 74 | gmp: Gmp, 75 | schedule_name: str, 76 | ): 77 | response_xml = gmp.get_schedules( 78 | filter_string="rows=-1, name=" + schedule_name 79 | ) 80 | schedules_xml = response_xml.xpath("schedule") 81 | schedule_id = "" 82 | 83 | for schedule in schedules_xml: 84 | schedule_id = schedule.get("id") 85 | return schedule_id 86 | 87 | 88 | def create_schedules( 89 | gmp: Gmp, 90 | sched_file: Path, 91 | ): 92 | try: 93 | numberschedules = 0 94 | with open(sched_file, encoding="utf-8") as csvFile: 95 | content = csv.reader(csvFile, delimiter=",") # read the data 96 | for row in content: # loop through each row 97 | if len(row) == 0: 98 | continue 99 | sched_name = row[0] 100 | sched_tz = row[1] 101 | sched_ical = row[2] 102 | comment = f"Created: {time.strftime('%Y/%m/%d-%H:%M:%S')}" 103 | try: 104 | if schedule_id(gmp, sched_name): 105 | print(f"Schedule: {sched_name} exist, not creating...") 106 | continue 107 | print("Creating schedule: " + sched_name) 108 | gmp.create_schedule( 109 | name=sched_name, 110 | timezone=sched_tz, 111 | icalendar=sched_ical, 112 | comment=comment, 113 | ) 114 | numberschedules = numberschedules + 1 115 | except GvmResponseError as gvmerr: 116 | print(f"{gvmerr=}, name: {sched_name}") 117 | pass 118 | csvFile.close() # close the csv file 119 | 120 | except IOError as e: 121 | error_and_exit(f"Failed to read sched_file: {str(e)} (exit)") 122 | 123 | if len(row) == 0: 124 | error_and_exit("schedules file is empty (exit)") 125 | 126 | return numberschedules 127 | 128 | 129 | def main(gmp: Gmp, args: Namespace) -> None: 130 | # pylint: disable=undefined-variable 131 | if args.script: 132 | args = args.script[1:] 133 | 134 | parsed_args = parse_args(args=args) 135 | 136 | print("Creating schedules.\n") 137 | 138 | numberschedules = create_schedules( 139 | gmp, 140 | parsed_args.sched_file, 141 | ) 142 | 143 | numberschedules = str(numberschedules) 144 | print(" [" + numberschedules + "] schedule(s) created!\n") 145 | 146 | 147 | if __name__ == "__gmp__": 148 | main(gmp, args) 149 | -------------------------------------------------------------------------------- /scripts/create-targets-from-host-list.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | import time 7 | from argparse import ArgumentParser, Namespace, RawTextHelpFormatter 8 | from pathlib import Path 9 | from typing import List 10 | 11 | from gvm.protocols.gmp import Gmp 12 | from gvmtools.helper import error_and_exit 13 | 14 | HELP_TEXT = ( 15 | "This script pulls hostnames from a text " 16 | "file and creates a target for each." 17 | ) 18 | 19 | 20 | def check_args(args): 21 | len_args = len(args.script) - 1 22 | if len_args != 2: 23 | message = """ 24 | This script pulls hostnames from a text file and creates a target \ 25 | for each. 26 | One parameter after the script name is required. 27 | 28 | 1. -- IP of the GVM host 29 | 2. -- text file containing hostnames 30 | 31 | Example: 32 | $ gvm-script --gmp-username name --gmp-password pass \ 33 | ssh --hostname scripts/create_targets_from_host_list.gmp \ 34 | 35 | """ 36 | print(message) 37 | sys.exit() 38 | 39 | 40 | def parse_args(args: Namespace) -> Namespace: # pylint: disable=unused-argument 41 | """Parsing args ...""" 42 | 43 | parser = ArgumentParser( 44 | prefix_chars="+", 45 | add_help=False, 46 | formatter_class=RawTextHelpFormatter, 47 | description=HELP_TEXT, 48 | ) 49 | 50 | parser.add_argument( 51 | "+h", 52 | "++help", 53 | action="help", 54 | help="Show this help message and exit.", 55 | ) 56 | 57 | parser.add_argument( 58 | "hostname", 59 | type=str, 60 | help="Host name to create targets for.", 61 | ) 62 | 63 | parser.add_argument( 64 | "hosts_file", 65 | type=str, 66 | help=("File containing host names / IPs"), 67 | ) 68 | 69 | ports = parser.add_mutually_exclusive_group() 70 | ports.add_argument( 71 | "+pl", 72 | "++port-list-id", 73 | type=str, 74 | dest="port_list_id", 75 | help="UUID of existing port list.", 76 | ) 77 | ports.add_argument( 78 | "+pr", 79 | "++port-range", 80 | dest="port_range", 81 | type=str, 82 | help=( 83 | "Port range to create port list from, e.g. " 84 | "T:1-1234 for ports 1-1234/TCP" 85 | ), 86 | ) 87 | 88 | ports.set_defaults( 89 | port_list_id="4a4717fe-57d2-11e1-9a26-406186ea4fc5" 90 | ) # All IANA assigned TCP and UDP 91 | script_args, _ = parser.parse_known_args(args) 92 | return script_args 93 | 94 | 95 | def load_host_list(host_file): 96 | try: 97 | with open(host_file, encoding="utf-8") as f: 98 | content = f.readlines() 99 | host_list = [x.strip() for x in content] 100 | host_list = list(filter(None, host_list)) 101 | except IOError as e: 102 | error_and_exit(f"Failed to read host_file: {str(e)} (exit)") 103 | 104 | if len(host_list) == 0: 105 | error_and_exit("Host file is empty (exit)") 106 | 107 | return host_list 108 | 109 | 110 | def send_targets( 111 | gmp: Gmp, 112 | host_name: str, 113 | host_file: Path, 114 | host_list: List[str], 115 | port_list_id: str, 116 | ): 117 | print(f"\nSending targets from {host_file} to {host_name}...") 118 | 119 | for host in host_list: 120 | name = f"Target for {host}" 121 | comment = f"Created: {time.strftime('%Y/%m/%d-%H:%M:%S')}" 122 | hosts = [host] 123 | 124 | gmp.create_target( 125 | name=name, comment=comment, hosts=hosts, port_list_id=port_list_id 126 | ) 127 | 128 | 129 | def main(gmp: Gmp, args: Namespace) -> None: 130 | # pylint: disable=undefined-variable 131 | if args.script: 132 | args = args.script[1:] 133 | 134 | parsed_args = parse_args(args=args) 135 | 136 | hosts_list = load_host_list(parsed_args.hosts_file) 137 | 138 | if parsed_args.port_range: 139 | print(parsed_args.port_range) 140 | resp = gmp.create_port_list( 141 | name=f"Port list for target {parsed_args.hostname}", 142 | port_range=parsed_args.port_range, 143 | comment="Port List created by gvm-script", 144 | ) 145 | port_list_id = resp.xpath("//@id")[0] 146 | print(f"Port list {port_list_id} created!\n") 147 | else: 148 | port_list_id = parsed_args.port_list_id 149 | send_targets( 150 | gmp, 151 | parsed_args.hostname, 152 | parsed_args.hosts_file, 153 | hosts_list, 154 | port_list_id, 155 | ) 156 | 157 | print("\n Target(s) created!\n") 158 | 159 | 160 | if __name__ == "__gmp__": 161 | main(gmp, args) 162 | -------------------------------------------------------------------------------- /scripts/delete-overrides-by-filter.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | import time 7 | from argparse import Namespace 8 | 9 | from gvm.protocols.gmp import Gmp 10 | 11 | 12 | def check_args(args): 13 | len_args = len(args.script) - 1 14 | 15 | if len_args != 1: 16 | message = """ 17 | This script deletes overrides with a specific filter value 18 | 19 | -- the parameter for the filter. 20 | 21 | Example: 22 | $ gvm-script --gmp-username name --gmp-password pass \ 23 | ssh --hostname scripts/delete-overrides-by-filter.gmp.py 24 | """ 25 | print(message) 26 | sys.exit() 27 | 28 | 29 | def delete_overrides(gmp, filter_value): 30 | filters = gmp.get_overrides(filter=filter_value) 31 | 32 | if not filters.xpath("override"): 33 | print(f"No overrides with filter: {filter_value}") 34 | 35 | for f_id in filters.xpath("override/@id"): 36 | print(f"Delete override: {f_id}", end="") 37 | res = gmp.delete_override(f_id) 38 | 39 | if "OK" in res.xpath("@status_text")[0]: 40 | print(" OK") 41 | else: 42 | print(" ERROR") 43 | 44 | time.sleep(60) 45 | 46 | 47 | def main(gmp: Gmp, args: Namespace) -> None: 48 | # pylint: disable=undefined-variable 49 | 50 | check_args(args) 51 | 52 | filter_value = args.script[1] 53 | 54 | delete_overrides(gmp, filter_value) 55 | 56 | 57 | if __name__ == "__gmp__": 58 | main(gmp, args) 59 | -------------------------------------------------------------------------------- /scripts/empty-trash.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2014 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | 9 | 10 | def main(gmp: Gmp, args: Namespace) -> None: 11 | 12 | print("Emptying Trash...\n") 13 | 14 | try: 15 | status_text = gmp.empty_trashcan().xpath("@status_text")[0] 16 | print(status_text) 17 | except Exception as e: 18 | print(f"{e=}") 19 | 20 | 21 | if __name__ == "__gmp__": 22 | main(gmp, args) 23 | -------------------------------------------------------------------------------- /scripts/export-certificates.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # 5 | # Loosely based on other greenbone scripts 6 | # 7 | # Run with: gvm-script --gmp-username admin-user --gmp-password password socket export-hosts-csv.gmp.py days 8 | # example: gvm-script --gmp-username admin --gmp-password top$ecret socket export-hosts-csv.gmp.py hosts.csv 2 9 | 10 | import csv 11 | from argparse import ArgumentParser, Namespace, RawTextHelpFormatter 12 | from datetime import date, datetime, time, timedelta 13 | 14 | # GVM Specific 15 | from gvm.protocols.gmp import Gmp 16 | from gvmtools.helper import error_and_exit 17 | 18 | HELP_TEXT = ( 19 | "This script generates a csv file with certificates " 20 | "from Greenbone Vulnerability Manager.\n" 21 | "Optional: Specify csv filename and days in the past to get data from as positional arguments\n" 22 | "or live with the defaults\n" 23 | "csv file will contain:\n" 24 | "Subject, Issuer, Serial, SHA256 Fingerprint, MD5 Fingerprint, last_seen, Valid From, Valid To" 25 | ) 26 | 27 | 28 | def parse_args(args: Namespace) -> Namespace: # pylint: disable=unused-argument 29 | """Parsing args ...""" 30 | 31 | parser = ArgumentParser( 32 | prefix_chars="+", 33 | add_help=False, 34 | formatter_class=RawTextHelpFormatter, 35 | description=HELP_TEXT, 36 | ) 37 | 38 | parser.add_argument( 39 | "+h", 40 | "++help", 41 | action="help", 42 | help="Show this help message and exit.", 43 | ) 44 | 45 | parser.add_argument( 46 | "csv_filename", 47 | nargs="?", 48 | default="gvm_certificates.csv", 49 | type=str, 50 | help=( 51 | "Optional: CSV File with certificate information - Default: gvm_certificates.csv" 52 | ), 53 | ) 54 | 55 | parser.add_argument( 56 | "delta_days", 57 | nargs="?", 58 | default="1", 59 | type=int, 60 | help=( 61 | "Optional: Number of days in the past to pull information - Default: 1 day" 62 | ), 63 | ) 64 | 65 | script_args, _ = parser.parse_known_args(args) 66 | return script_args 67 | 68 | 69 | def list_tls_certificates( 70 | gmp: Gmp, from_date: date, to_date: date, csvfilename: str 71 | ) -> None: 72 | tls_cert_filter = ( 73 | f"rows=-1 and modified>{from_date.isoformat()} " 74 | f"and modified<{to_date.isoformat()}" 75 | ) 76 | 77 | cert_info = [] 78 | 79 | tls_cert_xml = gmp.get_tls_certificates(filter_string=tls_cert_filter) 80 | # pretty_print(tls_cert_xml) 81 | 82 | for tls_cert in tls_cert_xml.xpath("tls_certificate"): 83 | 84 | cert_seen = tls_cert.xpath("last_seen/text()")[0] 85 | 86 | cert_from = tls_cert.xpath("activation_time/text()")[0] 87 | 88 | cert_to = tls_cert.xpath("expiration_time/text()")[0] 89 | 90 | cert_subject = tls_cert.xpath("subject_dn/text()")[0] 91 | 92 | cert_issuer = tls_cert.xpath("issuer_dn/text()")[0] 93 | 94 | cert_serial = tls_cert.xpath("serial/text()")[0] 95 | 96 | cert_sha256 = tls_cert.xpath("sha256_fingerprint/text()")[0] 97 | 98 | cert_md5 = tls_cert.xpath("md5_fingerprint/text()")[0] 99 | 100 | cert_info.append( 101 | [ 102 | cert_subject, 103 | cert_issuer, 104 | cert_serial, 105 | cert_sha256, 106 | cert_md5, 107 | cert_seen, 108 | cert_from, 109 | cert_to, 110 | ] 111 | ) 112 | 113 | # Write the list host_info to csv file 114 | writecsv(csvfilename, cert_info) 115 | print( 116 | f"CSV file: {csvfilename}\n" 117 | f"From: {from_date}\n" 118 | f"To: {to_date}\n" 119 | ) 120 | 121 | 122 | def writecsv(csv_filename: str, hostinfo: list) -> None: 123 | field_names = [ 124 | "Subject", 125 | "Issuer", 126 | "Serial", 127 | "SHA256 Fingerprint", 128 | "MD5 Fingerprint", 129 | "Last seen", 130 | "Valid From", 131 | "Valid To", 132 | ] 133 | try: 134 | with open(csv_filename, "w") as csvfile: 135 | writer = csv.writer(csvfile, delimiter=",", quoting=csv.QUOTE_ALL) 136 | writer.writerow(field_names) 137 | writer.writerows(hostinfo) 138 | csvfile.close 139 | except IOError as e: 140 | error_and_exit(f"Failed to write csv file: {str(e)} (exit)") 141 | 142 | 143 | def main(gmp: Gmp, args: Namespace) -> None: 144 | # pylint: disable=undefined-variable 145 | args = args.script[1:] 146 | parsed_args = parse_args(args=args) 147 | csv_filename = parsed_args.csv_filename 148 | delta_days = parsed_args.delta_days 149 | 150 | # simply getting yesterday from midnight to now 151 | from_date = datetime.combine(datetime.today(), time.min) - timedelta( 152 | days=delta_days 153 | ) 154 | to_date = datetime.now() 155 | # get the certs 156 | list_tls_certificates(gmp, from_date, to_date, csv_filename) 157 | 158 | 159 | if __name__ == "__gmp__": 160 | main(gmp, args) 161 | -------------------------------------------------------------------------------- /scripts/export-csv-report.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | # Based on the export-pdf-report script and modified to 6 | # create csv and return more (all) details. 7 | 8 | import sys 9 | from argparse import Namespace 10 | from base64 import b64decode 11 | from pathlib import Path 12 | 13 | from gvm.protocols.gmp import Gmp 14 | 15 | 16 | def check_args(args): 17 | len_args = len(args.script) - 1 18 | if len_args < 1: 19 | message = """ 20 | This script requests the given report and exports it as a csv 21 | file locally. It requires one parameter after the script name. 22 | 23 | 1. -- ID of the report 24 | 25 | Optional a file name to save the csv in. 26 | 27 | Examples: 28 | $ gvm-script --gmp-username name --gmp-password pass \ 29 | ssh --hostname scripts/export-csv-report.gmp.py 30 | $ gvm-script --gmp-username admin --gmp-password '0f6fa69b-32bb-453a-9aa4-b8c9e56b3d00' socket export-csv-report.gmp.py b26229cd-94c8-44f8-9cb6-27486a3dedad ./test.csv 31 | """ 32 | print(message) 33 | sys.exit() 34 | 35 | 36 | def main(gmp: Gmp, args: Namespace) -> None: 37 | # check if report id and CSV filename are provided to the script 38 | # argv[0] contains the script name 39 | check_args(args) 40 | 41 | report_id = args.argv[1] 42 | if len(args.argv) == 3: 43 | csv_filename = args.argv[2] + ".csv" 44 | else: 45 | csv_filename = args.argv[1] + ".csv" 46 | 47 | csv_report_format_id = "c1645568-627a-11e3-a660-406186ea4fc5" 48 | 49 | response = gmp.get_report( 50 | report_id=report_id, 51 | report_format_id=csv_report_format_id, 52 | ignore_pagination=True, 53 | details=True, 54 | ) 55 | 56 | report_element = response.find("report") 57 | # get the full content of the report element 58 | content = report_element.find("report_format").tail 59 | 60 | if not content: 61 | print( 62 | "Requested report is empty. Either the report does not contain any " 63 | " results or the necessary tools for creating the report are " 64 | "not installed.", 65 | file=sys.stderr, 66 | ) 67 | sys.exit(1) 68 | 69 | # convert content to 8-bit ASCII bytes 70 | binary_base64_encoded_csv = content.encode("ascii") 71 | 72 | # decode base64 73 | binary_csv = b64decode(binary_base64_encoded_csv) 74 | 75 | # write to file and support ~ in filename path 76 | csv_path = Path(csv_filename).expanduser() 77 | 78 | csv_path.write_bytes(binary_csv) 79 | 80 | print("Done. CSV created: " + str(csv_path)) 81 | 82 | 83 | if __name__ == "__gmp__": 84 | main(gmp, args) 85 | -------------------------------------------------------------------------------- /scripts/export-operatingsystems-csv.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # 5 | # Loosely based on other greenbone scripts 6 | # 7 | # Run with: gvm-script --gmp-username admin-user --gmp-password password socket export-hosts-csv.gmp.py days 8 | # example: gvm-script --gmp-username admin --gmp-password top$ecret socket export-hosts-csv.gmp.py hosts.csv 2 9 | 10 | 11 | import csv 12 | import sys 13 | from argparse import ArgumentParser, Namespace, RawTextHelpFormatter 14 | from datetime import date, datetime, time, timedelta 15 | 16 | from gvm.protocols.gmp import Gmp 17 | from gvmtools.helper import error_and_exit 18 | 19 | HELP_TEXT = ( 20 | "This script generates a csv file with Operating System " 21 | "from Greenbone Vulnerability Manager.\n\n" 22 | "csv file will contain:\n" 23 | "IP Address, Hostname, MAC Address, Operating System, Last Seen, CVSS\n" 24 | ) 25 | 26 | 27 | def check_args(args: Namespace) -> None: 28 | len_args = len(args.script) - 1 29 | if len_args < 2: 30 | message = """ 31 | This script requests all hosts prior to today and exports it as a csv file. 32 | It requires two parameter after the script name: 33 | 1. filename -- name of the csv file of the report 34 | 2. days -- number of days before and until today to pull hosts information from 35 | 36 | Examples: 37 | $ gvm-script --gmp-username username --gmp-password password socket export-hosts-csv.gmp.py 38 | $ gvm-script --gmp-username admin --gmp-password 0f6fa69b-32bb-453a-9aa4-b8c9e56b3d00 socket export-hosts-csv.gmp.py operatingsystems.csv 4 39 | """ 40 | print(message) 41 | sys.exit() 42 | 43 | 44 | def parse_args(args: Namespace) -> Namespace: # pylint: disable=unused-argument 45 | """Parsing args ...""" 46 | 47 | parser = ArgumentParser( 48 | prefix_chars="+", 49 | add_help=False, 50 | formatter_class=RawTextHelpFormatter, 51 | description=HELP_TEXT, 52 | ) 53 | 54 | parser.add_argument( 55 | "+h", 56 | "++help", 57 | action="help", 58 | help="Show this help message and exit.", 59 | ) 60 | 61 | parser.add_argument( 62 | "csv_filename", 63 | type=str, 64 | help=("CSV File containing credentials"), 65 | ) 66 | 67 | parser.add_argument( 68 | "delta_days", 69 | type=int, 70 | help=("Number of days in the past to pull hosts information"), 71 | ) 72 | 73 | script_args, _ = parser.parse_known_args(args) 74 | return script_args 75 | 76 | 77 | def list_operating_systems( 78 | gmp: Gmp, from_date: date, to_date: date, csvfilename: str 79 | ) -> None: 80 | operating_system_filter = ( 81 | f"rows=-1 " 82 | f"and modified>{from_date.isoformat()} " 83 | f"and modified<{to_date.isoformat()}" 84 | ) 85 | 86 | os_info = [] 87 | 88 | operating_systems_xml = gmp.get_operating_systems( 89 | filter_string=operating_system_filter 90 | ) 91 | 92 | for operating_system in operating_systems_xml.xpath("asset"): 93 | # title will always be there 94 | os_title = operating_system.xpath("name/text()")[0] 95 | 96 | os_latest_severity = operating_system.xpath( 97 | "os/latest_severity/value/text()" 98 | )[0] 99 | 100 | os_host_count = operating_system.xpath("os/installs/text()")[0] 101 | 102 | os_info.append( 103 | [ 104 | os_title, 105 | os_latest_severity, 106 | os_host_count, 107 | ] 108 | ) 109 | 110 | # Write the list host_info to csv file 111 | writecsv(csvfilename, os_info) 112 | print( 113 | f"CSV file: {csvfilename}\n" 114 | f"From: {from_date}\n" 115 | f"To: {to_date}\n" 116 | ) 117 | 118 | 119 | def writecsv(csv_filename: str, hostinfo: list) -> None: 120 | field_names = [ 121 | "IP Address", 122 | "Hostname", 123 | "MAC Address", 124 | "Operating System", 125 | "Last Seen", 126 | "CVSS", 127 | ] 128 | try: 129 | with open(csv_filename, "w") as csvfile: 130 | writer = csv.writer(csvfile, delimiter=",", quoting=csv.QUOTE_ALL) 131 | writer.writerow(field_names) 132 | writer.writerows(hostinfo) 133 | csvfile.close 134 | except IOError as e: 135 | error_and_exit(f"Failed to write csv file: {str(e)} (exit)") 136 | 137 | 138 | def main(gmp: Gmp, args: Namespace) -> None: 139 | # pylint: disable=undefined-variable 140 | # argv[0] contains the csv file name 141 | check_args(args) 142 | if args.script: 143 | args = args.script[1:] 144 | parsed_args = parse_args(args=args) 145 | 146 | delta_days = parsed_args.delta_days 147 | # simply getting yesterday from midnight to now 148 | from_date = datetime.combine(datetime.today(), time.min) - timedelta( 149 | days=delta_days 150 | ) 151 | to_date = datetime.now() 152 | # get the hosts 153 | list_operating_systems(gmp, from_date, to_date, parsed_args.csv_filename) 154 | 155 | 156 | if __name__ == "__gmp__": 157 | main(gmp, args) 158 | -------------------------------------------------------------------------------- /scripts/export-pdf-report.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2019-2021 Greenbone AG 2 | # SPDX-FileCopyrightText: 2024 Martin Boller 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | 6 | import sys 7 | from argparse import Namespace 8 | from base64 import b64decode 9 | from pathlib import Path 10 | 11 | from gvm.protocols.gmp import Gmp 12 | 13 | 14 | def check_args(args): 15 | len_args = len(args.script) - 1 16 | if len_args < 1: 17 | message = """ 18 | This script requests the given report and exports it as a pdf 19 | file locally. It requires one parameters after the script name. 20 | 21 | 1. -- ID of the report 22 | 23 | Optional a file name to save the pdf in. 24 | 25 | Example: 26 | $ gvm-script --gmp-username name --gmp-password pass \ 27 | ssh --hostname scripts/export-pdf-report.gmp.py 28 | """ 29 | print(message) 30 | sys.exit() 31 | 32 | 33 | def main(gmp: Gmp, args: Namespace) -> None: 34 | # check if report id and PDF filename are provided to the script 35 | # argv[0] contains the script name 36 | check_args(args) 37 | 38 | report_id = args.argv[1] 39 | if len(args.argv) == 3: 40 | pdf_filename = args.argv[2] + ".pdf" 41 | else: 42 | pdf_filename = args.argv[1] + ".pdf" 43 | 44 | pdf_report_format_id = "c402cc3e-b531-11e1-9163-406186ea4fc5" 45 | 46 | response = gmp.get_report( 47 | report_id=report_id, 48 | report_format_id=pdf_report_format_id, 49 | ignore_pagination=True, 50 | details=True, 51 | ) 52 | 53 | report_element = response.find("report") 54 | # get the full content of the report element 55 | content = report_element.find("report_format").tail 56 | 57 | if not content: 58 | print( 59 | "Requested report is empty. Either the report does not contain any " 60 | "results or the necessary tools for creating the report are " 61 | "not installed.", 62 | file=sys.stderr, 63 | ) 64 | sys.exit(1) 65 | 66 | # convert content to 8-bit ASCII bytes 67 | binary_base64_encoded_pdf = content.encode("ascii") 68 | 69 | # decode base64 70 | binary_pdf = b64decode(binary_base64_encoded_pdf) 71 | 72 | # write to file and support ~ in filename path 73 | pdf_path = Path(pdf_filename).expanduser() 74 | 75 | pdf_path.write_bytes(binary_pdf) 76 | 77 | print("Done. PDF created: " + str(pdf_path)) 78 | 79 | 80 | if __name__ == "__gmp__": 81 | main(gmp, args) 82 | -------------------------------------------------------------------------------- /scripts/export-xml-report.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | from base64 import b64decode 8 | from pathlib import Path 9 | 10 | from gvm.protocols.gmp import Gmp 11 | from gvm.xml import pretty_print 12 | 13 | 14 | def check_args(args): 15 | len_args = len(args.script) - 1 16 | if len_args < 1: 17 | message = """ 18 | This script requests the given report and exports it as a xml 19 | file locally. It requires one parameters after the script name. 20 | 21 | 1. -- ID of the report 22 | 23 | Optional a file name to save the xml in. 24 | 25 | Example: 26 | $ gvm-script --gmp-username name --gmp-password pass \ 27 | ssh --hostname scripts/export-xml-report.gmp.py 28 | """ 29 | print(message) 30 | sys.exit() 31 | 32 | 33 | def main(gmp: Gmp, args: Namespace) -> None: 34 | # check if report id and xml filename are provided to the script 35 | # argv[0] contains the script name 36 | check_args(args) 37 | 38 | report_id = args.argv[1] 39 | if len(args.argv) == 3: 40 | xml_filename = args.argv[2] + ".xml" 41 | else: 42 | xml_filename = args.argv[1] + ".xml" 43 | 44 | xml_report_format_id = "5057e5cc-b825-11e4-9d0e-28d24461215b" 45 | 46 | response = gmp.get_report( 47 | report_id=report_id, 48 | report_format_id=xml_report_format_id, 49 | ignore_pagination=True, 50 | details=True, 51 | ) 52 | 53 | report_element = response.find("report") 54 | pretty_print(report_element) 55 | # get the full content of the report element 56 | content = report_element.find("report_format").tail 57 | 58 | if not content: 59 | print( 60 | "Requested report is empty. Either the report does not contain any" 61 | " results or the necessary tools for creating the report are " 62 | "not installed.", 63 | file=sys.stderr, 64 | ) 65 | sys.exit(1) 66 | 67 | # convert content to 8-bit ASCII bytes 68 | binary_base64_encoded_xml = content.encode("ascii") 69 | 70 | # decode base64 71 | binary_xml = b64decode(binary_base64_encoded_xml) 72 | 73 | # write to file and support ~ in filename path 74 | xml_path = Path(xml_filename).expanduser() 75 | 76 | xml_path.write_bytes(binary_xml) 77 | 78 | print("Done. xml created: " + str(xml_path)) 79 | 80 | 81 | if __name__ == "__gmp__": 82 | main(gmp, args) 83 | -------------------------------------------------------------------------------- /scripts/generate-random-targets.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | from random import choice, gauss 8 | 9 | from gvm.protocols.gmp import Gmp 10 | from gvmtools.helper import generate_random_ips 11 | 12 | 13 | def check_args(args): 14 | len_args = len(args.script) - 1 15 | if len_args < 2: 16 | message = """ 17 | This script generates random task data and feeds it to\ 18 | a desired GSM 19 | It needs two parameters after the script name. 20 | 21 | 1. -- number of dummy hosts to select from 22 | 2. -- number of targets to be generated 23 | 24 | In addition, if you would like for the number of targets generated 25 | to be randomized on a Gaussian distribution, add 'with-gauss' 26 | 27 | Example: 28 | $ gvm-script --gmp-username name --gmp-password pass \ 29 | ssh --hostname scripts/gen-random-targets.gmp.py 3 40 with-gauss 30 | """ 31 | print(message) 32 | sys.exit() 33 | 34 | 35 | def generate(gmp, args, n_targets, n_ips): 36 | ips = generate_random_ips(n_ips) 37 | 38 | if "with-gauss" in args.script: 39 | n_targets = int(gauss(n_targets, 2)) 40 | 41 | for i in range(n_targets): 42 | host_ip = choice(ips) 43 | index = f"{{0:0>{len(str(n_targets))}}}" 44 | name = f"Target_{index.format(i + 1)}" 45 | 46 | gmp.create_target(name=name, make_unique=True, hosts=[host_ip]) 47 | 48 | 49 | def main(gmp: Gmp, args: Namespace) -> None: 50 | # pylint: disable=undefined-variable 51 | 52 | check_args(args) 53 | 54 | host_number = int(args.script[1]) 55 | number_targets = int(args.script[2]) 56 | 57 | print("Generating random targets...") 58 | 59 | generate(gmp, args, number_targets, host_number) 60 | 61 | 62 | if __name__ == "__gmp__": 63 | main(gmp, args) 64 | -------------------------------------------------------------------------------- /scripts/list-alerts.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_alerts(filter_string="rows=-1") 15 | alerts_xml = response_xml.xpath("alert") 16 | 17 | heading = [ 18 | "#", 19 | "Name", 20 | "Id", 21 | "Event", 22 | "Event type", 23 | "Method", 24 | "Condition", 25 | "In use", 26 | ] 27 | 28 | rows = [] 29 | numberRows = 0 30 | 31 | print("Listing alerts.\n") 32 | 33 | for alert in alerts_xml: 34 | # Count number of reports 35 | numberRows = numberRows + 1 36 | # Cast/convert to text to show in list 37 | rowNumber = str(numberRows) 38 | 39 | name = "".join(alert.xpath("name/text()")) 40 | alert_id = alert.get("id") 41 | alert_condition = "".join(alert.xpath("condition/text()")) 42 | alert_method = "".join(alert.xpath("method/text()")) 43 | alert_event_type = "".join(alert.xpath("event/data/text()")) 44 | alert_event = "".join(alert.xpath("event/text()")) 45 | alert_inuse = "".join(alert.xpath("in_use/text()")) 46 | if alert_inuse == "1": 47 | alert_inuse = "Yes" 48 | else: 49 | alert_inuse = "No" 50 | 51 | rows.append( 52 | [ 53 | rowNumber, 54 | name, 55 | alert_id, 56 | alert_event, 57 | alert_event_type, 58 | alert_method, 59 | alert_condition, 60 | alert_inuse, 61 | ] 62 | ) 63 | 64 | print(Table(heading=heading, rows=rows)) 65 | 66 | 67 | if __name__ == "__gmp__": 68 | main(gmp, args) 69 | -------------------------------------------------------------------------------- /scripts/list-credentials.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_credentials(filter_string="rows=-1") 15 | credentials_xml = response_xml.xpath("credential") 16 | 17 | heading = ["#", "Id", "Name", "Type", "Insecure use"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing credentials.\n") 23 | 24 | for credential in credentials_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(credential.xpath("name/text()")) 31 | credential_id = credential.get("id") 32 | cred_type = "".join(credential.xpath("type/text()")) 33 | if cred_type.upper() == "UP": 34 | cred_type = "Username + Password (up)" 35 | elif cred_type.upper() == "USK": 36 | cred_type = "Username + SSH Key (usk)" 37 | elif cred_type.upper() == "SMIME": 38 | cred_type = "S/MIME Certificate (smime)" 39 | elif cred_type.upper() == "PGP": 40 | cred_type = "PGP Encryption Key (pgp)" 41 | elif cred_type.upper() == "SNMP": 42 | cred_type = "Simple Network Management Protocol (snmp)" 43 | elif cred_type.upper() == "PW": 44 | cred_type = "Password only (pw)" 45 | cred_insecureuse = "".join(credential.xpath("allow_insecure/text()")) 46 | if cred_insecureuse == "1": 47 | cred_insecureuse = "Yes" 48 | else: 49 | cred_insecureuse = "No" 50 | 51 | rows.append( 52 | [rowNumber, credential_id, name, cred_type, cred_insecureuse] 53 | ) 54 | 55 | print(Table(heading=heading, rows=rows)) 56 | 57 | 58 | if __name__ == "__gmp__": 59 | main(gmp, args) 60 | -------------------------------------------------------------------------------- /scripts/list-feeds.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | # from gvm.xml import pretty_print 11 | 12 | 13 | def main(gmp: Gmp, args: Namespace) -> None: 14 | # pylint: disable=unused-argument 15 | 16 | response_xml = gmp.get_feeds() 17 | feeds_xml = response_xml.xpath("feed") 18 | heading = ["#", "Name", "Version", "Type", "Status"] 19 | rows = [] 20 | numberRows = 0 21 | # pretty_print(feeds_xml) 22 | 23 | print("Listing feeds and their status.\n") 24 | 25 | for feed in feeds_xml: 26 | # Count number of reports 27 | numberRows = numberRows + 1 28 | # Cast/convert to text to show in list 29 | rowNumber = str(numberRows) 30 | name = "".join(feed.xpath("name/text()")) 31 | version = "".join(feed.xpath("version/text()")) 32 | feed_type = "".join(feed.xpath("type/text()")) 33 | status = "".join(feed.xpath("currently_syncing/timestamp/text()")) 34 | if not status: 35 | status = "Up-to-date..." 36 | else: 37 | status = "Update in progress..." 38 | 39 | rows.append([rowNumber, name, version, feed_type, status]) 40 | 41 | print(Table(heading=heading, rows=rows)) 42 | 43 | 44 | if __name__ == "__gmp__": 45 | main(gmp, args) 46 | -------------------------------------------------------------------------------- /scripts/list-filters.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_filters(filter_string="rows=-1") 15 | filters_xml = response_xml.xpath("filter") 16 | 17 | heading = ["#", "Name", "Id", "Modified", "Type", "Term"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing filters.\n") 23 | 24 | for filter in filters_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(filter.xpath("name/text()")) 31 | modified = "".join(filter.xpath("modification_time/text()")) 32 | term = "".join(filter.xpath("term/text()")) 33 | type = "".join(filter.xpath("type/text()")) 34 | filter_id = filter.get("id") 35 | rows.append([rowNumber, name, filter_id, modified, type, term]) 36 | 37 | print(Table(heading=heading, rows=rows)) 38 | 39 | 40 | if __name__ == "__gmp__": 41 | main(gmp, args) 42 | -------------------------------------------------------------------------------- /scripts/list-groups.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_groups(filter_string="rows=-1") 15 | groups_xml = response_xml.xpath("group") 16 | 17 | heading = ["#", "Name", "Id", "Members"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing groups.\n") 23 | 24 | for group in groups_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(group.xpath("name/text()")) 31 | group_id = group.get("id") 32 | group_members = "".join(group.xpath("users/text()")) 33 | 34 | rows.append([rowNumber, name, group_id, group_members]) 35 | 36 | print(Table(heading=heading, rows=rows)) 37 | 38 | 39 | if __name__ == "__gmp__": 40 | main(gmp, args) 41 | -------------------------------------------------------------------------------- /scripts/list-hosts.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # 5 | # Loosely based on other greenbone scripts 6 | # 7 | # Run with: gvm-script --gmp-username admin-user --gmp-password password socket list-hosts.gmp.py 8 | # example: gvm-script --gmp-username admin --gmp-password top$ecret socket list-hosts.gmp.py 2 9 | 10 | 11 | import sys 12 | from argparse import ArgumentParser, Namespace, RawTextHelpFormatter 13 | from datetime import date, datetime, time, timedelta 14 | 15 | from gvm.protocols.gmp import Gmp 16 | from gvmtools.helper import Table 17 | 18 | HELP_TEXT = ( 19 | "This script generates a table of hosts (assets) " 20 | "from Greenbone Vulnerability Manager.\n\n" 21 | "table will contain:\n" 22 | "Hostname, IP Address, MAC Address, Operating System, last seen, and severity\n" 23 | ) 24 | 25 | 26 | def check_args(args: Namespace) -> None: 27 | len_args = len(args.script) - 1 28 | if len_args < 1: 29 | message = """ 30 | This script requests information about all hosts days prior to today (included) and 31 | displays it as a table. It requires one parameter after the script name: 32 | 1. days -- number of days prior to today to pull hosts information from 33 | 34 | Examples: 35 | $ gvm-script --gmp-username username --gmp-password password socket list-hosts.gmp.py 36 | $ gvm-script --gmp-username admin --gmp-password 0f6fa69b-32bb-453a-9aa4-b8c9e56b3d00 socket list-hosts.gmp.py 4 37 | """ 38 | print(message) 39 | sys.exit() 40 | 41 | 42 | def parse_args(args: Namespace) -> Namespace: # pylint: disable=unused-argument 43 | """Parsing args ...""" 44 | 45 | parser = ArgumentParser( 46 | prefix_chars="+", 47 | add_help=False, 48 | formatter_class=RawTextHelpFormatter, 49 | ) 50 | 51 | parser.add_argument( 52 | "+h", 53 | "++help", 54 | action="help", 55 | help="Show this help message and exit.", 56 | ) 57 | 58 | parser.add_argument( 59 | "delta_days", 60 | type=int, 61 | help=("Number of days in the past to pull hosts information"), 62 | ) 63 | 64 | script_args, _ = parser.parse_known_args(args) 65 | return script_args 66 | 67 | 68 | def list_hosts(gmp: Gmp, from_date: date, to_date: date) -> None: 69 | host_filter = ( 70 | f"rows=-1 " 71 | f"and modified>{from_date.isoformat()} " 72 | f"and modified<{to_date.isoformat()}" 73 | ) 74 | 75 | # Get the XML of hosts 76 | hosts_xml = gmp.get_hosts(filter_string=host_filter) 77 | heading = [ 78 | "#", 79 | "IP Address", 80 | "Hostname", 81 | "MAC Address", 82 | "Operating System", 83 | "Last Seen", 84 | "CVSS", 85 | ] 86 | rows = [] 87 | numberRows = 0 88 | 89 | print("Listing hosts.\n" f"From: {from_date}\n" f"To: {to_date}\n") 90 | 91 | for host in hosts_xml.xpath("asset"): 92 | # ip will always be there 93 | ip = host.xpath("name/text()")[0] 94 | host_seendates = host.xpath("modification_time/text()") 95 | host_lastseen = host_seendates[0] 96 | 97 | # hostnames and other attributes may not be there 98 | hostnames = host.xpath( 99 | 'identifiers/identifier/name[text()="hostname"]/../value/text()' 100 | ) 101 | if len(hostnames) == 0: 102 | hostname = "" 103 | pass 104 | else: 105 | hostname = hostnames[0] 106 | 107 | host_macs = host.xpath( 108 | 'identifiers/identifier/name[text()="MAC"]/../value/text()' 109 | ) 110 | if len(host_macs) == 0: 111 | host_mac = "" 112 | pass 113 | else: 114 | host_mac = host_macs[0] 115 | 116 | host_severity = host.xpath("host/severity/value/text()") 117 | if len(host_severity) == 0: 118 | host_severity = "0.0" 119 | pass 120 | else: 121 | host_severity = host_severity[0] 122 | 123 | host_os = host.xpath( 124 | 'host/detail/name[text()="best_os_txt"]/../value/text()' 125 | ) 126 | if len(host_os) == 0: 127 | host_os = "" 128 | pass 129 | else: 130 | host_os = host_os[0] 131 | # Count number of hosts 132 | numberRows = numberRows + 1 133 | # Cast/convert to text to show in list 134 | rowNumber = str(numberRows) 135 | rows.append( 136 | [ 137 | rowNumber, 138 | ip, 139 | hostname, 140 | host_mac, 141 | host_os, 142 | host_lastseen, 143 | host_severity, 144 | ] 145 | ) 146 | 147 | print(Table(heading=heading, rows=rows)) 148 | 149 | 150 | def main(gmp: Gmp, args: Namespace) -> None: 151 | # pylint: disable=undefined-variable 152 | check_args(args) 153 | if args.script: 154 | args = args.script[1:] 155 | parsed_args = parse_args(args=args) 156 | delta_days = parsed_args.delta_days 157 | # simply getting yesterday from midnight to today (now) 158 | from_date = datetime.combine(datetime.today(), time.min) - timedelta( 159 | days=delta_days 160 | ) 161 | to_date = datetime.now() 162 | # print(from_date, to_date) 163 | 164 | list_hosts(gmp, from_date, to_date) 165 | 166 | 167 | if __name__ == "__gmp__": 168 | main(gmp, args) 169 | -------------------------------------------------------------------------------- /scripts/list-policies.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_policies(filter_string="rows=-1") 15 | policies_xml = response_xml.xpath("config") 16 | 17 | heading = ["#", "Name", "Id", "NVT Count"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing compliance policies.\n") 23 | 24 | for policy in policies_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(policy.xpath("name/text()")) 31 | policy_id = policy.get("id") 32 | policy_nvt = "".join(policy.xpath("nvt_count/text()")) 33 | 34 | rows.append([rowNumber, name, policy_id, policy_nvt]) 35 | 36 | print(Table(heading=heading, rows=rows)) 37 | 38 | 39 | if __name__ == "__gmp__": 40 | main(gmp, args) 41 | -------------------------------------------------------------------------------- /scripts/list-portlists.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_port_lists(filter_string="rows=-1") 15 | portlists_xml = response_xml.xpath("port_list") 16 | 17 | heading = ["#", "Name", "Id", "Ports All", "Ports TCP", "Ports UDP"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing portlists.\n") 23 | 24 | for portlist in portlists_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(portlist.xpath("name/text()")) 31 | port_list_id = portlist.get("id") 32 | port_all = "".join(portlist.xpath("port_count/all/text()")) 33 | port_tcp = "".join(portlist.xpath("port_count/tcp/text()")) 34 | port_udp = "".join(portlist.xpath("port_count/udp/text()")) 35 | 36 | rows.append( 37 | [rowNumber, name, port_list_id, port_all, port_tcp, port_udp] 38 | ) 39 | 40 | print(Table(heading=heading, rows=rows)) 41 | 42 | 43 | if __name__ == "__gmp__": 44 | main(gmp, args) 45 | -------------------------------------------------------------------------------- /scripts/list-report-formats.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_report_formats(details=True, filter_string="rows=-1") 15 | report_formats_xml = response_xml.xpath("report_format") 16 | heading = ["#", "Name", "Id", "Summary"] 17 | rows = [] 18 | numberRows = 0 19 | 20 | print("Listing report formats.\n") 21 | 22 | for report_format in report_formats_xml: 23 | # Count number of reports 24 | numberRows = numberRows + 1 25 | # Cast/convert to text to show in list 26 | rowNumber = str(numberRows) 27 | name = "".join(report_format.xpath("name/text()")) 28 | report_format_id = report_format.get("id") 29 | report_format_summary = "".join(report_format.xpath("summary/text()")) 30 | 31 | rows.append([rowNumber, name, report_format_id, report_format_summary]) 32 | 33 | print(Table(heading=heading, rows=rows)) 34 | 35 | 36 | if __name__ == "__gmp__": 37 | main(gmp, args) 38 | -------------------------------------------------------------------------------- /scripts/list-reports.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import ArgumentParser, Namespace, RawTextHelpFormatter 7 | 8 | from gvm.protocols.gmp import Gmp 9 | from gvmtools.helper import Table 10 | 11 | HELP_TEXT = ( 12 | "This script list reports with the status " 13 | "defined on the commandline. Status can be: \n" 14 | "Requested, Queued, Interrupted, Running, or Done \n" 15 | "Note: Case matters. E.g. - done - won't work, but - Done - will" 16 | ) 17 | 18 | 19 | def check_args(args): 20 | len_args = len(args.script) - 1 21 | if len_args != 1: 22 | message = """ 23 | This script lists all reports depending on status. 24 | One parameter after the script name is required. 25 | 26 | 1. Status -- Either \"All\", \"Requested\", \"Queued\", \"Interrupted\", \"Running\", \"StopRequested\", \"Stopped\", or \"Done\" 27 | 28 | Example: 29 | $ gvm-script --gmp-username name --gmp-password pass \ 30 | socket list-reports.gmp.py Done \n 31 | """ 32 | print(message) 33 | sys.exit() 34 | 35 | 36 | def parse_args(args: Namespace) -> Namespace: # pylint: disable=unused-argument 37 | """Parsing args ...""" 38 | 39 | parser = ArgumentParser( 40 | prefix_chars="+", 41 | add_help=False, 42 | formatter_class=RawTextHelpFormatter, 43 | description=HELP_TEXT, 44 | ) 45 | 46 | parser.add_argument( 47 | "+h", 48 | "++help", 49 | action="help", 50 | help="Show this help message and exit.", 51 | ) 52 | 53 | parser.add_argument( 54 | "status_cmd", 55 | type=str, 56 | help=( 57 | 'Status: "All", "Queued", "Requested", "Interrupted", "Running", "Stop Requested", "Stopped" or "Done"' 58 | ), 59 | ) 60 | script_args, _ = parser.parse_known_args(args) 61 | return script_args 62 | 63 | 64 | def list_reports( 65 | gmp: Gmp, 66 | status: str, 67 | ): 68 | str_status = status 69 | if status.upper() == "ALL": 70 | status = "All" 71 | elif status.upper() == "REQUESTED": 72 | str_status = "Requested" 73 | elif status.upper() == "INTERRUPTED": 74 | str_status = "Interrupted" 75 | elif status.upper() == "QUEUED": 76 | str_status = "Queued" 77 | elif status.upper()[:6] == "STOPRE": 78 | str_status = "Stop Requested" 79 | elif status.upper()[:6] == "STOP R": 80 | str_status = "Stop Requested" 81 | elif status.upper() == "DONE": 82 | str_status = "Done" 83 | elif status.upper() == "RUNNING": 84 | str_status = "Running" 85 | elif status.upper() == "STOPPED": 86 | str_status = "Stopped" 87 | else: 88 | str_status = "All" 89 | 90 | print("Reports with status: " + str_status + "\n") 91 | 92 | if str_status == "All": 93 | response_xml = gmp.get_reports( 94 | ignore_pagination=True, details=True, filter_string="rows=-1" 95 | ) 96 | else: 97 | response_xml = gmp.get_reports( 98 | ignore_pagination=True, 99 | details=True, 100 | filter_string="status=" 101 | + str_status 102 | + " and sort-reverse=name and rows=-1", 103 | ) 104 | 105 | reports_xml = response_xml.xpath("report") 106 | heading = [ 107 | "#", 108 | "Id", 109 | "Creation Time", 110 | "Modification Time", 111 | "Task Name", 112 | "Status", 113 | "Progress", 114 | ] 115 | rows = [] 116 | numberRows = 0 117 | 118 | for report in reports_xml: 119 | # Count number of reports 120 | numberRows = numberRows + 1 121 | # Cast/convert to text to show in list 122 | rowNumber = str(numberRows) 123 | creation_time = "".join(report.xpath("creation_time/text()")) 124 | # report_name = "".join(report.xpath("name/text()")) # Report name is the same as Creation Time 125 | report_id = report.get("id") 126 | report_task = "".join(report.xpath("task/name/text()")) 127 | mod_time = "".join(report.xpath("modification_time/text()")) 128 | report_status = "".join(report.xpath("report/scan_run_status/text()")) 129 | report_progress = ( 130 | "".join(report.xpath("report/task/progress/text()")) + "%" 131 | ) 132 | rows.append( 133 | [ 134 | rowNumber, 135 | report_id, 136 | creation_time, 137 | mod_time, 138 | report_task, 139 | report_status, 140 | report_progress, 141 | ] 142 | ) 143 | 144 | print(Table(heading=heading, rows=rows)) 145 | 146 | 147 | def main(gmp: Gmp, args: Namespace) -> None: 148 | # pylint: disable=unused-argument 149 | if args.script: 150 | args = args.script[1:] 151 | 152 | parsed_args = parse_args(args=args) 153 | 154 | print("Listing reports.\n") 155 | 156 | list_reports(gmp, parsed_args.status_cmd) 157 | 158 | 159 | if __name__ == "__gmp__": 160 | main(gmp, args) 161 | -------------------------------------------------------------------------------- /scripts/list-roles.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_roles(filter_string="rows=-1") 15 | roles_xml = response_xml.xpath("role") 16 | 17 | heading = ["#", "Name", "Id", "Members"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing roles.\n") 23 | 24 | for role in roles_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(role.xpath("name/text()")) 31 | role_id = role.get("id") 32 | role_members = "".join(role.xpath("users/text()")) 33 | 34 | rows.append([rowNumber, name, role_id, role_members]) 35 | 36 | print(Table(heading=heading, rows=rows)) 37 | 38 | 39 | if __name__ == "__gmp__": 40 | main(gmp, args) 41 | -------------------------------------------------------------------------------- /scripts/list-scan-configs.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_scan_configs(filter_string="rows=-1") 15 | scan_configs_xml = response_xml.xpath("config") 16 | 17 | heading = ["#", "Name", "Id", "NVT Count"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing scan configurations.\n") 23 | 24 | for scan_config in scan_configs_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(scan_config.xpath("name/text()")) 31 | scan_config_id = scan_config.get("id") 32 | scan_config_nvt = "".join(scan_config.xpath("nvt_count/text()")) 33 | 34 | rows.append([rowNumber, name, scan_config_id, scan_config_nvt]) 35 | 36 | print(Table(heading=heading, rows=rows)) 37 | 38 | 39 | if __name__ == "__gmp__": 40 | main(gmp, args) 41 | -------------------------------------------------------------------------------- /scripts/list-scanners.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_scanners(filter_string="rows=-1") 15 | scanners_xml = response_xml.xpath("scanner") 16 | 17 | heading = ["#", "Name", "Id", "host"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing scanners.\n") 23 | 24 | for scanner in scanners_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(scanner.xpath("name/text()")) 31 | scanner_id = scanner.get("id") 32 | host = "".join(scanner.xpath("host/text()")) 33 | 34 | rows.append([rowNumber, name, scanner_id, host]) 35 | 36 | print(Table(heading=heading, rows=rows)) 37 | 38 | 39 | if __name__ == "__gmp__": 40 | main(gmp, args) 41 | -------------------------------------------------------------------------------- /scripts/list-schedules.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_schedules(filter_string="rows=-1") 15 | schedules_xml = response_xml.xpath("schedule") 16 | 17 | heading = ["#", "Name", "Id", "TZ", "iCalendar"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing schedules.\n") 23 | 24 | for schedule in schedules_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(schedule.xpath("name/text()")) 31 | schedule_id = schedule.get("id") 32 | icalendar = "".join(schedule.xpath("icalendar/text()")) 33 | timezone = "".join(schedule.xpath("timezone/text()")) 34 | rows.append([rowNumber, name, schedule_id, timezone, icalendar]) 35 | # print(icalendar) 36 | 37 | print(Table(heading=heading, rows=rows)) 38 | 39 | 40 | if __name__ == "__gmp__": 41 | main(gmp, args) 42 | -------------------------------------------------------------------------------- /scripts/list-tags.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_tags(filter_string="rows=-1") 15 | tags_xml = response_xml.xpath("tag") 16 | 17 | heading = ["#", "Name", "Id", "Modified", "Value", "Type", "Count"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing tags.\n") 23 | 24 | for tag in tags_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(tag.xpath("name/text()")) 31 | modified = "".join(tag.xpath("modification_time/text()")) 32 | value = "".join(tag.xpath("value/text()")) 33 | type = "".join(tag.xpath("resources/type/text()")) 34 | count = "".join(tag.xpath("resources/count/total/text()")) 35 | tag_id = tag.get("id") 36 | rows.append([rowNumber, name, tag_id, modified, value, type, count]) 37 | 38 | print(Table(heading=heading, rows=rows)) 39 | 40 | 41 | if __name__ == "__gmp__": 42 | main(gmp, args) 43 | -------------------------------------------------------------------------------- /scripts/list-targets.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_targets(filter_string="rows=-1") 15 | targets_xml = response_xml.xpath("target") 16 | 17 | heading = [ 18 | "#", 19 | "Name", 20 | "Id", 21 | "Count", 22 | "SSH Credential", 23 | "SMB Cred", 24 | "ESXi Cred", 25 | "SNMP Cred", 26 | "Alive test", 27 | ] 28 | 29 | rows = [] 30 | numberRows = 0 31 | 32 | print("Listing targets.\n") 33 | 34 | for target in targets_xml: 35 | # Count number of reports 36 | numberRows = numberRows + 1 37 | # Cast/convert to text to show in list 38 | rowNumber = str(numberRows) 39 | 40 | name = "".join(target.xpath("name/text()")) 41 | maxhosts = "".join(target.xpath("max_hosts/text()")) 42 | sshcred = "".join(target.xpath("ssh_credential/name/text()")) 43 | smbcred = "".join(target.xpath("smb_credential/name/text()")) 44 | esxicred = "".join(target.xpath("esxi_credential/name/text()")) 45 | snmpcred = "".join(target.xpath("snmp_credential/name/text()")) 46 | target_id = target.get("id") 47 | alive_test = "".join(target.xpath("alive_tests/text()")) 48 | rows.append( 49 | [ 50 | rowNumber, 51 | name, 52 | target_id, 53 | maxhosts, 54 | sshcred, 55 | smbcred, 56 | esxicred, 57 | snmpcred, 58 | alive_test, 59 | ] 60 | ) 61 | 62 | print(Table(heading=heading, rows=rows)) 63 | 64 | 65 | if __name__ == "__gmp__": 66 | main(gmp, args) 67 | -------------------------------------------------------------------------------- /scripts/list-tasks.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | from datetime import datetime 10 | 11 | 12 | def list_tasks(gmp: Gmp, args: Namespace) -> None: 13 | # pylint: disable=unused-argument 14 | 15 | response_xml = gmp.get_tasks(details=True, filter_string="rows=-1") 16 | tasks_xml = response_xml.xpath("task") 17 | 18 | heading = [ 19 | "#", 20 | "Name", 21 | "Id", 22 | "Target", 23 | "Scanner", 24 | "Scan Order", 25 | "Severity", 26 | "Average Duration", 27 | "Last Scan Duration (hours)", 28 | ] 29 | 30 | rows = [] 31 | numberRows = 0 32 | 33 | for task in tasks_xml: 34 | # Count number of reports 35 | numberRows = numberRows + 1 36 | # Cast/convert to text to show in list 37 | rowNumber = str(numberRows) 38 | 39 | name = "".join(task.xpath("name/text()")) 40 | task_id = task.get("id") 41 | targetname = "".join(task.xpath("target/name/text()")) 42 | scanner = "".join(task.xpath("scanner/name/text()")) 43 | severity = "".join(task.xpath("last_report/report/severity/text()")) 44 | order = "".join(task.xpath("hosts_ordering/text()")) 45 | average_duration = "".join(task.xpath("average_duration/text()")) 46 | average_duration_int = ( 47 | 0 if not average_duration else int(average_duration) 48 | ) 49 | average_duration_hours = f"{average_duration_int / 3600:.2f}" 50 | scan_start_iso = "".join( 51 | task.xpath("last_report/report/scan_start/text()") 52 | ) 53 | scan_end_iso = "".join(task.xpath("last_report/report/scan_end/text()")) 54 | if not scan_start_iso or not scan_end_iso: 55 | duration_hours = "" 56 | else: 57 | scan_start_time = datetime.fromisoformat( 58 | scan_start_iso.replace("Z", "+00:00") 59 | ) 60 | scan_end_time = datetime.fromisoformat( 61 | scan_end_iso.replace("Z", "+00:00") 62 | ) 63 | duration = scan_end_time - scan_start_time 64 | duration_hours = f"{duration.total_seconds() / 3600:.2f}" 65 | rows.append( 66 | [ 67 | rowNumber, 68 | name, 69 | task_id, 70 | targetname, 71 | scanner, 72 | order, 73 | severity, 74 | average_duration_hours, 75 | duration_hours, 76 | ] 77 | ) 78 | 79 | print(Table(heading=heading, rows=rows)) 80 | 81 | 82 | def main(gmp: Gmp, args: Namespace) -> None: 83 | 84 | print("Listing tasks.\n") 85 | 86 | list_tasks(gmp, args) 87 | 88 | 89 | if __name__ == "__gmp__": 90 | main(gmp, args) 91 | -------------------------------------------------------------------------------- /scripts/list-tickets.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_tickets(filter_string="rows=-1") 15 | tickets_xml = response_xml.xpath("ticket") 16 | 17 | heading = ["#", "ID", "Name", "Host", "Task", "Status", "Note"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing tickets.\n") 23 | 24 | for ticket in tickets_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(ticket.xpath("name/text()")) 31 | ticket_id = ticket.get("id") 32 | ticket_status = "".join(ticket.xpath("status/text()")) 33 | ticket_task = "".join(ticket.xpath("task/name/text()")) 34 | ticket_host = "".join(ticket.xpath("host/text()")) 35 | if ticket_status.upper() == "OPEN": 36 | ticket_note = "".join(ticket.xpath("open_note/text()")) 37 | elif ticket_status.upper() == "FIXED": 38 | ticket_note = "".join(ticket.xpath("fixed_note/text()")) 39 | elif ticket_status.upper() == "CLOSED": 40 | ticket_note = "".join(ticket.xpath("closed_note/text()")) 41 | 42 | rows.append( 43 | [ 44 | rowNumber, 45 | ticket_id, 46 | name, 47 | ticket_host, 48 | ticket_task, 49 | ticket_status, 50 | ticket_note, 51 | ] 52 | ) 53 | 54 | print(Table(heading=heading, rows=rows)) 55 | 56 | 57 | if __name__ == "__gmp__": 58 | main(gmp, args) 59 | -------------------------------------------------------------------------------- /scripts/list-users.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | from gvmtools.helper import Table 9 | 10 | 11 | def main(gmp: Gmp, args: Namespace) -> None: 12 | # pylint: disable=unused-argument 13 | 14 | response_xml = gmp.get_users(filter_string="rows=-1") 15 | users_xml = response_xml.xpath("user") 16 | 17 | heading = ["#", "Name", "Id", "Role", "Groups"] 18 | 19 | rows = [] 20 | numberRows = 0 21 | 22 | print("Listing users.\n") 23 | 24 | for user in users_xml: 25 | # Count number of reports 26 | numberRows = numberRows + 1 27 | # Cast/convert to text to show in list 28 | rowNumber = str(numberRows) 29 | 30 | name = "".join(user.xpath("name/text()")) 31 | user_id = user.get("id") 32 | user_role = "".join(user.xpath("role/name/text()")) 33 | user_groups = "".join(user.xpath("groups/group/name/text()")) 34 | 35 | rows.append([rowNumber, name, user_id, user_role, user_groups]) 36 | 37 | print(Table(heading=heading, rows=rows)) 38 | 39 | 40 | if __name__ == "__gmp__": 41 | main(gmp, args) 42 | -------------------------------------------------------------------------------- /scripts/monthly-report-gos24.10.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2024 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | from datetime import date, timedelta 8 | 9 | from gvm.protocols.gmp import Gmp 10 | from terminaltables import AsciiTable 11 | 12 | 13 | def check_args(args: Namespace) -> None: 14 | len_args = len(args.script) - 1 15 | if len_args < 2: 16 | message = """ 17 | This script will display all vulnerabilities from the hosts of the 18 | reports in a given month! 19 | It needs two parameters after the script name. 20 | First one is the month and second one is the year. 21 | Both parameters are plain numbers, so no text. 22 | 23 | Explicitly made for GOS 24.10. 24 | 25 | 1. -- month of the monthly report 26 | 2. -- year of the monthly report 27 | 28 | Example: 29 | $ gvm-script --gmp-username name --gmp-password pass \ 30 | ssh --hostname scripts/monthly-report2.gmp.py 05 2019 31 | """ 32 | print(message) 33 | sys.exit() 34 | 35 | 36 | def print_reports(gmp: Gmp, from_date: date, to_date: date) -> None: 37 | host_filter = ( 38 | f"rows=-1 and modified>{from_date.isoformat()} " 39 | f"and modified<{to_date.isoformat()}" 40 | ) 41 | 42 | hosts_xml = gmp.get_hosts(filter_string=host_filter) 43 | 44 | sum_critical = 0 45 | sum_high = 0 46 | sum_medium = 0 47 | sum_low = 0 48 | table_data = [ 49 | ["Hostname", "IP", "Bericht", "critical", "high", "medium", "low"] 50 | ] 51 | 52 | for host in hosts_xml.xpath("asset"): 53 | ip = host.xpath("name/text()")[0] 54 | 55 | hostnames = host.xpath( 56 | 'identifiers/identifier/name[text()="hostname"]/../value/text()' 57 | ) 58 | 59 | if len(hostnames) == 0: 60 | continue 61 | 62 | hostname = hostnames[0] 63 | 64 | results = gmp.get_results( 65 | details=False, filter=f"host={ip} and severity>0.0" 66 | ) 67 | 68 | low = int(results.xpath('count(//result/threat[text()="Low"])')) 69 | sum_low += low 70 | 71 | medium = int(results.xpath('count(//result/threat[text()="Medium"])')) 72 | sum_medium += medium 73 | 74 | high = int(results.xpath('count(//result/threat[text()="High"])')) 75 | sum_high += high 76 | 77 | critical = int( 78 | results.xpath('count(//result/threat[text()="Critical"])') 79 | ) 80 | sum_critical += critical 81 | 82 | best_os_cpe_report_id = host.xpath( 83 | 'host/detail/name[text()="best_os_cpe"]/../source/@id' 84 | )[0] 85 | 86 | table_data.append( 87 | [hostname, ip, best_os_cpe_report_id, critical, high, medium, low] 88 | ) 89 | 90 | table = AsciiTable(table_data) 91 | print(f"{table.table}\n") 92 | print( 93 | f"Summary of results from {from_date.isoformat()} " 94 | f"to {to_date.isoformat()}" 95 | ) 96 | print(f"Critical: {int(sum_critical)}") 97 | print(f"High: {int(sum_high)}") 98 | print(f"Medium: {int(sum_medium)}") 99 | print(f"Low: {int(sum_low)}\n\n") 100 | 101 | 102 | def main(gmp: Gmp, args: Namespace) -> None: 103 | # pylint: disable=undefined-variable 104 | 105 | check_args(args) 106 | 107 | month = int(args.script[1]) 108 | year = int(args.script[2]) 109 | from_date = date(year, month, 1) 110 | to_date = from_date + timedelta(days=31) 111 | # To have the first day in month 112 | to_date = to_date.replace(day=1) 113 | 114 | print_reports(gmp, from_date, to_date) 115 | 116 | 117 | if __name__ == "__gmp__": 118 | main(gmp, args) 119 | -------------------------------------------------------------------------------- /scripts/monthly-report-gos3.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | from datetime import date, timedelta 8 | 9 | from gvm.protocols.gmp import Gmp 10 | from lxml.etree import Element 11 | from terminaltables import AsciiTable 12 | 13 | 14 | def check_args(args: Namespace) -> None: 15 | len_args = len(args.script) - 1 16 | if len_args < 2: 17 | message = """ 18 | This script will display all vulnerabilities from the hosts of the 19 | reports in a given month! 20 | 21 | 1. -- month of the monthly report 22 | 2. -- year of the monthly report 23 | 24 | The third is 'with-tables' parameter to activate a verbose output of 25 | hosts. 26 | 27 | Explicitly made for GOS 3.1. 28 | 29 | Example: 30 | $ gvm-script --gmp-username name --gmp-password pass \ 31 | ssh --hostname scripts/monthly-report.gmp.py 05 2017 with-tables 32 | """ 33 | print(message) 34 | sys.exit() 35 | 36 | 37 | def get_reports_xml(gmp: Gmp, from_date: date, to_date: date) -> Element: 38 | """Getting the Reports in the defined time period""" 39 | 40 | report_filter = ( 41 | f"rows=-1 created>{from_date.isoformat()} and " 42 | f"created<{to_date.isoformat()}" 43 | ) 44 | 45 | return gmp.get_reports(filter_string=report_filter) 46 | 47 | 48 | def print_result_sums( 49 | reports_xml: Element, from_date: date, to_date: date 50 | ) -> None: 51 | report_count = len(reports_xml.xpath("report")) 52 | print(f"Found {report_count} reports") 53 | 54 | sum_high = reports_xml.xpath( 55 | "sum(report/report/result_count/hole/full/text())" 56 | ) 57 | sum_medium = reports_xml.xpath( 58 | "sum(report/report/result_count/warning/full/text())" 59 | ) 60 | sum_low = reports_xml.xpath( 61 | "sum(report/report/result_count/info/full/text())" 62 | ) 63 | 64 | print( 65 | f"Summary of results from {from_date.isoformat()} " 66 | f"to {to_date.isoformat()}" 67 | ) 68 | print(f"High: {int(sum_high)}") 69 | print(f"Medium: {int(sum_medium)}") 70 | print(f"Low: {int(sum_low)}") 71 | 72 | 73 | def print_result_tables(gmp: Gmp, reports_xml: Element) -> None: 74 | report_list = reports_xml.xpath("report") 75 | 76 | for report in report_list: 77 | report_id = report.xpath("report/@id")[0] 78 | name = report.xpath("name/text()")[0] 79 | 80 | res = gmp.get_report(report_id) 81 | 82 | print(f"\nReport: {report_id}") 83 | 84 | table_data = [["Hostname", "IP", "Bericht", "high", "medium", "low"]] 85 | 86 | for host in res.xpath("report/report/host"): 87 | hostname = host.xpath( 88 | 'detail/name[text()="hostname"]/../value/text()' 89 | ) 90 | if len(hostname) > 0: 91 | hostname = str(hostname[0]) 92 | else: 93 | hostname = "" 94 | 95 | ip = host.xpath("ip/text()")[0] 96 | high = host.xpath("result_count/hole/page/text()")[0] 97 | medium = host.xpath("result_count/warning/page/text()")[0] 98 | low = host.xpath("result_count/info/page/text()")[0] 99 | 100 | table_data.append([hostname, ip, name, high, medium, low]) 101 | 102 | table = AsciiTable(table_data) 103 | print(table.table + "\n") 104 | 105 | 106 | def main(gmp: Gmp, args: Namespace) -> None: 107 | # pylint: disable=undefined-variable 108 | 109 | check_args(args) 110 | 111 | month = int(args.script[1]) 112 | year = int(args.script[2]) 113 | from_date = date(year, month, 1) 114 | to_date = from_date + timedelta(days=31) 115 | # To have the first day in month 116 | to_date = to_date.replace(day=1) 117 | 118 | reports_xml = get_reports_xml(gmp, from_date, to_date) 119 | 120 | print_result_sums(reports_xml, from_date, to_date) 121 | if "with-tables" in args.script: 122 | print_result_tables(gmp, reports_xml) 123 | 124 | 125 | if __name__ == "__gmp__": 126 | main(gmp, args) 127 | -------------------------------------------------------------------------------- /scripts/monthly-report-gos4.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | from datetime import date, timedelta 8 | 9 | from gvm.protocols.gmp import Gmp 10 | from terminaltables import AsciiTable 11 | 12 | 13 | def check_args(args: Namespace) -> None: 14 | len_args = len(args.script) - 1 15 | if len_args < 2: 16 | message = """ 17 | This script will display all vulnerabilities from the hosts of the 18 | reports in a given month! 19 | It needs two parameters after the script name. 20 | First one is the month and second one is the year. 21 | Both parameters are plain numbers, so no text. 22 | 23 | Explicitly made for GOS 4.X, compatible up to GOS 22.04. 24 | 25 | 1. -- month of the monthly report 26 | 2. -- year of the monthly report 27 | 28 | Example: 29 | $ gvm-script --gmp-username name --gmp-password pass \ 30 | ssh --hostname scripts/monthly-report2.gmp.py 05 2019 31 | """ 32 | print(message) 33 | sys.exit() 34 | 35 | 36 | def print_reports(gmp: Gmp, from_date: date, to_date: date) -> None: 37 | host_filter = ( 38 | f"rows=-1 and modified>{from_date.isoformat()} " 39 | f"and modified<{to_date.isoformat()}" 40 | ) 41 | 42 | hosts_xml = gmp.get_hosts(filter_string=host_filter) 43 | 44 | sum_high = 0 45 | sum_medium = 0 46 | sum_low = 0 47 | table_data = [["Hostname", "IP", "Bericht", "high", "medium", "low"]] 48 | 49 | for host in hosts_xml.xpath("asset"): 50 | ip = host.xpath("name/text()")[0] 51 | 52 | hostnames = host.xpath( 53 | 'identifiers/identifier/name[text()="hostname"]/../value/text()' 54 | ) 55 | 56 | if len(hostnames) == 0: 57 | continue 58 | 59 | hostname = hostnames[0] 60 | 61 | results = gmp.get_results( 62 | details=False, filter=f"host={ip} and severity>0.0" 63 | ) 64 | 65 | low = int(results.xpath('count(//result/threat[text()="Low"])')) 66 | sum_low += low 67 | 68 | medium = int(results.xpath('count(//result/threat[text()="Medium"])')) 69 | sum_medium += medium 70 | 71 | high = int(results.xpath('count(//result/threat[text()="High"])')) 72 | sum_high += high 73 | 74 | best_os_cpe_report_id = host.xpath( 75 | 'host/detail/name[text()="best_os_cpe"]/../source/@id' 76 | )[0] 77 | 78 | table_data.append( 79 | [hostname, ip, best_os_cpe_report_id, high, medium, low] 80 | ) 81 | 82 | table = AsciiTable(table_data) 83 | print(f"{table.table}\n") 84 | print( 85 | f"Summary of results from {from_date.isoformat()} " 86 | f"to {to_date.isoformat()}" 87 | ) 88 | print(f"High: {int(sum_high)}") 89 | print(f"Medium: {int(sum_medium)}") 90 | print(f"Low: {int(sum_low)}\n\n") 91 | 92 | 93 | def main(gmp: Gmp, args: Namespace) -> None: 94 | # pylint: disable=undefined-variable 95 | 96 | check_args(args) 97 | 98 | month = int(args.script[1]) 99 | year = int(args.script[2]) 100 | from_date = date(year, month, 1) 101 | to_date = from_date + timedelta(days=31) 102 | # To have the first day in month 103 | to_date = to_date.replace(day=1) 104 | 105 | print_reports(gmp, from_date, to_date) 106 | 107 | 108 | if __name__ == "__gmp__": 109 | main(gmp, args) 110 | -------------------------------------------------------------------------------- /scripts/nvt-scan.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | from datetime import datetime 8 | 9 | from gvm.errors import GvmError 10 | from gvm.protocols.gmp import Gmp 11 | 12 | 13 | def check_args(args): 14 | len_args = len(args.script) - 1 15 | if len_args != 2: 16 | message = """ 17 | This script creates a new task with specific host and nvt! 18 | It needs two parameters after the script name. 19 | 20 | -- oid of the nvt 21 | -- scan target 22 | 23 | Example: 24 | $ gvm-script --gmp-username name --gmp-password pass \ 25 | ssh --hostname 1.3.6.1.4.1.25623.1.0.106223 localhost 26 | """ 27 | print(message) 28 | sys.exit() 29 | 30 | 31 | def create_scan_config(gmp, nvt_oid) -> str: 32 | # Create new config 33 | copy_id = "085569ce-73ed-11df-83c3-002264764cea" 34 | config_name = nvt_oid 35 | config_id = "" 36 | 37 | try: 38 | res = gmp.create_scan_config(copy_id, config_name) 39 | config_id = res.xpath("@id")[0] 40 | 41 | # Modify the config with an nvt oid 42 | nvt = gmp.get_scan_config_nvt(nvt_oid) 43 | family = nvt.xpath("nvt/family/text()")[0] 44 | 45 | gmp.modify_scan_config_set_nvt_selection( 46 | config_id=config_id, nvt_oids=[nvt_oid], family=family 47 | ) 48 | 49 | # This nvts must be present to work 50 | family = "Port scanners" 51 | nvts = ["1.3.6.1.4.1.25623.1.0.14259", "1.3.6.1.4.1.25623.1.0.100315"] 52 | gmp.modify_scan_config_set_nvt_selection( 53 | config_id, nvt_oids=nvts, family=family 54 | ) 55 | 56 | except GvmError: 57 | res = gmp.get_scan_configs(filter_string=f"name={config_name}") 58 | config_id = res.xpath("config/@id")[0] 59 | 60 | return config_id 61 | 62 | 63 | def create_target(gmp: Gmp, name: str) -> str: 64 | try: 65 | res = gmp.create_target(name, hosts=[name]) 66 | target_id = res.xpath("@id")[0] 67 | except GvmError: 68 | res = gmp.get_targets(filter_string=f"name={name} hosts={name}") 69 | target_id = res.xpath("target/@id")[0] 70 | 71 | return target_id 72 | 73 | 74 | def create_and_start_task( 75 | gmp: Gmp, name: str, nvt_oid: str, config_id: str, target_id: str 76 | ) -> None: 77 | # Standard Scanner OpenVAS Default 78 | scanner_id = "08b69003-5fc2-4037-a479-93b440211c73" 79 | date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 80 | # Create task 81 | task_name = f"{name}_{nvt_oid}_{date_time}" 82 | res = gmp.create_task( 83 | name=task_name, 84 | config_id=config_id, 85 | target_id=target_id, 86 | scanner_id=scanner_id, 87 | ) 88 | task_id = res.xpath("@id")[0] 89 | 90 | # Start the task 91 | gmp.start_task(task_id=task_id) 92 | print(f"\nTask {task_id} started") 93 | 94 | 95 | def main(gmp: Gmp, args: Namespace) -> None: 96 | # pylint: disable=undefined-variable 97 | 98 | check_args(args) 99 | 100 | nvt_oid = args.script[1] 101 | target_name = args.script[2] 102 | 103 | config_id = create_scan_config(gmp, nvt_oid) 104 | target_id = create_target(gmp, target_name) 105 | 106 | create_and_start_task(gmp, target_name, nvt_oid, config_id, target_id) 107 | 108 | 109 | if __name__ == "__gmp__": 110 | main(gmp, args) 111 | -------------------------------------------------------------------------------- /scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | # required for monthly-report and monthly-report2 and certbund-report 2 | terminaltables 3 | # required for create-cve-report-from-json 4 | cpe -------------------------------------------------------------------------------- /scripts/ruff.toml: -------------------------------------------------------------------------------- 1 | builtins = ["gmp", "args"] 2 | -------------------------------------------------------------------------------- /scripts/scan-new-system.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2019-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import datetime 6 | import sys 7 | from argparse import Namespace 8 | 9 | from gvm.protocols.gmp import Gmp 10 | 11 | 12 | def check_args(args): 13 | len_args = len(args.script) - 1 14 | message = """ 15 | This script starts a new scan on the given host. 16 | It needs one parameters after the script name. 17 | 18 | 1. IP Address of the host system 19 | 2. Port List UUID for scanning the host system. 20 | Preconfigured UUID might be under 21 | /var/lib/gvm/data-objects/gvmd/20.08/port_lists/. 22 | ex. iana-tcp-udp is 23 | "4a4717fe-57d2-11e1-9a26-406186ea4fc5". 24 | 25 | Example: 26 | $ gvm-script --gmp-username name --gmp-password pass \ 27 | ssh --hostname scripts/scan-new-system.gmp.py 28 | """ 29 | if len_args != 2: 30 | print(message) 31 | sys.exit() 32 | 33 | 34 | def create_target(gmp, ipaddress, port_list_id): 35 | # create a unique name by adding the current datetime 36 | name = f"Suspect Host {ipaddress} {str(datetime.datetime.now())}" 37 | 38 | response = gmp.create_target( 39 | name=name, hosts=[ipaddress], port_list_id=port_list_id 40 | ) 41 | return response.get("id") 42 | 43 | 44 | def create_task(gmp, ipaddress, target_id, scan_config_id, scanner_id): 45 | name = f"Scan Suspect Host {ipaddress}" 46 | response = gmp.create_task( 47 | name=name, 48 | config_id=scan_config_id, 49 | target_id=target_id, 50 | scanner_id=scanner_id, 51 | ) 52 | return response.get("id") 53 | 54 | 55 | def start_task(gmp, task_id): 56 | response = gmp.start_task(task_id) 57 | # the response is 58 | # id 59 | return response[0].text 60 | 61 | 62 | def main(gmp: Gmp, args: Namespace) -> None: 63 | check_args(args) 64 | 65 | ipaddress = args.argv[1] 66 | port_list_id = args.argv[2] 67 | 68 | target_id = create_target(gmp, ipaddress, port_list_id) 69 | 70 | full_and_fast_scan_config_id = "daba56c8-73ec-11df-a475-002264764cea" 71 | openvas_scanner_id = "08b69003-5fc2-4037-a479-93b440211c73" 72 | task_id = create_task( 73 | gmp, 74 | ipaddress, 75 | target_id, 76 | full_and_fast_scan_config_id, 77 | openvas_scanner_id, 78 | ) 79 | 80 | report_id = start_task(gmp, task_id) 81 | 82 | print( 83 | f"Started scan of host {ipaddress}. " 84 | f"Corresponding report ID is {report_id}" 85 | ) 86 | 87 | 88 | if __name__ == "__gmp__": 89 | # pylint: disable=undefined-variable 90 | main(gmp, args) 91 | -------------------------------------------------------------------------------- /scripts/send-schedules.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | 8 | from gvm.protocols.gmp import Gmp 9 | from gvmtools.helper import create_xml_tree 10 | from lxml.etree import Element 11 | 12 | 13 | def check_args(gmp: Gmp, args: Namespace) -> None: 14 | len_args = len(args.script) - 1 15 | if len_args != 1: 16 | message = """ 17 | This script pulls schedule data from an xml document and feeds it to \ 18 | a desired GSM 19 | One parameter after the script name is required. 20 | 21 | 1. -- .xml file containing schedules 22 | 23 | Example: 24 | $ gvm-script --gmp-username name --gmp-password pass \ 25 | ssh --hostname scripts/send-schedules.gmp.py example_file.xml 26 | 27 | """ 28 | print(message) 29 | sys.exit() 30 | major, minor = gmp.get_protocol_version() 31 | if major < 21 and minor < 5: 32 | print(f"This script requires GMP version {major}.{minor}") 33 | sys.exit() 34 | 35 | 36 | def parse_send_xml_tree(gmp: Gmp, xml_tree: Element) -> None: 37 | for schedule in xml_tree.xpath("schedule"): 38 | name = schedule.find("name").text 39 | 40 | comment = schedule.find("comment").text 41 | if comment is None: 42 | comment = "" 43 | 44 | ical = schedule.find("icalendar").text 45 | 46 | timezone = schedule.find("timezone").text 47 | 48 | gmp.create_schedule( 49 | name=name, comment=comment, timezone=timezone, icalendar=ical 50 | ) 51 | 52 | 53 | def main(gmp: Gmp, args: Namespace) -> None: 54 | # pylint: disable=undefined-variable 55 | 56 | check_args(gmp=gmp, args=args) 57 | 58 | xml_doc = args.script[1] 59 | 60 | print("\nSending schedules...") 61 | 62 | xml_tree = create_xml_tree(xml_doc) 63 | parse_send_xml_tree(gmp, xml_tree) 64 | 65 | print("\n Schedule(s) created!\n") 66 | 67 | 68 | if __name__ == "__gmp__": 69 | main(gmp, args) 70 | -------------------------------------------------------------------------------- /scripts/send-targets.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2018-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | 8 | from gvm.protocols.gmp import Gmp 9 | from gvmtools.helper import create_xml_tree, yes_or_no 10 | from lxml.etree import Element 11 | 12 | 13 | def check_args(args: Namespace) -> None: 14 | len_args = len(args.script) - 1 15 | if len_args != 1: 16 | message = """ 17 | This script pulls target data from an xml document and feeds it to \ 18 | a desired GSM 19 | One parameter after the script name is required. 20 | 21 | 1. -- .xml file containing targets 22 | 23 | Example: 24 | $ gvm-script --gmp-username name --gmp-password pass \ 25 | ssh --hostname scripts/send-targets.gmp.py example_file.xml 26 | """ 27 | print(message) 28 | sys.exit() 29 | 30 | 31 | def parse_send_xml_tree(gmp: Gmp, xml_tree: Element) -> None: 32 | credential_options = [ 33 | "ssh_credential", 34 | "smb_credential", 35 | "esxi_credential", 36 | "snmp_credential", 37 | ] 38 | counter = 1 39 | 40 | for target in xml_tree.xpath("target"): 41 | keywords = {} # {'make_unique': True} 42 | 43 | keywords["name"] = target.find("name").text 44 | 45 | keywords["hosts"] = target.find("hosts").text.split(",") 46 | 47 | exclude_hosts = target.find("exclude_hosts").text 48 | if exclude_hosts is not None: 49 | keywords["exclude_hosts"] = exclude_hosts.split(",") 50 | 51 | comment = target.find("comment").text 52 | if comment is not None: 53 | keywords["comment"] = comment 54 | 55 | credentials = gmp.get_credentials()[0].xpath("//credential/@id") 56 | 57 | for credential in credential_options: 58 | cred_id = target.find(credential).xpath("@id")[0] 59 | if cred_id == "": 60 | continue 61 | if cred_id not in credentials: 62 | response = yes_or_no( 63 | f"\nThe credential '{credential}' for 'target {counter}' " 64 | "could not be located...\nWould you like to continue?" 65 | ) 66 | 67 | if response is False: 68 | print("Terminating...\n") 69 | sys.exit() 70 | else: 71 | continue 72 | 73 | key = f"{credential}_id" 74 | keywords[key] = cred_id 75 | elem_path = target.find(credential) 76 | port = elem_path.find("port") 77 | if port is not None and port.text is not None: 78 | port_key = f"{credential}_port" 79 | keywords[port_key] = elem_path.find("port").text 80 | 81 | alive_test = gmp.types.AliveTest.from_string( 82 | target.find("alive_tests").text 83 | ) 84 | 85 | if alive_test is not None: 86 | keywords["alive_test"] = alive_test 87 | 88 | reverse_lookup_only = target.find("reverse_lookup_only").text 89 | if reverse_lookup_only == "1": 90 | keywords["reverse_lookup_only"] = 1 91 | 92 | reverse_lookup_unify = target.find("reverse_lookup_unify").text 93 | if reverse_lookup_unify == "1": 94 | keywords["reverse_lookup_unify"] = 1 95 | 96 | port_range = target.find("port_range") 97 | if port_range is not None: 98 | keywords["port_range"] = port_range.text 99 | 100 | if target.xpath("port_list/@id") is not None: 101 | port_list = {} 102 | port_list = target.xpath("port_list/@id")[0] 103 | keywords["port_list_id"] = port_list 104 | 105 | print(keywords) 106 | 107 | gmp.create_target(**keywords) 108 | 109 | counter += 1 110 | 111 | 112 | def main(gmp: Gmp, args: Namespace) -> None: 113 | # pylint: disable=undefined-variable 114 | 115 | check_args(args) 116 | 117 | xml_doc = args.script[1] 118 | 119 | print("\nSending targets...") 120 | 121 | xml_tree = create_xml_tree(xml_doc) 122 | parse_send_xml_tree(gmp, xml_tree) 123 | 124 | print("\n Target(s) created!\n") 125 | 126 | 127 | if __name__ == "__gmp__": 128 | main(gmp, args) # pylint: disable=undefined-variable 129 | -------------------------------------------------------------------------------- /scripts/start-nvt-scan.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import sys 6 | from argparse import Namespace 7 | 8 | from gvm.protocols.gmp import Gmp 9 | 10 | 11 | def check_args(args): 12 | len_args = len(args.script) - 1 13 | if len_args != 2: 14 | message = """ 15 | This script creates a new task with specific host and nvt! 16 | It needs two parameters after the script name. 17 | First one is the oid of the nvt and the second one is the 18 | chosen scan target. 19 | 20 | Example: 21 | $ gvm-script --gmp-username name --gmp-password pass \ 22 | ssh --hostname scripts/start-nvt-scan.gmp.py \ 23 | 1.3.6.1.4.1.25623.1.0.106223 localhost 24 | """ 25 | print(message) 26 | sys.exit() 27 | 28 | 29 | def get_scan_config(gmp, nvt_oid): 30 | # Choose from existing config, which to copy or create new config 31 | res = gmp.get_scan_configs() 32 | 33 | config_ids = res.xpath("config/@id") 34 | 35 | for i, conf in enumerate(res.xpath("config")): 36 | config_id = conf.xpath("@id")[0] 37 | name = conf.xpath("name/text()")[0] 38 | print(f"\n({i}) {name}: ({config_id})") 39 | 40 | while True: 41 | chosen_config = input( 42 | "\nChoose your config or create new one" 43 | f"[0-{len(config_ids) - 1} | n]: " 44 | ) 45 | 46 | if chosen_config == "n": 47 | chosen_copy_config = int( 48 | input(f"Which config to copy from? [0-{len(config_ids) - 1}]: ") 49 | ) 50 | config_name = input("Enter new Name for config: ") 51 | 52 | copy_id = config_ids[chosen_copy_config] 53 | 54 | res = gmp.clone_scan_config(copy_id) 55 | 56 | config_id = res.xpath("@id")[0] 57 | 58 | # Modify the config with an nvt oid 59 | if len(nvt_oid) == 0: 60 | nvt_oid = input("NVT OID: ") 61 | 62 | nvt = gmp.get_scan_config_nvt(nvt_oid=nvt_oid) 63 | family = nvt.xpath("nvt/family/text()")[0] 64 | 65 | gmp.modify_scan_config( 66 | config_id, 67 | "nvt_selection", 68 | name=config_name, 69 | nvt_oids=[nvt_oid], 70 | family=family, 71 | ) 72 | 73 | # This nvts must be present to work 74 | family = "Port scanners" 75 | nvts = [ 76 | "1.3.6.1.4.1.25623.1.0.14259", 77 | "1.3.6.1.4.1.25623.1.0.100315", 78 | ] 79 | 80 | gmp.modify_scan_config( 81 | config_id, "nvt_selection", nvt_oids=nvts, family=family 82 | ) 83 | return config_id 84 | 85 | if 0 <= int(chosen_config) < len(config_ids): 86 | return config_ids[int(chosen_config)] 87 | 88 | 89 | def get_target(gmp, hosts): 90 | # create a new target or use an existing 91 | targets = gmp.get_targets() 92 | target_ids = targets.xpath("target/@id") 93 | 94 | for i, target in enumerate(targets.xpath("target")): 95 | name = target.xpath("name/text()")[0] 96 | print(f"\n({i}) {name}") 97 | 98 | while True: 99 | if target_ids: 100 | chosen_target = input( 101 | "\nChoose your target or create new" 102 | f" one[0-{len(target_ids) - 1} | n]: " 103 | ) 104 | else: 105 | chosen_target = "n" 106 | 107 | if chosen_target == "n": 108 | if len(hosts) == 0: 109 | hosts = input("Target hosts (comma separated): ") 110 | 111 | name = input("Name of target: ") 112 | 113 | res = gmp.create_target(name, hosts=hosts.split(",")) 114 | return res.xpath("@id")[0] 115 | 116 | if 0 <= int(chosen_target) < len(target_ids): 117 | return target_ids[int(chosen_target)] 118 | 119 | 120 | def get_scanner(gmp): 121 | res = gmp.get_scanners() 122 | scanner_ids = res.xpath("scanner/@id") 123 | 124 | for i, scanner in enumerate(res.xpath("scanner")): 125 | scanner_id = scanner.xpath("@id")[0] 126 | name = scanner.xpath("name/text()")[0] 127 | # configs[id] = name 128 | print(f"\n({i})\n{name}: ({scanner_id})") 129 | 130 | while True: 131 | chosen_scanner = int( 132 | input(f"\nChoose your scanner [0-{len(scanner_ids) - 1}]: ") 133 | ) 134 | if 0 <= chosen_scanner < len(scanner_ids): 135 | return scanner_ids[chosen_scanner] 136 | 137 | 138 | def create_and_start_task( 139 | gmp, task_name, task_comment, config_id, target_id, scanner_id 140 | ): 141 | res = gmp.create_task( 142 | name=task_name, 143 | config_id=config_id, 144 | target_id=target_id, 145 | scanner_id=scanner_id, 146 | comment=task_comment, 147 | ) 148 | 149 | # Start the task 150 | task_id = res.xpath("@id")[0] 151 | gmp.start_task(task_id) 152 | print("Task started") 153 | 154 | 155 | def main(gmp: Gmp, args: Namespace) -> None: 156 | # pylint: disable=undefined-variable 157 | 158 | check_args(args) 159 | 160 | nvt_oid = args.script[1] 161 | hosts = args.script[2] 162 | 163 | task_name = input("Task name: ") 164 | task_comment = input("Task comment: ") 165 | 166 | config_id = get_scan_config(gmp, nvt_oid) 167 | target_id = get_target(gmp, hosts) 168 | scanner_id = get_scanner(gmp) 169 | 170 | create_and_start_task( 171 | gmp, task_name, task_comment, config_id, target_id, scanner_id 172 | ) 173 | 174 | 175 | if __name__ == "__gmp__": 176 | main(gmp, args) 177 | -------------------------------------------------------------------------------- /scripts/start-scans-from-csv.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | # Run with gvm-script --gmp-username admin-user --gmp-password password socket start-scans-from-csv.gmp.py startscans.csv 6 | 7 | import csv 8 | import sys 9 | from argparse import ArgumentParser, Namespace, RawTextHelpFormatter 10 | from pathlib import Path 11 | 12 | from gvm.errors import GvmResponseError 13 | from gvm.protocols.gmp import Gmp 14 | from gvmtools.helper import error_and_exit 15 | 16 | HELP_TEXT = "This script pulls task names from a csv file and starts the tasks listed in every row. \n" 17 | 18 | 19 | def check_args(args): 20 | len_args = len(args.script) - 1 21 | if len_args != 2: 22 | message = """ 23 | This script pulls tasks from a csv file and creates a \ 24 | task for each row in the csv file. 25 | One parameter after the script name is required. 26 | 27 | 1. -- csv file containing names and secrets required for scan tasks 28 | 29 | Example: 30 | $ gvm-script --gmp-username name --gmp-password pass \ 31 | ssh --hostname scripts/start_tasks_from_csv.gmp.py \ 32 | 33 | """ 34 | print(message) 35 | sys.exit() 36 | 37 | 38 | def parse_args(args: Namespace) -> Namespace: # pylint: disable=unused-argument 39 | """Parsing args ...""" 40 | 41 | parser = ArgumentParser( 42 | prefix_chars="+", 43 | add_help=False, 44 | formatter_class=RawTextHelpFormatter, 45 | description=HELP_TEXT, 46 | ) 47 | 48 | parser.add_argument( 49 | "+h", 50 | "++help", 51 | action="help", 52 | help="Show this help message and exit.", 53 | ) 54 | 55 | parser.add_argument( 56 | "task_file", 57 | type=str, 58 | help=("CSV File containing tasks"), 59 | ) 60 | script_args, _ = parser.parse_known_args(args) 61 | return script_args 62 | 63 | 64 | def task_id( 65 | gmp: Gmp, 66 | task_name: str, 67 | ): 68 | response_xml = gmp.get_tasks( 69 | filter_string="rows=-1, not status=Running and " 70 | "not status=Requested and not " 71 | "status=Queued " 72 | "and name=" + task_name 73 | ) 74 | tasks_xml = response_xml.xpath("task") 75 | task_id = "" 76 | 77 | for task in tasks_xml: 78 | task_id = task.get("id") 79 | return task_id 80 | 81 | 82 | def start_tasks( 83 | gmp: Gmp, 84 | task_file: Path, 85 | ): 86 | try: 87 | numbertasks = 0 88 | with open(task_file, encoding="utf-8") as csvFile: 89 | content = csv.reader(csvFile, delimiter=",") # read the data 90 | try: 91 | for row in content: # loop through each row 92 | if len(row) == 0: 93 | continue 94 | task_start = task_id(gmp, row[0]) 95 | if task_start: 96 | numbertasks = numbertasks + 1 97 | print( 98 | f"Starting task name: {row[0]} with uuid: {task_start} ..." 99 | ) 100 | status_text = gmp.start_task(task_start).xpath( 101 | "@status_text" 102 | )[0] 103 | print(status_text) 104 | else: 105 | print( 106 | "Task " 107 | + row[0] 108 | + " is either in status Requested, Queued, Running, or does not exist on this system.\n" 109 | ) 110 | except GvmResponseError as gvmerr: 111 | print(f"{gvmerr=}, task: {task_start}") 112 | pass 113 | csvFile.close() # close the csv file 114 | 115 | except IOError as e: 116 | error_and_exit(f"Failed to read task_file: {str(e)} (exit)") 117 | 118 | return numbertasks 119 | 120 | 121 | def main(gmp: Gmp, args: Namespace) -> None: 122 | # pylint: disable=undefined-variable 123 | if args.script: 124 | args = args.script[1:] 125 | 126 | parsed_args = parse_args(args=args) 127 | 128 | print("Starting tasks.\n") 129 | 130 | numbertasks = start_tasks( 131 | gmp, 132 | parsed_args.task_file, 133 | ) 134 | 135 | numbertasks = str(numbertasks) 136 | print(" \n [" + numbertasks + "] task(s)/scan(s) started!\n") 137 | 138 | 139 | if __name__ == "__gmp__": 140 | main(gmp, args) 141 | -------------------------------------------------------------------------------- /scripts/stop-all-scans.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | from argparse import Namespace 6 | 7 | from gvm.protocols.gmp import Gmp 8 | 9 | 10 | def stop_tasks(gmp: Gmp) -> None: 11 | tasks = gmp.get_tasks( 12 | filter_string="rows=-1 status=Running or status=Requested or status=Queued" 13 | ) 14 | try: 15 | for task_id in tasks.xpath("task/@id"): 16 | print(f"Stopping task {task_id} ... ") 17 | status_text = gmp.stop_task(task_id).xpath("@status_text")[0] 18 | print(status_text) 19 | except Exception as e: 20 | print(f"{e=}") 21 | 22 | 23 | def main(gmp: Gmp, args: Namespace) -> None: 24 | # pylint: disable=undefined-variable 25 | print("This script stops all tasks on the system.\n") 26 | 27 | stop_tasks(gmp) 28 | 29 | 30 | if __name__ == "__gmp__": 31 | main(gmp, args) 32 | -------------------------------------------------------------------------------- /scripts/stop-scans-from-csv.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | # Run with gvm-script --gmp-username admin-user --gmp-password password socket start-scans-from-csv.gmp.py startscans.csv 6 | 7 | import csv 8 | import sys 9 | from argparse import ArgumentParser, Namespace, RawTextHelpFormatter 10 | from pathlib import Path 11 | 12 | from gvm.errors import GvmResponseError 13 | from gvm.protocols.gmp import Gmp 14 | from gvmtools.helper import error_and_exit 15 | 16 | HELP_TEXT = "This script pulls task names from a csv file and starts the tasks listed in every row. \n" 17 | 18 | 19 | def check_args(args): 20 | len_args = len(args.script) - 1 21 | if len_args != 2: 22 | message = """ 23 | This script pulls tasks from a csv file and creates a \ 24 | task for each row in the csv file. 25 | One parameter after the script name is required. 26 | 27 | 1. -- csv file containing names and secrets required for scan tasks 28 | 29 | Example: 30 | $ gvm-script --gmp-username name --gmp-password pass \ 31 | ssh --hostname scripts/stop_tasks_from_csv.gmp.py \ 32 | 33 | """ 34 | print(message) 35 | sys.exit() 36 | 37 | 38 | def parse_args(args: Namespace) -> Namespace: # pylint: disable=unused-argument 39 | """Parsing args ...""" 40 | 41 | parser = ArgumentParser( 42 | prefix_chars="+", 43 | add_help=False, 44 | formatter_class=RawTextHelpFormatter, 45 | description=HELP_TEXT, 46 | ) 47 | 48 | parser.add_argument( 49 | "+h", 50 | "++help", 51 | action="help", 52 | help="Show this help message and exit.", 53 | ) 54 | 55 | parser.add_argument( 56 | "task_file", 57 | type=str, 58 | help=("CSV File containing tasks"), 59 | ) 60 | script_args, _ = parser.parse_known_args(args) 61 | return script_args 62 | 63 | 64 | def task_id( 65 | gmp: Gmp, 66 | task_name: str, 67 | ): 68 | response_xml = gmp.get_tasks( 69 | filter_string="rows=-1, status=Running " 70 | "or status=Requested " 71 | "or status=Queued " 72 | "and name=" + task_name 73 | ) 74 | tasks_xml = response_xml.xpath("task") 75 | task_id = "" 76 | 77 | for task in tasks_xml: 78 | task_id = task.get("id") 79 | return task_id 80 | 81 | 82 | def stop_tasks( 83 | gmp: Gmp, 84 | task_file: Path, 85 | ): 86 | try: 87 | numbertasks = 0 88 | with open(task_file, encoding="utf-8") as csvFile: 89 | content = csv.reader(csvFile, delimiter=",") # read the data 90 | try: 91 | for row in content: # loop through each row 92 | if len(row) == 0: 93 | continue 94 | task_stop = task_id(gmp, row[0]) 95 | if task_stop: 96 | numbertasks = numbertasks + 1 97 | print( 98 | f"Stopping task name: {row[0]} with uuid: {task_stop} ..." 99 | ) 100 | status_text = gmp.stop_task(task_stop).xpath( 101 | "@status_text" 102 | )[0] 103 | print(status_text) 104 | else: 105 | print( 106 | "Task " 107 | + row[0] 108 | + " is either in status Stopped, Stop Requested, or does not exist on this system.\n" 109 | ) 110 | except GvmResponseError as gvmerr: 111 | print(f"{gvmerr=}, task: {task_stop}") 112 | pass 113 | csvFile.close() # close the csv file 114 | 115 | except IOError as e: 116 | error_and_exit(f"Failed to read task_file: {str(e)} (exit)") 117 | 118 | if len(row) == 0: 119 | error_and_exit("tasks file is empty (exit)") 120 | 121 | return numbertasks 122 | 123 | 124 | def main(gmp: Gmp, args: Namespace) -> None: 125 | # pylint: disable=undefined-variable 126 | if args.script: 127 | args = args.script[1:] 128 | 129 | parsed_args = parse_args(args=args) 130 | 131 | print("Stopping tasks.\n") 132 | 133 | numbertasks = stop_tasks( 134 | gmp, 135 | parsed_args.task_file, 136 | ) 137 | 138 | numbertasks = str(numbertasks) 139 | print(" \n [" + numbertasks + "] task(s)/scan(s) stopped!\n") 140 | 141 | 142 | if __name__ == "__gmp__": 143 | main(gmp, args) 144 | -------------------------------------------------------------------------------- /scripts/sync-hosts.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import csv 6 | import sys 7 | from argparse import Namespace 8 | 9 | from gvm.protocols.gmp import Gmp 10 | 11 | 12 | def check_args(args): 13 | len_args = len(args.script) - 1 14 | if len_args != 1: 15 | message = """ 16 | This script reads host data from a csv file and sync it with the gsm. 17 | It needs one parameters after the script name. 18 | 19 | 1. - should contain a table of IP-addresses with an 20 | optional a comment 21 | 22 | Example: 23 | $ gvm-script --gmp-username name --gmp-password pass \ 24 | ssh --hostname scripts/sync-hosts.gmp.py 25 | """ 26 | print(message) 27 | sys.exit() 28 | 29 | 30 | def sync_hosts(gmp, filename): 31 | with open(filename, newline="", encoding="utf-8") as f: 32 | reader = csv.reader(f, delimiter=",", quotechar="|") 33 | for row in reader: 34 | if len(row) == 2: 35 | ip = row[0] 36 | comment = row[1] 37 | 38 | # check if host exists 39 | ret = gmp.get_hosts(filter_string=f"ip={ip}") 40 | if ret.xpath("host"): 41 | print(f"\nAsset with IP {ip} exist") 42 | host_id = ret.xpath("host/@id")[0] 43 | gmp.delete_host(host_id=host_id) 44 | else: 45 | print(f"Asset with ip {ip} does not exist. Sync...") 46 | ret = gmp.create_host(name=ip, comment=comment) 47 | 48 | if "OK" in ret.xpath("@status_text")[0]: 49 | print("Asset synced") 50 | 51 | 52 | def main(gmp: Gmp, args: Namespace) -> None: 53 | # pylint: disable=undefined-variable 54 | 55 | check_args(args) 56 | 57 | file = args.script[1] 58 | 59 | sync_hosts(gmp, file) 60 | 61 | 62 | if __name__ == "__gmp__": 63 | main(gmp, args) 64 | -------------------------------------------------------------------------------- /scripts/update-task-target.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2021 Greenbone AG 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | import time 6 | from argparse import ArgumentParser, FileType, Namespace, RawTextHelpFormatter 7 | from typing import List 8 | 9 | from gvm.protocols.gmp import Gmp 10 | from gvmtools.helper import error_and_exit 11 | 12 | HELP_TEXT = ( 13 | "This script will update target hosts information for a desired task.\n" 14 | 'The given task needs to have the status "new".\n\n' 15 | "Example for starting up the routine:\n" 16 | " $ gvm-script --gmp-username name --gmp-password pass " 17 | "ssh --hostname scripts/update-task-target.gmp.py +hf hosts_file.csv " 18 | "+t 303fa0a6-aa9b-43c4-bac0-66ae0b2d1698" 19 | ) 20 | 21 | 22 | def parse_args(args: Namespace) -> Namespace: # pylint: disable=unused-argument 23 | """Parsing args ...""" 24 | 25 | parser = ArgumentParser( 26 | prefix_chars="+", 27 | add_help=False, 28 | formatter_class=RawTextHelpFormatter, 29 | description=HELP_TEXT, 30 | ) 31 | 32 | parser.add_argument( 33 | "+h", 34 | "++help", 35 | action="help", 36 | help="Show this help message and exit.", 37 | ) 38 | 39 | parser.add_argument( 40 | "+t", 41 | "++task-id", 42 | type=str, 43 | required=True, 44 | dest="task_id", 45 | help="UUID of task to be modified", 46 | ) 47 | 48 | hosts_args = parser.add_mutually_exclusive_group() 49 | 50 | hosts_args.add_argument( 51 | "+hl", 52 | "++host-list", 53 | nargs="+", 54 | type=str, 55 | dest="host_list", 56 | help="Use the given hosts (IPs) for the new target.", 57 | ) 58 | 59 | hosts_args.add_argument( 60 | "+hf", 61 | "++host-file", 62 | type=FileType("r"), 63 | dest="host_file", 64 | help=".csv file containing desired target hosts separated by ','", 65 | ) 66 | 67 | script_args, _ = parser.parse_known_args() 68 | return script_args 69 | 70 | 71 | def load_host_file(filename) -> List[str]: 72 | host_list = list() 73 | 74 | try: 75 | for line in filename.readlines(): 76 | host = line.split(",")[0] 77 | host = host.strip() 78 | if len(host) == 0: 79 | continue 80 | host_list.append(host) 81 | 82 | except IOError as e: 83 | error_and_exit(f"Failed to read host_file: {str(e)} (exit)") 84 | 85 | if len(host_list) == 0: 86 | error_and_exit("Host file is empty (exit)") 87 | 88 | return host_list 89 | 90 | 91 | def copy_send_target(gmp, host_list, old_target_id): 92 | keywords = {"hosts": host_list} 93 | 94 | keywords["comment"] = ( 95 | "This target was automatically " 96 | f'modified: {time.strftime("%Y/%m/%d-%H:%M:%S")}' 97 | ) 98 | 99 | old_target = gmp.get_target(target_id=old_target_id)[0] 100 | 101 | objects = ("reverse_lookup_only", "reverse_lookup_unify", "name") 102 | for obj in objects: 103 | var = old_target.xpath(f"{obj}/text()")[0] 104 | if var == "0": 105 | var = "" 106 | keywords[f"{obj}"] = var 107 | 108 | port_list = {} 109 | port_list = old_target.xpath("port_list/@id")[0] 110 | keywords["port_list_id"] = port_list 111 | 112 | keywords["name"] += "_copy" # the name must differ from existing names 113 | 114 | new_target_id = gmp.create_target(**keywords).xpath("@id")[0] 115 | 116 | print("\n New target created!\n") 117 | print(f"Target_id: {new_target_id}") 118 | print(f'Target_name: {keywords["name"]}\n') 119 | 120 | return new_target_id 121 | 122 | 123 | def create_target_hosts(gmp: Gmp, host_file, task_id, old_target_id): 124 | new_target_id = copy_send_target(gmp, host_file, old_target_id) 125 | 126 | gmp.modify_task(task_id=task_id, target_id=new_target_id) 127 | 128 | print(" Task successfully modified!\n") 129 | 130 | 131 | def check_to_delete(gmp: Gmp, target_id: str) -> None: 132 | target = gmp.get_target(target_id=target_id)[0] 133 | if "0" in target.xpath("in_use/text()"): 134 | gmp.delete_target(target_id=target_id) 135 | 136 | 137 | def main(gmp: Gmp, args: Namespace) -> None: 138 | # pylint: disable=undefined-variable 139 | parsed_args = parse_args(args=args) 140 | 141 | host_list = parsed_args.host_list 142 | if parsed_args.host_file: 143 | host_list = load_host_file(filename=parsed_args.host_file) 144 | task_id = parsed_args.task_id 145 | 146 | task = gmp.get_task(task_id=task_id)[1] 147 | old_target_id = task.xpath("target/@id")[0] 148 | 149 | if old_target_id: 150 | create_target_hosts(gmp, host_list, task_id, old_target_id) 151 | check_to_delete(gmp, old_target_id) 152 | else: 153 | error_and_exit("The given task doesn't have an existing target.") 154 | 155 | 156 | if __name__ == "__gmp__": 157 | main(gmp, args) 158 | -------------------------------------------------------------------------------- /scripts/verify-scanners.gmp.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2025 Martin Boller 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-or-later 4 | # 5 | # Loosely based on other greenbone scripts 6 | # 7 | # Run with: gvm-script --gmp-username admin-user --gmp-password password socket verify-scanners.gmp.py 8 | 9 | from argparse import Namespace 10 | 11 | from gvm.errors import GvmServerError 12 | from gvm.protocols.gmp import Gmp 13 | from gvmtools.helper import Table 14 | 15 | 16 | def main(gmp: Gmp, args: Namespace) -> None: 17 | # pylint: disable=unused-argument 18 | 19 | heading = ["#", "Name", "Id", "Host", "Version"] 20 | 21 | rows = [] 22 | numberRows = 0 23 | 24 | print("Verifying scanners.\n") 25 | response_xml = gmp.get_scanners(filter_string="rows=-1") 26 | scanners_xml = response_xml.xpath("scanner") 27 | 28 | for scanner in scanners_xml: 29 | # Count number of reports 30 | numberRows = numberRows + 1 31 | # Cast/convert to text to show in list 32 | rowNumber = str(numberRows) 33 | name = "".join(scanner.xpath("name/text()")) 34 | scanner_id = scanner.get("id") 35 | host = "".join(scanner.xpath("host/text()")) 36 | if host == "": 37 | host = "local scanner" 38 | try: 39 | status_xml = gmp.verify_scanner(str(scanner_id)) 40 | # pretty_print(status_xml) 41 | for scanner_status in status_xml: 42 | scanner_version = "".join(scanner_status.xpath("text()")) 43 | except GvmServerError: 44 | scanner_version = "*No Response*" 45 | pass 46 | 47 | rows.append([rowNumber, name, scanner_id, host, scanner_version]) 48 | 49 | print(Table(heading=heading, rows=rows)) 50 | 51 | 52 | if __name__ == "__gmp__": 53 | main(gmp, args) 54 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2019-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | import sys 21 | 22 | 23 | class SuppressOutput: 24 | def __init__(self, *, suppress_stdout=False, suppress_stderr=False): 25 | self.suppress_stdout = suppress_stdout 26 | self.suppress_stderr = suppress_stderr 27 | self.original_stdout = None 28 | self.original_stderr = None 29 | 30 | def __enter__(self): 31 | self.devnull = open(os.devnull, "w", encoding="utf-8") 32 | 33 | # Suppress streams 34 | if self.suppress_stdout: 35 | self.original_stdout = sys.stdout 36 | sys.stdout = self.devnull 37 | 38 | if self.suppress_stderr: 39 | self.original_stderr = sys.stderr 40 | sys.stderr = self.devnull 41 | 42 | def __exit__(self, *args, **kwargs): 43 | # Restore streams 44 | if self.suppress_stdout: 45 | sys.stdout = self.original_stdout 46 | 47 | if self.suppress_stderr: 48 | sys.stderr = self.original_stderr 49 | 50 | self.devnull.close() 51 | -------------------------------------------------------------------------------- /tests/root_help.3.10.snap: -------------------------------------------------------------------------------- 1 | usage: gvm-test-cli [-h] [-c [CONFIG]] 2 | [--log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}]] 3 | [--timeout TIMEOUT] [--gmp-username GMP_USERNAME] 4 | [--gmp-password GMP_PASSWORD] [-V] 5 | CONNECTION_TYPE ... 6 | 7 | options: 8 | -h, --help show this help message and exit 9 | -c [CONFIG], --config [CONFIG] 10 | Configuration file path (default: ~/.config/gvm- 11 | tools.conf) 12 | --log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}] 13 | Activate logging (default level: None) 14 | --timeout TIMEOUT Response timeout in seconds, or -1 to wait 15 | indefinitely (default: 60) 16 | --gmp-username GMP_USERNAME 17 | Username for GMP service (default: None) 18 | --gmp-password GMP_PASSWORD 19 | Password for GMP service (default: None) 20 | -V, --version Show version information and exit 21 | 22 | connections: 23 | valid connection types 24 | 25 | CONNECTION_TYPE Connection type to use 26 | ssh Use SSH to connect to service 27 | tls Use TLS secured connection to connect to service 28 | socket Use UNIX Domain socket to connect to service 29 | -------------------------------------------------------------------------------- /tests/root_help.snap: -------------------------------------------------------------------------------- 1 | usage: gvm-test-cli [-h] [-c [CONFIG]] 2 | [--log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}]] 3 | [--timeout TIMEOUT] [--gmp-username GMP_USERNAME] 4 | [--gmp-password GMP_PASSWORD] [-V] 5 | CONNECTION_TYPE ... 6 | 7 | optional arguments: 8 | -h, --help show this help message and exit 9 | -c [CONFIG], --config [CONFIG] 10 | Configuration file path (default: ~/.config/gvm- 11 | tools.conf) 12 | --log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}] 13 | Activate logging (default level: None) 14 | --timeout TIMEOUT Response timeout in seconds, or -1 to wait 15 | indefinitely (default: 60) 16 | --gmp-username GMP_USERNAME 17 | Username for GMP service (default: None) 18 | --gmp-password GMP_PASSWORD 19 | Password for GMP service (default: None) 20 | -V, --version Show version information and exit 21 | 22 | connections: 23 | valid connection types 24 | 25 | CONNECTION_TYPE Connection type to use 26 | ssh Use SSH to connect to service 27 | tls Use TLS secured connection to connect to service 28 | socket Use UNIX Domain socket to connect to service 29 | -------------------------------------------------------------------------------- /tests/scripts/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2020-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from importlib.util import module_from_spec, spec_from_file_location 20 | from pathlib import Path 21 | from typing import Union 22 | from unittest.mock import MagicMock, create_autospec 23 | 24 | from gvm.protocols.latest import Gmp 25 | from lxml import etree 26 | 27 | 28 | def load_script(path: Union[str, Path], script_name: str): 29 | """loading a script for a test case""" 30 | spec = spec_from_file_location( 31 | script_name, f"{str(path)}/{script_name}.gmp.py" 32 | ) 33 | script = module_from_spec(spec) 34 | spec.loader.exec_module(script) 35 | 36 | return script 37 | 38 | 39 | class GmpMockFactory: 40 | def __init__(self, *args, **kwargs): # pylint: disable=unused-argument 41 | gmp_protocol_mock = create_autospec(Gmp) 42 | 43 | self.gmp_protocol = gmp_protocol_mock 44 | self.gmp = MagicMock() 45 | self.gmp.is_authenticated = MagicMock(return_value=True) 46 | self.gmp_protocol.types = MagicMock() 47 | self.gmp.__enter__.return_value = gmp_protocol_mock 48 | 49 | def __call__(self, *args, **kwargs): 50 | return self.gmp 51 | 52 | def mock_response(self, request_name: str, content: str): 53 | func = getattr(self.gmp_protocol, request_name) 54 | func.return_value = etree.fromstring(content) 55 | 56 | def mock_responses(self, request_name: str, content: str): 57 | func = getattr(self.gmp_protocol, request_name) 58 | func.side_effect = [etree.fromstring(c) for c in content] 59 | -------------------------------------------------------------------------------- /tests/scripts/get_alerts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | jloechte 26 | 27 | test_alert 28 | 29 | 2021-01-03T13:45:20Z 30 | 2021-01-03T13:45:20Z 31 | 1 32 | 0 33 | 34 | 35 | Everything 36 | 37 | 38 | Always 39 | Task run status changedstatusDone 40 | EmailTask '$n': $e 41 | 42 | After the event $e, 43 | the following condition was met: $c 44 | 45 | This email escalation is configured to attach report format '$r'. 46 | Full details and other report formats are available on the scan engine. 47 | 48 | $t 49 | 50 | Note: 51 | This email was sent to you as a configured security scan escalation. 52 | Please contact your local system administrator if you think you 53 | should not have received it. 54 | message2noticesender@test.comfrom_address[OpenVAS-Manager] Tasksubjectc402cc3e-b531-11e1-9163-406186ea4fc5notice_attach_formatrecipient@test.comto_address 55 | 1 56 | 57 | 58 | name=test_alert first=1 rows=100 sort=name 59 | 60 | 61 | name 62 | = 63 | test_alert 64 | 65 | 66 | first 67 | = 68 | 1 69 | 70 | 71 | rows 72 | = 73 | 100 74 | 75 | 76 | sort 77 | = 78 | name 79 | 80 | 81 | 82 | 83 | nameascending 84 | 85 | 86 | 1311 87 | 88 | -------------------------------------------------------------------------------- /tests/scripts/get_scan_configs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | Base 25 | Basic configuration template with a minimum set of NVTs required for a scan. Version 20200827. 26 | 2020-02-26T23:52:51Z 27 | 2020-12-02T04:09:50Z 28 | 29 | 30 | Discovery 31 | Network Discovery scan configuration. Version 20200827. 32 | 2019-09-05T12:25:40Z 33 | 2020-12-02T04:09:55Z 34 | 35 | 36 | empty 37 | Empty and static configuration template. Version 20200827. 38 | 2019-09-05T12:25:40Z 39 | 2020-12-02T04:09:56Z 40 | 41 | 42 | EulerOS Linux Security Configuration 43 | Check compliance status of EulerOS installation against above named Policy as distributed by Huawei. Version 20200910. 44 | 2020-09-28T09:50:58Z 45 | 2020-12-02T04:09:59Z 46 | 47 | 48 | Full and fast 49 | Most NVT's; optimized by using previously collected information. Version 20200827. 50 | 2019-09-05T12:25:40Z 51 | 2020-12-02T04:09:55Z 52 | 53 | 54 | Full and fast ultimate 55 | Most NVT's including those that can stop services/hosts; optimized by using previously collected information. Version 20200827. 56 | 2019-09-05T12:25:40Z 57 | 2020-12-02T04:09:50Z 58 | 59 | 60 | Full and very deep 61 | Most NVT's; don't trust previously collected information; slow. Version 20200827. 62 | 2019-09-05T12:25:40Z 63 | 2020-12-02T04:09:56Z 64 | 65 | 66 | Full and very deep ultimate 67 | Most NVT's including those that can stop services/hosts; don't trust previously collected information; slow. Version 20200827. 68 | 2019-09-05T12:25:40Z 69 | 2020-12-02T04:09:56Z 70 | 71 | 72 | Host Discovery 73 | Network Host Discovery scan configuration. Version 20200827. 74 | 2019-09-05T12:25:40Z 75 | 2020-12-02T04:09:56Z 76 | 77 | 78 | System Discovery 79 | Network System Discovery scan configuration. Version 20200827. 80 | 2019-09-05T12:25:40Z 81 | 2020-12-02T04:09:55Z 82 | 83 | 84 | -------------------------------------------------------------------------------- /tests/scripts/invalid_xml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | 26 | jloechte 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/scripts/test_list_tasks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2020-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see 18 | 19 | 20 | import unittest 21 | from argparse import Namespace 22 | from pathlib import Path 23 | from unittest.mock import patch 24 | 25 | from gvmtools.helper import Table 26 | 27 | from . import GmpMockFactory, load_script 28 | 29 | CWD = Path(__file__).absolute().parent 30 | 31 | 32 | class ListTasksTestCase(unittest.TestCase): 33 | def setUp(self): 34 | self.list_tasks = load_script( 35 | (CWD.parent.parent / "scripts"), "list-tasks" 36 | ) 37 | 38 | @patch("gvm.protocols.latest.Gmp", new_callable=GmpMockFactory) 39 | @patch("builtins.print") 40 | def test_duration_with_timezone_offset( 41 | self, mock_print, mock_gmp: GmpMockFactory 42 | ): 43 | args = Namespace(script=["foo"]) 44 | 45 | mock_gmp.mock_response( 46 | "get_tasks", 47 | '' 48 | '' 49 | "Test" 50 | "4115" 51 | "" 52 | '' 53 | "2024-03-12T16:35:01-07:00" 54 | "2024-03-12T17:43:36-07:00" 55 | "" 56 | "" 57 | "" 58 | "", 59 | ) 60 | self.list_tasks.list_tasks(mock_gmp.gmp_protocol, args) 61 | 62 | table = mock_print.call_args[0][0] 63 | self.assertIsInstance(table, Table) 64 | self.assertEqual(len(table.rows), 1) 65 | self.assertEqual(table.rows[0][1], "Test") 66 | self.assertEqual(table.rows[0][7], "1.14") 67 | self.assertEqual(table.rows[0][8], "1.14") 68 | 69 | @patch("gvm.protocols.latest.Gmp", new_callable=GmpMockFactory) 70 | @patch("builtins.print") 71 | def test_duration_in_UTC(self, mock_print, mock_gmp: GmpMockFactory): 72 | args = Namespace(script=["foo"]) 73 | 74 | mock_gmp.mock_response( 75 | "get_tasks", 76 | '' 77 | '' 78 | "Test" 79 | "14444" 80 | "" 81 | '' 82 | "2024-09-27T14:30:01Z" 83 | "2024-09-27T18:30:45Z" 84 | "" 85 | "" 86 | "" 87 | "", 88 | ) 89 | self.list_tasks.list_tasks(mock_gmp.gmp_protocol, args) 90 | 91 | table = mock_print.call_args[0][0] 92 | self.assertIsInstance(table, Table) 93 | self.assertEqual(len(table.rows), 1) 94 | self.assertEqual(table.rows[0][1], "Test") 95 | self.assertEqual(table.rows[0][7], "4.01") 96 | self.assertEqual(table.rows[0][8], "4.01") 97 | 98 | @patch("gvm.protocols.latest.Gmp", new_callable=GmpMockFactory) 99 | @patch("builtins.print") 100 | def test_missing_last_report(self, mock_print, mock_gmp: GmpMockFactory): 101 | args = Namespace(script=["foo"]) 102 | 103 | mock_gmp.mock_response( 104 | "get_tasks", 105 | '' 106 | '' 107 | "Test" 108 | "0" 109 | "" 110 | "", 111 | ) 112 | self.list_tasks.list_tasks(mock_gmp.gmp_protocol, args) 113 | 114 | table = mock_print.call_args[0][0] 115 | self.assertIsInstance(table, Table) 116 | self.assertEqual(len(table.rows), 1) 117 | self.assertEqual(table.rows[0][1], "Test") 118 | self.assertEqual(table.rows[0][7], "0.00") 119 | self.assertEqual(table.rows[0][8], "") 120 | -------------------------------------------------------------------------------- /tests/scripts/test_send_schedules.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2020-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see 18 | 19 | 20 | import unittest 21 | from argparse import Namespace 22 | from pathlib import Path 23 | from unittest.mock import patch 24 | 25 | from lxml import etree 26 | 27 | from . import GmpMockFactory, load_script 28 | 29 | CWD = Path(__file__).absolute().parent 30 | 31 | 32 | class SendSchedulesTestCase(unittest.TestCase): 33 | def setUp(self): 34 | self.send_schedules = load_script( 35 | (CWD.parent.parent / "scripts"), "send-schedules" 36 | ) 37 | 38 | @patch("gvm.protocols.latest.Gmp", new_callable=GmpMockFactory) 39 | def test_sent_schedule(self, mock_gmp: GmpMockFactory): 40 | schedule_xml_path = CWD / "example_schedules.xml" 41 | schedule_xml_str = schedule_xml_path.read_text(encoding="utf-8") 42 | 43 | mock_gmp.mock_responses( 44 | "create_schedule", 45 | [ 46 | '', 48 | '', 50 | ], 51 | ) 52 | 53 | schedule = etree.XML(schedule_xml_str) 54 | 55 | self.send_schedules.parse_send_xml_tree(mock_gmp.gmp_protocol, schedule) 56 | 57 | @patch("gvm.protocols.latest.Gmp", new_callable=GmpMockFactory) 58 | def test_args(self, mock_gmp: GmpMockFactory): 59 | args = Namespace(script=["foo"]) 60 | with self.assertRaises(SystemExit): 61 | self.send_schedules.check_args(gmp=mock_gmp, args=args) 62 | 63 | args2 = Namespace(script=["foo", "bar", "baz"]) 64 | 65 | with self.assertRaises(SystemExit): 66 | self.send_schedules.check_args(gmp=mock_gmp, args=args2) 67 | -------------------------------------------------------------------------------- /tests/scripts/test_send_targets.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2020-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import unittest 20 | from argparse import Namespace 21 | from pathlib import Path 22 | from unittest.mock import patch 23 | 24 | from lxml import etree 25 | 26 | from . import GmpMockFactory, load_script 27 | 28 | CWD = Path(__file__).absolute().parent 29 | 30 | 31 | class SendTargetTestCase(unittest.TestCase): 32 | def setUp(self): 33 | self.send_targets = load_script( 34 | (CWD.parent.parent / "scripts"), "send-targets" 35 | ) 36 | 37 | @patch("gvm.protocols.latest.Gmp", new_callable=GmpMockFactory) 38 | def test_sent_target(self, mock_gmp: GmpMockFactory): 39 | target_xml_path = CWD / "example_target.xml" 40 | target_xml_str = target_xml_path.read_text(encoding="utf-8") 41 | 42 | mock_gmp.mock_response( 43 | "get_credentials", 44 | '' 45 | '' 46 | "" 47 | '' 48 | "" 49 | '' 50 | "" 51 | '' 52 | "" 53 | "", 54 | ) 55 | mock_gmp.mock_response( 56 | "create_target", 57 | '', 59 | ) 60 | 61 | target = etree.XML(target_xml_str) 62 | 63 | self.send_targets.parse_send_xml_tree(mock_gmp.gmp_protocol, target) 64 | 65 | @patch("builtins.input", lambda *args: "n") 66 | @patch("gvm.protocols.latest.Gmp", new_callable=GmpMockFactory) 67 | def test_sent_target_no_credential(self, mock_gmp: GmpMockFactory): 68 | target_xml_path = CWD / "example_target.xml" 69 | target_xml_str = target_xml_path.read_text(encoding="utf-8") 70 | 71 | mock_gmp.mock_response( 72 | "get_credentials", 73 | '' 74 | '' 75 | "" 76 | '' 77 | "" 78 | "", 79 | ) 80 | mock_gmp.mock_response( 81 | "create_target", 82 | '', 84 | ) 85 | 86 | target = etree.XML(target_xml_str) 87 | 88 | with self.assertRaises(SystemExit): 89 | self.send_targets.parse_send_xml_tree(mock_gmp.gmp_protocol, target) 90 | 91 | def test_args(self): 92 | args = Namespace(script=["foo"]) 93 | with self.assertRaises(SystemExit): 94 | self.send_targets.check_args(args) 95 | 96 | args2 = Namespace(script=["foo", "bar", "baz"]) 97 | 98 | with self.assertRaises(SystemExit): 99 | self.send_targets.check_args(args2) 100 | -------------------------------------------------------------------------------- /tests/scripts/test_send_tasks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2020-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see 18 | 19 | 20 | import unittest 21 | from pathlib import Path 22 | from unittest.mock import MagicMock, patch 23 | 24 | from lxml import etree 25 | 26 | from . import GmpMockFactory, load_script 27 | 28 | CWD = Path(__file__).absolute().parent 29 | 30 | 31 | class SendTasksTestCase(unittest.TestCase): 32 | def setUp(self): 33 | self.send_tasks = load_script( 34 | (CWD.parent.parent / "scripts"), "send-tasks" 35 | ) 36 | 37 | @patch("builtins.input", lambda *args: "y") 38 | @patch("gvm.protocols.latest.Gmp", new_callable=GmpMockFactory) 39 | def test_sent_task(self, mock_gmp: GmpMockFactory): 40 | task_xml_path = CWD / "example_task.xml" 41 | task_xml_str = task_xml_path.read_text(encoding="utf-8") 42 | 43 | self.send_tasks.numerical_option = MagicMock(return_value=1) 44 | 45 | configs_file = CWD / "get_scan_configs.xml" 46 | configs = configs_file.read_text(encoding="utf-8") 47 | mock_gmp.mock_response("get_scan_configs", configs) 48 | 49 | mock_gmp.mock_response( 50 | "get_scanners", 51 | '' 52 | '' 53 | "as" 54 | "" 55 | '' 56 | "CVE" 57 | "" 58 | '' 59 | "OpenVAS Default" 60 | "" 61 | "", 62 | ) 63 | 64 | mock_gmp.mock_response( 65 | "get_targets", 66 | '' 67 | '' 68 | "own" 69 | "" 70 | '' 71 | "Target for xn" 72 | "" 73 | '' 74 | "Unnamed" 75 | "" 76 | '' 77 | "work" 78 | "" 79 | '' 80 | "work2" 81 | "" 82 | "", 83 | ) 84 | 85 | mock_gmp.mock_response( 86 | "create_task", 87 | '', 89 | ) 90 | 91 | task = etree.XML(task_xml_str) 92 | 93 | tasks = self.send_tasks.parse_send_xml_tree(mock_gmp.gmp_protocol, task) 94 | self.assertEqual(tasks, ["c8ef0597-e2c1-4e23-869f-072fa2914bf2"]) 95 | -------------------------------------------------------------------------------- /tests/socket_help.3.10.snap: -------------------------------------------------------------------------------- 1 | usage: gvm-test-cli socket [-h] [--sockpath [SOCKETPATH] | --socketpath 2 | [SOCKETPATH]] 3 | 4 | options: 5 | -h, --help show this help message and exit 6 | --sockpath [SOCKETPATH] 7 | Deprecated, use --socketpath instead 8 | --socketpath [SOCKETPATH] 9 | Path to UNIX Domain socket (default: None) 10 | -------------------------------------------------------------------------------- /tests/socket_help.snap: -------------------------------------------------------------------------------- 1 | usage: gvm-test-cli socket [-h] [--sockpath [SOCKETPATH] | --socketpath 2 | [SOCKETPATH]] 3 | 4 | optional arguments: 5 | -h, --help show this help message and exit 6 | --sockpath [SOCKETPATH] 7 | Deprecated, use --socketpath instead 8 | --socketpath [SOCKETPATH] 9 | Path to UNIX Domain socket (default: None) 10 | -------------------------------------------------------------------------------- /tests/ssh_help.3.10.snap: -------------------------------------------------------------------------------- 1 | usage: gvm-test-cli ssh [-h] [--hostname HOSTNAME] [--port PORT] 2 | [--ssh-username SSH_USERNAME] 3 | [--ssh-password SSH_PASSWORD] [-A] 4 | 5 | options: 6 | -h, --help show this help message and exit 7 | --hostname HOSTNAME Hostname or IP address (default: 127.0.0.1) 8 | --port PORT SSH port (default: 22) 9 | --ssh-username SSH_USERNAME 10 | SSH username (default: 'gmp') 11 | --ssh-password SSH_PASSWORD 12 | SSH password (default: 'gmp') 13 | -A, --auto-accept-host 14 | When executed in e.g. CI, auto accept SSH host 15 | addition 16 | -------------------------------------------------------------------------------- /tests/ssh_help.snap: -------------------------------------------------------------------------------- 1 | usage: gvm-test-cli ssh [-h] [--hostname HOSTNAME] [--port PORT] 2 | [--ssh-username SSH_USERNAME] 3 | [--ssh-password SSH_PASSWORD] [-A] 4 | 5 | optional arguments: 6 | -h, --help show this help message and exit 7 | --hostname HOSTNAME Hostname or IP address (default: 127.0.0.1) 8 | --port PORT SSH port (default: 22) 9 | --ssh-username SSH_USERNAME 10 | SSH username (default: 'gmp') 11 | --ssh-password SSH_PASSWORD 12 | SSH password (default: 'gmp') 13 | -A, --auto-accept-host 14 | When executed in e.g. CI, auto accept SSH host 15 | addition 16 | -------------------------------------------------------------------------------- /tests/test.cfg: -------------------------------------------------------------------------------- 1 | [main] 2 | foo=bar 3 | timeout=1000 4 | username=ipsum 5 | 6 | [gmp] 7 | username=%(foo)s 8 | password=bar 9 | 10 | [unixsocket] 11 | socketpath=/foo/bar.sock 12 | 13 | [ssh] 14 | password=lorem 15 | port=123 16 | 17 | [tls] 18 | port=123 19 | certfile=foo.cert 20 | keyfile=foo.key 21 | cafile=foo.ca 22 | -------------------------------------------------------------------------------- /tests/test_auth.cfg: -------------------------------------------------------------------------------- 1 | [Auth] 2 | gmp_username=foo 3 | gmp_password=bar 4 | -------------------------------------------------------------------------------- /tests/test_config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # SPDX-FileCopyrightText: 2019-2024 Greenbone AG 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | import logging 19 | import unittest 20 | from pathlib import Path 21 | 22 | from gvm.connections import DEFAULT_GVM_PORT, DEFAULT_UNIX_SOCKET_PATH 23 | 24 | from gvmtools.config import DEFAULT_SSH_PORT, Config 25 | from gvmtools.config import __name__ as name 26 | 27 | __here__ = Path(__file__).parent.resolve() 28 | 29 | 30 | class ConfigTestCase(unittest.TestCase): 31 | def test_config_defaults(self): 32 | config = Config() 33 | 34 | self.assertEqual(config.get("gmp", "username"), "") 35 | self.assertEqual(config.get("gmp", "password"), "") 36 | 37 | self.assertEqual(config.get("ssh", "username"), "gmp") 38 | self.assertEqual(config.get("ssh", "password"), "gmp") 39 | self.assertEqual(config.get("ssh", "port"), DEFAULT_SSH_PORT) 40 | 41 | self.assertEqual( 42 | config.get("unixsocket", "socketpath"), DEFAULT_UNIX_SOCKET_PATH 43 | ) 44 | 45 | self.assertEqual(config.get("tls", "port"), DEFAULT_GVM_PORT) 46 | 47 | def test_get_unknown_setting(self): 48 | config = Config() 49 | self.assertIsNone(config.get("foo", "bar")) 50 | 51 | def test_load(self): 52 | test_config_path = __here__ / "test.cfg" 53 | 54 | self.assertTrue(test_config_path.is_file()) 55 | 56 | config = Config() 57 | config.load(test_config_path) 58 | 59 | self.assertEqual(config.get("gmp", "username"), "bar") 60 | self.assertEqual(config.get("gmp", "password"), "bar") 61 | 62 | self.assertEqual(config.get("ssh", "username"), "ipsum") 63 | self.assertEqual(config.get("ssh", "password"), "lorem") 64 | self.assertEqual(config.get("ssh", "port"), "123") 65 | 66 | self.assertEqual( 67 | config.get("unixsocket", "socketpath"), "/foo/bar.sock" 68 | ) 69 | 70 | self.assertEqual(config.get("tls", "port"), "123") 71 | self.assertEqual(config.get("tls", "certfile"), "foo.cert") 72 | self.assertEqual(config.get("tls", "keyfile"), "foo.key") 73 | self.assertEqual(config.get("tls", "cafile"), "foo.ca") 74 | 75 | self.assertDictEqual( 76 | config.defaults(), dict(timeout="1000", foo="bar", username="ipsum") 77 | ) 78 | 79 | def test_load_auth(self): 80 | root = logging.getLogger(name) 81 | root.disabled = True 82 | 83 | test_config_path = __here__ / "test_auth.cfg" 84 | 85 | self.assertTrue(test_config_path.is_file()) 86 | 87 | config = Config() 88 | config.load(test_config_path) 89 | 90 | self.assertEqual(config.get("gmp", "username"), "foo") 91 | self.assertEqual(config.get("gmp", "password"), "bar") 92 | 93 | root.disabled = False 94 | 95 | def test_load_with_non_existing_configfile(self): 96 | test_config_path = __here__ / "foo.cfg" 97 | 98 | self.assertFalse(test_config_path.is_file()) 99 | 100 | config = Config() 101 | 102 | with self.assertRaises(FileNotFoundError): 103 | config.load(test_config_path) 104 | -------------------------------------------------------------------------------- /tests/tls_help.3.10.snap: -------------------------------------------------------------------------------- 1 | usage: gvm-test-cli tls [-h] [--hostname HOSTNAME] [--port PORT] 2 | [--certfile CERTFILE] [--keyfile KEYFILE] 3 | [--cafile CAFILE] [--no-credentials] 4 | 5 | options: 6 | -h, --help show this help message and exit 7 | --hostname HOSTNAME Hostname or IP address (default: 127.0.0.1) 8 | --port PORT GMP/OSP port (default: 9390) 9 | --certfile CERTFILE Path to the certificate file for client authentication. 10 | (default: None) 11 | --keyfile KEYFILE Path to key file for client authentication. (default: 12 | None) 13 | --cafile CAFILE Path to CA certificate for server authentication. 14 | (default: None) 15 | --no-credentials Use only certificates for authentication 16 | -------------------------------------------------------------------------------- /tests/tls_help.snap: -------------------------------------------------------------------------------- 1 | usage: gvm-test-cli tls [-h] [--hostname HOSTNAME] [--port PORT] 2 | [--certfile CERTFILE] [--keyfile KEYFILE] 3 | [--cafile CAFILE] [--no-credentials] 4 | 5 | optional arguments: 6 | -h, --help show this help message and exit 7 | --hostname HOSTNAME Hostname or IP address (default: 127.0.0.1) 8 | --port PORT GMP/OSP port (default: 9390) 9 | --certfile CERTFILE Path to the certificate file for client authentication. 10 | (default: None) 11 | --keyfile KEYFILE Path to key file for client authentication. (default: 12 | None) 13 | --cafile CAFILE Path to CA certificate for server authentication. 14 | (default: None) 15 | --no-credentials Use only certificates for authentication 16 | --------------------------------------------------------------------------------