├── docs
├── __init__.py
├── api
│ ├── configuration.rst
│ ├── index.rst
│ ├── commands.rst
│ ├── clients.rst
│ ├── sessions.rst
│ └── beacons.rst
├── protobuf
│ ├── index.rst
│ ├── common_pb2.rst
│ ├── client_pb2.rst
│ └── sliver_pb2.rst
├── requirements.txt
├── install.rst
├── index.rst
├── Makefile
├── make.bat
├── conf.py
└── getting-started.rst
├── tests
├── __init__.py
├── data
│ ├── test_write.exe
│ ├── website.html
│ ├── website_update.html
│ └── test_write.v
├── test_interactive.py
└── test_client.py
├── src
└── sliver
│ ├── pb
│ ├── __init__.py
│ ├── rpcpb
│ │ ├── __init__.py
│ │ ├── services_pb2.pyi
│ │ └── services_pb2.py
│ ├── clientpb
│ │ ├── __init__.py
│ │ └── client_pb2.py
│ ├── commonpb
│ │ ├── __init__.py
│ │ ├── common_pb2.py
│ │ └── common_pb2.pyi
│ └── sliverpb
│ │ └── __init__.py
│ ├── protobuf.py
│ ├── __init__.py
│ ├── _protocols.py
│ ├── utils.py
│ ├── config.py
│ ├── session.py
│ ├── beacon.py
│ └── interactive.py
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
└── workflows
│ └── autorelease.yml
├── .gitmodules
├── Dockerfile
├── .readthedocs.yaml
├── pyproject.toml
├── .gitignore
├── SliverPy (9F68D30C) – Public.asc
├── scripts
├── protobufgen.py
└── sliver_install.sh
└── README.md
/docs/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/sliver/pb/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/sliver/pb/rpcpb/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/sliver/pb/clientpb/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/sliver/pb/commonpb/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/sliver/pb/sliverpb/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @moloch--
2 | * @daddycocoaman
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "sliver"]
2 | path = sliver
3 | url = https://github.com/BishopFox/sliver
4 |
--------------------------------------------------------------------------------
/tests/data/test_write.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moloch--/sliver-py/HEAD/tests/data/test_write.exe
--------------------------------------------------------------------------------
/src/sliver/protobuf.py:
--------------------------------------------------------------------------------
1 | from .pb.clientpb import client_pb2
2 | from .pb.commonpb import common_pb2
3 | from .pb.sliverpb import sliver_pb2
4 |
--------------------------------------------------------------------------------
/tests/data/website.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | SliverPy Test
4 |
5 |
6 | SliverPy Test
7 |
8 |
--------------------------------------------------------------------------------
/docs/api/configuration.rst:
--------------------------------------------------------------------------------
1 | Configuration
2 | =============
3 |
4 |
5 | .. autoclass:: sliver.config.SliverClientConfig
6 | :members:
7 | :undoc-members:
8 |
--------------------------------------------------------------------------------
/docs/protobuf/index.rst:
--------------------------------------------------------------------------------
1 | Protobuf
2 | ========
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 |
7 | common_pb2
8 | client_pb2
9 | sliver_pb2
10 |
--------------------------------------------------------------------------------
/tests/data/website_update.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | SliverPy Test
4 |
5 |
6 | SliverPy Test (UPDATED!)
7 |
8 |
--------------------------------------------------------------------------------
/docs/api/index.rst:
--------------------------------------------------------------------------------
1 | API
2 | ===
3 |
4 | .. toctree::
5 | :maxdepth: 3
6 |
7 | beacons
8 | clients
9 | commands
10 | configuration
11 | sessions
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | grpcio-tools~=1.47
2 | grpcio~=1.47
3 | sphinx-rtd-theme~=1.0.0
4 | sphinx~=5.1
5 | sphinx-autodoc-typehints~=1.19.4
6 | typing_extensions~=4.4.0; python_version < '3.8'
--------------------------------------------------------------------------------
/src/sliver/pb/rpcpb/services_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 | from google.protobuf.descriptor import (
6 | FileDescriptor,
7 | )
8 |
9 | DESCRIPTOR: FileDescriptor
10 |
--------------------------------------------------------------------------------
/tests/data/test_write.v:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | [callconv: stdcall]
4 | [export: Main]
5 | fn output() {
6 | mut output := os.open_file("test_write.txt", "w") or {return}
7 | output.write_string("Hello, DLL!") or {return}
8 | output.close()
9 | }
10 |
11 | fn main () {
12 | output()
13 | }
14 |
--------------------------------------------------------------------------------
/docs/api/commands.rst:
--------------------------------------------------------------------------------
1 | Commands
2 | ========
3 |
4 | This module contains the commands that can be used by interactive classes. Users should not need to implement this themselves, as the commands are called by `InteractiveBeacon` and `InteractiveSession`.
5 |
6 |
7 | BaseInteractiveCommands
8 | ^^^^^^^^^^^^^^^^^^^^^^^
9 |
10 | .. autoclass:: sliver.interactive.BaseInteractiveCommands
11 | :members:
12 | :undoc-members:
--------------------------------------------------------------------------------
/src/sliver/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from .beacon import InteractiveBeacon
4 | from .client import SliverClient
5 | from .config import SliverClientConfig
6 | from .protobuf import client_pb2, common_pb2, sliver_pb2
7 | from .session import InteractiveSession
8 |
9 | __version__ = "0.0.19"
10 |
11 |
12 | if os.getenv("HATCH_ENV_ACTIVE"):
13 | from rich import traceback
14 |
15 | traceback.install(show_locals=True)
16 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8-bullseye
2 |
3 | WORKDIR /sliver-py
4 | RUN apt-get update -y && apt-get upgrade -y && apt-get install curl -y
5 |
6 |
7 | # Configure hatch
8 | RUN python3 -m pip install --upgrade pip hatch
9 | RUN hatch config set dirs.env.virtual .venv && hatch config update
10 |
11 |
12 | # This is a little backwards than usual since we need the dynamic version for 'hatch env' so we copy everything
13 | COPY . .
14 | RUN hatch env create dev
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # Read the Docs configuration file
2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3 |
4 | # Required
5 | version: 2
6 |
7 | # Build documentation in the docs/ directory with Sphinx
8 | sphinx:
9 | configuration: docs/conf.py
10 |
11 | # Optionally build your docs in additional formats such as PDF and ePub
12 | formats: all
13 |
14 | python:
15 | version: "3.7"
16 | install:
17 | - requirements: docs/requirements.txt
18 | - method: pip
19 | path: .
20 |
--------------------------------------------------------------------------------
/docs/api/clients.rst:
--------------------------------------------------------------------------------
1 | Clients
2 | =======
3 |
4 | This module is used to connect to client gRPC APIs. Users should only need to use the `SliverClient` class. The `BaseClient` class is not intended to be directly but can be inherited by other Client classes.
5 |
6 |
7 | BaseClient
8 | ^^^^^^^^^^
9 |
10 | .. autoclass:: sliver.client.BaseClient
11 | :members:
12 | :undoc-members:
13 |
14 | SliverClient
15 | ^^^^^^^^^^^^
16 |
17 | .. autoclass:: sliver.SliverClient
18 | :members:
19 | :undoc-members:
20 | :show-inheritance:
21 |
22 |
--------------------------------------------------------------------------------
/docs/install.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | The easiest way to install SliverPy is using PyPI. SliverPy should work on any platform supported by `Python's gRPC library `_.
5 |
6 | .. code-block:: console
7 |
8 | $ python3 -m pip install sliver-py
9 |
10 |
11 | However, you can also manually install the package by downloading the `latest release from GitHub `_.
12 |
13 | .. code-block:: console
14 |
15 | $ python3 -m pip install ./sliver-py-VERSION.tar.gz
--------------------------------------------------------------------------------
/docs/api/sessions.rst:
--------------------------------------------------------------------------------
1 | Sessions
2 | ========
3 |
4 | This module is used to connect to session gRPC APIs. Users should only need to use the `InteractiveSession` class. The `BaseSession` class is not intended to be used directly but can be inherited by other Session classes.
5 |
6 | BaseSessions
7 | ^^^^^^^^^^^^
8 | .. autoclass:: sliver.session.BaseSession
9 | :members:
10 | :undoc-members:
11 |
12 | InteractiveSession
13 | ^^^^^^^^^^^^^^^^^^
14 |
15 | .. autoclass:: sliver.InteractiveSession
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
--------------------------------------------------------------------------------
/docs/api/beacons.rst:
--------------------------------------------------------------------------------
1 | Beacons
2 | =======
3 |
4 | This module is used to connect to beacon gRPC APIs. Users should only need to use the `InteractiveBeacon` class. The `BaseBeacon` class is not intended to be used directly but can be inherited by other Beacon classes.
5 |
6 |
7 | BaseBeacon
8 | ^^^^^^^^^^^^^^^^^^
9 |
10 | .. autoclass:: sliver.beacon.BaseBeacon
11 | :members:
12 | :undoc-members:
13 |
14 | InteractiveBeacon
15 | ^^^^^^^^^^^^^^^^^^
16 |
17 | .. autoclass:: sliver.InteractiveBeacon
18 | :members:
19 | :undoc-members:
20 | :show-inheritance:
21 |
22 |
--------------------------------------------------------------------------------
/docs/protobuf/common_pb2.rst:
--------------------------------------------------------------------------------
1 | Common Protobuf
2 | ===============
3 |
4 | This module contains the common Protobuf definitions, shared across both
5 | ``client_pb2`` and ``sliver_pb2``.
6 |
7 | .. autoclass:: sliver.pb.commonpb.common_pb2.EnvVar
8 | :members:
9 |
10 | .. autoclass:: sliver.pb.commonpb.common_pb2.Empty
11 | :members:
12 |
13 | .. autoclass:: sliver.pb.commonpb.common_pb2.File
14 | :members:
15 |
16 | .. autoclass:: sliver.pb.commonpb.common_pb2.Process
17 | :members:
18 |
19 | .. autoclass:: sliver.pb.commonpb.common_pb2.Request
20 | :members:
21 |
22 | .. autoclass:: sliver.pb.commonpb.common_pb2.Response
23 | :members:
24 |
25 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | Welcome to SliverPy's documentation!
2 | ====================================
3 |
4 | SliverPy is a Python gRPC client library for Sliver. SliverPy can be used to automate any operator interaction with Sliver_ and
5 | connects to servers using gRPC over Mutual TLS (i.e., multiplayer) using Sliver operator configuration files.
6 |
7 | .. _Sliver: https://github.com/BishopFox/sliver
8 |
9 | .. toctree::
10 | :maxdepth: 3
11 | :caption: Table of Contents
12 |
13 | install
14 | getting-started
15 |
16 | api/index
17 |
18 | protobuf/index
19 |
20 |
21 | Indices and tables
22 | ==================
23 |
24 | * :ref:`genindex`
25 | * :ref:`search`
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ""
5 | labels: ""
6 | assignees: ""
7 | ---
8 |
9 | **Is your feature request related to a problem? Please describe.**
10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11 |
12 | **Describe the solution you'd like**
13 | A clear and concise description of what you want to happen.
14 |
15 | **Describe alternatives you've considered**
16 | A clear and concise description of any alternative solutions or features you've considered.
17 |
18 | **Additional context**
19 | Add any other context or screenshots about the feature request here.
20 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ""
5 | labels: ""
6 | assignees: ""
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Command 1 '....'
17 | 3. Command 2 '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 |
28 | - OS: [e.g. MacOS]
29 | - Version [e.g. v0.0.5]
30 |
31 | **Additional context**
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/src/sliver/_protocols.py:
--------------------------------------------------------------------------------
1 | from .pb.commonpb.common_pb2 import Request
2 | from .pb.rpcpb.services_pb2_grpc import SliverRPCStub
3 |
4 | try:
5 | from typing import Protocol
6 | except ImportError:
7 | from typing_extensions import Protocol
8 |
9 |
10 | class PbWithRequestProp(Protocol): # type: ignore
11 | """Protocol for protobuf with Request field"""
12 |
13 | @property
14 | def Request(self) -> Request:
15 | ...
16 |
17 |
18 | class InteractiveObject(Protocol): # type: ignore
19 | """Protocol for objects with interactive methods"""
20 |
21 | @property
22 | def timeout(self) -> int:
23 | ...
24 |
25 | @property
26 | def _stub(self) -> SliverRPCStub:
27 | ...
28 |
29 | def _request(self, pb: PbWithRequestProp) -> PbWithRequestProp:
30 | ...
31 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/.github/workflows/autorelease.yml:
--------------------------------------------------------------------------------
1 | name: SliverPy
2 | on:
3 | push:
4 | tags: v[0-9]+.[0-9]+.[0-9]+
5 | branches: master
6 |
7 | jobs:
8 |
9 | build:
10 | name: Build
11 | runs-on: ubuntu-latest
12 | if: startsWith( github.ref, 'refs/tags/v')
13 | timeout-minutes: 45
14 |
15 | steps:
16 |
17 | - id: install-secret-key
18 | name: GPG Secret Key(s)
19 | run: |
20 | cat <(echo -e "${{ secrets.SLIVERPY_GPG }}") | gpg --batch --import
21 | gpg --list-secret-keys --keyid-format LONG
22 |
23 | - uses: actions/setup-python@v2
24 | with:
25 | python-version: '3.x'
26 | architecture: 'x64'
27 |
28 | - name: Python Setup
29 | run: python3 -m pip install --upgrade build twine hatch
30 |
31 | - name: Check Out Code
32 | uses: actions/checkout@v2
33 |
34 | - name: Git Fetch Tags
35 | run: git fetch --prune --unshallow --tags -f
36 |
37 | - name: Package
38 | run: hatch build
39 |
40 | - name: Github Release
41 | uses: "marvinpinto/action-automatic-releases@latest"
42 | with:
43 | repo_token: "${{ secrets.GITHUB_TOKEN }}"
44 | prerelease: false
45 | files: |
46 | ./dist/*
47 |
48 | - name: PyPI Upload
49 | env:
50 | TWINE_NON_INTERACTIVE: 1
51 | TWINE_USERNAME: __token__
52 | TWINE_PASSWORD: "${{ secrets.TWINE_PASSWORD }}"
53 | run: python3 -m twine upload --sign --identity 9F68D30C -r pypi dist/*
54 |
--------------------------------------------------------------------------------
/src/sliver/utils.py:
--------------------------------------------------------------------------------
1 | import functools
2 | import inspect
3 | import logging
4 | import os
5 |
6 |
7 | def inspect_debug(obj):
8 | # If we are in dev environment and the result is a class, inspect the class
9 | if os.getenv("HATCH_ENV_ACTIVE"):
10 | from rich import inspect as rinspect
11 |
12 | rinspect(obj)
13 |
14 |
15 | def log_return(level: str):
16 | """Logs return value of function or coroutine at level specified"""
17 |
18 | def is_async(func):
19 | """Determine if function or generator is async"""
20 | return (
21 | inspect.iscoroutinefunction(func)
22 | or inspect.isasyncgenfunction(func)
23 | or inspect.isasyncgen(func)
24 | or inspect.iscoroutine(func)
25 | )
26 |
27 | def decorator(func):
28 | @functools.wraps(func)
29 | async def wrapper(*args, **kwargs):
30 | result = None
31 | if is_async(func):
32 | result = await func(*args, **kwargs)
33 | else:
34 | result = func(*args, **kwargs)
35 | logging.log(
36 | logging.getLevelName(level.upper()),
37 | f"{func.__qualname__} returned:\n{result}",
38 | )
39 |
40 | # If we are in dev environment and the result is a class, inspect the class
41 | inspect_debug(result)
42 |
43 | return result
44 |
45 | return wrapper
46 |
47 | return decorator
48 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["hatchling>=1.8.0"]
3 | build-backend = "hatchling.build"
4 |
5 | [project]
6 | name = "sliver-py"
7 | description = "Sliver gRPC client library."
8 | readme = "README.md"
9 | license-files = { paths = ["LICENSE"] }
10 | requires-python = ">=3.7"
11 | authors = [
12 | { name = "moloch", email = "875022+moloch--@users.noreply.github.com" },
13 | { name = "daddycocoaman", email = "daddycocoaman@gmail.com"}
14 | ]
15 | classifiers = [
16 | "Programming Language :: Python :: 3.7",
17 | "Programming Language :: Python :: 3.8",
18 | "Programming Language :: Python :: 3.9",
19 | "Programming Language :: Python :: 3.10",
20 | ]
21 | dependencies = [
22 | "grpcio~=1.47",
23 | "grpcio-tools~=1.47",
24 | "mypy-protobuf~=3.3.0",
25 | "typing_extensions~=4.4.0; python_version < '3.8'",
26 | ]
27 | dynamic = ["version"]
28 |
29 | [project.urls]
30 | "Bug Tracker" = "https://github.com/moloch--/sliver-py/issues"
31 | Homepage = "https://github.com/moloch--/sliver-py"
32 |
33 |
34 | [tool.hatch.envs.dev]
35 | extra-dependencies = [
36 | "rich~=12.5",
37 | "black~=22.6",
38 | "isort~=5.10",
39 | "ward~=0.66.1b0",
40 | "sphinx~=5.1",
41 | "sphinx-rtd-theme~=1.0.0",
42 | "sphinx-autodoc-typehints~=1.19.4",
43 | ]
44 |
45 | [tool.hatch.envs.dev.scripts]
46 | fmt = [
47 | "isort src",
48 | "black src",
49 | ]
50 |
51 | [tool.hatch.version]
52 | path = "src/sliver/__init__.py"
53 |
54 | [tool.hatch.build]
55 | packages = ["src/sliver"]
56 |
57 | [tool.black]
58 | include = "^/src"
59 | extend-exclude = "^/src/silver/pb"
60 |
61 | [tool.isort]
62 | profile = "black"
63 |
--------------------------------------------------------------------------------
/src/sliver/pb/commonpb/common_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: commonpb/common.proto
4 | """Generated protocol buffer code."""
5 | from google.protobuf import descriptor as _descriptor
6 | from google.protobuf import descriptor_pool as _descriptor_pool
7 | from google.protobuf import symbol_database as _symbol_database
8 | from google.protobuf.internal import builder as _builder
9 |
10 | # @@protoc_insertion_point(imports)
11 |
12 | _sym_db = _symbol_database.Default()
13 |
14 |
15 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
16 | b'\n\x15\x63ommonpb/common.proto\x12\x08\x63ommonpb"\x07\n\x05\x45mpty"N\n\x07Request\x12\r\n\x05\x41sync\x18\x01 \x01(\x08\x12\x0f\n\x07Timeout\x18\x02 \x01(\x03\x12\x10\n\x08\x42\x65\x61\x63onID\x18\x08 \x01(\t\x12\x11\n\tSessionID\x18\t \x01(\t"H\n\x08Response\x12\x0b\n\x03\x45rr\x18\x01 \x01(\t\x12\r\n\x05\x41sync\x18\x02 \x01(\x08\x12\x10\n\x08\x42\x65\x61\x63onID\x18\x08 \x01(\t\x12\x0e\n\x06TaskID\x18\t \x01(\t""\n\x04\x46ile\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12\x0c\n\x04\x44\x61ta\x18\x02 \x01(\x0c"\x81\x01\n\x07Process\x12\x0b\n\x03Pid\x18\x01 \x01(\x05\x12\x0c\n\x04Ppid\x18\x02 \x01(\x05\x12\x12\n\nExecutable\x18\x03 \x01(\t\x12\r\n\x05Owner\x18\x04 \x01(\t\x12\x14\n\x0c\x41rchitecture\x18\x07 \x01(\t\x12\x11\n\tSessionID\x18\x05 \x01(\x05\x12\x0f\n\x07\x43mdLine\x18\x06 \x03(\t"$\n\x06\x45nvVar\x12\x0b\n\x03Key\x18\x01 \x01(\t\x12\r\n\x05Value\x18\x02 \x01(\tB/Z-github.com/bishopfox/sliver/protobuf/commonpbb\x06proto3'
17 | )
18 |
19 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
20 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "commonpb.common_pb2", globals())
21 | if _descriptor._USE_C_DESCRIPTORS == False:
22 |
23 | DESCRIPTOR._options = None
24 | DESCRIPTOR._serialized_options = b"Z-github.com/bishopfox/sliver/protobuf/commonpb"
25 | _EMPTY._serialized_start = 35
26 | _EMPTY._serialized_end = 42
27 | _REQUEST._serialized_start = 44
28 | _REQUEST._serialized_end = 122
29 | _RESPONSE._serialized_start = 124
30 | _RESPONSE._serialized_end = 196
31 | _FILE._serialized_start = 198
32 | _FILE._serialized_end = 232
33 | _PROCESS._serialized_start = 235
34 | _PROCESS._serialized_end = 364
35 | _ENVVAR._serialized_start = 366
36 | _ENVVAR._serialized_end = 402
37 | # @@protoc_insertion_point(module_scope)
38 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 | import os
13 | import sys
14 | from subprocess import PIPE, Popen
15 |
16 | DOCS = os.path.dirname(os.path.abspath(__file__))
17 | sys.path.insert(0, os.path.abspath(os.path.join(DOCS, "..", "src")))
18 |
19 | # -- Project information -----------------------------------------------------
20 | # VERSION = Popen(['git', 'describe', '--abbrev=0'], stdout=PIPE).communicate()[0].decode('utf-8').strip()
21 | # AUTHOR = 'moloch'
22 |
23 | project = "SliverPy"
24 | copyright = "2022, moloch"
25 | author = "moloch"
26 | release = "0.0.17"
27 |
28 | # -- General configuration ---------------------------------------------------
29 |
30 | # Add any Sphinx extension module names here, as strings. They can be
31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
32 | # ones.
33 | extensions = [
34 | "sphinx.ext.autodoc",
35 | "sphinx.ext.autosectionlabel",
36 | "sphinx.ext.intersphinx",
37 | "sphinx.ext.viewcode",
38 | "sphinx_autodoc_typehints",
39 | ]
40 |
41 | autodoc_default_options = {
42 | "members": True,
43 | "special-members": False,
44 | "undoc-members": True,
45 | "exclude-members": "__weakref__, DESCRIPTOR",
46 | }
47 |
48 | # Add any paths that contain templates here, relative to this directory.
49 | templates_path = ["_templates"]
50 | #
51 | # List of patterns, relative to source directory, that match files and
52 | # directories to ignore when looking for source files.
53 | # This pattern also affects html_static_path and html_extra_path.
54 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
55 | autodoc_typehints_description_target = "documented"
56 | # -- Options for HTML output -------------------------------------------------
57 |
58 | # The theme to use for HTML and HTML Help pages. See the documentation for
59 | # a list of builtin themes.
60 | #
61 | html_theme = "sphinx_rtd_theme"
62 | html_theme_options = {
63 | "collapse_navigation": False,
64 | "sticky_navigation": True,
65 | }
66 | # Add any paths that contain custom static files (such as style sheets) here,
67 | # relative to this directory. They are copied after the builtin static files,
68 | # so a file named "default.css" will overwrite the builtin "default.css".
69 | html_static_path = ["_static"]
70 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.vscode
2 | /src/test*.py
3 | /workdir
4 |
5 | # Byte-compiled / optimized / DLL files
6 | __pycache__/
7 | *.py[cod]
8 | *$py.class
9 |
10 | # C extensions
11 | *.so
12 |
13 | # Distribution / packaging
14 | .Python
15 | build/
16 | develop-eggs/
17 | dist/
18 | downloads/
19 | eggs/
20 | .eggs/
21 | lib/
22 | lib64/
23 | parts/
24 | sdist/
25 | var/
26 | wheels/
27 | share/python-wheels/
28 | *.egg-info/
29 | .installed.cfg
30 | *.egg
31 | MANIFEST
32 |
33 | # PyInstaller
34 | # Usually these files are written by a python script from a template
35 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
36 | *.manifest
37 | *.spec
38 |
39 | # Installer logs
40 | pip-log.txt
41 | pip-delete-this-directory.txt
42 |
43 | # Unit test / coverage reports
44 | htmlcov/
45 | .tox/
46 | .nox/
47 | .coverage
48 | .coverage.*
49 | .cache
50 | nosetests.xml
51 | coverage.xml
52 | *.cover
53 | *.py,cover
54 | .hypothesis/
55 | .pytest_cache/
56 | cover/
57 |
58 | # Translations
59 | *.mo
60 | *.pot
61 |
62 | # Django stuff:
63 | *.log
64 | local_settings.py
65 | db.sqlite3
66 | db.sqlite3-journal
67 |
68 | # Flask stuff:
69 | instance/
70 | .webassets-cache
71 |
72 | # Scrapy stuff:
73 | .scrapy
74 |
75 | # Sphinx documentation
76 | docs/_build/
77 |
78 | # PyBuilder
79 | .pybuilder/
80 | target/
81 |
82 | # Jupyter Notebook
83 | .ipynb_checkpoints
84 |
85 | # IPython
86 | profile_default/
87 | ipython_config.py
88 |
89 | # pyenv
90 | # For a library or package, you might want to ignore these files since the code is
91 | # intended to run in multiple environments; otherwise, check them in:
92 | # .python-version
93 |
94 | # pipenv
95 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
96 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
97 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
98 | # install all needed dependencies.
99 | #Pipfile.lock
100 |
101 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
102 | __pypackages__/
103 |
104 | # Celery stuff
105 | celerybeat-schedule
106 | celerybeat.pid
107 |
108 | # SageMath parsed files
109 | *.sage.py
110 |
111 | # Environments
112 | .env
113 | .venv
114 | env/
115 | venv/
116 | ENV/
117 | env.bak/
118 | venv.bak/
119 |
120 | # Spyder project settings
121 | .spyderproject
122 | .spyproject
123 |
124 | # Rope project settings
125 | .ropeproject
126 |
127 | # mkdocs documentation
128 | /site
129 |
130 | # mypy
131 | .mypy_cache/
132 | .dmypy.json
133 | dmypy.json
134 |
135 | # Pyre type checker
136 | .pyre/
137 |
138 | # pytype static type analyzer
139 | .pytype/
140 |
141 | # Cython debug symbols
142 | cython_debug/
143 |
--------------------------------------------------------------------------------
/SliverPy (9F68D30C) – Public.asc:
--------------------------------------------------------------------------------
1 | -----BEGIN PGP PUBLIC KEY BLOCK-----
2 |
3 | mQINBGBxl9gBEAC/ZoVCd8JItNODnHV81+kN13/M3290CRVWuX4hmU7sdHm4xMO4
4 | tV7mzY09pipVk8V9DfjrnSDV43Gn7Hizs8GO8K0SnPRs0pPl1RjNo+Mbto3ivR6a
5 | BFr48PimLbJMTL3PqBHYaqCk8NrhqLdQfnBEt9Vjnwko5lvSTVcy8GdIIILulBdl
6 | gJ647jun0O7jBvOWz1Rfm634tvlikA+8Pyim4WUwCRZcTWrgkw9ddTtFw+cA89sc
7 | FimasEsfg/5YKjnRRI7ePgfL5pk78yrisqh+IsLKD1AvQp+h+nnGUlJUrlbdk7Es
8 | 2l0zqXhRq/AlaPyi8nw1TX5HKh0kPkrYKUNjL03TLYze2ve0PnEd2jWq++4BT2W1
9 | 2KApED9ut+V1YRVKW/deKBSfVKHEV8uNby0tpkDlQLW0iftfogKjKVGZlVIKMSZE
10 | WO7CA6iPIXkAqzN+4s5VZoTu7aU+I7IzpSpjAC67Dno4WPCFM2umD3YnWLNLvYFi
11 | 8fpkjFMhE2iaTGQVsCJxQUpwig/y8/eWaFUzHzdCSFLRN0Gv+jtHe0nf36jSDH9y
12 | 99Zh7nxJTA14nv5cEoHtea0b5EyY0pr+vpqsOez4JYG6ZZjqBjyEah1IiIuWls4X
13 | G2ETyGyHJdnnU5KDVieUVFHNL67LJl/ZHCb0Qm23fHe5ucQ6Pp7G5/qtlwARAQAB
14 | tCdTbGl2ZXJQeSA8am9lZGVtZXN5K3NsaXZlcnB5QGdtYWlsLmNvbT6JAk4EEwEI
15 | ADgWIQRurccEsYIQiG/s38tmjDZgn2jTDAUCYHGX2AIbAwULCQgHAgYVCgkICwIE
16 | FgIDAQIeAQIXgAAKCRBmjDZgn2jTDGOrEAC56Y/lj8gfImbyeDF2zS2iwNFM+BBK
17 | 3bJWddgY071f43M0CnRvHv26y7XE0DUs6DLdN7Sz+l9ASluTOjSMsvAYq/sHoeHP
18 | g3fjlQYQTedE83amIGD+hSpDJrxT4Oc09UjALrTFL723+5Ci41k1S70MNzJ/HlKf
19 | GAVOF8Rlacp9FGBzo/9GcwzrlafPpdaiEZ6Z2wCB2IgvV6zhuPPnDwjMTylcrYql
20 | jkAR4F6WWBR32RUlMj6KRiSOm+okJhtLzqTbXeExBZs6p6B0gBu0XN2t5DAygdTr
21 | cV93wnnTHn2XcBu4B0wOmHgEvfX8TOdf987Uord/LBcIMao6ih682/nqmSGMUCaX
22 | dsSsmqEG4/UfOZUS2LapoJrVECyViYpPfngR5lYizlnAxMoJ8J4gAk9n1UlluyXf
23 | pk6yKgwFXxUfQjWGmKgaz0kfv8T7qd+lUymL7vhtSa5PFxCfyTKtohrnEMsmcA0C
24 | Q2ibN+GYxWJXTkH8S3Fci2aCXJHijJm+X7QgVKfwbge7AFjPLm58/33LDep8M3V3
25 | FWpGXxOjKYnnMB6bzBORXwelzbl219gObW0Sq8VsUSpDJkHmwimZRoH0WZIPep3+
26 | ssuhfNJqGPmGWH9fwdnD27LhMpmW2CyNbSGUsUsIjbj6ZehqmdKvV5vZmN7KliE3
27 | NhdkKV+CSflS47kCDQRgcZfYARAAtTmgakxN2X9PHCb2rInHQE9GxY+o5ZrwZn20
28 | 0o2LRvfe6gJ2Npi3j1VBuM5ZxvS45m2L9WR22RYI6I69FEDNb2XfH2uvHOpFpQC1
29 | pf8eA0EOkvfiUvmoTcAh5p70PAje/YGxqK+FbZJZ8n9i0XA+v6bIAsrf0tXHX5x0
30 | Pj23oXCRwrymocfzD3Sl3733Kg54kWuuH9tJn0R1/TdeIfxlbTBE7CahRIU4fvd4
31 | ejbni6AgiowyfJRGeYG6uySl+jNDQL7NiLAJkkNe+Bx0E/u18aEjmE5IZR4zprFr
32 | bvmVbIJ178aJZwzhF9mA6DEvF/nL0vTfQ+OJkKWpFUqfP1bdQrI0tSPQ3eKEc/x4
33 | 9oWCL2bjchRl5y1P+utvZAo8Jieqjlno0UD5D+FuZpBE8aQ5eUmJUFudvaEFurJV
34 | MsJYgGu3ZqbnAjZLw3nIOTzTi5XfbFjuBQWMCsSyx7UOzP8rQxcAo1cxJiTqiTr5
35 | CUe5juqZSf5yLNNr+NSKlA5MuanbqGxZwko2EGiinWJ8JnmJY2KCzKCp4U1jX4Uk
36 | OnqUd+Qn4BqvL2rlXxY3TTA+LunhxP9waqRuLnaGSBcL257jmpWt3+zK9uQkT4K0
37 | moSxv/9xLS5xLv7xSxEF8X0FCN6eEOFy+yzKNQDyskPH+OIuqapsJQK4MYV67vok
38 | AjDrzJ8AEQEAAYkCNgQYAQgAIBYhBG6txwSxghCIb+zfy2aMNmCfaNMMBQJgcZfY
39 | AhsMAAoJEGaMNmCfaNMMb5cP/3uYTTWL4/77XDWaqKLQ/s3gCLEFGfB8e+bbXCZw
40 | 5raqQvTkVHcww/4f9Crrtz0uSKFZHB7zZ71HaPTJaYuI7k5JzzibwriH+Z8ZJsKG
41 | CE5PSYKNMVJ/rikG88t925l9gk23srLQtm1PiCR9YFF60YVI/4Lg/AOdzHJH4CLu
42 | RFRyvs0HNqYsCDfxSZC6VHCxsipB+gjY/N3Cejy5PuBGbn3GqfnHMUEQfoysYpNh
43 | w9sUMsgCRua3QmdaZpNv9g+VaD13tVy5smVYFGulrV2S9nEt8/WG7WC2yNHDFKCN
44 | ZLcsB+2HIMocaD7HM72tItjeYmOOKXwlYUFhV4BAy95fQg46Qnm/JRkGMRDLof0n
45 | zAIeAETMa40r7Lzyk8Z/ZqQhVcY70yB8njgBPVaEHMok2wgNfWffCN/m5xLo2mKm
46 | 58XYrV41TMCT/v/1wxEylPdfHh07mCk6hCpATrOvKHNpvTnwoF2YT3oB5PRrPv8T
47 | Ecn7iLpS5ae+6ZUyJwpo7HJoXgdzGNi0mtGadSrqqfPnJQzPlN5BuVRpwDuIcAK5
48 | ksAw0YYAexplZUBSjNr8x4UBzeBTbk2vvjOufMvaOC7QYZZ8D67i447SmqtlBkiY
49 | rG9Yc3Rettho4JLwrQFysYf1oVUETSUsdeAXo1zpP/ragu1WXQcmDCZ8e0YPzQFz
50 | 8b2Q
51 | =bZks
52 | -----END PGP PUBLIC KEY BLOCK-----
53 |
--------------------------------------------------------------------------------
/src/sliver/config.py:
--------------------------------------------------------------------------------
1 | """
2 | Sliver Implant Framework
3 | Copyright (C) 2021 Bishop Fox
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 | """
16 | from __future__ import annotations
17 |
18 | import json
19 | import os
20 | from typing import Type, Union
21 |
22 |
23 | class SliverClientConfig(object):
24 | """
25 | This class parses and represents Sliver operator configuration files, typically this class is automatically
26 | instantiated using one of the class methods :class:`SliverClientConfig.parse_config()` or :class:`SliverClientConfig.parse_config_file()` but can be directly
27 | instantiated too.
28 |
29 | :param operator: Operator name, note that this value is only used by the client and is ignored by the server.
30 | :param lhost: The listener host to connect to (i.e., the Sliver server host).
31 | :param lhost: The TCP port of the host listener (i.e., the TCP port of the Sliver "multiplayer" service).
32 | :param ca_certificate: The Sliver server certificate authority.
33 | :param certificate: The mTLS client certificate.
34 | :param private_key: The mTLS private key.
35 | :param token: The user's authentication token.
36 |
37 | :raises ValueError: A parameter contained an invalid value.
38 | """
39 |
40 | def __init__(
41 | self,
42 | operator: str,
43 | lhost: str,
44 | lport: int,
45 | ca_certificate: str,
46 | certificate: str,
47 | private_key: str,
48 | token: str,
49 | ):
50 | self.operator = operator
51 | self.lhost = lhost
52 | if not 0 < lport < 65535:
53 | raise ValueError("Invalid lport %d" % lport)
54 | self.lport = lport
55 | self.ca_certificate = ca_certificate
56 | self.certificate = certificate
57 | self.private_key = private_key
58 | self.token = token
59 |
60 | def __str__(self):
61 | return "%s@%s%d" % (
62 | self.operator,
63 | self.lhost,
64 | self.lport,
65 | )
66 |
67 | def __repr__(self):
68 | return "" % (
69 | self.operator,
70 | self.lhost,
71 | self.lport,
72 | self.ca_certificate,
73 | self.certificate,
74 | )
75 |
76 | @classmethod
77 | def parse_config(cls, data: Union[str, bytes]) -> SliverClientConfig:
78 | """Parses the content of a Sliver operator configuration file and
79 | returns the instantiated :class:`SliverClientConfig`
80 |
81 | :param data: The Sliver operator configuration file content.
82 | :type data: Union[str, bytes]
83 | :return: An instantiated :class:`SliverClientConfig` object.
84 | :rtype: SliverClientConfig
85 | """
86 | return cls(**json.loads(data))
87 |
88 | @classmethod
89 | def parse_config_file(cls, filepath: os.PathLike[str]) -> SliverClientConfig:
90 | """Parse a given file path as a Sliver operator configuration file.
91 |
92 | :param filepath: File system path to an operator configuration file.
93 | :type filepath: str
94 | :return: An instantiated :class:`SliverClientConfig` object.
95 | :rtype: SliverClientConfig
96 | """
97 | with open(filepath, "r") as fp:
98 | data = fp.read()
99 | return cls.parse_config(data)
100 |
--------------------------------------------------------------------------------
/tests/test_interactive.py:
--------------------------------------------------------------------------------
1 | from ward import fixture, test
2 |
3 | from sliver import SliverClient
4 | from sliver.session import InteractiveSession
5 |
6 | from .test_client import sliver_client, sliverpy_random_name
7 |
8 |
9 | @fixture(scope="module")
10 | async def session_zero(client: SliverClient = sliver_client) -> InteractiveSession: # type: ignore
11 | sessions = await client.sessions()
12 | return await client.interact_session(sessions[0].ID) # type: ignore
13 |
14 |
15 | @test("InteractiveObject can send ping to server", tags=["interactive"])
16 | async def _(session: InteractiveSession = session_zero): # type: ignore
17 | assert await session.ping()
18 |
19 |
20 | @test("InteractiveObject can list processes", tags=["interactive"])
21 | async def _(session: InteractiveSession = session_zero): # type: ignore
22 | assert await session.ps()
23 |
24 |
25 | @test("InteractiveObject can get network interfaces", tags=["interactive"])
26 | async def _(session: InteractiveSession = session_zero): # type: ignore
27 | assert await session.ifconfig()
28 |
29 |
30 | @test("InteractiveObject can get network connections", tags=["interactive"])
31 | async def _(session: InteractiveSession = session_zero): # type: ignore
32 | assert await session.netstat(True, True, True, True, True)
33 |
34 |
35 | @test("InteractiveObject can get working directory", tags=["interactive"])
36 | async def _(session: InteractiveSession = session_zero): # type: ignore
37 | assert await session.pwd()
38 |
39 |
40 | @test("InteractiveObject can list directory", tags=["interactive"])
41 | async def _(session: InteractiveSession = session_zero): # type: ignore
42 | assert await session.ls()
43 |
44 |
45 | @test("InteractiveObject can change directory", tags=["interactive"])
46 | async def _(session: InteractiveSession = session_zero): # type: ignore
47 | assert await session.cd(".")
48 |
49 |
50 | @test("InteractiveObject can make a directory", tags=["interactive"])
51 | async def _(
52 | session: InteractiveSession = session_zero, target_dir: str = sliverpy_random_name # type: ignore
53 | ):
54 | assert await session.mkdir(target_dir)
55 |
56 |
57 | @test("InteractiveObject can upload a file", tags=["interactive"])
58 | async def _(
59 | session: InteractiveSession = session_zero, # type: ignore
60 | target_dir: str = sliverpy_random_name, # type: ignore
61 | ):
62 | assert await session.upload(target_dir + "/sliverpy.txt", b"sliverpy")
63 |
64 |
65 | @test("InteractiveObject can download files", tags=["interactive"])
66 | async def _(
67 | session: InteractiveSession = session_zero, # type: ignore
68 | target_dir: str = sliverpy_random_name, # type: ignore
69 | ):
70 | assert await session.download(target_dir, True)
71 |
72 |
73 | @test("InteractiveObject can remove a directory", tags=["interactive"])
74 | async def _(
75 | session: InteractiveSession = session_zero, path: str = sliverpy_random_name # type: ignore
76 | ):
77 | assert await session.rm(path, recursive=True, force=True)
78 |
79 |
80 | @test("InteractiveObject can set an environment variable", tags=["interactive"])
81 | async def _(
82 | session: InteractiveSession = session_zero, value: str = sliverpy_random_name # type: ignore
83 | ):
84 | assert await session.set_env("SLIVERPY_TEST", value)
85 |
86 |
87 | @test("InteractiveObject can get an environment variable", tags=["interactive"])
88 | async def _(
89 | session: InteractiveSession = session_zero, value: str = sliverpy_random_name # type: ignore
90 | ):
91 | assert await session.get_env(value)
92 |
93 |
94 | @test("InteractiveObject can unset an environment variable", tags=["interactive"])
95 | async def _(
96 | session: InteractiveSession = session_zero, value: str = sliverpy_random_name # type: ignore
97 | ):
98 | assert await session.unset_env(value)
99 |
100 |
101 | @test("InteractiveObject can take a screenshot", tags=["interactive"])
102 | async def _(session: InteractiveSession = session_zero): # type: ignore
103 | assert await session.screenshot()
104 |
105 |
106 | @test("InteractiveObject can take a memory dump", tags=["interactive"])
107 | async def _(session: InteractiveSession = session_zero): # type: ignore
108 | procs = await session.ps()
109 | found_process = False
110 | for proc in procs[::-1]:
111 | if proc.Owner == session.username:
112 | dump = await session.process_dump(proc.Pid)
113 | if len(dump.Data) > 0:
114 | found_process = True
115 | break
116 | assert found_process
117 |
--------------------------------------------------------------------------------
/src/sliver/pb/commonpb/common_pb2.pyi:
--------------------------------------------------------------------------------
1 | """
2 | @generated by mypy-protobuf. Do not edit manually!
3 | isort:skip_file
4 | """
5 | import sys
6 |
7 | if sys.version_info >= (3, 8):
8 | import typing as typing_extensions
9 | else:
10 | import typing_extensions
11 | from builtins import (
12 | bool,
13 | bytes,
14 | int,
15 | str,
16 | )
17 | from collections.abc import (
18 | Iterable,
19 | )
20 | from google.protobuf.descriptor import (
21 | Descriptor,
22 | FileDescriptor,
23 | )
24 | from google.protobuf.internal.containers import (
25 | RepeatedScalarFieldContainer,
26 | )
27 | from google.protobuf.message import (
28 | Message,
29 | )
30 |
31 | DESCRIPTOR: FileDescriptor
32 |
33 | class Empty(Message):
34 | """
35 | Generic protobuf messages
36 | """
37 |
38 | DESCRIPTOR: Descriptor
39 |
40 | def __init__(
41 | self,
42 | ) -> None: ...
43 |
44 | class Request(Message):
45 | """Request - Common fields used in all gRPC requests"""
46 |
47 | DESCRIPTOR: Descriptor
48 |
49 | ASYNC_FIELD_NUMBER: int
50 | TIMEOUT_FIELD_NUMBER: int
51 | BEACONID_FIELD_NUMBER: int
52 | SESSIONID_FIELD_NUMBER: int
53 | Async: bool
54 | Timeout: int
55 | BeaconID: str
56 | SessionID: str
57 | def __init__(
58 | self,
59 | *,
60 | Async: bool = ...,
61 | Timeout: int = ...,
62 | BeaconID: str = ...,
63 | SessionID: str = ...,
64 | ) -> None: ...
65 | def ClearField(
66 | self,
67 | field_name: typing_extensions.Literal[
68 | "Async",
69 | b"Async",
70 | "BeaconID",
71 | b"BeaconID",
72 | "SessionID",
73 | b"SessionID",
74 | "Timeout",
75 | b"Timeout",
76 | ],
77 | ) -> None: ...
78 |
79 | class Response(Message):
80 | """Response - Common fields used in all gRPC responses. Note that the Err field
81 | only used when the implant needs to return an error to the server.
82 | Client<->Server comms should use normal gRPC error handling.
83 | """
84 |
85 | DESCRIPTOR: Descriptor
86 |
87 | ERR_FIELD_NUMBER: int
88 | ASYNC_FIELD_NUMBER: int
89 | BEACONID_FIELD_NUMBER: int
90 | TASKID_FIELD_NUMBER: int
91 | Err: str
92 | Async: bool
93 | BeaconID: str
94 | TaskID: str
95 | def __init__(
96 | self,
97 | *,
98 | Err: str = ...,
99 | Async: bool = ...,
100 | BeaconID: str = ...,
101 | TaskID: str = ...,
102 | ) -> None: ...
103 | def ClearField(
104 | self,
105 | field_name: typing_extensions.Literal[
106 | "Async",
107 | b"Async",
108 | "BeaconID",
109 | b"BeaconID",
110 | "Err",
111 | b"Err",
112 | "TaskID",
113 | b"TaskID",
114 | ],
115 | ) -> None: ...
116 |
117 | class File(Message):
118 | """File - A basic file data type"""
119 |
120 | DESCRIPTOR: Descriptor
121 |
122 | NAME_FIELD_NUMBER: int
123 | DATA_FIELD_NUMBER: int
124 | Name: str
125 | Data: bytes
126 | def __init__(
127 | self,
128 | *,
129 | Name: str = ...,
130 | Data: bytes = ...,
131 | ) -> None: ...
132 | def ClearField(
133 | self, field_name: typing_extensions.Literal["Data", b"Data", "Name", b"Name"]
134 | ) -> None: ...
135 |
136 | class Process(Message):
137 | """Process - A basic process data type"""
138 |
139 | DESCRIPTOR: Descriptor
140 |
141 | PID_FIELD_NUMBER: int
142 | PPID_FIELD_NUMBER: int
143 | EXECUTABLE_FIELD_NUMBER: int
144 | OWNER_FIELD_NUMBER: int
145 | ARCHITECTURE_FIELD_NUMBER: int
146 | SESSIONID_FIELD_NUMBER: int
147 | CMDLINE_FIELD_NUMBER: int
148 | Pid: int
149 | Ppid: int
150 | Executable: str
151 | Owner: str
152 | Architecture: str
153 | SessionID: int
154 | @property
155 | def CmdLine(self) -> RepeatedScalarFieldContainer[str]: ...
156 | def __init__(
157 | self,
158 | *,
159 | Pid: int = ...,
160 | Ppid: int = ...,
161 | Executable: str = ...,
162 | Owner: str = ...,
163 | Architecture: str = ...,
164 | SessionID: int = ...,
165 | CmdLine: Iterable[str] | None = ...,
166 | ) -> None: ...
167 | def ClearField(
168 | self,
169 | field_name: typing_extensions.Literal[
170 | "Architecture",
171 | b"Architecture",
172 | "CmdLine",
173 | b"CmdLine",
174 | "Executable",
175 | b"Executable",
176 | "Owner",
177 | b"Owner",
178 | "Pid",
179 | b"Pid",
180 | "Ppid",
181 | b"Ppid",
182 | "SessionID",
183 | b"SessionID",
184 | ],
185 | ) -> None: ...
186 |
187 | class EnvVar(Message):
188 | """EnvVar - Environment variable K/V"""
189 |
190 | DESCRIPTOR: Descriptor
191 |
192 | KEY_FIELD_NUMBER: int
193 | VALUE_FIELD_NUMBER: int
194 | Key: str
195 | Value: str
196 | def __init__(
197 | self,
198 | *,
199 | Key: str = ...,
200 | Value: str = ...,
201 | ) -> None: ...
202 | def ClearField(
203 | self, field_name: typing_extensions.Literal["Key", b"Key", "Value", b"Value"]
204 | ) -> None: ...
205 |
--------------------------------------------------------------------------------
/scripts/protobufgen.py:
--------------------------------------------------------------------------------
1 | import os
2 | from pathlib import Path
3 |
4 | import pkg_resources
5 | from grpc_tools import protoc
6 | from rich.console import Console
7 |
8 | console = Console(log_time=False, log_path=False)
9 | ROOT_DIR = Path(__file__).parents[1]
10 | os.chdir(ROOT_DIR)
11 |
12 | IN_DIR = ROOT_DIR / "sliver/protobuf"
13 | OUT_DIR = ROOT_DIR / "src/sliver/pb"
14 |
15 | COMMON_PROTO_PATH = IN_DIR / "commonpb/common.proto"
16 | SLIVER_PROTO_PATH = IN_DIR / "sliverpb/sliver.proto"
17 | CLIENT_PROTO_PATH = IN_DIR / "clientpb/client.proto"
18 | GRPC_PROTO_PATH = IN_DIR / "rpcpb/services.proto"
19 |
20 | # There is a more accurate way to do all of this using the ast module but this works for now
21 | try:
22 | # Cleanup old files
23 | console.log("[bold green]Removing old generated files...")
24 | for file in OUT_DIR.glob("**/*.py"):
25 | if file.name.split("_")[0] in ["common", "sliver", "client", "services"]:
26 | file.unlink()
27 | console.log(f"Removed {file}")
28 |
29 | console.log("[bold green]Generating new files...")
30 | proto_pyd = pkg_resources.resource_filename("grpc_tools", "_proto")
31 |
32 | # Generate commonpb
33 | protoc.main(
34 | f"-I{proto_pyd} -I {IN_DIR.relative_to(ROOT_DIR)} --mypy_out=readable_stubs:{OUT_DIR} --python_out={OUT_DIR} {COMMON_PROTO_PATH.relative_to(ROOT_DIR)}".split()
35 | )
36 | console.log(f"Generated {COMMON_PROTO_PATH.name}")
37 |
38 | # Generate sliverpb
39 | protoc.main(
40 | f"-I{proto_pyd} -I {IN_DIR.relative_to(ROOT_DIR)} --mypy_out=readable_stubs:{OUT_DIR} --python_out={OUT_DIR} {SLIVER_PROTO_PATH.relative_to(ROOT_DIR)}".split()
41 | )
42 | console.log(f"Generated {SLIVER_PROTO_PATH.name}")
43 |
44 | # Generate clientpb
45 | protoc.main(
46 | f"-I{proto_pyd} -I {IN_DIR.relative_to(ROOT_DIR)} --mypy_out=readable_stubs:{OUT_DIR} --python_out={OUT_DIR} {CLIENT_PROTO_PATH.relative_to(ROOT_DIR)}".split()
47 | )
48 | console.log(f"Generated {CLIENT_PROTO_PATH.name}")
49 |
50 | # Generate rpcpb
51 | protoc.main(
52 | f"-I{proto_pyd} -I {IN_DIR.relative_to(ROOT_DIR)} --mypy_out=readable_stubs:{OUT_DIR} --mypy_grpc_out={OUT_DIR} --python_out={OUT_DIR} --grpc_python_out={OUT_DIR} {GRPC_PROTO_PATH.relative_to(ROOT_DIR)}".split()
53 | )
54 | console.log(f"Generated {GRPC_PROTO_PATH.name}")
55 |
56 | # Rewrite imports for py files
57 | console.log("[bold green]Rewriting imports for py files...")
58 | for file in OUT_DIR.glob("**/*.py"):
59 | if file.name.split("_")[0] in ["sliver", "client", "services"]:
60 | content = (
61 | file.read_text()
62 | .replace(
63 | "from commonpb import common_pb2 as commonpb_dot_common__pb2",
64 | "from ..commonpb import common_pb2 as commonpb_dot_common__pb2",
65 | )
66 | .replace(
67 | "from sliverpb import sliver_pb2 as sliverpb_dot_sliver__pb2",
68 | "from ..sliverpb import sliver_pb2 as sliverpb_dot_sliver__pb2",
69 | )
70 | .replace(
71 | "from clientpb import client_pb2 as clientpb_dot_client__pb2",
72 | "from ..clientpb import client_pb2 as clientpb_dot_client__pb2",
73 | )
74 | )
75 | # Need to make sure grpc.experimental is imported
76 | if file.name == "services_pb2_grpc.py":
77 | content = (content
78 | .replace("grpc.Channel", "grpc.aio.Channel")
79 | .replace("import grpc", "import grpc\nimport grpc.experimental")
80 | ) # fmt: skip
81 |
82 | file.write_text(content)
83 | console.log(f"Rewrote imports for {file}")
84 |
85 | # Rewrite imports for pyi files
86 | console.log("[bold green]Rewriting imports for pyi files...")
87 | for file in OUT_DIR.glob("**/*.pyi"):
88 | if file.name.split("_")[0] in ["sliver", "client", "services"]:
89 | content = (
90 | file.read_text()
91 | .replace(
92 | "import commonpb.common_pb2",
93 | "from ..commonpb import common_pb2",
94 | )
95 | .replace(
96 | "commonpb.common_pb2",
97 | "common_pb2",
98 | )
99 | .replace(
100 | "import sliverpb.sliver_pb2",
101 | "from ..sliverpb import sliver_pb2",
102 | )
103 | .replace(
104 | "sliverpb.sliver_pb2",
105 | "sliver_pb2",
106 | )
107 | .replace(
108 | "import clientpb.client_pb2",
109 | "from ..clientpb import client_pb2",
110 | )
111 | .replace(
112 | "clientpb.client_pb2",
113 | "client_pb2",
114 | )
115 | )
116 |
117 | # Need to correct type hints. This is a hacky way to do it but it works
118 | if file.name == "services_pb2_grpc.pyi":
119 | content = content.replace("grpc.Channel", "grpc.aio.Channel")
120 |
121 | if file.name == "sliver_pb2.pyi":
122 | content = content.replace(
123 | "from common_pb2 import", "from ..commonpb.common_pb2 import"
124 | )
125 |
126 | file.write_text(content)
127 | console.log(f"Rewrote imports for {file}")
128 | except Exception as e:
129 | console.log("[bold red]Failed to generate files!")
130 | console.log(e)
131 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SliverPy
2 |
3 | SliverPy is a Python gRPC client library for [Sliver](https://github.com/BishopFox/sliver). SliverPy can be used to automate any operator interaction with Sliver and connects to servers using gRPC over Mutual TLS (i.e., multiplayer) using Sliver operator configuration files. [For more details, please see the project documentation](http://sliverpy.rtfd.io/).
4 |
5 | ⚠️ Not all features in Sliver v1.5+ are supported yet.
6 |
7 | [](https://github.com/moloch--/sliver-py/actions/workflows/autorelease.yml)
8 | [](https://sliverpy.readthedocs.io/en/latest/?badge=latest)
9 | [](https://www.gnu.org/licenses/gpl-3.0)
10 |
11 | ### Install
12 |
13 | Install the package using pip, for best compatibility use Sliver Server v1.5.29 or later:
14 |
15 | `pip3 install sliver-py`
16 |
17 | #### Kali Linux / Fix OpenSSL Errors
18 |
19 | [Python's TLS implementation](https://docs.python.org/3/library/ssl.html) may exhibit platform specific behavoir, if you encounter OpenSSL connection errors you may need to re-install the gRPC Python library from source. This issue is known to affect recent versions of Kali Linux. To fix the issue use the following command to re-install gRPC from source, note depending on your distribution you may also need to install gcc (i.e. `build-essential`) and the development package for OpenSSL:
20 |
21 | `GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=True pip install --use-pep517 --force-reinstall grpcio`
22 |
23 | ## Examples
24 |
25 | For more examples and details please read the [project documentation](http://sliverpy.rtfd.io/).
26 |
27 | #### Interact with Sessions
28 |
29 | ```python
30 | #!/usr/bin/env python3
31 |
32 | import os
33 | import asyncio
34 | from sliver import SliverClientConfig, SliverClient
35 |
36 | CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".sliver-client", "configs")
37 | DEFAULT_CONFIG = os.path.join(CONFIG_DIR, "default.cfg")
38 |
39 | async def main():
40 | config = SliverClientConfig.parse_config_file(DEFAULT_CONFIG)
41 | client = SliverClient(config)
42 | print('[*] Connected to server ...')
43 | await client.connect()
44 | sessions = await client.sessions()
45 | print('[*] Sessions: %r' % sessions)
46 | if len(sessions):
47 | print('[*] Interacting with session %s', sessions[0].ID)
48 | interact = await client.interact_session(sessions[0].ID)
49 | ls = await interact.ls()
50 | print('[*] ls: %r' % ls)
51 |
52 | if __name__ == '__main__':
53 | asyncio.run(main())
54 | ```
55 |
56 | #### Interact with Beacons
57 |
58 | ```python
59 | #!/usr/bin/env python3
60 |
61 | import os
62 | import asyncio
63 | from sliver import SliverClientConfig, SliverClient
64 |
65 | CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".sliver-client", "configs")
66 | DEFAULT_CONFIG = os.path.join(CONFIG_DIR, "default.cfg")
67 |
68 | async def main():
69 | config = SliverClientConfig.parse_config_file(DEFAULT_CONFIG)
70 | client = SliverClient(config)
71 | print('[*] Connected to server ...')
72 | await client.connect()
73 | version = await client.version()
74 | print('[*] Server version: %s' % version)
75 |
76 | beacons = await client.beacons()
77 | print('[*] Beacons: %r' % beacons)
78 | if len(beacons):
79 | print('[*] Interacting with beacon: %r' % beacons[0].ID)
80 | interact = await client.interact_beacon(beacons[0].ID)
81 | ls_task = await interact.ls()
82 | print('[*] Created ls task: %r' % ls_task)
83 | print('[*] Waiting for task results ...')
84 | ls = await ls_task
85 | print('[*] ls: %r' % ls)
86 |
87 | if __name__ == '__main__':
88 | asyncio.run(main())
89 | ```
90 |
91 | ## Development
92 |
93 | The development environment has migrated to [hatch](https://github.com/pypa/hatch) and the installation instructions can be found [here](https://hatch.pypa.io/latest/install/).
94 |
95 | ### Note on VS Code
96 |
97 | Unfortunately, VS Code does not automatically detect hatch virtual environments yet due to how it structures environments. However, you can make setting the Python interpreter path easier by including the virtual environment directly in the folder by running these commands before setting up the virtual environment:
98 |
99 | ```
100 | hatch config set dirs.env.virtual .venv
101 | hatch config update
102 | ```
103 |
104 | ### Setting up Hatch environment
105 |
106 | Once installed, run `hatch -e dev shell` to enter the development environment. Hatch allows for scripts to be defined as well. These scripts are executed in the context of the defined environment. The current scripts defined are:
107 |
108 |
109 | - `hatch run dev:fmt` -- runs `black` and `isort` for formatting
110 |
111 | ### Docker/WSL2
112 |
113 | A Dockerfile is included if you wish to develop inside a container. This may be preferable for development on any operating system to keep the dev environment isolated. Windows developers may choose to develop inside WSL2.
114 |
115 | In either case, `scripts/sliver_install.sh` contains a modified version of the official Sliver installation script that does not create a `systemd` based service. After running this script, you may start a local Sliver server in your container or WSL2 instance by running:
116 |
117 | `sudo /root/sliver-server daemon &`
118 |
119 | Alternatively, you can still choose to set up an external Sliver instance to connect to via Sliver's [multi-player mode](https://github.com/BishopFox/sliver/wiki/Multiplayer-Mode). The `sliver_install` script is purely for local development convenience.
120 |
121 | ### Updating protobufs
122 | This should only be necessary when changes are made to Sliver's protobuf. Running `scripts/protobufgen.py` will update `sliver-py` protobuf files. Ensure that the `.pyi` type hints are generated also.
123 |
124 | ### Running tests
125 | To run tests, you should have at least one beacon implant and one session implant connected to you Sliver instance. Currently, it is ok to only have them running on a Linux system (implants running on your sliver server works fine). In the future, you may need to have a session implant on the type of operating system the test is for, particularly for Windows.
126 |
127 | Tests are implemented using [Ward](https://github.com/darrenburns/ward). The tests have been tagged so you can run all the tests or just the tests you need. Recommendation is to run all tests when making a major change.
128 |
129 | - `ward` : All tests
130 | - `ward --tags client`: Client tests only
131 | - `ward --tags interactive`: InteractiveObject tests
132 |
--------------------------------------------------------------------------------
/docs/protobuf/client_pb2.rst:
--------------------------------------------------------------------------------
1 | Client Protobuf
2 | ===============
3 |
4 | This module contains the client Protobuf definitions, client Protobuf messages are only
5 | passed between the client and server (and not to the implant).
6 |
7 | .. autoclass:: sliver.pb.clientpb.client_pb2.AllHosts
8 | :members:
9 |
10 | .. autoclass:: sliver.pb.clientpb.client_pb2.AllLoot
11 | :members:
12 |
13 | .. autoclass:: sliver.pb.clientpb.client_pb2.Beacon
14 | :members:
15 |
16 | .. autoclass:: sliver.pb.clientpb.client_pb2.Beacons
17 | :members:
18 |
19 | .. autoclass:: sliver.pb.clientpb.client_pb2.BeaconTask
20 | :members:
21 |
22 | .. autoclass:: sliver.pb.clientpb.client_pb2.BeaconTasks
23 | :members:
24 |
25 | .. autoclass:: sliver.pb.clientpb.client_pb2.Canaries
26 | :members:
27 |
28 | .. autoclass:: sliver.pb.clientpb.client_pb2.Client
29 | :members:
30 |
31 | .. autoclass:: sliver.pb.clientpb.client_pb2.CloseTunnelReq
32 | :members:
33 |
34 | .. autoclass:: sliver.pb.clientpb.client_pb2.Compiler
35 | :members:
36 |
37 | .. autoclass:: sliver.pb.clientpb.client_pb2.CompilerTarget
38 | :members:
39 |
40 | .. autoclass:: sliver.pb.clientpb.client_pb2.CreateTunnel
41 | :members:
42 |
43 | .. autoclass:: sliver.pb.clientpb.client_pb2.CreateTunnelReq
44 | :members:
45 |
46 | .. autoclass:: sliver.pb.clientpb.client_pb2.Credential
47 | :members:
48 |
49 | .. autoclass:: sliver.pb.clientpb.client_pb2.CrossCompiler
50 | :members:
51 |
52 | .. autoclass:: sliver.pb.clientpb.client_pb2.DeleteReq
53 | :members:
54 |
55 | .. autoclass:: sliver.pb.clientpb.client_pb2.DllHijack
56 | :members:
57 |
58 | .. autoclass:: sliver.pb.clientpb.client_pb2.DllHijackReq
59 | :members:
60 |
61 | .. autoclass:: sliver.pb.clientpb.client_pb2.DNSCanary
62 | :members:
63 |
64 | .. autoclass:: sliver.pb.clientpb.client_pb2.DNSListener
65 | :members:
66 |
67 | .. autoclass:: sliver.pb.clientpb.client_pb2.DNSListenerReq
68 | :members:
69 |
70 | .. autoclass:: sliver.pb.clientpb.client_pb2.Event
71 | :members:
72 |
73 | .. autoclass:: sliver.pb.clientpb.client_pb2.ExtensionData
74 | :members:
75 |
76 | .. autoclass:: sliver.pb.clientpb.client_pb2.Generate
77 | :members:
78 |
79 | .. autoclass:: sliver.pb.clientpb.client_pb2.GenerateReq
80 | :members:
81 |
82 | .. autoclass:: sliver.pb.clientpb.client_pb2.GetSystemReq
83 | :members:
84 |
85 | .. autoclass:: sliver.pb.clientpb.client_pb2.Host
86 | :members:
87 |
88 | .. autoclass:: sliver.pb.clientpb.client_pb2.HTTPListener
89 | :members:
90 |
91 | .. autoclass:: sliver.pb.clientpb.client_pb2.HTTPListenerReq
92 | :members:
93 |
94 | .. autoclass:: sliver.pb.clientpb.client_pb2.ImplantBuilds
95 | :members:
96 |
97 | .. autoclass:: sliver.pb.clientpb.client_pb2.ImplantC2
98 | :members:
99 |
100 | .. autoclass:: sliver.pb.clientpb.client_pb2.ImplantConfig
101 | :members:
102 |
103 | .. autoclass:: sliver.pb.clientpb.client_pb2.ImplantProfile
104 | :members:
105 |
106 | .. autoclass:: sliver.pb.clientpb.client_pb2.ImplantProfiles
107 | :members:
108 |
109 | .. autoclass:: sliver.pb.clientpb.client_pb2.IOC
110 | :members:
111 |
112 | .. autoclass:: sliver.pb.clientpb.client_pb2.Job
113 | :members:
114 |
115 | .. autoclass:: sliver.pb.clientpb.client_pb2.Jobs
116 | :members:
117 |
118 | .. autoclass:: sliver.pb.clientpb.client_pb2.KillJob
119 | :members:
120 |
121 | .. autoclass:: sliver.pb.clientpb.client_pb2.KillJobReq
122 | :members:
123 |
124 | .. autoclass:: sliver.pb.clientpb.client_pb2.Loot
125 | :members:
126 |
127 | .. autoclass:: sliver.pb.clientpb.client_pb2.MigrateReq
128 | :members:
129 |
130 | .. autoclass:: sliver.pb.clientpb.client_pb2.MSFRemoteReq
131 | :members:
132 |
133 | .. autoclass:: sliver.pb.clientpb.client_pb2.MSFReq
134 | :members:
135 |
136 | .. autoclass:: sliver.pb.clientpb.client_pb2.MsfStager
137 | :members:
138 |
139 | .. autoclass:: sliver.pb.clientpb.client_pb2.MsfStagerReq
140 | :members:
141 |
142 | .. autoclass:: sliver.pb.clientpb.client_pb2.MTLSListener
143 | :members:
144 |
145 | .. autoclass:: sliver.pb.clientpb.client_pb2.MTLSListenerReq
146 | :members:
147 |
148 | .. autoclass:: sliver.pb.clientpb.client_pb2.NamedPipes
149 | :members:
150 |
151 | .. autoclass:: sliver.pb.clientpb.client_pb2.NamedPipesReq
152 | :members:
153 |
154 | .. autoclass:: sliver.pb.clientpb.client_pb2.Operator
155 | :members:
156 |
157 | .. autoclass:: sliver.pb.clientpb.client_pb2.Operators
158 | :members:
159 |
160 | .. autoclass:: sliver.pb.clientpb.client_pb2.PivotGraph
161 | :members:
162 |
163 | .. autoclass:: sliver.pb.clientpb.client_pb2.PivotGraphEntry
164 | :members:
165 |
166 | .. autoclass:: sliver.pb.clientpb.client_pb2.RegenerateReq
167 | :members:
168 |
169 | .. autoclass:: sliver.pb.clientpb.client_pb2.RenameReq
170 | :members:
171 |
172 | .. autoclass:: sliver.pb.clientpb.client_pb2.Session
173 | :members:
174 |
175 | .. autoclass:: sliver.pb.clientpb.client_pb2.Sessions
176 | :members:
177 |
178 | .. autoclass:: sliver.pb.clientpb.client_pb2.ShellcodeEncode
179 | :members:
180 |
181 | .. autoclass:: sliver.pb.clientpb.client_pb2.ShellcodeEncodeReq
182 | :members:
183 |
184 | .. autoclass:: sliver.pb.clientpb.client_pb2.ShellcodeEncoderMap
185 | :members:
186 |
187 | .. autoclass:: sliver.pb.clientpb.client_pb2.ShellcodeRDI
188 | :members:
189 |
190 | .. autoclass:: sliver.pb.clientpb.client_pb2.ShellcodeRDIReq
191 | :members:
192 |
193 | .. autoclass:: sliver.pb.clientpb.client_pb2.StagerListener
194 | :members:
195 |
196 | .. autoclass:: sliver.pb.clientpb.client_pb2.StagerListenerReq
197 | :members:
198 |
199 | .. autoclass:: sliver.pb.clientpb.client_pb2.TCPPivot
200 | :members:
201 |
202 | .. autoclass:: sliver.pb.clientpb.client_pb2.TCPPivotReq
203 | :members:
204 |
205 | .. autoclass:: sliver.pb.clientpb.client_pb2.UniqueWGIP
206 | :members:
207 |
208 | .. autoclass:: sliver.pb.clientpb.client_pb2.Version
209 | :members:
210 |
211 | .. autoclass:: sliver.pb.clientpb.client_pb2.WebContent
212 | :members:
213 |
214 | .. autoclass:: sliver.pb.clientpb.client_pb2.Website
215 | :members:
216 |
217 | .. autoclass:: sliver.pb.clientpb.client_pb2.Websites
218 | :members:
219 |
220 | .. autoclass:: sliver.pb.clientpb.client_pb2.WebsiteAddContent
221 | :members:
222 |
223 | .. autoclass:: sliver.pb.clientpb.client_pb2.WebsiteRemoveContent
224 | :members:
225 |
226 | .. autoclass:: sliver.pb.clientpb.client_pb2.WGClientConfig
227 | :members:
228 |
229 | .. autoclass:: sliver.pb.clientpb.client_pb2.WGListenerReq
230 | :members:
231 |
232 | .. autoclass:: sliver.pb.clientpb.client_pb2.WGListener
233 | :members:
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
--------------------------------------------------------------------------------
/scripts/sliver_install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Modified version of official script without systemd
4 | set -e
5 | set -m
6 |
7 | SLIVER_GPG_KEY_ID=4449039C
8 |
9 | if [ "$EUID" -ne 0 ]
10 | then echo "Please run as root"
11 | exit
12 | fi
13 |
14 | if [ -n "$(command -v yum)" ]
15 | then
16 | yum -y install gnupg curl gcc gcc-c++ make mingw64-gcc
17 | fi
18 |
19 | if [ -n "$(command -v apt-get)" ]
20 | then
21 | DEBIAN_FRONTEND=noninteractive apt-get install -yqq \
22 | gpg curl build-essential \
23 | mingw-w64 binutils-mingw-w64 g++-mingw-w64
24 | fi
25 |
26 | # Curl
27 | if ! command -v curl &> /dev/null
28 | then
29 | echo "curl could not be found"
30 | exit 1
31 | fi
32 | # Awk
33 | if ! command -v awk &> /dev/null
34 | then
35 | echo "awk could not be found"
36 | exit 1
37 | fi
38 | # GPG
39 | if ! command -v gpg &> /dev/null
40 | then
41 | echo "gpg could not be found"
42 | exit 1
43 | fi
44 |
45 | cd /root
46 | echo "Running from $(pwd)"
47 |
48 | gpg --import < /etc/systemd/system/sliver.service <<-EOF
145 | # [Unit]
146 | # Description=Sliver
147 | # After=network.target
148 | # StartLimitIntervalSec=0
149 |
150 | # [Service]
151 | # Type=simple
152 | # Restart=on-failure
153 | # RestartSec=3
154 | # User=root
155 | # ExecStart=/root/sliver-server daemon
156 |
157 | # [Install]
158 | # WantedBy=multi-user.target
159 | # EOF
160 | # chown root:root /etc/systemd/system/sliver.service
161 | # chmod 600 /etc/systemd/system/sliver.service
162 | # systemctl start sliver
163 |
164 | # Generate local configs
165 | echo "Generating operator configs ..."
166 | mkdir -p /root/.sliver-client/configs
167 | /root/sliver-server operator --name root --lhost localhost --save /root/.sliver-client/configs
168 | chown -R root:root /root/.sliver-client/
169 |
170 | USER_DIRS=(/home/*)
171 | for USER_DIR in "${USER_DIRS[@]}"; do
172 | USER=$(basename $USER_DIR)
173 | if id -u $USER >/dev/null 2>&1; then
174 | mkdir -p $USER_DIR/.sliver-client/configs
175 | /root/sliver-server operator --name $USER --lhost localhost --save $USER_DIR/.sliver-client/configs
176 | chown -R $USER:$USER $USER_DIR/.sliver-client/
177 | fi
178 | done
--------------------------------------------------------------------------------
/src/sliver/session.py:
--------------------------------------------------------------------------------
1 | """
2 | Sliver Implant Framework
3 | Copyright (C) 2022 Bishop Fox
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 | """
16 |
17 | import logging
18 | from typing import List, Union
19 |
20 | import grpc
21 |
22 | from .interactive import BaseInteractiveCommands
23 | from .pb.rpcpb.services_pb2_grpc import SliverRPCStub
24 | from .protobuf import client_pb2, sliver_pb2
25 |
26 |
27 | class BaseSession:
28 | """Base class for Session objects.
29 |
30 | :param session: Session protobuf.
31 | :type session: client_pb2.Session
32 | :param channel: A gRPC channel.
33 | :type channel: grpc.Channel
34 | :param timeout: Timeout in seconds
35 | :type timeout: int, optional
36 | """
37 |
38 | def __init__(
39 | self,
40 | session: client_pb2.Session,
41 | channel: grpc.aio.Channel,
42 | timeout: int = 60,
43 | ):
44 | self._channel = channel
45 | self._session = session
46 | self._stub = SliverRPCStub(channel)
47 | self.timeout = timeout
48 |
49 | def _request(self, pb):
50 | """
51 | Set request attributes based on current session, I'd prefer to return a generic Request
52 | object, but protobuf for whatever reason doesn't let you assign this type of field directly.
53 |
54 | `pb` in this case is any protobuf message with a .Request field.
55 |
56 | :param pb: A protobuf request object.
57 | """
58 | pb.Request.SessionID = self._session.ID
59 | pb.Request.Timeout = self.timeout - 1
60 | return pb
61 |
62 | @property
63 | def session_id(self) -> str:
64 | """Session ID"""
65 | return self._session.ID
66 |
67 | @property
68 | def name(self) -> str:
69 | """Session name"""
70 | return self._session.Name
71 |
72 | @property
73 | def hostname(self) -> str:
74 | """Hostname"""
75 | return self._session.Hostname
76 |
77 | @property
78 | def uuid(self) -> str:
79 | """Session UUID"""
80 | return self._session.UUID
81 |
82 | @property
83 | def username(self) -> str:
84 | """Username"""
85 | return self._session.Username
86 |
87 | @property
88 | def uid(self) -> str:
89 | """User ID"""
90 | return self._session.UID
91 |
92 | @property
93 | def gid(self) -> str:
94 | """Group ID"""
95 | return self._session.GID
96 |
97 | @property
98 | def os(self) -> str:
99 | """Operating system"""
100 | return self._session.OS
101 |
102 | @property
103 | def arch(self) -> str:
104 | """Architecture"""
105 | return self._session.Arch
106 |
107 | @property
108 | def transport(self) -> str:
109 | """Transport Method"""
110 | return self._session.Transport
111 |
112 | @property
113 | def remote_address(self) -> str:
114 | """Remote address"""
115 | return self._session.RemoteAddress
116 |
117 | @property
118 | def pid(self) -> int:
119 | """Process ID"""
120 | return self._session.PID
121 |
122 | @property
123 | def filename(self) -> str:
124 | """Implant filename"""
125 | return self._session.Filename
126 |
127 | @property
128 | def last_checkin(self) -> int:
129 | """Last check in"""
130 | return self._session.LastCheckin
131 |
132 | @property
133 | def active_c2(self) -> str:
134 | """Active C2"""
135 | return self._session.ActiveC2
136 |
137 | @property
138 | def version(self) -> str:
139 | """Version"""
140 | return self._session.Version
141 |
142 | @property
143 | def is_dead(self) -> bool:
144 | """Is dead"""
145 | return self._session.IsDead
146 |
147 | @property
148 | def reconnect_interval(self) -> int:
149 | """Reconnect interval"""
150 | return self._session.ReconnectInterval
151 |
152 | @property
153 | def proxy_url(self) -> str:
154 | """Proxy URL"""
155 |
156 | return self._session.ProxyURL
157 |
158 |
159 | class InteractiveSession(BaseSession, BaseInteractiveCommands):
160 | """Session only commands"""
161 |
162 | async def pivot_listeners(self) -> List[sliver_pb2.PivotListener]:
163 | """List C2 pivots
164 |
165 | :return: Protobuf PivotListener list
166 | :rtype: List[sliver_pb2.PivotListener]
167 | """
168 | pivots = await self._stub.PivotSessionListeners(
169 | self._request(sliver_pb2.PivotListenersReq()), timeout=self.timeout
170 | )
171 | return list(pivots.Listeners)
172 |
173 | async def start_service(
174 | self, name: str, description: str, exe: str, hostname: str, arguments: str
175 | ) -> sliver_pb2.ServiceInfo:
176 | """Create and start a Windows service (Windows only)
177 |
178 | :param name: Name of the service
179 | :type name: str
180 | :param description: Service description
181 | :type description: str
182 | :param exe: Path to the service .exe file
183 | :type exe: str
184 | :param hostname: Hostname
185 | :type hostname: str
186 | :param arguments: Arguments to start the service with
187 | :type arguments: str
188 | :return: Protobuf ServiceInfo object
189 | :rtype: sliver_pb2.ServiceInfo
190 | """
191 | svc = sliver_pb2.StartServiceReq()
192 | svc.ServiceName = name
193 | svc.ServiceDescription = description
194 | svc.BinPath = exe
195 | svc.Hostname = hostname
196 | svc.Arguments = arguments
197 | return await self._stub.StartService(self._request(svc), timeout=self.timeout)
198 |
199 | async def stop_service(self, name: str, hostname: str) -> sliver_pb2.ServiceInfo:
200 | """Stop a Windows service (Windows only)
201 |
202 | :param name: Name of the servie
203 | :type name: str
204 | :param hostname: Hostname
205 | :type hostname: str
206 | :return: Protobuf ServiceInfo object
207 | :rtype: sliver_pb2.ServiceInfo
208 | """
209 | svc = sliver_pb2.StopServiceReq()
210 | svc.ServiceInfo.ServiceName = name
211 | svc.ServiceInfo.Hostname = hostname
212 | return await self._stub.StopService(self._request(svc), timeout=self.timeout)
213 |
214 | async def remove_service(self, name: str, hostname: str) -> sliver_pb2.ServiceInfo:
215 | """Remove a Windows service (Windows only)
216 |
217 | :param name: Name of the service
218 | :type name: str
219 | :param hostname: Hostname
220 | :type hostname: str
221 | :return: Protobuf ServiceInfo object
222 | :rtype: sliver_pb2.ServiceInfo
223 | """
224 | svc = sliver_pb2.StopServiceReq()
225 | svc.ServiceInfo.ServiceName = name
226 | svc.ServiceInfo.Hostname = hostname
227 | return await self._stub.RemoveService(self._request(svc), timeout=self.timeout)
228 |
229 | async def backdoor(
230 | self, remote_path: str, profile_name: str
231 | ) -> sliver_pb2.Backdoor:
232 | """Backdoor a remote binary by injecting a Sliver payload into the executable using a code cave
233 |
234 | :param remote_path: Remote path to an executable to backdoor
235 | :type remote_path: str
236 | :param profile_name: Implant profile name to inject into the binary
237 | :type profile_name: str
238 | :return: Protobuf Backdoor object
239 | :rtype: sliver_pb2.Backdoor
240 | """
241 | backdoor = sliver_pb2.BackdoorReq()
242 | backdoor.FilePath = remote_path
243 | backdoor.ProfileName = profile_name
244 | return await self._stub.Backdoor(self._request(backdoor), timeout=self.timeout)
245 |
--------------------------------------------------------------------------------
/src/sliver/pb/rpcpb/services_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: rpcpb/services.proto
4 | """Generated protocol buffer code."""
5 | from google.protobuf import descriptor as _descriptor
6 | from google.protobuf import descriptor_pool as _descriptor_pool
7 | from google.protobuf import symbol_database as _symbol_database
8 | from google.protobuf.internal import builder as _builder
9 |
10 | # @@protoc_insertion_point(imports)
11 |
12 | _sym_db = _symbol_database.Default()
13 |
14 |
15 | from ..clientpb import client_pb2 as clientpb_dot_client__pb2
16 | from ..commonpb import common_pb2 as commonpb_dot_common__pb2
17 | from ..sliverpb import sliver_pb2 as sliverpb_dot_sliver__pb2
18 |
19 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
20 | b"\n\x14rpcpb/services.proto\x12\x05rpcpb\x1a\x15\x63ommonpb/common.proto\x1a\x15sliverpb/sliver.proto\x1a\x15\x63lientpb/client.proto2\xe4<\n\tSliverRPC\x12\x30\n\nGetVersion\x12\x0f.commonpb.Empty\x1a\x11.clientpb.Version\x12\x34\n\x0cGetOperators\x12\x0f.commonpb.Empty\x1a\x13.clientpb.Operators\x12*\n\x04Kill\x12\x11.sliverpb.KillReq\x1a\x0f.commonpb.Empty\x12>\n\x0bReconfigure\x12\x18.sliverpb.ReconfigureReq\x1a\x15.sliverpb.Reconfigure\x12.\n\x06Rename\x12\x13.clientpb.RenameReq\x1a\x0f.commonpb.Empty\x12\x32\n\x0bGetSessions\x12\x0f.commonpb.Empty\x1a\x12.clientpb.Sessions\x12\x30\n\nGetBeacons\x12\x0f.commonpb.Empty\x1a\x11.clientpb.Beacons\x12/\n\tGetBeacon\x12\x10.clientpb.Beacon\x1a\x10.clientpb.Beacon\x12-\n\x08RmBeacon\x12\x10.clientpb.Beacon\x1a\x0f.commonpb.Empty\x12\x39\n\x0eGetBeaconTasks\x12\x10.clientpb.Beacon\x1a\x15.clientpb.BeaconTasks\x12\x42\n\x14GetBeaconTaskContent\x12\x14.clientpb.BeaconTask\x1a\x14.clientpb.BeaconTask\x12>\n\x10\x43\x61ncelBeaconTask\x12\x14.clientpb.BeaconTask\x1a\x14.clientpb.BeaconTask\x12\x33\n\x0cMonitorStart\x12\x0f.commonpb.Empty\x1a\x12.commonpb.Response\x12/\n\x0bMonitorStop\x12\x0f.commonpb.Empty\x1a\x0f.commonpb.Empty\x12*\n\x07GetJobs\x12\x0f.commonpb.Empty\x1a\x0e.clientpb.Jobs\x12\x32\n\x07KillJob\x12\x14.clientpb.KillJobReq\x1a\x11.clientpb.KillJob\x12\x46\n\x11StartMTLSListener\x12\x19.clientpb.MTLSListenerReq\x1a\x16.clientpb.MTLSListener\x12@\n\x0fStartWGListener\x12\x17.clientpb.WGListenerReq\x1a\x14.clientpb.WGListener\x12\x43\n\x10StartDNSListener\x12\x18.clientpb.DNSListenerReq\x1a\x15.clientpb.DNSListener\x12G\n\x12StartHTTPSListener\x12\x19.clientpb.HTTPListenerReq\x1a\x16.clientpb.HTTPListener\x12\x46\n\x11StartHTTPListener\x12\x19.clientpb.HTTPListenerReq\x1a\x16.clientpb.HTTPListener\x12O\n\x16StartTCPStagerListener\x12\x1b.clientpb.StagerListenerReq\x1a\x18.clientpb.StagerListener\x12P\n\x17StartHTTPStagerListener\x12\x1b.clientpb.StagerListenerReq\x1a\x18.clientpb.StagerListener\x12)\n\x07LootAdd\x12\x0e.clientpb.Loot\x1a\x0e.clientpb.Loot\x12)\n\x06LootRm\x12\x0e.clientpb.Loot\x1a\x0f.commonpb.Empty\x12,\n\nLootUpdate\x12\x0e.clientpb.Loot\x1a\x0e.clientpb.Loot\x12-\n\x0bLootContent\x12\x0e.clientpb.Loot\x1a\x0e.clientpb.Loot\x12-\n\x07LootAll\x12\x0f.commonpb.Empty\x1a\x11.clientpb.AllLoot\x12.\n\tLootAllOf\x12\x0e.clientpb.Loot\x1a\x11.clientpb.AllLoot\x12,\n\x05Hosts\x12\x0f.commonpb.Empty\x1a\x12.clientpb.AllHosts\x12&\n\x04Host\x12\x0e.clientpb.Host\x1a\x0e.clientpb.Host\x12)\n\x06HostRm\x12\x0e.clientpb.Host\x1a\x0f.commonpb.Empty\x12+\n\tHostIOCRm\x12\r.clientpb.IOC\x1a\x0f.commonpb.Empty\x12\x35\n\x08Generate\x12\x15.clientpb.GenerateReq\x1a\x12.clientpb.Generate\x12J\n\x10GenerateExternal\x12\x15.clientpb.GenerateReq\x1a\x1f.clientpb.ExternalImplantConfig\x12M\n\x19GenerateExternalSaveBuild\x12\x1f.clientpb.ExternalImplantBinary\x1a\x0f.commonpb.Empty\x12\\\n GenerateExternalGetImplantConfig\x12\x17.clientpb.ImplantConfig\x1a\x1f.clientpb.ExternalImplantConfig\x12\x39\n\nRegenerate\x12\x17.clientpb.RegenerateReq\x1a\x12.clientpb.Generate\x12\x39\n\rImplantBuilds\x12\x0f.commonpb.Empty\x1a\x17.clientpb.ImplantBuilds\x12:\n\x12\x44\x65leteImplantBuild\x12\x13.clientpb.DeleteReq\x1a\x0f.commonpb.Empty\x12/\n\x08\x43\x61naries\x12\x0f.commonpb.Empty\x1a\x12.clientpb.Canaries\x12\x43\n\x16GenerateWGClientConfig\x12\x0f.commonpb.Empty\x1a\x18.clientpb.WGClientConfig\x12\x39\n\x10GenerateUniqueIP\x12\x0f.commonpb.Empty\x1a\x14.clientpb.UniqueWGIP\x12=\n\x0fImplantProfiles\x12\x0f.commonpb.Empty\x1a\x19.clientpb.ImplantProfiles\x12<\n\x14\x44\x65leteImplantProfile\x12\x13.clientpb.DeleteReq\x1a\x0f.commonpb.Empty\x12H\n\x12SaveImplantProfile\x12\x18.clientpb.ImplantProfile\x1a\x18.clientpb.ImplantProfile\x12\x37\n\x08MsfStage\x12\x16.clientpb.MsfStagerReq\x1a\x13.clientpb.MsfStager\x12\x41\n\x0cShellcodeRDI\x12\x19.clientpb.ShellcodeRDIReq\x1a\x16.clientpb.ShellcodeRDI\x12\x32\n\x0bGetCompiler\x12\x0f.commonpb.Empty\x1a\x12.clientpb.Compiler\x12K\n\x10ShellcodeEncoder\x12\x1c.clientpb.ShellcodeEncodeReq\x1a\x19.clientpb.ShellcodeEncode\x12\x45\n\x13ShellcodeEncoderMap\x12\x0f.commonpb.Empty\x1a\x1d.clientpb.ShellcodeEncoderMap\x12/\n\x08Websites\x12\x0f.commonpb.Empty\x1a\x12.clientpb.Websites\x12/\n\x07Website\x12\x11.clientpb.Website\x1a\x11.clientpb.Website\x12\x33\n\rWebsiteRemove\x12\x11.clientpb.Website\x1a\x0f.commonpb.Empty\x12\x43\n\x11WebsiteAddContent\x12\x1b.clientpb.WebsiteAddContent\x1a\x11.clientpb.Website\x12\x46\n\x14WebsiteUpdateContent\x12\x1b.clientpb.WebsiteAddContent\x1a\x11.clientpb.Website\x12I\n\x14WebsiteRemoveContent\x12\x1e.clientpb.WebsiteRemoveContent\x1a\x11.clientpb.Website\x12&\n\x04Ping\x12\x0e.sliverpb.Ping\x1a\x0e.sliverpb.Ping\x12#\n\x02Ps\x12\x0f.sliverpb.PsReq\x1a\x0c.sliverpb.Ps\x12\x38\n\tTerminate\x12\x16.sliverpb.TerminateReq\x1a\x13.sliverpb.Terminate\x12\x35\n\x08Ifconfig\x12\x15.sliverpb.IfconfigReq\x1a\x12.sliverpb.Ifconfig\x12\x32\n\x07Netstat\x12\x14.sliverpb.NetstatReq\x1a\x11.sliverpb.Netstat\x12#\n\x02Ls\x12\x0f.sliverpb.LsReq\x1a\x0c.sliverpb.Ls\x12$\n\x02\x43\x64\x12\x0f.sliverpb.CdReq\x1a\r.sliverpb.Pwd\x12&\n\x03Pwd\x12\x10.sliverpb.PwdReq\x1a\r.sliverpb.Pwd\x12#\n\x02Mv\x12\x0f.sliverpb.MvReq\x1a\x0c.sliverpb.Mv\x12#\n\x02Rm\x12\x0f.sliverpb.RmReq\x1a\x0c.sliverpb.Rm\x12,\n\x05Mkdir\x12\x12.sliverpb.MkdirReq\x1a\x0f.sliverpb.Mkdir\x12\x35\n\x08\x44ownload\x12\x15.sliverpb.DownloadReq\x1a\x12.sliverpb.Download\x12/\n\x06Upload\x12\x13.sliverpb.UploadReq\x1a\x10.sliverpb.Upload\x12>\n\x0bProcessDump\x12\x18.sliverpb.ProcessDumpReq\x1a\x15.sliverpb.ProcessDump\x12,\n\x05RunAs\x12\x12.sliverpb.RunAsReq\x1a\x0f.sliverpb.RunAs\x12>\n\x0bImpersonate\x12\x18.sliverpb.ImpersonateReq\x1a\x15.sliverpb.Impersonate\x12\x38\n\tRevToSelf\x12\x16.sliverpb.RevToSelfReq\x1a\x13.sliverpb.RevToSelf\x12\x38\n\tGetSystem\x12\x16.clientpb.GetSystemReq\x1a\x13.sliverpb.GetSystem\x12)\n\x04Task\x12\x11.sliverpb.TaskReq\x1a\x0e.sliverpb.Task\x12'\n\x03Msf\x12\x10.clientpb.MSFReq\x1a\x0e.sliverpb.Task\x12\x33\n\tMsfRemote\x12\x16.clientpb.MSFRemoteReq\x1a\x0e.sliverpb.Task\x12J\n\x0f\x45xecuteAssembly\x12\x1c.sliverpb.ExecuteAssemblyReq\x1a\x19.sliverpb.ExecuteAssembly\x12\x32\n\x07Migrate\x12\x14.clientpb.MigrateReq\x1a\x11.sliverpb.Migrate\x12\x32\n\x07\x45xecute\x12\x14.sliverpb.ExecuteReq\x1a\x11.sliverpb.Execute\x12@\n\x0e\x45xecuteWindows\x12\x1b.sliverpb.ExecuteWindowsReq\x1a\x11.sliverpb.Execute\x12\x35\n\x08Sideload\x12\x15.sliverpb.SideloadReq\x1a\x12.sliverpb.Sideload\x12;\n\x08SpawnDll\x12\x1b.sliverpb.InvokeSpawnDllReq\x1a\x12.sliverpb.SpawnDll\x12;\n\nScreenshot\x12\x17.sliverpb.ScreenshotReq\x1a\x14.sliverpb.Screenshot\x12P\n\x11\x43urrentTokenOwner\x12\x1e.sliverpb.CurrentTokenOwnerReq\x1a\x1b.sliverpb.CurrentTokenOwner\x12N\n\x12PivotStartListener\x12\x1f.sliverpb.PivotStartListenerReq\x1a\x17.sliverpb.PivotListener\x12\x44\n\x11PivotStopListener\x12\x1e.sliverpb.PivotStopListenerReq\x1a\x0f.commonpb.Empty\x12N\n\x15PivotSessionListeners\x12\x1b.sliverpb.PivotListenersReq\x1a\x18.sliverpb.PivotListeners\x12\x33\n\nPivotGraph\x12\x0f.commonpb.Empty\x1a\x14.clientpb.PivotGraph\x12@\n\x0cStartService\x12\x19.sliverpb.StartServiceReq\x1a\x15.sliverpb.ServiceInfo\x12>\n\x0bStopService\x12\x18.sliverpb.StopServiceReq\x1a\x15.sliverpb.ServiceInfo\x12\x42\n\rRemoveService\x12\x1a.sliverpb.RemoveServiceReq\x1a\x15.sliverpb.ServiceInfo\x12\x38\n\tMakeToken\x12\x16.sliverpb.MakeTokenReq\x1a\x13.sliverpb.MakeToken\x12-\n\x06GetEnv\x12\x10.sliverpb.EnvReq\x1a\x11.sliverpb.EnvInfo\x12/\n\x06SetEnv\x12\x13.sliverpb.SetEnvReq\x1a\x10.sliverpb.SetEnv\x12\x35\n\x08UnsetEnv\x12\x15.sliverpb.UnsetEnvReq\x1a\x12.sliverpb.UnsetEnv\x12\x35\n\x08\x42\x61\x63kdoor\x12\x15.sliverpb.BackdoorReq\x1a\x12.sliverpb.Backdoor\x12\x41\n\x0cRegistryRead\x12\x19.sliverpb.RegistryReadReq\x1a\x16.sliverpb.RegistryRead\x12\x44\n\rRegistryWrite\x12\x1a.sliverpb.RegistryWriteReq\x1a\x17.sliverpb.RegistryWrite\x12P\n\x11RegistryCreateKey\x12\x1e.sliverpb.RegistryCreateKeyReq\x1a\x1b.sliverpb.RegistryCreateKey\x12P\n\x11RegistryDeleteKey\x12\x1e.sliverpb.RegistryDeleteKeyReq\x1a\x1b.sliverpb.RegistryDeleteKey\x12T\n\x13RegistryListSubKeys\x12\x1f.sliverpb.RegistrySubKeyListReq\x1a\x1c.sliverpb.RegistrySubKeyList\x12S\n\x12RegistryListValues\x12\x1f.sliverpb.RegistryListValuesReq\x1a\x1c.sliverpb.RegistryValuesList\x12>\n\rRunSSHCommand\x12\x17.sliverpb.SSHCommandReq\x1a\x14.sliverpb.SSHCommand\x12\x38\n\tHijackDLL\x12\x16.clientpb.DllHijackReq\x1a\x13.clientpb.DllHijack\x12\x35\n\x08GetPrivs\x12\x15.sliverpb.GetPrivsReq\x1a\x12.sliverpb.GetPrivs\x12W\n\x15StartRportFwdListener\x12\".sliverpb.RportFwdStartListenerReq\x1a\x1a.sliverpb.RportFwdListener\x12S\n\x14GetRportFwdListeners\x12\x1e.sliverpb.RportFwdListenersReq\x1a\x1b.sliverpb.RportFwdListeners\x12U\n\x14StopRportFwdListener\x12!.sliverpb.RportFwdStopListenerReq\x1a\x1a.sliverpb.RportFwdListener\x12;\n\x0bOpenSession\x12\x15.sliverpb.OpenSession\x1a\x15.sliverpb.OpenSession\x12\x37\n\x0c\x43loseSession\x12\x16.sliverpb.CloseSession\x1a\x0f.commonpb.Empty\x12P\n\x11RegisterExtension\x12\x1e.sliverpb.RegisterExtensionReq\x1a\x1b.sliverpb.RegisterExtension\x12\x44\n\rCallExtension\x12\x1a.sliverpb.CallExtensionReq\x1a\x17.sliverpb.CallExtension\x12G\n\x0eListExtensions\x12\x1b.sliverpb.ListExtensionsReq\x1a\x18.sliverpb.ListExtensions\x12N\n\x12WGStartPortForward\x12\x1f.sliverpb.WGPortForwardStartReq\x1a\x17.sliverpb.WGPortForward\x12L\n\x11WGStopPortForward\x12\x1e.sliverpb.WGPortForwardStopReq\x1a\x17.sliverpb.WGPortForward\x12<\n\x0cWGStartSocks\x12\x19.sliverpb.WGSocksStartReq\x1a\x11.sliverpb.WGSocks\x12:\n\x0bWGStopSocks\x12\x18.sliverpb.WGSocksStopReq\x1a\x11.sliverpb.WGSocks\x12K\n\x10WGListForwarders\x12\x1c.sliverpb.WGTCPForwardersReq\x1a\x19.sliverpb.WGTCPForwarders\x12K\n\x12WGListSocksServers\x12\x1b.sliverpb.WGSocksServersReq\x1a\x18.sliverpb.WGSocksServers\x12,\n\x05Shell\x12\x12.sliverpb.ShellReq\x1a\x0f.sliverpb.Shell\x12\x32\n\x07Portfwd\x12\x14.sliverpb.PortfwdReq\x1a\x11.sliverpb.Portfwd\x12/\n\x0b\x43reateSocks\x12\x0f.sliverpb.Socks\x1a\x0f.sliverpb.Socks\x12.\n\nCloseSocks\x12\x0f.sliverpb.Socks\x1a\x0f.commonpb.Empty\x12:\n\nSocksProxy\x12\x13.sliverpb.SocksData\x1a\x13.sliverpb.SocksData(\x01\x30\x01\x12\x32\n\x0c\x43reateTunnel\x12\x10.sliverpb.Tunnel\x1a\x10.sliverpb.Tunnel\x12\x30\n\x0b\x43loseTunnel\x12\x10.sliverpb.Tunnel\x1a\x0f.commonpb.Empty\x12<\n\nTunnelData\x12\x14.sliverpb.TunnelData\x1a\x14.sliverpb.TunnelData(\x01\x30\x01\x12,\n\x06\x45vents\x12\x0f.commonpb.Empty\x1a\x0f.clientpb.Event0\x01\x42,Z*github.com/bishopfox/sliver/protobuf/rpcpbb\x06proto3"
21 | )
22 |
23 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
24 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "rpcpb.services_pb2", globals())
25 | if _descriptor._USE_C_DESCRIPTORS == False:
26 |
27 | DESCRIPTOR._options = None
28 | DESCRIPTOR._serialized_options = b"Z*github.com/bishopfox/sliver/protobuf/rpcpb"
29 | _SLIVERRPC._serialized_start = 101
30 | _SLIVERRPC._serialized_end = 7881
31 | # @@protoc_insertion_point(module_scope)
32 |
--------------------------------------------------------------------------------
/docs/protobuf/sliver_pb2.rst:
--------------------------------------------------------------------------------
1 | Sliver Protobuf
2 | ===============
3 |
4 | This module contains the Sliver Protobuf definitions, Sliver Protobuf messages are
5 | passed between the client, server, and implant.
6 |
7 |
8 |
9 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Backdoor
10 | :members:
11 |
12 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.BackdoorReq
13 | :members:
14 |
15 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.BeaconRegister
16 | :members:
17 |
18 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.BeaconTasks
19 | :members:
20 |
21 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.CallExtension
22 | :members:
23 |
24 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.CallExtensionReq
25 | :members:
26 |
27 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.CdReq
28 | :members:
29 |
30 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.CloseSession
31 | :members:
32 |
33 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.CurrentTokenOwner
34 | :members:
35 |
36 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.CurrentTokenOwnerReq
37 | :members:
38 |
39 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.DNSBlockHeader
40 | :members:
41 |
42 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Envelope
43 | :members:
44 |
45 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.EnvInfo
46 | :members:
47 |
48 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.EnvReq
49 | :members:
50 |
51 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Execute
52 | :members:
53 |
54 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ExecuteAssembly
55 | :members:
56 |
57 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ExecuteAssemblyReq
58 | :members:
59 |
60 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ExecuteReq
61 | :members:
62 |
63 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ExecuteWindowsReq
64 | :members:
65 |
66 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.FileInfo
67 | :members:
68 |
69 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.GetPrivs
70 | :members:
71 |
72 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.GetPrivsReq
73 | :members:
74 |
75 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.GetSystem
76 | :members:
77 |
78 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.HTTPSessionInit
79 | :members:
80 |
81 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Ifconfig
82 | :members:
83 |
84 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.IfconfigReq
85 | :members:
86 |
87 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Impersonate
88 | :members:
89 |
90 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ImpersonateReq
91 | :members:
92 |
93 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.InvokeExecuteAssemblyReq
94 | :members:
95 |
96 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.InvokeGetSystemReq
97 | :members:
98 |
99 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.InvokeInProcExecuteAssemblyReq
100 | :members:
101 |
102 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.InvokeMigrateReq
103 | :members:
104 |
105 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.InvokeSpawnDllReq
106 | :members:
107 |
108 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.KillReq
109 | :members:
110 |
111 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ListExtensions
112 | :members:
113 |
114 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ListExtensionsReq
115 | :members:
116 |
117 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Ls
118 | :members:
119 |
120 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.LsReq
121 | :members:
122 |
123 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.MakeTokenReq
124 | :members:
125 |
126 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Migrate
127 | :members:
128 |
129 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Mkdir
130 | :members:
131 |
132 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.MkdirReq
133 | :members:
134 |
135 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Mv
136 | :members:
137 |
138 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.MvReq
139 | :members:
140 |
141 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.NetConnPivot
142 | :members:
143 |
144 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.NetInterface
145 | :members:
146 |
147 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Netstat
148 | :members:
149 |
150 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.NetstatReq
151 | :members:
152 |
153 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.OpenSession
154 | :members:
155 |
156 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Ping
157 | :members:
158 |
159 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotHello
160 | :members:
161 |
162 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotListener
163 | :members:
164 |
165 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotListeners
166 | :members:
167 |
168 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotListenersReq
169 | :members:
170 |
171 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotPeer
172 | :members:
173 |
174 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotPeerEnvelope
175 | :members:
176 |
177 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotPeerFailure
178 | :members:
179 |
180 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotPing
181 | :members:
182 |
183 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotServerKeyExchange
184 | :members:
185 |
186 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotStartListenerReq
187 | :members:
188 |
189 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PivotStopListenerReq
190 | :members:
191 |
192 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PollInterval
193 | :members:
194 |
195 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PollIntervalReq
196 | :members:
197 |
198 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Portfwd
199 | :members:
200 |
201 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PortfwdReq
202 | :members:
203 |
204 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ProcessDump
205 | :members:
206 |
207 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ProcessDumpReq
208 | :members:
209 |
210 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Ps
211 | :members:
212 |
213 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PsReq
214 | :members:
215 |
216 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Pwd
217 | :members:
218 |
219 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.PwdReq
220 | :members:
221 |
222 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Reconfigure
223 | :members:
224 |
225 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ReconfigureReq
226 | :members:
227 |
228 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Register
229 | :members:
230 |
231 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegisterExtension
232 | :members:
233 |
234 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegisterExtensionReq
235 | :members:
236 |
237 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryCreateKey
238 | :members:
239 |
240 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryCreateKeyReq
241 | :members:
242 |
243 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryDeleteKey
244 | :members:
245 |
246 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryDeleteKeyReq
247 | :members:
248 |
249 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryListValuesReq
250 | :members:
251 |
252 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryRead
253 | :members:
254 |
255 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryReadReq
256 | :members:
257 |
258 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistrySubKeyList
259 | :members:
260 |
261 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistrySubKeyListReq
262 | :members:
263 |
264 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryValuesList
265 | :members:
266 |
267 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryWrite
268 | :members:
269 |
270 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RegistryWriteReq
271 | :members:
272 |
273 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RemoveServiceReq
274 | :members:
275 |
276 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RevToSelf
277 | :members:
278 |
279 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RevToSelfReq
280 | :members:
281 |
282 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Rm
283 | :members:
284 |
285 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RmReq
286 | :members:
287 |
288 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RunAs
289 | :members:
290 |
291 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.RunAsReq
292 | :members:
293 |
294 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Screenshot
295 | :members:
296 |
297 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ScreenshotReq
298 | :members:
299 |
300 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ServiceInfo
301 | :members:
302 |
303 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ServiceInfoReq
304 | :members:
305 |
306 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SessionRegister
307 | :members:
308 |
309 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SetEnv
310 | :members:
311 |
312 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SetEnvReq
313 | :members:
314 |
315 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Shell
316 | :members:
317 |
318 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.ShellReq
319 | :members:
320 |
321 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Sideload
322 | :members:
323 |
324 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SideloadReq
325 | :members:
326 |
327 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Socks
328 | :members:
329 |
330 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SocksData
331 | :members:
332 |
333 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SockTabEntry
334 | :members:
335 |
336 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SpawnDll
337 | :members:
338 |
339 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SpawnDllReq
340 | :members:
341 |
342 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SSHCommand
343 | :members:
344 |
345 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.SSHCommandReq
346 | :members:
347 |
348 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.StartServiceReq
349 | :members:
350 |
351 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.StopServiceReq
352 | :members:
353 |
354 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Task
355 | :members:
356 |
357 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.TaskReq
358 | :members:
359 |
360 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Terminate
361 | :members:
362 |
363 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.TerminateReq
364 | :members:
365 |
366 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Tunnel
367 | :members:
368 |
369 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.TunnelData
370 | :members:
371 |
372 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.UnsetEnv
373 | :members:
374 |
375 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.UnsetEnvReq
376 | :members:
377 |
378 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.Upload
379 | :members:
380 |
381 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.UploadReq
382 | :members:
383 |
384 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGPortForward
385 | :members:
386 |
387 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGPortForwardStartReq
388 | :members:
389 |
390 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGPortForwardStopReq
391 | :members:
392 |
393 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGSocks
394 | :members:
395 |
396 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGSocksServer
397 | :members:
398 |
399 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGSocksServers
400 | :members:
401 |
402 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGSocksServersReq
403 | :members:
404 |
405 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGSocksStartReq
406 | :members:
407 |
408 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGSocksStopReq
409 | :members:
410 |
411 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGTCPForwarder
412 | :members:
413 |
414 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGTCPForwarders
415 | :members:
416 |
417 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WGTCPForwardersReq
418 | :members:
419 |
420 | .. autoclass:: sliver.pb.sliverpb.sliver_pb2.WindowsPrivilegeEntry
421 | :members:
--------------------------------------------------------------------------------
/tests/test_client.py:
--------------------------------------------------------------------------------
1 | import os
2 | from pathlib import Path
3 |
4 | from ward import fixture, skip, test
5 |
6 | from sliver import SliverClient, SliverClientConfig
7 | from sliver.pb.clientpb.client_pb2 import (
8 | ImplantC2,
9 | ImplantConfig,
10 | ImplantProfile,
11 | OutputFormat,
12 | StageProtocol,
13 | )
14 |
15 |
16 | @fixture(scope="global")
17 | async def sliver_client() -> SliverClient:
18 | CONFIG_PATH = Path("~/.sliver-client/configs/sliverpy.cfg").expanduser()
19 | config = SliverClientConfig.parse_config_file(CONFIG_PATH)
20 | client = SliverClient(config)
21 | await client.connect()
22 | return client
23 |
24 |
25 | @fixture(scope="global")
26 | async def implant_config() -> ImplantConfig:
27 | return ImplantConfig(
28 | IsBeacon=False,
29 | Name="sliver-pytest-" + os.urandom(8).hex(),
30 | GOARCH="amd64",
31 | GOOS="linux",
32 | Format=OutputFormat.EXECUTABLE,
33 | ObfuscateSymbols=False,
34 | C2=[ImplantC2(Priority=0, URL="http://localhost:80")],
35 | )
36 |
37 |
38 | @fixture(scope="global")
39 | def sliverpy_random_name() -> str:
40 | return "sliver-pytest-" + os.urandom(8).hex()
41 |
42 |
43 | @fixture(scope="global")
44 | def data_dir() -> Path:
45 | return Path(__file__).parent / "data"
46 |
47 |
48 | @test("Client can get version", tags=["client"])
49 | async def _(client: SliverClient = sliver_client): # type: ignore
50 | assert await client.version()
51 |
52 |
53 | @test("Client can list operators", tags=["client"])
54 | async def _(client: SliverClient = sliver_client): # type: ignore
55 | assert await client.operators()
56 |
57 |
58 | @test("Client can list beacons", tags=["client"])
59 | async def _(client: SliverClient = sliver_client): # type: ignore
60 | assert await client.beacons()
61 |
62 |
63 | @test("Client can list beacons by ID", tags=["client"])
64 | async def _(client: SliverClient = sliver_client): # type: ignore
65 | beacons = await client.beacons()
66 | assert await client.beacon_by_id(beacons[0].ID)
67 |
68 |
69 | @test("Client can rename a beacon", tags=["client"])
70 | async def _(client: SliverClient = sliver_client): # type: ignore
71 | beacons = await client.beacons()
72 | beacon_name = beacons[0].Name
73 | beacon_id = beacons[0].ID
74 | await client.rename_beacon(beacon_id, "sliver-pytest")
75 |
76 | beacon = await client.beacon_by_id(beacon_id)
77 | assert beacon.Name == "sliver-pytest"
78 |
79 | await client.rename_beacon(beacon.ID, beacon_name)
80 |
81 |
82 | @test("Client can list sessions", tags=["client"])
83 | async def _(client: SliverClient = sliver_client): # type: ignore
84 | assert await client.sessions()
85 |
86 |
87 | @test("Client can list sessions by ID")
88 | async def _(client: SliverClient = sliver_client): # type: ignore
89 | sessions = await client.sessions()
90 | assert await client.session_by_id(sessions[0].ID)
91 |
92 |
93 | @test("Client can rename a session", tags=["client"])
94 | async def _(client: SliverClient = sliver_client): # type: ignore
95 | sessions = await client.sessions()
96 | session_name = sessions[0].Name
97 | session_id = sessions[0].ID
98 | await client.rename_session(session_id, "sliver-pytest")
99 |
100 | session = await client.session_by_id(session_id)
101 | assert session.Name == "sliver-pytest"
102 |
103 | await client.rename_session(session.ID, session_name)
104 |
105 |
106 | @test("Client can list implant builds", tags=["client"])
107 | async def _(client: SliverClient = sliver_client): # type: ignore
108 | assert await client.implant_builds()
109 |
110 |
111 | @test("Client can generate a new implant", tags=["client"])
112 | async def _(
113 | client: SliverClient = sliver_client, config: ImplantConfig = implant_config # type: ignore
114 | ):
115 |
116 | assert await client.generate_implant(config)
117 |
118 |
119 | @test("Client can regenerate an implant", tags=["client"])
120 | async def _(
121 | client: SliverClient = sliver_client, config: ImplantConfig = implant_config # type: ignore
122 | ):
123 | assert await client.regenerate_implant(config.Name)
124 |
125 |
126 | @test("Client can save implant profiles", tags=["client"])
127 | async def _(
128 | client: SliverClient = sliver_client, # type: ignore
129 | config: ImplantConfig = implant_config, # type: ignore
130 | name: str = sliverpy_random_name, # type: ignore
131 | ):
132 | implant_profile = ImplantProfile(Name=name, Config=config)
133 | assert await client.save_implant_profile(implant_profile)
134 |
135 |
136 | @test("Client can list implant profiles", tags=["client"])
137 | async def _(client: SliverClient = sliver_client, name: str = sliverpy_random_name): # type: ignore
138 | assert name in [profile.Name for profile in await client.implant_profiles()]
139 |
140 |
141 | @test("Client can delete implant profiles", tags=["client"])
142 | async def _(client: SliverClient = sliver_client, name: str = sliverpy_random_name): # type: ignore
143 | await client.delete_implant_profile(name)
144 | assert name not in [profile.Name for profile in await client.implant_profiles()]
145 |
146 |
147 | @test("Client can delete implant builds", tags=["client"])
148 | async def _(
149 | client: SliverClient = sliver_client, # type: ignore
150 | config: ImplantConfig = implant_config, # type: ignore
151 | ):
152 | await client.delete_implant_build(config.Name)
153 | assert config.Name not in [build for build in await client.implant_builds()]
154 |
155 |
156 | @test("Client can list jobs", tags=["client"])
157 | async def _(client: SliverClient = sliver_client): # type: ignore
158 | assert await client.jobs()
159 |
160 |
161 | @test("Client can get job by ID", tags=["client"])
162 | async def _(client: SliverClient = sliver_client): # type: ignore
163 | jobs = await client.jobs()
164 | assert await client.job_by_id(jobs[0].ID)
165 |
166 |
167 | @test("Client can get job by port", tags=["client"])
168 | async def _(client: SliverClient = sliver_client): # type: ignore
169 | assert await client.job_by_port(80)
170 |
171 |
172 | @test("Client can kill jobs", tags=["client"])
173 | async def _(client: SliverClient = sliver_client): # type: ignore
174 | jobs = await client.jobs()
175 | for job in jobs:
176 | if job.Port != 80:
177 | await client.kill_job(job.ID)
178 | assert len(await client.jobs()) == 1
179 |
180 |
181 | @test("Client can start HTTP listener on port 8080", tags=["client"])
182 | async def _(client: SliverClient = sliver_client): # type: ignore
183 | assert await client.start_http_listener()
184 |
185 |
186 | @test("Client can start HTTPS listener on port 8443", tags=["client"])
187 | async def _(client: SliverClient = sliver_client): # type: ignore
188 | assert await client.start_https_listener()
189 |
190 |
191 | @test("Client can start DNS listener on port 53", tags=["client"])
192 | async def _(client: SliverClient = sliver_client): # type: ignore
193 | assert await client.start_dns_listener(domains=["sliverpy.local"])
194 |
195 |
196 | @test("Client can start MTLS listener on port 8888", tags=["client"])
197 | async def _(client: SliverClient = sliver_client): # type: ignore
198 | assert await client.start_mtls_listener()
199 |
200 |
201 | @test("Client can start TCP stager listener on port 9000", tags=["client"])
202 | async def _(client: SliverClient = sliver_client): # type: ignore
203 | assert await client.start_tcp_stager_listener("0.0.0.0", 9000, b"sliver-pytest")
204 |
205 |
206 | @test("Client can start HTTP stager listener on port 9001", tags=["client"])
207 | async def _(client: SliverClient = sliver_client): # type: ignore
208 | assert await client.start_http_stager_listener("0.0.0.0", 9001, b"sliver-pytest")
209 |
210 |
211 | @skip("Cert generation not implemented")
212 | @test("Client can start HTTPS stager listener on port 9002", tags=["client"])
213 | async def _(client: SliverClient = sliver_client): # type: ignore
214 | assert await client.start_http_stager_listener("0.0.0.0", 9002, b"sliver-pytest")
215 |
216 |
217 | @test("Client can generate a WireGuard IP")
218 | async def _(client: SliverClient = sliver_client): # type: ignore
219 | assert await client.generate_wg_ip()
220 |
221 |
222 | @skip("Something is wrong with killing WG listeners on the server")
223 | @test("Client can start WG listener on ports 5353/8889/1338", tags=["client"])
224 | async def _(client: SliverClient = sliver_client): # type: ignore
225 | ip = await client.generate_wg_ip()
226 | print(ip.IP)
227 | assert await client.start_wg_listener(ip.IP, 5353, 8889, 1338)
228 |
229 |
230 | @test("Client can generate a WireGuard client config", tags=["client"])
231 | async def _(client: SliverClient = sliver_client): # type: ignore
232 | assert await client.generate_wg_client_config()
233 |
234 |
235 | @test("Client can kill jobs (again) except WireGuard", tags=["client"])
236 | async def _(client: SliverClient = sliver_client): # type: ignore
237 | jobs = await client.jobs()
238 | for job in jobs:
239 | if job.Port != 80:
240 | await client.kill_job(job.ID)
241 | assert len(await client.jobs()) <= 2
242 |
243 |
244 | @test("Client can generate an MSF stager", tags=["client"])
245 | async def _(client: SliverClient = sliver_client): # type: ignore
246 | stager = await client.generate_msf_stager(
247 | arch="amd64",
248 | format="raw",
249 | host="127.0.0.1",
250 | port=9000,
251 | os="windows",
252 | protocol=StageProtocol.TCP,
253 | badchars=[],
254 | )
255 | assert Path(stager.File.Name)
256 |
257 |
258 | @test("Client can generate Donut shellcode", tags=["client"])
259 | async def _(client: SliverClient = sliver_client, data_dir: Path = data_dir): # type: ignore
260 | dll_data = Path(data_dir / "test_write.exe").read_bytes()
261 | assert await client.shellcode(dll_data, "Main")
262 |
263 |
264 | @test("Client can interact with a session", tags=["client"])
265 | async def _(client: SliverClient = sliver_client): # type: ignore
266 | sessions = await client.sessions()
267 | session = sessions[0]
268 | assert await client.interact_session(session.ID)
269 |
270 |
271 | @test("Client can interact with a beacon", tags=["client"])
272 | async def _(client: SliverClient = sliver_client): # type: ignore
273 | beacons = await client.beacons()
274 | beacon = beacons[0]
275 | assert await client.interact_beacon(beacon.ID)
276 |
277 |
278 | @test("Client can add website content", tags=["client"])
279 | async def _(client: SliverClient = sliver_client, data_dir: Path = data_dir): # type: ignore
280 | html_content = Path(data_dir / "website.html").read_bytes()
281 | assert await client.add_website_content(
282 | "sliverpy-test", "sliverpy", "test/html", html_content
283 | )
284 |
285 |
286 | @test("Client can update website content", tags=["client"])
287 | async def _(client: SliverClient = sliver_client, data_dir: Path = data_dir): # type: ignore
288 | html_content = Path(data_dir / "website_update.html").read_bytes()
289 | assert await client.add_website_content(
290 | "sliverpy-test", "sliverpy", "test/html", html_content
291 | )
292 |
293 |
294 | @test("Client can list websites", tags=["client"])
295 | async def _(client: SliverClient = sliver_client): # type: ignore
296 | assert "sliverpy-test" in [website.Name for website in await client.websites()]
297 |
298 |
299 | @test("Client can remove website content", tags=["client"])
300 | async def _(client: SliverClient = sliver_client): # type: ignore
301 | assert await client.remove_website_content("sliverpy-test", ["sliverpy"])
302 |
303 |
304 | @test("Client can remove website", tags=["client"])
305 | async def _(client: SliverClient = sliver_client): # type: ignore
306 | await client.remove_website("sliverpy-test")
307 | assert "sliverpy-test" not in [website.Name for website in await client.websites()]
308 |
--------------------------------------------------------------------------------
/src/sliver/beacon.py:
--------------------------------------------------------------------------------
1 | """
2 | Sliver Implant Framework
3 | Copyright (C) 2022 Bishop Fox
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 | """
16 |
17 | import asyncio
18 | import functools
19 | import logging
20 | from typing import Any, Dict, List, Tuple
21 |
22 | import grpc
23 |
24 | from ._protocols import PbWithRequestProp
25 | from .interactive import BaseInteractiveCommands
26 | from .pb.rpcpb.services_pb2_grpc import SliverRPCStub
27 | from .protobuf import client_pb2, common_pb2, sliver_pb2
28 |
29 |
30 | class BaseBeacon:
31 | def __init__(
32 | self,
33 | beacon: client_pb2.Beacon,
34 | channel: grpc.aio.Channel,
35 | timeout: int = 60,
36 | ):
37 | """Base class for Beacon classes.
38 |
39 | :param beacon: Beacon protobuf object.
40 | :type beacon: client_pb2.Beacon
41 | :param channel: A gRPC channel.
42 | :type channel: grpc.aio.Channel
43 | :param timeout: Seconds to wait for timeout, defaults to TIMEOUT
44 | :type timeout: int, optional
45 | """
46 | self._log = logging.getLogger(self.__class__.__name__)
47 | self._channel = channel
48 | self._beacon = beacon
49 | self._stub = SliverRPCStub(channel)
50 | self.timeout = timeout
51 | self.beacon_tasks: Dict[str, Tuple[asyncio.Future, Any]] = {}
52 | asyncio.get_event_loop().create_task(self.taskresult_events())
53 |
54 | @property
55 | def beacon_id(self) -> str:
56 | """Beacon ID"""
57 | return self._beacon.ID
58 |
59 | @property
60 | def name(self) -> str:
61 | """Beacon name"""
62 | return self._beacon.Name
63 |
64 | @property
65 | def hostname(self) -> str:
66 | """Beacon hostname"""
67 | return self._beacon.Hostname
68 |
69 | @property
70 | def uuid(self) -> str:
71 | """Beacon UUID"""
72 | return self._beacon.UUID
73 |
74 | @property
75 | def username(self) -> str:
76 | """Username"""
77 | return self._beacon.Username
78 |
79 | @property
80 | def uid(self) -> str:
81 | """User ID"""
82 | return self._beacon.UID
83 |
84 | @property
85 | def gid(self) -> str:
86 | """Group ID"""
87 | return self._beacon.GID
88 |
89 | @property
90 | def os(self) -> str:
91 | """Operating system"""
92 | return self._beacon.OS
93 |
94 | @property
95 | def arch(self) -> str:
96 | """Architecture"""
97 | return self._beacon.Arch
98 |
99 | @property
100 | def transport(self) -> str:
101 | """Transport Method"""
102 | return self._beacon.Transport
103 |
104 | @property
105 | def remote_address(self) -> str:
106 | """Remote address"""
107 | return self._beacon.RemoteAddress
108 |
109 | @property
110 | def pid(self) -> int:
111 | """Process ID"""
112 | return self._beacon.PID
113 |
114 | @property
115 | def filename(self) -> str:
116 | """Beacon filename"""
117 | return self._beacon.Filename
118 |
119 | @property
120 | def last_checkin(self) -> int:
121 | """Last check in time"""
122 | return self._beacon.LastCheckin
123 |
124 | @property
125 | def active_c2(self) -> str:
126 | """Active C2"""
127 | return self._beacon.ActiveC2
128 |
129 | @property
130 | def version(self) -> str:
131 | """Version"""
132 | return self._beacon.Version
133 |
134 | @property
135 | def reconnect_interval(self) -> int:
136 | """Reconnect interval"""
137 | return self._beacon.ReconnectInterval
138 |
139 | def _request(self, pb: PbWithRequestProp):
140 | """
141 | Set request attributes based on current beacon, I'd prefer to return a generic Request
142 | object, but protobuf for whatever reason doesn't let you assign this type of field directly.
143 |
144 | `pb` in this case is any protobuf message with a .Request field.
145 |
146 | :param pb: A protobuf request object.
147 | """
148 | pb.Request.BeaconID = self._beacon.ID
149 | pb.Request.Timeout = self.timeout - 1
150 | pb.Request.Async = True
151 | return pb
152 |
153 | async def taskresult_events(self):
154 | """
155 | Monitor task events for results, resolve futures for any results
156 | we get back.
157 | """
158 | async for event in self._stub.Events(common_pb2.Empty()):
159 | if event.EventType != "beacon-taskresult":
160 | continue
161 | try:
162 | beacon_task = client_pb2.BeaconTask()
163 | beacon_task.ParseFromString(event.Data)
164 | if beacon_task.ID not in self.beacon_tasks:
165 | continue
166 | task_content = await self._stub.GetBeaconTaskContent(
167 | client_pb2.BeaconTask(ID=beacon_task.ID)
168 | )
169 | task_future, pb_object = self.beacon_tasks[beacon_task.ID]
170 | del self.beacon_tasks[beacon_task.ID]
171 | if pb_object is not None:
172 | result = pb_object()
173 | result.ParseFromString(task_content.Response)
174 | else:
175 | result = None
176 | task_future.set_result(result)
177 | except Exception as err:
178 | self._log.exception(err)
179 |
180 |
181 | def beacon_taskresult(pb_object: Any):
182 | """
183 | Wraps a class method to return a future that resolves when the
184 | beacon task result is available.
185 | """
186 |
187 | def func(method):
188 | @functools.wraps(method)
189 | async def wrapper(self, *args, **kwargs):
190 | task_response = await method(self, *args, **kwargs)
191 | self.beacon_tasks[task_response.Response.TaskID] = (
192 | asyncio.Future(),
193 | pb_object,
194 | )
195 | return self.beacon_tasks[task_response.Response.TaskID][0]
196 |
197 | return wrapper
198 |
199 | return func
200 |
201 |
202 | class InteractiveBeacon(BaseBeacon, BaseInteractiveCommands):
203 |
204 | """Wrap all commands that can be executed against a beacon mode implant"""
205 |
206 | async def interactive_session(self):
207 | pass
208 |
209 | # ---------------- Wrapped super() commands ----------------
210 |
211 | @beacon_taskresult(sliver_pb2.Ping)
212 | async def ping(self, *args, **kwargs) -> sliver_pb2.Ping:
213 | return await super().ping(*args, **kwargs)
214 |
215 | @beacon_taskresult(sliver_pb2.Ps)
216 | async def ps(self, *args, **kwargs) -> List[common_pb2.Process]:
217 | return await super().ps(*args, **kwargs)
218 |
219 | @beacon_taskresult(sliver_pb2.Terminate)
220 | async def terminate(self, *args, **kwargs) -> sliver_pb2.Terminate:
221 | return await super().terminate(*args, **kwargs)
222 |
223 | @beacon_taskresult(sliver_pb2.Ifconfig)
224 | async def ifconfig(self, *args, **kwargs) -> sliver_pb2.Ifconfig:
225 | return await super().ifconfig(*args, **kwargs)
226 |
227 | @beacon_taskresult(sliver_pb2.Netstat)
228 | async def netstat(self, *args, **kwargs) -> sliver_pb2.Netstat:
229 | return await super().netstat(*args, **kwargs)
230 |
231 | @beacon_taskresult(sliver_pb2.Ls)
232 | async def ls(self, *args, **kwargs) -> sliver_pb2.Ls:
233 | return await super().ls(*args, **kwargs)
234 |
235 | @beacon_taskresult(sliver_pb2.Pwd)
236 | async def cd(self, *args, **kwargs) -> sliver_pb2.Pwd:
237 | return await super().cd(*args, **kwargs)
238 |
239 | @beacon_taskresult(sliver_pb2.Pwd)
240 | async def pwd(self, *args, **kwargs) -> sliver_pb2.Pwd:
241 | return await super().pwd(*args, **kwargs)
242 |
243 | @beacon_taskresult(sliver_pb2.Rm)
244 | async def rm(self, *args, **kwargs) -> sliver_pb2.Rm:
245 | return await super().rm(*args, **kwargs)
246 |
247 | @beacon_taskresult(sliver_pb2.Mkdir)
248 | async def mkdir(self, *args, **kwargs) -> sliver_pb2.Mkdir:
249 | return await super().mkdir(*args, **kwargs)
250 |
251 | @beacon_taskresult(sliver_pb2.Download)
252 | async def download(self, *args, **kwargs) -> sliver_pb2.Download:
253 | return await super().download(*args, **kwargs)
254 |
255 | @beacon_taskresult(sliver_pb2.Upload)
256 | async def upload(self, *args, **kwargs) -> sliver_pb2.Upload:
257 | return await super().upload(*args, **kwargs)
258 |
259 | @beacon_taskresult(sliver_pb2.ProcessDump)
260 | async def process_dump(self, *args, **kwargs) -> sliver_pb2.ProcessDump:
261 | return await super().process_dump(*args, **kwargs)
262 |
263 | @beacon_taskresult(sliver_pb2.RunAs)
264 | async def run_as(self, *args, **kwargs) -> sliver_pb2.RunAs:
265 | return await super().run_as(*args, **kwargs)
266 |
267 | @beacon_taskresult(sliver_pb2.Impersonate)
268 | async def impersonate(self, *args, **kwargs) -> sliver_pb2.Impersonate:
269 | return await super().impersonate(*args, **kwargs)
270 |
271 | @beacon_taskresult(sliver_pb2.RevToSelf)
272 | async def revert_to_self(self, *args, **kwargs) -> sliver_pb2.RevToSelf:
273 | return await super().revert_to_self(*args, **kwargs)
274 |
275 | @beacon_taskresult(sliver_pb2.GetSystem)
276 | async def get_system(self, *args, **kwargs) -> sliver_pb2.GetSystem:
277 | return await super().get_system(*args, **kwargs)
278 |
279 | @beacon_taskresult(sliver_pb2.Task)
280 | async def execute_shellcode(self, *args, **kwargs) -> sliver_pb2.Task:
281 | return await super().execute_shellcode(*args, **kwargs)
282 |
283 | @beacon_taskresult(None)
284 | async def msf(self, *args, **kwargs) -> None:
285 | return await super().msf(*args, **kwargs)
286 |
287 | @beacon_taskresult(None)
288 | async def msf_remote(self, *args, **kwargs) -> None:
289 | return await super().msf_remote(*args, **kwargs)
290 |
291 | @beacon_taskresult(sliver_pb2.ExecuteAssembly)
292 | async def execute_assembly(self, *args, **kwargs) -> sliver_pb2.ExecuteAssembly:
293 | return await super().execute_assembly(*args, **kwargs)
294 |
295 | @beacon_taskresult(sliver_pb2.Migrate)
296 | async def migrate(self, *args, **kwargs) -> sliver_pb2.Migrate:
297 | return await super().migrate(*args, **kwargs)
298 |
299 | @beacon_taskresult(sliver_pb2.Execute)
300 | async def execute(self, *args, **kwargs) -> sliver_pb2.Execute:
301 | return await super().execute(*args, **kwargs)
302 |
303 | @beacon_taskresult(sliver_pb2.Sideload)
304 | async def sideload(self, *args, **kwargs) -> sliver_pb2.Sideload:
305 | return await super().sideload(*args, **kwargs)
306 |
307 | @beacon_taskresult(sliver_pb2.SpawnDll)
308 | async def spawn_dll(self, *args, **kwargs) -> sliver_pb2.SpawnDll:
309 | return await super().spawn_dll(*args, **kwargs)
310 |
311 | @beacon_taskresult(sliver_pb2.Screenshot)
312 | async def screenshot(self, *args, **kwargs) -> sliver_pb2.Screenshot:
313 | return await super().screenshot(*args, **kwargs)
314 |
315 | @beacon_taskresult(sliver_pb2.MakeToken)
316 | async def make_token(self, *args, **kwargs) -> sliver_pb2.MakeToken:
317 | return await super().make_token(*args, **kwargs)
318 |
319 | @beacon_taskresult(sliver_pb2.EnvInfo)
320 | async def get_env(self, *args, **kwargs) -> sliver_pb2.EnvInfo:
321 | return await super().get_env(*args, **kwargs)
322 |
323 | @beacon_taskresult(sliver_pb2.SetEnv)
324 | async def set_env(self, *args, **kwargs) -> sliver_pb2.SetEnv:
325 | return await super().set_env(*args, **kwargs)
326 |
327 | @beacon_taskresult(sliver_pb2.RegistryRead)
328 | async def registry_read(self, *args, **kwargs) -> sliver_pb2.RegistryRead:
329 | return await super().registry_read(*args, **kwargs)
330 |
331 | @beacon_taskresult(sliver_pb2.RegistryWrite)
332 | async def registry_write(self, *args, **kwargs) -> sliver_pb2.RegistryWrite:
333 | return await super().registry_write(*args, **kwargs)
334 |
335 | @beacon_taskresult(sliver_pb2.RegistryCreateKey)
336 | async def registry_create_key(
337 | self, *args, **kwargs
338 | ) -> sliver_pb2.RegistryCreateKey:
339 | return await super().registry_create_key(*args, **kwargs)
340 |
--------------------------------------------------------------------------------
/docs/getting-started.rst:
--------------------------------------------------------------------------------
1 | Getting Started
2 | ===============
3 |
4 | To get started first download the `latest Sliver server release `_
5 | you'll need v1.5 or later to use SliverPy.
6 |
7 | SliverPy connects to the Sliver server using "multiplayer mode" which can be enabled in the server console or using
8 | the Sliver server's command line interface. In order to connect to the server you'll need to first generate an operator
9 | configuration file. Clients connect to the Sliver server using mutual TLS (mTLS) and these operator configuration files
10 | contain the per-user TLS certificates (and other metadata) needed to make the connection to the server. These configuration
11 | files contain the user's private key and should be treated as if they were a credential.
12 |
13 | In the interactive console, the ``new-operator`` command is used to generate an operator configuration file. You'll need to
14 | subsequently enable multiplayer mode using the ``multiplayer`` command to start the multiplayer server listener. See the
15 | ``--help`` for each of these commands for more details:
16 |
17 | .. code-block:: console
18 |
19 | $ ./sliver-server
20 |
21 | sliver > new-operator --name zer0cool --lhost localhost --save ./zer0cool.cfg
22 | [*] Generating new client certificate, please wait ...
23 | [*] Saved new client config to: /Users/zer0cool/zer0cool.cfg
24 |
25 | sliver > multiplayer
26 | [*] Multiplayer mode enabled!
27 |
28 |
29 | Alternatively, the command line interface can be used to generate operator configuration files and start the multiplayer listener
30 | without entering into the interactive console. See each subcommand's ``--help`` for more details:
31 |
32 | .. code-block:: console
33 |
34 | $ ./sliver-server operator --name zer0cool --lhost localhost --save ./zer0cool.cfg
35 | $ ./sliver-server daemon
36 |
37 |
38 | Now with the server running in the background you can connect to Sliver remotely (or locally) using the ``.cfg`` with SliverPy!
39 |
40 | Connect Example
41 | ^^^^^^^^^^^^^^^^
42 |
43 | SliverPy is implemented using ``asyncio``, if you're unfamiliar with Python's ``asyncio`` you may want to go read up on it before continuing.
44 | I recommend starting with `this presentation `_ by Raymond Hettinger if you're completely unfamiliar with Python threads/asyncio.
45 |
46 | The main class is ``SliverClient``, which when paired with a configuration file, allows you to interact with the Sliver server, sessions, and beacons:
47 |
48 | .. code-block:: python
49 |
50 | #!/usr/bin/env python3
51 |
52 | import os
53 | import asyncio
54 | from sliver import SliverClientConfig, SliverClient
55 |
56 | CONFIG_PATH = os.path.join('path', 'to', 'default.cfg')
57 |
58 | async def main():
59 | ''' Async client connect example '''
60 | config = SliverClientConfig.parse_config_file(CONFIG_PATH)
61 | client = SliverClient(config)
62 | await client.connect()
63 | sessions = await client.sessions()
64 | print('Sessions: %r' % sessions)
65 |
66 | if __name__ == '__main__':
67 | asyncio.run(main())
68 |
69 |
70 | Protobuf / gRPC
71 | ^^^^^^^^^^^^^^^
72 |
73 | Under the hood SliverPy is communicating with the Sliver server using `Protobuf `_ and
74 | `gRPC `_. While most of the details of these libraries are abstracted for you, it may be useful to familiarize
75 | yourself with the library conventions as SliverPy operates largely on Protobuf objects which do not follow Python language conventions.
76 |
77 | There are three modules of Protobuf objects:
78 |
79 | - ``sliver.commonpb_pb2`` Contains common Protobuf objects that represent things like files and processes.
80 | - ``sliver.client_pb2`` Contains objects that are specifically passed between the client and server, but *not* to the implant.
81 | - ``sliver.sliver_pb2`` Contains objects that are passed to the client, server, and implant.
82 |
83 | **NOTE:** Protobuf objects use ``CapitolCase`` whereas the SliverPy classes/etc. use ``snake_case``.
84 |
85 | These modules contain generated code and are not easy to read. However, the source Protobuf definitions are in the `Sliver server repository `_
86 | to find the exact definitions that SliverPy is using see the `git submodule `_ in the SliverPy repository.
87 |
88 |
89 | Interactive Sessions
90 | ^^^^^^^^^^^^^^^^^^^^
91 |
92 | To interact with a Sliver session we need to create an ``InteractiveSession`` object, the easiest way to do this is using the ``SliverClient``'s
93 | ``.interact_session()`` method, which takes a session ID and returns an ``InteractiveSession`` for that ID:
94 |
95 | .. code-block:: python
96 |
97 | #!/usr/bin/env python3
98 |
99 | import os
100 | import asyncio
101 | from sliver import SliverClientConfig, SliverClient
102 |
103 | # Construct path to operator config file
104 | CONFIG_PATH = os.path.join('path', 'to', 'operator.cfg')
105 |
106 | async def main():
107 | ''' Session interact example '''
108 | config = SliverClientConfig.parse_config_file(CONFIG_PATH)
109 | client = SliverClient(config)
110 | await client.connect()
111 | sessions = await client.sessions() # <-- List Protobuf Session objects
112 | if not len(sessions):
113 | print('No sessions!')
114 | return
115 |
116 | session = await client.interact_session(sessions[0].ID) # <-- Create InteractiveSession object
117 | ls = await session.ls() # <-- Returns an Ls Protobuf object
118 | print('Listing directory contents of: %s' % ls.Path)
119 | for fi in ls.Files:
120 | print('FileName: %s (dir: %s, size: %d)' % (fi.Name, fi.IsDir, fi.Size))
121 |
122 | if __name__ == '__main__':
123 | asyncio.run(main())
124 |
125 | **NOTE:** There are two "session" related objects the Protobuf ``client_pb2.Session`` object, which contains metadata about the sessions such as
126 | the session ID, the active C2 protocol, etc. and the ``InteractiveSession`` class, which is used to interact with the session (i.e., execute commands, etc).
127 |
128 |
129 | Interactive Beacons
130 | ^^^^^^^^^^^^^^^^^^^^
131 |
132 | To interact with a Sliver beacon we need to create an ``InteractiveBeacon`` object, the easiest way to do this is using the ``SliverClient``'s
133 | ``.interact_beacon()`` method, which takes a beacon ID and returns an ``InteractiveBeacon`` for that ID:
134 |
135 | .. code-block:: python
136 |
137 | #!/usr/bin/env python3
138 |
139 | import os
140 | import asyncio
141 | from sliver import SliverClientConfig, SliverClient
142 |
143 | # Construct path to operator config file
144 | CONFIG_PATH = os.path.join('path', 'to', 'operator.cfg')
145 |
146 | async def main():
147 | ''' Session interact example '''
148 | config = SliverClientConfig.parse_config_file(CONFIG_PATH)
149 | client = SliverClient(config)
150 | await client.connect()
151 | beacons = await client.beacons() # <-- List Protobuf Session objects
152 | if not len(beacons):
153 | print('No beacons!')
154 | return
155 |
156 | beacon = await client.interact_beacon(beacons[0].ID) # <-- Create InteractiveSession object
157 | ls_task = await beacon.ls() # <-- Creates a beacon task Future
158 | print('Created beacon task: %s' % ls_task)
159 | print('Waiting for beacon task to complete ...')
160 | ls = await ls_task
161 |
162 | # Beacon Task has completed (Future was resolved)
163 | print('Listing directory contents of: %s' % ls.Path)
164 | for fi in ls.Files:
165 | print('FileName: %s (dir: %s, size: %d)' % (fi.Name, fi.IsDir, fi.Size))
166 |
167 |
168 | if __name__ == '__main__':
169 | asyncio.run(main())
170 |
171 | **NOTE:** The main difference between interacting with a session vs. a beacon, is that a beacon's command will return a ``Future`` object that eventually resolves to the task result.
172 |
173 |
174 | Realtime Events
175 | ^^^^^^^^^^^^^^^^
176 |
177 | SliverPy also supports realtime events, which are pushed from the server to the client whenever an event occurs. For example, some of the more common events you'll likely
178 | be interested in are when a new session is created or when a job starts/stops.
179 |
180 | The :class:`SliverClient` implements these real time events using ``asyncio``.
181 |
182 | Events are identified by an "event type," which is just a string set by the producer of the event. This loose form
183 | allows events to be very dynamic, however this also means there is no central authority for every event type. I
184 | recommend always filtering on expected event types. The data included in an event also depends on whatever produced
185 | the event, so you should always check that an attribute exists before accessing that attribute (with the exception of
186 | ``event.EventType`` which must exist).
187 |
188 | Here is a non exhaustive list of event types:
189 |
190 | +--------------------------+-----+----------------------------------------------------+
191 | | Event Type | | Description |
192 | +--------------------------+-----+----------------------------------------------------+
193 | | ``session-disconnected`` | | An existing session was lost |
194 | +--------------------------+-----+----------------------------------------------------+
195 | | ``session-updated`` | | An existing session was renamed / updated |
196 | +--------------------------+-----+----------------------------------------------------+
197 | | ``job-started`` | | A job was started on the server |
198 | +--------------------------+-----+----------------------------------------------------+
199 | | ``job-stopped`` | | A job stopped (due to error or user action) |
200 | +--------------------------+-----+----------------------------------------------------+
201 | | ``client-joined`` | | A new client connected to the server |
202 | +--------------------------+-----+----------------------------------------------------+
203 | | ``client-left`` | | A client disconnected from the server |
204 | +--------------------------+-----+----------------------------------------------------+
205 | | ``canary`` | | A canary was burned / triggered / etc. |
206 | +--------------------------+-----+----------------------------------------------------+
207 | | ``build`` | | A modification was made to implant builds |
208 | +--------------------------+-----+----------------------------------------------------+
209 | | ``build-completed`` | | An implant build completed (in success or failure) |
210 | +--------------------------+-----+----------------------------------------------------+
211 | | ``profile`` | | A modification was made to implant profiles |
212 | +--------------------------+-----+----------------------------------------------------+
213 | | ``website`` | | A modification was made to website(s) |
214 | +--------------------------+-----+----------------------------------------------------+
215 | | ``beacon-registered`` | | A new beacon connected to the server |
216 | +---------------------------+----+----------------------------------------------------+
217 | | ``beacon-taskresult`` | | A beacon task completed |
218 | +---------------------------+----+----------------------------------------------------+
219 |
220 |
221 | Automatically Interact With New Sessions
222 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
223 | The ``SliverClient``'s ``.on()`` method returns an async generator, which can be iterated over. ``.on()`` accepts a string or a list of strings to filter events.
224 | Additionally, ``.events()`` can be used to obtain a generator that will yield all events.
225 |
226 | Here is an example of using ``.on()`` to automatically interact with new sessions when they connect:
227 |
228 | .. code-block:: python
229 |
230 | #!/usr/bin/env python3
231 |
232 | import os
233 | import asyncio
234 | from sliver import SliverClientConfig, AsyncSliverClient, client_pb2
235 |
236 | CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".sliver-client", "configs")
237 | CONFIG_PATH = os.path.join(CONFIG_DIR, "default.cfg")
238 |
239 |
240 | async def main():
241 | ''' Client connect example '''
242 | config = SliverClientConfig.parse_config_file(CONFIG_PATH)
243 | client = AsyncSliverClient(config)
244 | await client.connect()
245 | async for event in client.on('session-connected'):
246 | print('Automatically interacting with session %s' % event.Session.ID)
247 | interact = await client.interact(event.Session.ID)
248 | exec_result = await interact.execute('whoami', [], True)
249 | print('Exec %r' % exec_result)
250 |
251 | if __name__ == '__main__':
252 | loop = asyncio.get_event_loop()
253 | loop.run_until_complete(main())
254 |
255 |
256 | SliverPy should integrate well with any framework that supports ``asyncio``, but doing so is left
257 | as an exercise for the reader.
258 |
--------------------------------------------------------------------------------
/src/sliver/pb/clientpb/client_pb2.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by the protocol buffer compiler. DO NOT EDIT!
3 | # source: clientpb/client.proto
4 | """Generated protocol buffer code."""
5 | from google.protobuf import descriptor as _descriptor
6 | from google.protobuf import descriptor_pool as _descriptor_pool
7 | from google.protobuf import symbol_database as _symbol_database
8 | from google.protobuf.internal import builder as _builder
9 |
10 | # @@protoc_insertion_point(imports)
11 |
12 | _sym_db = _symbol_database.Default()
13 |
14 |
15 | from ..commonpb import common_pb2 as commonpb_dot_common__pb2
16 |
17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
18 | b'\n\x15\x63lientpb/client.proto\x12\x08\x63lientpb\x1a\x15\x63ommonpb/common.proto"\x83\x01\n\x07Version\x12\r\n\x05Major\x18\x01 \x01(\x05\x12\r\n\x05Minor\x18\x02 \x01(\x05\x12\r\n\x05Patch\x18\x03 \x01(\x05\x12\x0e\n\x06\x43ommit\x18\x04 \x01(\t\x12\r\n\x05\x44irty\x18\x05 \x01(\x08\x12\x12\n\nCompiledAt\x18\x06 \x01(\x03\x12\n\n\x02OS\x18\x07 \x01(\t\x12\x0c\n\x04\x41rch\x18\x08 \x01(\t"\xb2\x03\n\x07Session\x12\n\n\x02ID\x18\x01 \x01(\t\x12\x0c\n\x04Name\x18\x02 \x01(\t\x12\x10\n\x08Hostname\x18\x03 \x01(\t\x12\x0c\n\x04UUID\x18\x04 \x01(\t\x12\x10\n\x08Username\x18\x05 \x01(\t\x12\x0b\n\x03UID\x18\x06 \x01(\t\x12\x0b\n\x03GID\x18\x07 \x01(\t\x12\n\n\x02OS\x18\x08 \x01(\t\x12\x0c\n\x04\x41rch\x18\t \x01(\t\x12\x11\n\tTransport\x18\n \x01(\t\x12\x15\n\rRemoteAddress\x18\x0b \x01(\t\x12\x0b\n\x03PID\x18\x0c \x01(\x05\x12\x10\n\x08\x46ilename\x18\r \x01(\t\x12\x13\n\x0bLastCheckin\x18\x0e \x01(\x03\x12\x10\n\x08\x41\x63tiveC2\x18\x0f \x01(\t\x12\x0f\n\x07Version\x18\x10 \x01(\t\x12\x0f\n\x07\x45vasion\x18\x11 \x01(\x08\x12\x0e\n\x06IsDead\x18\x12 \x01(\x08\x12\x19\n\x11ReconnectInterval\x18\x13 \x01(\x03\x12\x10\n\x08ProxyURL\x18\x14 \x01(\t\x12\x0e\n\x06\x42urned\x18\x16 \x01(\x08\x12\x12\n\nExtensions\x18\x17 \x03(\t\x12\x0e\n\x06PeerID\x18\x19 \x01(\x03\x12\x0e\n\x06Locale\x18\x1a \x01(\t\x12\x14\n\x0c\x46irstContact\x18\x1b \x01(\x03"\xf5\x03\n\x06\x42\x65\x61\x63on\x12\n\n\x02ID\x18\x01 \x01(\t\x12\x0c\n\x04Name\x18\x02 \x01(\t\x12\x10\n\x08Hostname\x18\x03 \x01(\t\x12\x0c\n\x04UUID\x18\x04 \x01(\t\x12\x10\n\x08Username\x18\x05 \x01(\t\x12\x0b\n\x03UID\x18\x06 \x01(\t\x12\x0b\n\x03GID\x18\x07 \x01(\t\x12\n\n\x02OS\x18\x08 \x01(\t\x12\x0c\n\x04\x41rch\x18\t \x01(\t\x12\x11\n\tTransport\x18\n \x01(\t\x12\x15\n\rRemoteAddress\x18\x0b \x01(\t\x12\x0b\n\x03PID\x18\x0c \x01(\x05\x12\x10\n\x08\x46ilename\x18\r \x01(\t\x12\x13\n\x0bLastCheckin\x18\x0e \x01(\x03\x12\x10\n\x08\x41\x63tiveC2\x18\x0f \x01(\t\x12\x0f\n\x07Version\x18\x10 \x01(\t\x12\x0f\n\x07\x45vasion\x18\x11 \x01(\x08\x12\x0e\n\x06IsDead\x18\x12 \x01(\x08\x12\x10\n\x08ProxyURL\x18\x14 \x01(\t\x12\x19\n\x11ReconnectInterval\x18\x15 \x01(\x03\x12\x10\n\x08Interval\x18\x16 \x01(\x03\x12\x0e\n\x06Jitter\x18\x17 \x01(\x03\x12\x0e\n\x06\x42urned\x18\x18 \x01(\x08\x12\x13\n\x0bNextCheckin\x18\x19 \x01(\x03\x12\x12\n\nTasksCount\x18\x1a \x01(\x03\x12\x1b\n\x13TasksCountCompleted\x18\x1b \x01(\x03\x12\x0e\n\x06Locale\x18\x1c \x01(\t\x12\x14\n\x0c\x46irstContact\x18\x1d \x01(\x03",\n\x07\x42\x65\x61\x63ons\x12!\n\x07\x42\x65\x61\x63ons\x18\x02 \x03(\x0b\x32\x10.clientpb.Beacon"\xa9\x01\n\nBeaconTask\x12\n\n\x02ID\x18\x01 \x01(\t\x12\x10\n\x08\x42\x65\x61\x63onID\x18\x02 \x01(\t\x12\x11\n\tCreatedAt\x18\x03 \x01(\x03\x12\r\n\x05State\x18\x04 \x01(\t\x12\x0e\n\x06SentAt\x18\x05 \x01(\x03\x12\x13\n\x0b\x43ompletedAt\x18\x06 \x01(\x03\x12\x0f\n\x07Request\x18\x07 \x01(\x0c\x12\x10\n\x08Response\x18\x08 \x01(\x0c\x12\x13\n\x0b\x44\x65scription\x18\t \x01(\t"D\n\x0b\x42\x65\x61\x63onTasks\x12\x10\n\x08\x42\x65\x61\x63onID\x18\x01 \x01(\t\x12#\n\x05Tasks\x18\x02 \x03(\x0b\x32\x14.clientpb.BeaconTask";\n\tImplantC2\x12\x10\n\x08Priority\x18\x01 \x01(\r\x12\x0b\n\x03URL\x18\x02 \x01(\t\x12\x0f\n\x07Options\x18\x03 \x01(\t"\x98\x07\n\rImplantConfig\x12\n\n\x02ID\x18\x01 \x01(\t\x12\x10\n\x08IsBeacon\x18\x02 \x01(\x08\x12\x16\n\x0e\x42\x65\x61\x63onInterval\x18\x03 \x01(\x03\x12\x14\n\x0c\x42\x65\x61\x63onJitter\x18\x04 \x01(\x03\x12\x0c\n\x04GOOS\x18\x05 \x01(\t\x12\x0e\n\x06GOARCH\x18\x06 \x01(\t\x12\x0c\n\x04Name\x18\x07 \x01(\t\x12\r\n\x05\x44\x65\x62ug\x18\x08 \x01(\x08\x12\x0f\n\x07\x45vasion\x18\t \x01(\x08\x12\x18\n\x10ObfuscateSymbols\x18\n \x01(\x08\x12\x12\n\nMtlsCACert\x18\x14 \x01(\t\x12\x10\n\x08MtlsCert\x18\x15 \x01(\t\x12\x0f\n\x07MtlsKey\x18\x16 \x01(\t\x12\x14\n\x0c\x45\x43\x43PublicKey\x18\x17 \x01(\t\x12\x15\n\rECCPrivateKey\x18\x18 \x01(\t\x12\x1d\n\x15\x45\x43\x43PublicKeySignature\x18\x19 \x01(\t\x12\x1f\n\x17MinisignServerPublicKey\x18\x1a \x01(\t\x12\x18\n\x10WGImplantPrivKey\x18\x1e \x01(\t\x12\x16\n\x0eWGServerPubKey\x18\x1f \x01(\t\x12\x13\n\x0bWGPeerTunIP\x18 \x01(\t\x12\x19\n\x11WGKeyExchangePort\x18! \x01(\r\x12\x16\n\x0eWGTcpCommsPort\x18" \x01(\r\x12\x19\n\x11ReconnectInterval\x18( \x01(\x03\x12\x1b\n\x13MaxConnectionErrors\x18) \x01(\r\x12\x13\n\x0bPollTimeout\x18* \x01(\x03\x12\x1f\n\x02\x43\x32\x18\x32 \x03(\x0b\x32\x13.clientpb.ImplantC2\x12\x15\n\rCanaryDomains\x18\x33 \x03(\t\x12\x1a\n\x12\x43onnectionStrategy\x18\x34 \x01(\t\x12\x19\n\x11LimitDomainJoined\x18< \x01(\x08\x12\x15\n\rLimitDatetime\x18= \x01(\t\x12\x15\n\rLimitHostname\x18> \x01(\t\x12\x15\n\rLimitUsername\x18? \x01(\t\x12\x17\n\x0fLimitFileExists\x18@ \x01(\t\x12\x13\n\x0bLimitLocale\x18\x41 \x01(\t\x12&\n\x06\x46ormat\x18\x64 \x01(\x0e\x32\x16.clientpb.OutputFormat\x12\x13\n\x0bIsSharedLib\x18\x65 \x01(\x08\x12\x10\n\x08\x46ileName\x18\x66 \x01(\t\x12\x11\n\tIsService\x18g \x01(\x08\x12\x13\n\x0bIsShellcode\x18h \x01(\x08\x12\x11\n\tRunAtLoad\x18i \x01(\x08"a\n\x15\x45xternalImplantConfig\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12\'\n\x06\x43onfig\x18\x02 \x01(\x0b\x32\x17.clientpb.ImplantConfig\x12\x11\n\tOTPSecret\x18\x03 \x01(\t"\\\n\x15\x45xternalImplantBinary\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12\x17\n\x0fImplantConfigID\x18\x02 \x01(\t\x12\x1c\n\x04\x46ile\x18\x03 \x01(\x0b\x32\x0e.commonpb.File"\x8f\x01\n\rImplantBuilds\x12\x35\n\x07\x43onfigs\x18\x01 \x03(\x0b\x32$.clientpb.ImplantBuilds.ConfigsEntry\x1aG\n\x0c\x43onfigsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.clientpb.ImplantConfig:\x02\x38\x01"V\n\x0e\x43ompilerTarget\x12\x0c\n\x04GOOS\x18\x01 \x01(\t\x12\x0e\n\x06GOARCH\x18\x02 \x01(\t\x12&\n\x06\x46ormat\x18\x03 \x01(\x0e\x32\x16.clientpb.OutputFormat"Z\n\rCrossCompiler\x12\x12\n\nTargetGOOS\x18\x01 \x01(\t\x12\x14\n\x0cTargetGOARCH\x18\x02 \x01(\t\x12\x0e\n\x06\x43\x43Path\x18\x03 \x01(\t\x12\x0f\n\x07\x43XXPath\x18\x04 \x01(\t"\xba\x01\n\x08\x43ompiler\x12\x0c\n\x04GOOS\x18\x01 \x01(\t\x12\x0e\n\x06GOARCH\x18\x02 \x01(\t\x12)\n\x07Targets\x18\x03 \x03(\x0b\x32\x18.clientpb.CompilerTarget\x12/\n\x0e\x43rossCompilers\x18\x04 \x03(\x0b\x32\x17.clientpb.CrossCompiler\x12\x34\n\x12UnsupportedTargets\x18\x05 \x03(\x0b\x32\x18.clientpb.CompilerTarget"\x19\n\tDeleteReq\x12\x0c\n\x04Name\x18\x01 \x01(\t"\x81\x01\n\tDNSCanary\x12\x13\n\x0bImplantName\x18\x01 \x01(\t\x12\x0e\n\x06\x44omain\x18\x02 \x01(\t\x12\x11\n\tTriggered\x18\x03 \x01(\x08\x12\x16\n\x0e\x46irstTriggered\x18\x04 \x01(\t\x12\x15\n\rLatestTrigger\x18\x05 \x01(\t\x12\r\n\x05\x43ount\x18\x06 \x01(\r"1\n\x08\x43\x61naries\x12%\n\x08\x43\x61naries\x18\x01 \x03(\x0b\x32\x13.clientpb.DNSCanary"\x18\n\nUniqueWGIP\x12\n\n\x02IP\x18\x01 \x01(\t"G\n\x0eImplantProfile\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12\'\n\x06\x43onfig\x18\x02 \x01(\x0b\x32\x17.clientpb.ImplantConfig"=\n\x0fImplantProfiles\x12*\n\x08Profiles\x18\x01 \x03(\x0b\x32\x18.clientpb.ImplantProfile"$\n\rRegenerateReq\x12\x13\n\x0bImplantName\x18\x01 \x01(\t"e\n\x03Job\x12\n\n\x02ID\x18\x01 \x01(\r\x12\x0c\n\x04Name\x18\x02 \x01(\t\x12\x13\n\x0b\x44\x65scription\x18\x03 \x01(\t\x12\x10\n\x08Protocol\x18\x04 \x01(\t\x12\x0c\n\x04Port\x18\x05 \x01(\r\x12\x0f\n\x07\x44omains\x18\x06 \x03(\t"%\n\x04Jobs\x12\x1d\n\x06\x41\x63tive\x18\x01 \x03(\x0b\x32\r.clientpb.Job"\x18\n\nKillJobReq\x12\n\n\x02ID\x18\x01 \x01(\r"&\n\x07KillJob\x12\n\n\x02ID\x18\x01 \x01(\r\x12\x0f\n\x07Success\x18\x02 \x01(\x08"A\n\x0fMTLSListenerReq\x12\x0c\n\x04Host\x18\x01 \x01(\t\x12\x0c\n\x04Port\x18\x02 \x01(\r\x12\x12\n\nPersistent\x18\x03 \x01(\x08"\x1d\n\x0cMTLSListener\x12\r\n\x05JobID\x18\x01 \x01(\r"n\n\rWGListenerReq\x12\x0c\n\x04Host\x18\x06 \x01(\t\x12\x0c\n\x04Port\x18\x01 \x01(\r\x12\r\n\x05TunIP\x18\x02 \x01(\t\x12\r\n\x05NPort\x18\x03 \x01(\r\x12\x0f\n\x07KeyPort\x18\x04 \x01(\r\x12\x12\n\nPersistent\x18\x05 \x01(\x08"\x1b\n\nWGListener\x12\r\n\x05JobID\x18\x01 \x01(\r"w\n\x0e\x44NSListenerReq\x12\x0f\n\x07\x44omains\x18\x01 \x03(\t\x12\x10\n\x08\x43\x61naries\x18\x02 \x01(\x08\x12\x0c\n\x04Host\x18\x03 \x01(\t\x12\x0c\n\x04Port\x18\x04 \x01(\r\x12\x12\n\nPersistent\x18\x05 \x01(\x08\x12\x12\n\nEnforceOTP\x18\x06 \x01(\x08"\x1c\n\x0b\x44NSListener\x12\r\n\x05JobID\x18\x01 \x01(\r"\xf7\x01\n\x0fHTTPListenerReq\x12\x0e\n\x06\x44omain\x18\x01 \x01(\t\x12\x0c\n\x04Host\x18\x02 \x01(\t\x12\x0c\n\x04Port\x18\x03 \x01(\r\x12\x0e\n\x06Secure\x18\x04 \x01(\x08\x12\x0f\n\x07Website\x18\x05 \x01(\t\x12\x0c\n\x04\x43\x65rt\x18\x06 \x01(\x0c\x12\x0b\n\x03Key\x18\x07 \x01(\x0c\x12\x0c\n\x04\x41\x43ME\x18\x08 \x01(\x08\x12\x12\n\nPersistent\x18\t \x01(\x08\x12\x12\n\nEnforceOTP\x18\n \x01(\x08\x12\x17\n\x0fLongPollTimeout\x18\x0b \x01(\x03\x12\x16\n\x0eLongPollJitter\x18\x0c \x01(\x03\x12\x15\n\rRandomizeJARM\x18\r \x01(\x08"E\n\rNamedPipesReq\x12\x10\n\x08PipeName\x18\x10 \x01(\t\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"P\n\nNamedPipes\x12\x0f\n\x07Success\x18\x01 \x01(\x08\x12\x0b\n\x03\x45rr\x18\x02 \x01(\t\x12$\n\x08Response\x18\t \x01(\x0b\x32\x12.commonpb.Response"B\n\x0bTCPPivotReq\x12\x0f\n\x07\x41\x64\x64ress\x18\x10 \x01(\t\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"N\n\x08TCPPivot\x12\x0f\n\x07Success\x18\x01 \x01(\x08\x12\x0b\n\x03\x45rr\x18\x02 \x01(\t\x12$\n\x08Response\x18\t \x01(\x0b\x32\x12.commonpb.Response"\x1d\n\x0cHTTPListener\x12\r\n\x05JobID\x18\x01 \x01(\r"/\n\x08Sessions\x12#\n\x08Sessions\x18\x01 \x03(\x0b\x32\x11.clientpb.Session">\n\tRenameReq\x12\x11\n\tSessionID\x18\x01 \x01(\t\x12\x10\n\x08\x42\x65\x61\x63onID\x18\x02 \x01(\t\x12\x0c\n\x04Name\x18\x03 \x01(\t"6\n\x0bGenerateReq\x12\'\n\x06\x43onfig\x18\x01 \x01(\x0b\x32\x17.clientpb.ImplantConfig"(\n\x08Generate\x12\x1c\n\x04\x46ile\x18\x01 \x01(\x0b\x32\x0e.commonpb.File"\x80\x01\n\x06MSFReq\x12\x0f\n\x07Payload\x18\x01 \x01(\t\x12\r\n\x05LHost\x18\x02 \x01(\t\x12\r\n\x05LPort\x18\x03 \x01(\r\x12\x0f\n\x07\x45ncoder\x18\x04 \x01(\t\x12\x12\n\nIterations\x18\x05 \x01(\x05\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"\x93\x01\n\x0cMSFRemoteReq\x12\x0f\n\x07Payload\x18\x01 \x01(\t\x12\r\n\x05LHost\x18\x02 \x01(\t\x12\r\n\x05LPort\x18\x03 \x01(\r\x12\x0f\n\x07\x45ncoder\x18\x04 \x01(\t\x12\x12\n\nIterations\x18\x05 \x01(\x05\x12\x0b\n\x03PID\x18\x08 \x01(\r\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"\x91\x01\n\x11StagerListenerReq\x12)\n\x08Protocol\x18\x01 \x01(\x0e\x32\x17.clientpb.StageProtocol\x12\x0c\n\x04Host\x18\x02 \x01(\t\x12\x0c\n\x04Port\x18\x03 \x01(\r\x12\x0c\n\x04\x44\x61ta\x18\x04 \x01(\x0c\x12\x0c\n\x04\x43\x65rt\x18\x05 \x01(\x0c\x12\x0b\n\x03Key\x18\x06 \x01(\x0c\x12\x0c\n\x04\x41\x43ME\x18\x07 \x01(\x08"\x1f\n\x0eStagerListener\x12\r\n\x05JobID\x18\x01 \x01(\r"H\n\x0fShellcodeRDIReq\x12\x0c\n\x04\x44\x61ta\x18\x01 \x01(\x0c\x12\x14\n\x0c\x46unctionName\x18\x02 \x01(\t\x12\x11\n\tArguments\x18\x03 \x01(\t"\x1c\n\x0cShellcodeRDI\x12\x0c\n\x04\x44\x61ta\x18\x01 \x01(\x0c"\x91\x01\n\x0cMsfStagerReq\x12\x0c\n\x04\x41rch\x18\x01 \x01(\t\x12\x0e\n\x06\x46ormat\x18\x02 \x01(\t\x12\x0c\n\x04Port\x18\x03 \x01(\r\x12\x0c\n\x04Host\x18\x04 \x01(\t\x12\n\n\x02OS\x18\x05 \x01(\t\x12)\n\x08Protocol\x18\x06 \x01(\x0e\x32\x17.clientpb.StageProtocol\x12\x10\n\x08\x42\x61\x64\x43hars\x18\x07 \x03(\t")\n\tMsfStager\x12\x1c\n\x04\x46ile\x18\x01 \x01(\x0b\x32\x0e.commonpb.File"s\n\x0cGetSystemReq\x12\x16\n\x0eHostingProcess\x18\x01 \x01(\t\x12\'\n\x06\x43onfig\x18\x02 \x01(\x0b\x32\x17.clientpb.ImplantConfig\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"f\n\nMigrateReq\x12\x0b\n\x03Pid\x18\x01 \x01(\r\x12\'\n\x06\x43onfig\x18\x02 \x01(\x0b\x32\x17.clientpb.ImplantConfig\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"5\n\x0f\x43reateTunnelReq\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"7\n\x0c\x43reateTunnel\x12\x11\n\tSessionID\x18\x01 \x01(\r\x12\x14\n\x08TunnelID\x18\x08 \x01(\x04\x42\x02\x30\x01"J\n\x0e\x43loseTunnelReq\x12\x14\n\x08TunnelID\x18\x08 \x01(\x04\x42\x02\x30\x01\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"\x80\x01\n\x0fPivotGraphEntry\x12\x0e\n\x06PeerID\x18\x01 \x01(\x03\x12"\n\x07Session\x18\x02 \x01(\x0b\x32\x11.clientpb.Session\x12\x0c\n\x04Name\x18\x03 \x01(\t\x12+\n\x08\x43hildren\x18\x04 \x03(\x0b\x32\x19.clientpb.PivotGraphEntry"9\n\nPivotGraph\x12+\n\x08\x43hildren\x18\x01 \x03(\x0b\x32\x19.clientpb.PivotGraphEntry"H\n\x06\x43lient\x12\n\n\x02ID\x18\x01 \x01(\r\x12\x0c\n\x04Name\x18\x02 \x01(\t\x12$\n\x08Operator\x18\x03 \x01(\x0b\x32\x12.clientpb.Operator"\x97\x01\n\x05\x45vent\x12\x11\n\tEventType\x18\x01 \x01(\t\x12"\n\x07Session\x18\x02 \x01(\x0b\x32\x11.clientpb.Session\x12\x1a\n\x03Job\x18\x03 \x01(\x0b\x32\r.clientpb.Job\x12 \n\x06\x43lient\x18\x04 \x01(\x0b\x32\x10.clientpb.Client\x12\x0c\n\x04\x44\x61ta\x18\x05 \x01(\x0c\x12\x0b\n\x03\x45rr\x18\x06 \x01(\t"2\n\tOperators\x12%\n\tOperators\x18\x01 \x03(\x0b\x32\x12.clientpb.Operator"(\n\x08Operator\x12\x0e\n\x06Online\x18\x01 \x01(\x08\x12\x0c\n\x04Name\x18\x02 \x01(\t"R\n\nWebContent\x12\x0c\n\x04Path\x18\x01 \x01(\t\x12\x13\n\x0b\x43ontentType\x18\x02 \x01(\t\x12\x10\n\x04Size\x18\x03 \x01(\x04\x42\x02\x30\x01\x12\x0f\n\x07\x43ontent\x18\t \x01(\x0c"\xa5\x01\n\x11WebsiteAddContent\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12;\n\x08\x43ontents\x18\x02 \x03(\x0b\x32).clientpb.WebsiteAddContent.ContentsEntry\x1a\x45\n\rContentsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.clientpb.WebContent:\x02\x38\x01"3\n\x14WebsiteRemoveContent\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12\r\n\x05Paths\x18\x02 \x03(\t"\x91\x01\n\x07Website\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12\x31\n\x08\x43ontents\x18\x02 \x03(\x0b\x32\x1f.clientpb.Website.ContentsEntry\x1a\x45\n\rContentsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.clientpb.WebContent:\x02\x38\x01"/\n\x08Websites\x12#\n\x08Websites\x18\x01 \x03(\x0b\x32\x11.clientpb.Website"h\n\x0eWGClientConfig\x12\x14\n\x0cServerPubKey\x18\x01 \x01(\t\x12\x18\n\x10\x43lientPrivateKey\x18\x02 \x01(\t\x12\x14\n\x0c\x43lientPubKey\x18\x03 \x01(\t\x12\x10\n\x08\x43lientIP\x18\x04 \x01(\t"<\n\nCredential\x12\x0c\n\x04User\x18\x02 \x01(\t\x12\x10\n\x08Password\x18\x03 \x01(\t\x12\x0e\n\x06\x41PIKey\x18\x04 \x01(\t"\xe6\x01\n\x04Loot\x12 \n\x04Type\x18\x01 \x01(\x0e\x32\x12.clientpb.LootType\x12\x0e\n\x06LootID\x18\x02 \x01(\t\x12\x0c\n\x04Name\x18\x03 \x01(\t\x12\x30\n\x0e\x43redentialType\x18\x04 \x01(\x0e\x32\x18.clientpb.CredentialType\x12(\n\nCredential\x18\x05 \x01(\x0b\x32\x14.clientpb.Credential\x12$\n\x08\x46ileType\x18\x06 \x01(\x0e\x32\x12.clientpb.FileType\x12\x1c\n\x04\x46ile\x18\t \x01(\x0b\x32\x0e.commonpb.File"\'\n\x07\x41llLoot\x12\x1c\n\x04Loot\x18\x01 \x03(\x0b\x32\x0e.clientpb.Loot"1\n\x03IOC\x12\x0c\n\x04Path\x18\x01 \x01(\t\x12\x10\n\x08\x46ileHash\x18\x02 \x01(\t\x12\n\n\x02ID\x18\x03 \x01(\t"\x1f\n\rExtensionData\x12\x0e\n\x06Output\x18\x01 \x01(\t"\x89\x02\n\x04Host\x12\x10\n\x08Hostname\x18\x01 \x01(\t\x12\x10\n\x08HostUUID\x18\x02 \x01(\t\x12\x11\n\tOSVersion\x18\x03 \x01(\t\x12\x1b\n\x04IOCs\x18\x04 \x03(\x0b\x32\r.clientpb.IOC\x12\x38\n\rExtensionData\x18\x05 \x03(\x0b\x32!.clientpb.Host.ExtensionDataEntry\x12\x0e\n\x06Locale\x18\x06 \x01(\t\x12\x14\n\x0c\x46irstContact\x18\x07 \x01(\x03\x1aM\n\x12\x45xtensionDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.clientpb.ExtensionData:\x02\x38\x01")\n\x08\x41llHosts\x12\x1d\n\x05Hosts\x18\x01 \x03(\x0b\x32\x0e.clientpb.Host"\xa2\x01\n\x0c\x44llHijackReq\x12\x18\n\x10ReferenceDLLPath\x18\x01 \x01(\t\x12\x16\n\x0eTargetLocation\x18\x02 \x01(\t\x12\x14\n\x0cReferenceDLL\x18\x03 \x01(\x0c\x12\x11\n\tTargetDLL\x18\x04 \x01(\x0c\x12\x13\n\x0bProfileName\x18\x05 \x01(\t\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"1\n\tDllHijack\x12$\n\x08Response\x18\t \x01(\x0b\x32\x12.commonpb.Response"\xaf\x01\n\x12ShellcodeEncodeReq\x12+\n\x07\x45ncoder\x18\x01 \x01(\x0e\x32\x1a.clientpb.ShellcodeEncoder\x12\x14\n\x0c\x41rchitecture\x18\x02 \x01(\t\x12\x12\n\nIterations\x18\x03 \x01(\r\x12\x10\n\x08\x42\x61\x64\x43hars\x18\x04 \x01(\x0c\x12\x0c\n\x04\x44\x61ta\x18\x08 \x01(\x0c\x12"\n\x07Request\x18\t \x01(\x0b\x32\x11.commonpb.Request"E\n\x0fShellcodeEncode\x12\x0c\n\x04\x44\x61ta\x18\x08 \x01(\x0c\x12$\n\x08Response\x18\t \x01(\x0b\x32\x12.commonpb.Response"\xa1\x01\n\x13ShellcodeEncoderMap\x12=\n\x08\x45ncoders\x18\x01 \x03(\x0b\x32+.clientpb.ShellcodeEncoderMap.EncodersEntry\x1aK\n\rEncodersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12)\n\x05value\x18\x02 \x01(\x0e\x32\x1a.clientpb.ShellcodeEncoder:\x02\x38\x01*X\n\x0cOutputFormat\x12\x0e\n\nSHARED_LIB\x10\x00\x12\r\n\tSHELLCODE\x10\x01\x12\x0e\n\nEXECUTABLE\x10\x02\x12\x0b\n\x07SERVICE\x10\x03\x12\x0c\n\x08\x45XTERNAL\x10\x04*-\n\rStageProtocol\x12\x07\n\x03TCP\x10\x00\x12\x08\n\x04HTTP\x10\x01\x12\t\n\x05HTTPS\x10\x02*.\n\x08LootType\x12\r\n\tLOOT_FILE\x10\x00\x12\x13\n\x0fLOOT_CREDENTIAL\x10\x01*M\n\x0e\x43redentialType\x12\x11\n\rNO_CREDENTIAL\x10\x00\x12\x11\n\rUSER_PASSWORD\x10\x01\x12\x0b\n\x07\x41PI_KEY\x10\x02\x12\x08\n\x04\x46ILE\x10\x03*-\n\x08\x46ileType\x12\x0b\n\x07NO_FILE\x10\x00\x12\n\n\x06\x42INARY\x10\x01\x12\x08\n\x04TEXT\x10\x02*&\n\x10ShellcodeEncoder\x12\x12\n\x0eSHIKATA_GA_NAI\x10\x00\x42/Z-github.com/bishopfox/sliver/protobuf/clientpbb\x06proto3'
19 | )
20 |
21 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
22 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "clientpb.client_pb2", globals())
23 | if _descriptor._USE_C_DESCRIPTORS == False:
24 |
25 | DESCRIPTOR._options = None
26 | DESCRIPTOR._serialized_options = b"Z-github.com/bishopfox/sliver/protobuf/clientpb"
27 | _IMPLANTBUILDS_CONFIGSENTRY._options = None
28 | _IMPLANTBUILDS_CONFIGSENTRY._serialized_options = b"8\001"
29 | _CREATETUNNEL.fields_by_name["TunnelID"]._options = None
30 | _CREATETUNNEL.fields_by_name["TunnelID"]._serialized_options = b"0\001"
31 | _CLOSETUNNELREQ.fields_by_name["TunnelID"]._options = None
32 | _CLOSETUNNELREQ.fields_by_name["TunnelID"]._serialized_options = b"0\001"
33 | _WEBCONTENT.fields_by_name["Size"]._options = None
34 | _WEBCONTENT.fields_by_name["Size"]._serialized_options = b"0\001"
35 | _WEBSITEADDCONTENT_CONTENTSENTRY._options = None
36 | _WEBSITEADDCONTENT_CONTENTSENTRY._serialized_options = b"8\001"
37 | _WEBSITE_CONTENTSENTRY._options = None
38 | _WEBSITE_CONTENTSENTRY._serialized_options = b"8\001"
39 | _HOST_EXTENSIONDATAENTRY._options = None
40 | _HOST_EXTENSIONDATAENTRY._serialized_options = b"8\001"
41 | _SHELLCODEENCODERMAP_ENCODERSENTRY._options = None
42 | _SHELLCODEENCODERMAP_ENCODERSENTRY._serialized_options = b"8\001"
43 | _OUTPUTFORMAT._serialized_start = 8560
44 | _OUTPUTFORMAT._serialized_end = 8648
45 | _STAGEPROTOCOL._serialized_start = 8650
46 | _STAGEPROTOCOL._serialized_end = 8695
47 | _LOOTTYPE._serialized_start = 8697
48 | _LOOTTYPE._serialized_end = 8743
49 | _CREDENTIALTYPE._serialized_start = 8745
50 | _CREDENTIALTYPE._serialized_end = 8822
51 | _FILETYPE._serialized_start = 8824
52 | _FILETYPE._serialized_end = 8869
53 | _SHELLCODEENCODER._serialized_start = 8871
54 | _SHELLCODEENCODER._serialized_end = 8909
55 | _VERSION._serialized_start = 59
56 | _VERSION._serialized_end = 190
57 | _SESSION._serialized_start = 193
58 | _SESSION._serialized_end = 627
59 | _BEACON._serialized_start = 630
60 | _BEACON._serialized_end = 1131
61 | _BEACONS._serialized_start = 1133
62 | _BEACONS._serialized_end = 1177
63 | _BEACONTASK._serialized_start = 1180
64 | _BEACONTASK._serialized_end = 1349
65 | _BEACONTASKS._serialized_start = 1351
66 | _BEACONTASKS._serialized_end = 1419
67 | _IMPLANTC2._serialized_start = 1421
68 | _IMPLANTC2._serialized_end = 1480
69 | _IMPLANTCONFIG._serialized_start = 1483
70 | _IMPLANTCONFIG._serialized_end = 2403
71 | _EXTERNALIMPLANTCONFIG._serialized_start = 2405
72 | _EXTERNALIMPLANTCONFIG._serialized_end = 2502
73 | _EXTERNALIMPLANTBINARY._serialized_start = 2504
74 | _EXTERNALIMPLANTBINARY._serialized_end = 2596
75 | _IMPLANTBUILDS._serialized_start = 2599
76 | _IMPLANTBUILDS._serialized_end = 2742
77 | _IMPLANTBUILDS_CONFIGSENTRY._serialized_start = 2671
78 | _IMPLANTBUILDS_CONFIGSENTRY._serialized_end = 2742
79 | _COMPILERTARGET._serialized_start = 2744
80 | _COMPILERTARGET._serialized_end = 2830
81 | _CROSSCOMPILER._serialized_start = 2832
82 | _CROSSCOMPILER._serialized_end = 2922
83 | _COMPILER._serialized_start = 2925
84 | _COMPILER._serialized_end = 3111
85 | _DELETEREQ._serialized_start = 3113
86 | _DELETEREQ._serialized_end = 3138
87 | _DNSCANARY._serialized_start = 3141
88 | _DNSCANARY._serialized_end = 3270
89 | _CANARIES._serialized_start = 3272
90 | _CANARIES._serialized_end = 3321
91 | _UNIQUEWGIP._serialized_start = 3323
92 | _UNIQUEWGIP._serialized_end = 3347
93 | _IMPLANTPROFILE._serialized_start = 3349
94 | _IMPLANTPROFILE._serialized_end = 3420
95 | _IMPLANTPROFILES._serialized_start = 3422
96 | _IMPLANTPROFILES._serialized_end = 3483
97 | _REGENERATEREQ._serialized_start = 3485
98 | _REGENERATEREQ._serialized_end = 3521
99 | _JOB._serialized_start = 3523
100 | _JOB._serialized_end = 3624
101 | _JOBS._serialized_start = 3626
102 | _JOBS._serialized_end = 3663
103 | _KILLJOBREQ._serialized_start = 3665
104 | _KILLJOBREQ._serialized_end = 3689
105 | _KILLJOB._serialized_start = 3691
106 | _KILLJOB._serialized_end = 3729
107 | _MTLSLISTENERREQ._serialized_start = 3731
108 | _MTLSLISTENERREQ._serialized_end = 3796
109 | _MTLSLISTENER._serialized_start = 3798
110 | _MTLSLISTENER._serialized_end = 3827
111 | _WGLISTENERREQ._serialized_start = 3829
112 | _WGLISTENERREQ._serialized_end = 3939
113 | _WGLISTENER._serialized_start = 3941
114 | _WGLISTENER._serialized_end = 3968
115 | _DNSLISTENERREQ._serialized_start = 3970
116 | _DNSLISTENERREQ._serialized_end = 4089
117 | _DNSLISTENER._serialized_start = 4091
118 | _DNSLISTENER._serialized_end = 4119
119 | _HTTPLISTENERREQ._serialized_start = 4122
120 | _HTTPLISTENERREQ._serialized_end = 4369
121 | _NAMEDPIPESREQ._serialized_start = 4371
122 | _NAMEDPIPESREQ._serialized_end = 4440
123 | _NAMEDPIPES._serialized_start = 4442
124 | _NAMEDPIPES._serialized_end = 4522
125 | _TCPPIVOTREQ._serialized_start = 4524
126 | _TCPPIVOTREQ._serialized_end = 4590
127 | _TCPPIVOT._serialized_start = 4592
128 | _TCPPIVOT._serialized_end = 4670
129 | _HTTPLISTENER._serialized_start = 4672
130 | _HTTPLISTENER._serialized_end = 4701
131 | _SESSIONS._serialized_start = 4703
132 | _SESSIONS._serialized_end = 4750
133 | _RENAMEREQ._serialized_start = 4752
134 | _RENAMEREQ._serialized_end = 4814
135 | _GENERATEREQ._serialized_start = 4816
136 | _GENERATEREQ._serialized_end = 4870
137 | _GENERATE._serialized_start = 4872
138 | _GENERATE._serialized_end = 4912
139 | _MSFREQ._serialized_start = 4915
140 | _MSFREQ._serialized_end = 5043
141 | _MSFREMOTEREQ._serialized_start = 5046
142 | _MSFREMOTEREQ._serialized_end = 5193
143 | _STAGERLISTENERREQ._serialized_start = 5196
144 | _STAGERLISTENERREQ._serialized_end = 5341
145 | _STAGERLISTENER._serialized_start = 5343
146 | _STAGERLISTENER._serialized_end = 5374
147 | _SHELLCODERDIREQ._serialized_start = 5376
148 | _SHELLCODERDIREQ._serialized_end = 5448
149 | _SHELLCODERDI._serialized_start = 5450
150 | _SHELLCODERDI._serialized_end = 5478
151 | _MSFSTAGERREQ._serialized_start = 5481
152 | _MSFSTAGERREQ._serialized_end = 5626
153 | _MSFSTAGER._serialized_start = 5628
154 | _MSFSTAGER._serialized_end = 5669
155 | _GETSYSTEMREQ._serialized_start = 5671
156 | _GETSYSTEMREQ._serialized_end = 5786
157 | _MIGRATEREQ._serialized_start = 5788
158 | _MIGRATEREQ._serialized_end = 5890
159 | _CREATETUNNELREQ._serialized_start = 5892
160 | _CREATETUNNELREQ._serialized_end = 5945
161 | _CREATETUNNEL._serialized_start = 5947
162 | _CREATETUNNEL._serialized_end = 6002
163 | _CLOSETUNNELREQ._serialized_start = 6004
164 | _CLOSETUNNELREQ._serialized_end = 6078
165 | _PIVOTGRAPHENTRY._serialized_start = 6081
166 | _PIVOTGRAPHENTRY._serialized_end = 6209
167 | _PIVOTGRAPH._serialized_start = 6211
168 | _PIVOTGRAPH._serialized_end = 6268
169 | _CLIENT._serialized_start = 6270
170 | _CLIENT._serialized_end = 6342
171 | _EVENT._serialized_start = 6345
172 | _EVENT._serialized_end = 6496
173 | _OPERATORS._serialized_start = 6498
174 | _OPERATORS._serialized_end = 6548
175 | _OPERATOR._serialized_start = 6550
176 | _OPERATOR._serialized_end = 6590
177 | _WEBCONTENT._serialized_start = 6592
178 | _WEBCONTENT._serialized_end = 6674
179 | _WEBSITEADDCONTENT._serialized_start = 6677
180 | _WEBSITEADDCONTENT._serialized_end = 6842
181 | _WEBSITEADDCONTENT_CONTENTSENTRY._serialized_start = 6773
182 | _WEBSITEADDCONTENT_CONTENTSENTRY._serialized_end = 6842
183 | _WEBSITEREMOVECONTENT._serialized_start = 6844
184 | _WEBSITEREMOVECONTENT._serialized_end = 6895
185 | _WEBSITE._serialized_start = 6898
186 | _WEBSITE._serialized_end = 7043
187 | _WEBSITE_CONTENTSENTRY._serialized_start = 6773
188 | _WEBSITE_CONTENTSENTRY._serialized_end = 6842
189 | _WEBSITES._serialized_start = 7045
190 | _WEBSITES._serialized_end = 7092
191 | _WGCLIENTCONFIG._serialized_start = 7094
192 | _WGCLIENTCONFIG._serialized_end = 7198
193 | _CREDENTIAL._serialized_start = 7200
194 | _CREDENTIAL._serialized_end = 7260
195 | _LOOT._serialized_start = 7263
196 | _LOOT._serialized_end = 7493
197 | _ALLLOOT._serialized_start = 7495
198 | _ALLLOOT._serialized_end = 7534
199 | _IOC._serialized_start = 7536
200 | _IOC._serialized_end = 7585
201 | _EXTENSIONDATA._serialized_start = 7587
202 | _EXTENSIONDATA._serialized_end = 7618
203 | _HOST._serialized_start = 7621
204 | _HOST._serialized_end = 7886
205 | _HOST_EXTENSIONDATAENTRY._serialized_start = 7809
206 | _HOST_EXTENSIONDATAENTRY._serialized_end = 7886
207 | _ALLHOSTS._serialized_start = 7888
208 | _ALLHOSTS._serialized_end = 7929
209 | _DLLHIJACKREQ._serialized_start = 7932
210 | _DLLHIJACKREQ._serialized_end = 8094
211 | _DLLHIJACK._serialized_start = 8096
212 | _DLLHIJACK._serialized_end = 8145
213 | _SHELLCODEENCODEREQ._serialized_start = 8148
214 | _SHELLCODEENCODEREQ._serialized_end = 8323
215 | _SHELLCODEENCODE._serialized_start = 8325
216 | _SHELLCODEENCODE._serialized_end = 8394
217 | _SHELLCODEENCODERMAP._serialized_start = 8397
218 | _SHELLCODEENCODERMAP._serialized_end = 8558
219 | _SHELLCODEENCODERMAP_ENCODERSENTRY._serialized_start = 8483
220 | _SHELLCODEENCODERMAP_ENCODERSENTRY._serialized_end = 8558
221 | # @@protoc_insertion_point(module_scope)
222 |
--------------------------------------------------------------------------------
/src/sliver/interactive.py:
--------------------------------------------------------------------------------
1 | """
2 | Sliver Implant Framework
3 | Copyright (C) 2022 Bishop Fox
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 | """
16 |
17 | from typing import List, Optional
18 |
19 | from sliver.pb.commonpb import common_pb2
20 |
21 | from ._protocols import InteractiveObject
22 | from .protobuf import client_pb2, sliver_pb2
23 |
24 |
25 | class BaseInteractiveCommands:
26 | async def ping(self: InteractiveObject) -> sliver_pb2.Ping:
27 | """Send a round trip message to the implant (does NOT use ICMP)
28 |
29 | :return: Protobuf ping object
30 | :rtype: sliver_pb2.Ping
31 | """
32 | return await self._stub.Ping(
33 | self._request(sliver_pb2.Ping()), timeout=self.timeout
34 | )
35 |
36 | async def ps(self: InteractiveObject) -> List[common_pb2.Process]:
37 | """List the processes of the remote system
38 |
39 | :return: Ps protobuf object
40 | :rtype: List[common_pb2.Process]
41 | """
42 | ps = sliver_pb2.PsReq()
43 | processes = await self._stub.Ps(self._request(ps), timeout=self.timeout)
44 | return list(processes.Processes)
45 |
46 | async def terminate(
47 | self: InteractiveObject, pid: int, force=False
48 | ) -> sliver_pb2.Terminate:
49 | """Terminate a remote process
50 |
51 | :param pid: The process ID to terminate.
52 | :type pid: int
53 | :param force: Force termination of the process, defaults to False
54 | :type force: bool, optional
55 | :return: Protobuf terminate object
56 | :rtype: sliver_pb2.Terminate
57 | """
58 | terminator = sliver_pb2.TerminateReq(Pid=pid, Force=force)
59 | return await self._stub.Terminate(
60 | self._request(terminator), timeout=self.timeout
61 | )
62 |
63 | async def ifconfig(self: InteractiveObject) -> sliver_pb2.Ifconfig:
64 | """Get network interface configuration information about the remote system
65 |
66 | :return: Protobuf ifconfig object
67 | :rtype: sliver_pb2.Ifconfig
68 | """
69 | return await self._stub.Ifconfig(
70 | self._request(sliver_pb2.IfconfigReq()), timeout=self.timeout
71 | )
72 |
73 | async def netstat(
74 | self: InteractiveObject,
75 | tcp: bool,
76 | udp: bool,
77 | ipv4: bool,
78 | ipv6: bool,
79 | listening=True,
80 | ) -> sliver_pb2.Netstat:
81 | """Get information about network connections on the remote system.
82 |
83 | :param tcp: Get TCP information
84 | :type tcp: bool
85 | :param udp: Get UDP information
86 | :type udp: bool
87 | :param ipv4: Get IPv4 connection information
88 | :type ipv4: bool
89 | :param ipv6: Get IPv6 connection information
90 | :type ipv6: bool
91 | :param listening: Get listening connection information, defaults to True
92 | :type listening: bool, optional
93 | :return: Protobuf netstat object
94 | :rtype: List[sliver_pb2.SockTabEntry]
95 | """
96 | net = sliver_pb2.NetstatReq(
97 | TCP=tcp, UDP=udp, IP4=ipv4, IP6=ipv6, Listening=listening
98 | )
99 | return await self._stub.Netstat(self._request(net), timeout=self.timeout)
100 |
101 | async def ls(self: InteractiveObject, remote_path: str = ".") -> sliver_pb2.Ls:
102 | """Get a directory listing from the remote system
103 |
104 | :param remote_path: Remote path
105 | :type remote_path: str
106 | :return: Protobuf ls object
107 | :rtype: sliver_pb2.Ls
108 | """
109 | ls = sliver_pb2.LsReq(Path=remote_path)
110 | return await self._stub.Ls(self._request(ls), timeout=self.timeout)
111 |
112 | async def cd(self: InteractiveObject, remote_path: str) -> sliver_pb2.Pwd:
113 | """Change the current working directory of the implant
114 |
115 | :param remote_path: Remote path
116 | :type remote_path: str
117 | :return: Protobuf pwd object
118 | :rtype: sliver_pb2.Pwd
119 | """
120 | cd = sliver_pb2.CdReq(Path=remote_path)
121 | return await self._stub.Cd(self._request(cd), timeout=self.timeout)
122 |
123 | async def pwd(self: InteractiveObject) -> sliver_pb2.Pwd:
124 | """Get the implant's current working directory
125 |
126 | :return: Protobuf pwd object
127 | :rtype: sliver_pb2.Pwd
128 | """
129 | pwd = sliver_pb2.PwdReq()
130 | return await self._stub.Pwd(self._request(pwd), timeout=self.timeout)
131 |
132 | async def rm(
133 | self: InteractiveObject, remote_path: str, recursive=False, force=False
134 | ) -> sliver_pb2.Rm:
135 | """Remove a directory or file(s)
136 |
137 | :param remote_path: Remote path
138 | :type remote_path: str
139 | :param recursive: Recursively remove file(s), defaults to False
140 | :type recursive: bool, optional
141 | :param force: Forcefully remove the file(s), defaults to False
142 | :type force: bool, optional
143 | :return: Protobuf rm object
144 | :rtype: sliver_pb2.Rm
145 | """
146 | rm = sliver_pb2.RmReq(Path=remote_path, Recursive=recursive, Force=force)
147 | return await self._stub.Rm(self._request(rm), timeout=self.timeout)
148 |
149 | async def mkdir(self: InteractiveObject, remote_path: str) -> sliver_pb2.Mkdir:
150 | """Make a directory on the remote file system
151 |
152 | :param remote_path: Directory to create
153 | :type remote_path: str
154 | :return: Protobuf Mkdir object
155 | :rtype: sliver_pb2.Mkdir
156 | """
157 | make = sliver_pb2.MkdirReq(Path=remote_path)
158 | return await self._stub.Mkdir(self._request(make), timeout=self.timeout)
159 |
160 | async def download(
161 | self: InteractiveObject, remote_path: str, recurse: bool = False
162 | ) -> sliver_pb2.Download:
163 | """Download a file or directory from the remote file system
164 |
165 | :param remote_path: File to download
166 | :type remote_path: str
167 | :param recurse: Download all files in a directory
168 | :type recurse: bool
169 | :return: Protobuf Download object
170 | :rtype: sliver_pb2.Download
171 | """
172 | download = sliver_pb2.DownloadReq(Path=remote_path, Recurse=recurse)
173 | return await self._stub.Download(self._request(download), timeout=self.timeout)
174 |
175 | async def upload(
176 | self: InteractiveObject,
177 | remote_path: str,
178 | data: bytes,
179 | is_ioc: bool = False,
180 | ) -> sliver_pb2.Upload:
181 | """Write data to specified path on remote file system
182 |
183 | :param remote_path: Remote path
184 | :type remote_path: str
185 | :param data: Data to write
186 | :type data: bytes
187 | :param is_ioc: Data is an indicator of compromise, defaults to False
188 | :type is_ioc: bool, optional
189 | :return: Protobuf Upload object
190 | :rtype: sliver_pb2.Upload
191 | """
192 | upload = sliver_pb2.UploadReq(Path=remote_path, Data=data, IsIOC=is_ioc)
193 | return await self._stub.Upload(self._request(upload), timeout=self.timeout)
194 |
195 | async def process_dump(self: InteractiveObject, pid: int) -> sliver_pb2.ProcessDump:
196 | """Dump a remote process' memory
197 |
198 | :param pid: PID of the process to dump
199 | :type pid: int
200 | :return: Protobuf ProcessDump object
201 | :rtype: sliver_pb2.ProcessDump
202 | """
203 | procdump = sliver_pb2.ProcessDumpReq(Pid=pid)
204 | return await self._stub.ProcessDump(
205 | self._request(procdump), timeout=self.timeout
206 | )
207 |
208 | async def run_as(
209 | self: InteractiveObject, username: str, process_name: str, args: str
210 | ) -> sliver_pb2.RunAs:
211 | """Run a command as another user on the remote system
212 |
213 | :param username: User to run process as
214 | :type username: str
215 | :param process_name: Process to execute
216 | :type process_name: str
217 | :param args: Arguments to process
218 | :type args: str
219 | :return: Protobuf RunAs object
220 | :rtype: sliver_pb2.RunAs
221 | """
222 | run_as = sliver_pb2.RunAsReq(
223 | Username=username, ProcessName=process_name, Args=args
224 | )
225 | return await self._stub.RunAs(self._request(run_as), timeout=self.timeout)
226 |
227 | async def impersonate(
228 | self: InteractiveObject, username: str
229 | ) -> sliver_pb2.Impersonate:
230 | """Impersonate a user using tokens (Windows only)
231 |
232 | :param username: User to impersonate
233 | :type username: str
234 | :return: Protobuf Impersonate object
235 | :rtype: sliver_pb2.Impersonate
236 | """
237 | impersonate = sliver_pb2.ImpersonateReq(Username=username)
238 | return await self._stub.Impersonate(
239 | self._request(impersonate), timeout=self.timeout
240 | )
241 |
242 | async def revert_to_self(self: InteractiveObject) -> sliver_pb2.RevToSelf:
243 | """Revert to self from impersonation context
244 |
245 | :return: Protobuf RevToSelf object
246 | :rtype: sliver_pb2.RevToSelf
247 | """
248 | return await self._stub.RevToSelf(
249 | self._request(sliver_pb2.RevToSelfReq()), timeout=self.timeout
250 | )
251 |
252 | async def get_system(
253 | self: InteractiveObject, hosting_process: str, config: client_pb2.ImplantConfig
254 | ) -> sliver_pb2.GetSystem:
255 | """Attempt to get SYSTEM (Windows only)
256 |
257 | :param hosting_process: Hosting process to attempt gaining privileges
258 | :type hosting_process: str
259 | :param config: Implant configuration to be injected into the hosting process
260 | :type config: client_pb2.ImplantConfig
261 | :return: Protobuf GetSystem object
262 | :rtype: sliver_pb2.GetSystem
263 | """
264 | system = client_pb2.GetSystemReq(HostingProcess=hosting_process, Config=config)
265 | return await self._stub.GetSystem(self._request(system), timeout=self.timeout)
266 |
267 | async def execute_shellcode(
268 | self: InteractiveObject, data: bytes, rwx: bool, pid: int, encoder=""
269 | ) -> sliver_pb2.Task:
270 | """Execute shellcode in-memory
271 |
272 | :param data: Shellcode buffer
273 | :type data: bytes
274 | :param rwx: Enable/disable RWX pages
275 | :type rwx: bool
276 | :param pid: Process ID to inject shellcode into
277 | :type pid: int
278 | :param encoder: Encoder ('', 'gzip'), defaults to ''
279 | :type encoder: str, optional
280 | :return: Protobuf Task object
281 | :rtype: sliver_pb2.Task
282 | """
283 | task = sliver_pb2.TaskReq(Encoder=encoder, Data=data, RWXPages=rwx, Pid=pid)
284 | return await self._stub.Task(self._request(task), timeout=self.timeout)
285 |
286 | async def msf(
287 | self: InteractiveObject,
288 | payload: str,
289 | lhost: str,
290 | lport: int,
291 | encoder: str,
292 | iterations: int,
293 | ) -> None:
294 | """Execute Metasploit payload on remote system, the payload will be generated by the server
295 | based on the parameters to this function. The server must be configured with Metasploit.
296 |
297 | :param payload: Payload to generate
298 | :type payload: str
299 | :param lhost: Metasploit LHOST parameter
300 | :type lhost: str
301 | :param lport: Metasploit LPORT parameter
302 | :type lport: int
303 | :param encoder: Metasploit encoder
304 | :type encoder: str
305 | :param iterations: Iterations for Metasploit encoder
306 | :type iterations: int
307 | """
308 | msf = client_pb2.MSFReq()
309 | msf.Payload = payload
310 | msf.LHost = lhost
311 | msf.LPort = lport
312 | msf.Encoder = encoder
313 | msf.Iterations = iterations
314 | return await self._stub.Msf(self._request(msf), timeout=self.timeout)
315 |
316 | async def msf_remote(
317 | self: InteractiveObject,
318 | payload: str,
319 | lhost: str,
320 | lport: int,
321 | encoder: str,
322 | iterations: int,
323 | pid: int,
324 | ) -> None:
325 | """Execute Metasploit payload in a remote process, the payload will be generated by the server
326 | based on the parameters to this function. The server must be configured with Metasploit.
327 |
328 | :param payload: Payload to generate
329 | :type payload: str
330 | :param lhost: Metasploit LHOST parameter
331 | :type lhost: str
332 | :param lport: Metasploit LPORT parameter
333 | :type lport: int
334 | :param encoder: Metasploit encoder
335 | :type encoder: str
336 | :param iterations: Iterations for Metasploit encoder
337 | :type iterations: int
338 | :param pid: Process ID to inject the payload into
339 | :type pid: int
340 | """
341 | msf = client_pb2.MSFRemoteReq()
342 | msf.Payload = payload
343 | msf.LHost = lhost
344 | msf.LPort = lport
345 | msf.Encoder = encoder
346 | msf.Iterations = iterations
347 | msf.PID = pid
348 | return await self._stub.Msf(self._request(msf), timeout=self.timeout)
349 |
350 | async def execute_assembly(
351 | self: InteractiveObject,
352 | assembly: bytes,
353 | arguments: str,
354 | process: str,
355 | is_dll: bool,
356 | arch: str,
357 | class_name: str,
358 | method: str,
359 | app_domain: str,
360 | ) -> sliver_pb2.ExecuteAssembly:
361 | """Execute a .NET assembly in-memory on the remote system
362 |
363 | :param assembly: A buffer of the .NET assembly to execute
364 | :type assembly: bytes
365 | :param arguments: Arguments to the .NET assembly
366 | :type arguments: str
367 | :param process: Process to execute assembly
368 | :type process: str
369 | :param is_dll: Is assembly a DLL
370 | :type is_dll: bool
371 | :param arch: Assembly architecture
372 | :type arch: str
373 | :param class_name: Class name of the assembly
374 | :type class_name: str
375 | :param method: Method to execute
376 | :type method: str
377 | :param app_domain: AppDomain
378 | :type app_domain: str
379 | :return: Protobuf ExecuteAssembly object
380 | :rtype: sliver_pb2.ExecuteAssembly
381 | """
382 | asm = sliver_pb2.ExecuteAssemblyReq()
383 | asm.Assembly = assembly
384 | asm.Arguments = arguments
385 | asm.Process = process
386 | asm.IsDLL = is_dll
387 | asm.Arch = arch
388 | asm.ClassName = class_name
389 | asm.AppDomain = app_domain
390 | return await self._stub.ExecuteAssembly(
391 | self._request(asm), timeout=self.timeout
392 | )
393 |
394 | async def migrate(
395 | self: InteractiveObject, pid: int, config: client_pb2.ImplantConfig
396 | ) -> sliver_pb2.Migrate:
397 | """Migrate implant to another process
398 |
399 | :param pid: Process ID to inject implant into
400 | :type pid: int
401 | :param config: Implant configuration to inject into the remote process
402 | :type config: client_pb2.ImplantConfig
403 | :return: Protobuf Migrate object
404 | :rtype: sliver_pb2.Migrate
405 | """
406 | migrate = client_pb2.MigrateReq()
407 | migrate.Pid = pid
408 | migrate.Config.CopyFrom(config)
409 | return await self._stub.Migrate(self._request(migrate), timeout=self.timeout)
410 |
411 | async def execute(
412 | self: InteractiveObject,
413 | exe: str,
414 | args: Optional[List[str]],
415 | output: bool = True,
416 | ) -> sliver_pb2.Execute:
417 | """Execute a command/subprocess on the remote system
418 |
419 | :param exe: Command/subprocess to execute
420 | :type exe: str
421 | :param args: Arguments to the command/subprocess
422 | :type args: List[str]
423 | :param output: Enable capturing command/subprocess stdout
424 | :type output: bool
425 | :return: Protobuf Execute object
426 | :rtype: sliver_pb2.Execute
427 | """
428 | if not args:
429 | args = []
430 | execute_req = sliver_pb2.ExecuteReq(Path=exe, Args=args, Output=output)
431 | return await self._stub.Execute(
432 | self._request(execute_req), timeout=self.timeout
433 | )
434 |
435 | async def sideload(
436 | self: InteractiveObject,
437 | data: bytes,
438 | process_name: str,
439 | arguments: str,
440 | entry_point: str,
441 | kill: bool,
442 | ) -> sliver_pb2.Sideload:
443 | """Sideload a shared library into a remote process using a platform specific in-memory loader (Windows, MacOS, Linux only)
444 |
445 | :param data: Shared library raw bytes
446 | :type data: bytes
447 | :param process_name: Process name to sideload library into
448 | :type process_name: str
449 | :param arguments: Arguments to the shared library
450 | :type arguments: str
451 | :param entry_point: Entrypoint of the shared library
452 | :type entry_point: str
453 | :param kill: Kill normal execution of the process when side loading the shared library
454 | :type kill: bool
455 | :return: Protobuf Sideload object
456 | :rtype: sliver_pb2.Sideload
457 | """
458 | side = sliver_pb2.SideloadReq(
459 | Data=data,
460 | ProcessName=process_name,
461 | Args=arguments,
462 | EntryPoint=entry_point,
463 | Kill=kill,
464 | )
465 | return await self._stub.Sideload(self._request(side), timeout=self.timeout)
466 |
467 | async def spawn_dll(
468 | self: InteractiveObject,
469 | data: bytes,
470 | process_name: str,
471 | arguments: str,
472 | entry_point: str,
473 | kill: bool,
474 | ) -> sliver_pb2.SpawnDll:
475 | """Spawn a DLL on the remote system from memory (Windows only)
476 |
477 | :param data: DLL raw bytes
478 | :type data: bytes
479 | :param process_name: Process name to spawn DLL into
480 | :type process_name: str
481 | :param arguments: Arguments to the DLL
482 | :type arguments: str
483 | :param entry_point: Entrypoint of the DLL
484 | :type entry_point: str
485 | :param kill: Kill normal execution of the remote process when spawing the DLL
486 | :type kill: bool
487 | :return: Protobuf SpawnDll object
488 | :rtype: sliver_pb2.SpawnDll
489 | """
490 | spawn = sliver_pb2.InvokeSpawnDllReq(
491 | Data=data,
492 | ProcessName=process_name,
493 | Args=arguments,
494 | EntryPoint=entry_point,
495 | Kill=kill,
496 | )
497 | return await self._stub.SpawnDll(self._request(spawn), timeout=self.timeout)
498 |
499 | async def list_extensions(
500 | self: InteractiveObject,
501 | ) -> sliver_pb2.ListExtensions:
502 | """List extensions
503 |
504 | :return: Protobuf ListExtensions object
505 | :rtype: sliver_pb2.ListExtensions
506 | """
507 | listex = sliver_pb2.ListExtensionsReq()
508 | return await self._stub.ListExtensions(self._request(listex), timeout=self.timeout)
509 |
510 | async def register_extension(
511 | self: InteractiveObject,
512 | name: str,
513 | data: bytes,
514 | goos: str,
515 | init: str
516 | ) -> sliver_pb2.RegisterExtension:
517 | """Call an extension
518 |
519 | :param name: Extension name
520 | :type name: str
521 | :param data: Extension binary data
522 | :type data: bytes
523 | :param goos: OS
524 | :type goos: str
525 | :param init: Init entrypoint to run
526 | :type init: str
527 | :return: Protobuf RegisterExtension object
528 | :rtype: sliver_pb2.RegisterExtension
529 | """
530 | regext = sliver_pb2.RegisterExtensionReq(
531 | Name = name,
532 | Data = data,
533 | OS = goos,
534 | Init = init
535 | )
536 | return await self._stub.RegisterExtension(self._request(regext), timeout=self.timeout)
537 |
538 | async def call_extension(
539 | self: InteractiveObject,
540 | name: str,
541 | export: str,
542 | ext_args: bytes,
543 | ) -> sliver_pb2.CallExtension:
544 | """Call an extension
545 |
546 | :param name: Extension name
547 | :type name: str
548 | :param export: Extension entrypoint
549 | :type export: str
550 | :param ext_args: Extension argument buffer
551 | :type ext_args: bytes
552 | :return: Protobuf CallExtension object
553 | :rtype: sliver_pb2.CallExtension
554 | """
555 | callex = sliver_pb2.CallExtensionReq(
556 | Name = name,
557 | Export = export,
558 | Args = ext_args
559 | )
560 | return await self._stub.CallExtension(self._request(callex), timeout=self.timeout)
561 |
562 | async def screenshot(self: InteractiveObject) -> sliver_pb2.Screenshot:
563 | """Take a screenshot of the remote system, screenshot data is PNG formatted
564 |
565 | :return: Protobuf Screenshot object
566 | :rtype: sliver_pb2.Screenshot
567 | """
568 | return await self._stub.Screenshot(
569 | self._request(sliver_pb2.ScreenshotReq()), timeout=self.timeout
570 | )
571 |
572 | async def make_token(
573 | self: InteractiveObject, username: str, password: str, domain: str
574 | ) -> sliver_pb2.MakeToken:
575 | """Make a Windows user token from a valid login (Windows only)
576 |
577 | :param username: Username
578 | :type username: str
579 | :param password: Password
580 | :type password: str
581 | :param domain: Domain
582 | :type domain: str
583 | :return: Protobuf MakeToken object
584 | :rtype: sliver_pb2.MakeToken
585 | """
586 | make = sliver_pb2.MakeTokenReq(
587 | Username=username, Password=password, Domain=domain
588 | )
589 | return await self._stub.MakeToken(self._request(make), timeout=self.timeout)
590 |
591 | async def get_env(self: InteractiveObject, name: str) -> sliver_pb2.EnvInfo:
592 | """Get an environment variable
593 |
594 | :param name: Name of the variable
595 | :type name: str
596 | :return: Protobuf EnvInfo object
597 | :rtype: sliver_pb2.EnvInfo
598 | """
599 | env = sliver_pb2.EnvReq(Name=name)
600 | return await self._stub.GetEnv(self._request(env), timeout=self.timeout)
601 |
602 | async def set_env(
603 | self: InteractiveObject, key: str, value: str
604 | ) -> sliver_pb2.SetEnv:
605 | """Set an environment variable
606 |
607 | :param name: Name of the environment variable
608 | :type name: str
609 | :param value: Value of the environment variable
610 | :type value: str
611 | :return: Protobuf SetEnv object
612 | :rtype: sliver_pb2.SetEnv
613 | """
614 | env_var = common_pb2.EnvVar(Key=key, Value=value)
615 | env_req = sliver_pb2.SetEnvReq(Variable=env_var)
616 | return await self._stub.SetEnv(self._request(env_req), timeout=self.timeout)
617 |
618 | async def unset_env(self: InteractiveObject, key: str) -> sliver_pb2.UnsetEnv:
619 | """Unset an environment variable
620 |
621 | :param value: Value of the environment variable
622 | :type value: str
623 | :return: Protobuf SetEnv object
624 | :rtype: sliver_pb2.SetEnv
625 | """
626 | env = sliver_pb2.UnsetEnvReq(Name=key)
627 | return await self._stub.UnsetEnv(self._request(env), timeout=self.timeout)
628 |
629 | async def registry_read(
630 | self: InteractiveObject, hive: str, reg_path: str, key: str, hostname: str
631 | ) -> sliver_pb2.RegistryRead:
632 | """Read a value from the remote system's registry (Windows only)
633 |
634 | :param hive: Registry hive to read value from
635 | :type hive: str
636 | :param reg_path: Path to registry key to read
637 | :type reg_path: str
638 | :param key: Key name to read
639 | :type key: str
640 | :param hostname: Hostname
641 | :type hostname: str
642 | :return: Protobuf RegistryRead object
643 | :rtype: sliver_pb2.RegistryRead
644 | """
645 | reg = sliver_pb2.RegistryReadReq()
646 | reg.Hive = hive
647 | reg.Path = reg_path
648 | reg.Key = key
649 | reg.Hostname = hostname
650 | return await self._stub.RegistryRead(self._request(reg), timeout=self.timeout)
651 |
652 | async def registry_write(
653 | self: InteractiveObject,
654 | hive: str,
655 | reg_path: str,
656 | key: str,
657 | hostname: str,
658 | string_value: str,
659 | byte_value: bytes,
660 | dword_value: int,
661 | qword_value: int,
662 | reg_type: sliver_pb2.RegistryType.ValueType,
663 | ) -> sliver_pb2.RegistryWrite:
664 | """Write a value to the remote system's registry (Windows only)
665 |
666 | :param hive: Registry hive to write the key/value to
667 | :type hive: str
668 | :param reg_path: Registry path to write to
669 | :type reg_path: str
670 | :param key: Registry key to write to
671 | :type key: str
672 | :param hostname: Hostname
673 | :type hostname: str
674 | :param string_value: String value to write (ignored for non-string key)
675 | :type string_value: str
676 | :param byte_value: Byte value to write (ignored for non-byte key)
677 | :type byte_value: bytes
678 | :param dword_value: DWORD value to write (ignored for non-DWORD key)
679 | :type dword_value: int
680 | :param qword_value: QWORD value to write (ignored for non-QWORD key)
681 | :type qword_value: int
682 | :param reg_type: Type of registry key to write
683 | :type reg_type: sliver_pb2.RegistryType
684 | :return: Protobuf RegistryWrite object
685 | :rtype: sliver_pb2.RegistryWrite
686 | """
687 | reg = sliver_pb2.RegistryWriteReq(
688 | Hive=hive,
689 | Path=reg_path,
690 | Key=key,
691 | Hostname=hostname,
692 | StringValue=string_value,
693 | ByteValue=byte_value,
694 | DWordValue=dword_value,
695 | QWordValue=qword_value,
696 | Type=int(reg_type),
697 | )
698 | reg.Hive = hive
699 | reg.Path = reg_path
700 | reg.Key = key
701 | reg.Hostname = hostname
702 | reg.StringValue = string_value
703 | reg.ByteValue = byte_value
704 | reg.DWordValue = dword_value
705 | reg.QWordValue = qword_value
706 | reg.Type = reg_type
707 |
708 | return await self._stub.RegistryWrite(self._request(reg), timeout=self.timeout)
709 |
710 | async def registry_create_key(
711 | self: InteractiveObject, hive: str, reg_path: str, key: str, hostname: str
712 | ) -> sliver_pb2.RegistryCreateKey:
713 | """Create a registry key on the remote system (Windows only)
714 |
715 | :param hive: Registry hive to create key in
716 | :type hive: str
717 | :param reg_path: Registry path to create key in
718 | :type reg_path: str
719 | :param key: Key name
720 | :type key: str
721 | :param hostname: Hostname
722 | :type hostname: str
723 | :return: Protobuf RegistryCreateKey object
724 | :rtype: sliver_pb2.RegistryCreateKey
725 | """
726 | reg = sliver_pb2.RegistryCreateKeyReq(
727 | Hive=hive, Path=reg_path, Key=key, Hostname=hostname
728 | )
729 | return await self._stub.RegistryCreateKey(
730 | self._request(reg), timeout=self.timeout
731 | )
732 |
--------------------------------------------------------------------------------