├── 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 | [![SliverPy](https://github.com/moloch--/sliver-py/actions/workflows/autorelease.yml/badge.svg)](https://github.com/moloch--/sliver-py/actions/workflows/autorelease.yml) 8 | [![Documentation Status](https://readthedocs.org/projects/sliverpy/badge/?version=latest)](https://sliverpy.readthedocs.io/en/latest/?badge=latest) 9 | [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](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 | --------------------------------------------------------------------------------