mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-08 01:38:17 -10:00
Compare commits
263
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9344a4c79 | ||
|
|
67d9a772e3 | ||
|
|
dae284e62e | ||
|
|
60f48bdc51 | ||
|
|
0d7885de29 | ||
|
|
d41d29fc1e | ||
|
|
3f400bd3f0 | ||
|
|
d43f664821 | ||
|
|
85c57c07da | ||
|
|
60d15447e0 | ||
|
|
6351b2d671 | ||
|
|
c7535ec509 | ||
|
|
67e17d073b | ||
|
|
c5cb4dcb6c | ||
|
|
0b9fe603a8 | ||
|
|
c7141892d1 | ||
|
|
c5556f9e2b | ||
|
|
1bc45c2ab2 | ||
|
|
739ad98b81 | ||
|
|
95c1697d1b | ||
|
|
f7b9571cfc | ||
|
|
0d08f8c62f | ||
|
|
aa9c8d89e9 | ||
|
|
152e60ba29 | ||
|
|
d13a71b808 | ||
|
|
b17e2f056f | ||
|
|
42fb1e835e | ||
|
|
521356ff6e | ||
|
|
74b5d720b2 | ||
|
|
cd75545323 | ||
|
|
396dc9724f | ||
|
|
33398146d3 | ||
|
|
21039554e5 | ||
|
|
cca73be1c8 | ||
|
|
596bc455d8 | ||
|
|
400c36c5df | ||
|
|
c94dde3efb | ||
|
|
827a9ca156 | ||
|
|
d066dbc49a | ||
|
|
f1fbc345a2 | ||
|
|
2889c1ee29 | ||
|
|
28ee216b36 | ||
|
|
2dd3e84f60 | ||
|
|
067cdf712d | ||
|
|
22ae941e17 | ||
|
|
7c0c2c2dda | ||
|
|
39de742223 | ||
|
|
b07e750cf5 | ||
|
|
8786979001 | ||
|
|
aa223e4488 | ||
|
|
8785c55cf3 | ||
|
|
38fa64d266 | ||
|
|
b04fff21fd | ||
|
|
3f656da786 | ||
|
|
55311868a7 | ||
|
|
422a1d39c3 | ||
|
|
6938759e9d | ||
|
|
5febe5e539 | ||
|
|
38479e34aa | ||
|
|
abe8f8e77b | ||
|
|
c0f3161525 | ||
|
|
c6bbba16e1 | ||
|
|
af4f99de51 | ||
|
|
8e6e8e18ad | ||
|
|
544e577eb2 | ||
|
|
9939d2c320 | ||
|
|
f47af1e94e | ||
|
|
d3302583f5 | ||
|
|
d9403c7f05 | ||
|
|
65eb72506b | ||
|
|
d86cdcad8e | ||
|
|
7d7f858c15 | ||
|
|
ee1ad9edd1 | ||
|
|
d985564198 | ||
|
|
c1b5a3f7b4 | ||
|
|
927ff9c4ab | ||
|
|
3411b438b6 | ||
|
|
40bc0d6464 | ||
|
|
b0639275f4 | ||
|
|
6216cd1dc6 | ||
|
|
78e6b3a9b3 | ||
|
|
509d1b46ff | ||
|
|
f06b2c2192 | ||
|
|
4138ddd84a | ||
|
|
e9a300bab2 | ||
|
|
6edd10a010 | ||
|
|
b438df4db9 | ||
|
|
49eab476bb | ||
|
|
8976654010 | ||
|
|
a78b8c2097 | ||
|
|
5709bb9a24 | ||
|
|
25668a6d82 | ||
|
|
3ae8353030 | ||
|
|
a3d053bde5 | ||
|
|
7e27a18245 | ||
|
|
6d09b27c85 | ||
|
|
c389bac46e | ||
|
|
fae8e77665 | ||
|
|
38cf0aeb8b | ||
|
|
a755750a89 | ||
|
|
555ee5c63d | ||
|
|
0fc51677c1 | ||
|
|
cc1c7a5364 | ||
|
|
d1fa99d6eb | ||
|
|
6697801f59 | ||
|
|
32fa69356c | ||
|
|
c42d754e72 | ||
|
|
e4babaf471 | ||
|
|
da196a789d | ||
|
|
6a656d63ab | ||
|
|
b0e226199a | ||
|
|
7cce6b17b2 | ||
|
|
d07aae4d0b | ||
|
|
f4a2ba536c | ||
|
|
2bbd69719d | ||
|
|
cf4ff14342 | ||
|
|
ae3a2fd51e | ||
|
|
d14ba3d35f | ||
|
|
10ef8b3e88 | ||
|
|
4bc65e2193 | ||
|
|
a45a5795d3 | ||
|
|
e1c5b77db4 | ||
|
|
280d08d074 | ||
|
|
1d55b34b62 | ||
|
|
d32302a1ab | ||
|
|
2eabfc255b | ||
|
|
d0375da6e4 | ||
|
|
4523c83b89 | ||
|
|
1decc7f462 | ||
|
|
f97a1e3fdf | ||
|
|
1e12ea3242 | ||
|
|
8919bc3b07 | ||
|
|
1a2b392d20 | ||
|
|
11a6584973 | ||
|
|
1e06fe6612 | ||
|
|
65ee18026e | ||
|
|
9c1617c213 | ||
|
|
d74067ddff | ||
|
|
60772c7659 | ||
|
|
25a70e6e4f | ||
|
|
a89675d961 | ||
|
|
0f340a25cf | ||
|
|
9cdc326b57 | ||
|
|
3faabd36c1 | ||
|
|
113ef5d7d0 | ||
|
|
9fa1e15425 | ||
|
|
2d9a46543d | ||
|
|
e5e589e1b0 | ||
|
|
2e0fab3a71 | ||
|
|
2f486be19c | ||
|
|
85868e5b8f | ||
|
|
31c70938bd | ||
|
|
99571dc73e | ||
|
|
5c2848c84c | ||
|
|
ffcfa8d1b5 | ||
|
|
debc03203c | ||
|
|
63668f57b5 | ||
|
|
aefe6b31e9 | ||
|
|
f854af1134 | ||
|
|
a9ef42a416 | ||
|
|
67c6140e6a | ||
|
|
b84037af11 | ||
|
|
61ed176683 | ||
|
|
12e44644ed | ||
|
|
59352177eb | ||
|
|
0b185cc885 | ||
|
|
ae0c106595 | ||
|
|
6d2b0f8319 | ||
|
|
60443f4fc7 | ||
|
|
418fe757d1 | ||
|
|
c9a624831a | ||
|
|
ed64f2e0d2 | ||
|
|
5f18609ed7 | ||
|
|
53c61cb024 | ||
|
|
3d70247f8b | ||
|
|
52b1c7b93b | ||
|
|
daeb463f77 | ||
|
|
0c75f70a1d | ||
|
|
674df112a4 | ||
|
|
26efc776c7 | ||
|
|
f221dc95cf | ||
|
|
187fc6acd2 | ||
|
|
9ecb68f6a3 | ||
|
|
f0113655ce | ||
|
|
31265c626b | ||
|
|
e2603ac3ae | ||
|
|
7acbed9637 | ||
|
|
20786fa6fb | ||
|
|
03c750a8b5 | ||
|
|
4da8c6053f | ||
|
|
a43061c61b | ||
|
|
11dc6bac4d | ||
|
|
7d5a886397 | ||
|
|
77aef8179d | ||
|
|
69e7c8ce71 | ||
|
|
82e294e3ef | ||
|
|
ccf3701011 | ||
|
|
e4b64e1050 | ||
|
|
0b8f702aa0 | ||
|
|
8caf90536b | ||
|
|
50e7d89576 | ||
|
|
fe5e9382d7 | ||
|
|
934c01f08d | ||
|
|
4ced15e528 | ||
|
|
3c151ed172 | ||
|
|
dd09895d7e | ||
|
|
3dd2b2ddce | ||
|
|
e4027d6373 | ||
|
|
7e880d33c7 | ||
|
|
356b17160e | ||
|
|
9a9b0c74ba | ||
|
|
dbde661d90 | ||
|
|
8904267cad | ||
|
|
c58cb2d4e7 | ||
|
|
cf971ea599 | ||
|
|
71c922c914 | ||
|
|
3607b526f0 | ||
|
|
1c87e8134c | ||
|
|
2a849312cc | ||
|
|
127caf54ae | ||
|
|
5902f4b02d | ||
|
|
40dfa95291 | ||
|
|
b8cef5fbd6 | ||
|
|
eed6890700 | ||
|
|
36e0c71b10 | ||
|
|
1bf020c594 | ||
|
|
072111a692 | ||
|
|
2cd7a96324 | ||
|
|
d8ff64222d | ||
|
|
0deaee625d | ||
|
|
bdfd89167d | ||
|
|
6b35032c0e | ||
|
|
8bf4f8ef02 | ||
|
|
7676fc6c37 | ||
|
|
d2ff8dca46 | ||
|
|
9c3d7abff5 | ||
|
|
4df4e21255 | ||
|
|
3fdde93255 | ||
|
|
65a7faebd5 | ||
|
|
c3b0909be0 | ||
|
|
641361d7c3 | ||
|
|
4a149f073a | ||
|
|
ba43b3fd4b | ||
|
|
5c2314702b | ||
|
|
3051de7a61 | ||
|
|
1abf8e54c3 | ||
|
|
93624cdb2d | ||
|
|
a7c6ea1f43 | ||
|
|
f23093c3a9 | ||
|
|
6f4a150d82 | ||
|
|
6790cd1647 | ||
|
|
05408ef4ea | ||
|
|
2bc3fe8a57 | ||
|
|
015942a1e4 | ||
|
|
321da76fd9 | ||
|
|
f67b08768d | ||
|
|
fb1e59ef5a | ||
|
|
a1318f1061 | ||
|
|
9543951747 | ||
|
|
0926339482 | ||
|
|
7f60e133dc | ||
|
|
ba3893980d | ||
|
|
363f59d276 |
No files matched your search
@@ -1,4 +1,9 @@
|
||||
# go-assets.sh downloads
|
||||
/server/assets/fs/**.zip
|
||||
/server/assets/fs/**/garble*
|
||||
/server/assets/fs/**/zig.tar.xz
|
||||
/server/assets/fs/**/zig.zip
|
||||
/server/assets/fs/src.zip
|
||||
|
||||
/*.sdk.tar.xz
|
||||
|
||||
@@ -19,3 +24,5 @@
|
||||
/SECURITY.md
|
||||
/README.md
|
||||
/CONTRIBUTING.md
|
||||
|
||||
.downloaded_assets
|
||||
@@ -11,10 +11,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Go 1.21
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.21"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
git build-essential zlib1g zlib1g-dev wget zip unzip
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -42,13 +42,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- run: mkdir -p ./builds
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: ./builds
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Setup go environment
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# Must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head of the pull request.
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
git build-essential zlib1g zlib1g-dev wget zip unzip
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Detect package manager
|
||||
id: detect-package-manager
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "**/package-lock.json"
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
run: ${{ steps.detect-package-manager.outputs.runner }} next build
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
uses: actions/upload-pages-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/docs/sliver-docs/out
|
||||
|
||||
|
||||
@@ -21,12 +21,12 @@ jobs:
|
||||
linux-windows-build-test:
|
||||
name: Linux & Windows Test
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -34,38 +34,36 @@ jobs:
|
||||
git build-essential zlib1g zlib1g-dev wget zip unzip
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
|
||||
- name: Make Linux (amd64)
|
||||
run: make linux-amd64
|
||||
|
||||
- name: Test Linux
|
||||
run: ./sliver-server unpack --force && ./go-tests.sh
|
||||
|
||||
- name: Make Windows (amd64)
|
||||
run: make windows-amd64
|
||||
|
||||
- name: Make Linux (arm64)
|
||||
run: make linux-arm64
|
||||
|
||||
- name: Make Linux (amd64)
|
||||
run: make linux-amd64
|
||||
|
||||
- name: Test Linux
|
||||
run: make clean && make && ./sliver-server unpack --force && ./go-tests.sh
|
||||
|
||||
|
||||
macos-build-test:
|
||||
name: MacOS Test
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
|
||||
- name: Mingw
|
||||
run: brew install mingw-w64
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -73,24 +71,24 @@ jobs:
|
||||
- name: Make MacOS (amd64)
|
||||
run: make macos-amd64
|
||||
|
||||
- name: Test MacOS (amd64)
|
||||
run: ./sliver-server unpack --force && ./go-tests.sh
|
||||
|
||||
- name: Make MacOS (arm64)
|
||||
run: make macos-arm64
|
||||
|
||||
- name: Test MacOS
|
||||
run: make clean && make && ./sliver-server unpack --force && ./go-tests.sh
|
||||
|
||||
clients-build:
|
||||
name: Clients Build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Go 1.22
|
||||
uses: actions/setup-go@v5
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.22"
|
||||
go-version: "^1.25"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
|
||||
@@ -45,6 +45,8 @@ sliver-server-windows.zip
|
||||
.DS_Store
|
||||
|
||||
dist/
|
||||
.gocache/
|
||||
.gomodcache/
|
||||
|
||||
# Flag to show that go-assets.sh has been run
|
||||
.downloaded_assets
|
||||
@@ -0,0 +1,23 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
Sliver is a Go monorepo. Core client code lives in `client/` (CLI, assets, transports) and server code in `server/` (C2 services, assets, configs). `implant/` holds implant payload sources, while `util/` provides shared helpers that must stay server-side. Protocol buffers live under `protobuf/`, and documentation assets are in `docs/`. Keep generated artifacts (e.g., `sliver-client`, `sliver-server`, `.downloaded_assets`) out of commits.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
Use `make` targets to stay consistent:
|
||||
- `make` (or `make default`) compiles client/server binaries with vendored modules and tag defaults.
|
||||
- `make client` and `make linux-amd64` build platform-specific emitters; prefer `GOOS/GOARCH` env vars over editing sources.
|
||||
- `./go-assets.sh` refreshes client asset bundles; rerun when static files change.
|
||||
Regenerate protobuf bindings with `make pb`. For quick checks, `GOFLAGS="-tags client" go build ./client/...` is acceptable, but ensure the matching `server` build also succeeds.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
Target Go 1.22+ (see `Makefile` validation). Format code with `gofmt` or `goimports` before committing. Keep package imports segregated (stdlib, third-party, internal). Use lower_snake filenames for assets, PascalCase for exported Go symbols, and prefer explicit names (`sessionID`, `operatorConfig`) over abbreviations. Never import `server` packages inside `client`. Avoid introducing CGO unless justified for cross-platform support.
|
||||
|
||||
## Testing Guidelines
|
||||
Run targeted unit tests with Go’s tooling and project tags, e.g. `go test -tags=client,go_sqlite ./client/command/...`. Full coverage uses `./build.py`; expect long runtimes and ensure ample CPU/RAM. Add tests beside code (`*_test.go`) and mirror package paths. When adding transports or implants, verify integration logs under `~/.sliver/logs/` for regressions and clean up fixtures.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
Sign every commit (`git commit -S`) and write imperative, scoped messages ("Fix DNS canary retry" rather than status updates). Keep vendor updates isolated in their own commit. Pull requests should describe the intent, affected modules, testing performed, and reference GitHub issues. Include before/after screenshots only when UI behavior changes (client console). Ensure CI passes and note any required follow-up.
|
||||
|
||||
## Security & Configuration Tips
|
||||
Default to secure settings: avoid `math/rand` for secrets, prefer vetted crypto (AES-GCM, Curve25519) per `CONTRIBUTING.md`. Lock down file permissions for generated assets and redact secrets from logs. When touching configuration, favor secure defaults even if it means additional setup for operators.
|
||||
+6
-6
@@ -9,7 +9,7 @@
|
||||
|
||||
# STAGE: base
|
||||
## Compiles Sliver for use
|
||||
FROM golang:1.22.2 as base
|
||||
FROM golang:latest AS base
|
||||
|
||||
### Base packages
|
||||
RUN apt-get update --fix-missing && apt-get -y install \
|
||||
@@ -20,16 +20,16 @@ RUN groupadd -g 999 sliver && useradd -r -u 999 -g sliver sliver
|
||||
RUN mkdir -p /home/sliver/ && chown -R sliver:sliver /home/sliver
|
||||
|
||||
### Build sliver:
|
||||
RUN mkdir -p /go/src/github.com/bishopfox/sliver
|
||||
WORKDIR /go/src/github.com/bishopfox/sliver
|
||||
ADD . /go/src/github.com/bishopfox/sliver/
|
||||
RUN make clean-all
|
||||
RUN make
|
||||
RUN make
|
||||
RUN cp -vv sliver-server /opt/sliver-server
|
||||
|
||||
# STAGE: test
|
||||
## Run unit tests against the compiled instance
|
||||
## Use `--target test` in the docker build command to run this stage
|
||||
FROM base as test
|
||||
FROM base AS test
|
||||
|
||||
RUN apt-get update --fix-missing \
|
||||
&& apt-get -y upgrade \
|
||||
@@ -43,7 +43,7 @@ RUN /go/src/github.com/bishopfox/sliver/go-tests.sh
|
||||
|
||||
# STAGE: production
|
||||
## Final dockerized form of Sliver
|
||||
FROM debian:bookworm-slim as production
|
||||
FROM debian:bookworm-slim AS production
|
||||
|
||||
### Install production packages
|
||||
RUN apt-get update --fix-missing \
|
||||
@@ -91,7 +91,7 @@ ENTRYPOINT [ "/opt/sliver-server" ]
|
||||
|
||||
|
||||
# STAGE: production-slim (about 1Gb smaller)
|
||||
FROM debian:bookworm-slim as production-slim
|
||||
FROM debian:bookworm-slim AS production-slim
|
||||
|
||||
### Install production packages
|
||||
RUN apt-get update --fix-missing \
|
||||
|
||||
@@ -27,7 +27,7 @@ GO_VERSION = $(shell $(GO) version)
|
||||
GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1)
|
||||
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
|
||||
MIN_SUPPORTED_GO_MAJOR_VERSION = 1
|
||||
MIN_SUPPORTED_GO_MINOR_VERSION = 21
|
||||
MIN_SUPPORTED_GO_MINOR_VERSION = 24
|
||||
GO_VERSION_VALIDATION_ERR_MSG = Golang version is not supported, please update to at least $(MIN_SUPPORTED_GO_MAJOR_VERSION).$(MIN_SUPPORTED_GO_MINOR_VERSION)
|
||||
|
||||
VERSION ?= $(shell git describe --abbrev=0)
|
||||
|
||||
@@ -8,7 +8,7 @@ The server and client support MacOS, Windows, and Linux. Implants are supported
|
||||
|
||||
# v1.6.0 / `master`
|
||||
|
||||
**NOTE:** You are looking the latest master branch of Sliver v1.6.0; new PRs should target this branch. However, this branch is NOT RECOMMENDED for production use yet. Please use release tagged versions for the best experience.
|
||||
**NOTE:** You are looking at the latest master branch of Sliver v1.6.0; new PRs should target this branch. However, this branch is NOT RECOMMENDED for production use yet. Please use release tagged versions for the best experience.
|
||||
|
||||
For PRs containing bug fixes specific to Sliver v1.5, please target the [`v1.5.x/master` branch](https://github.com/BishopFox/sliver/tree/v1.5.x/master).
|
||||
|
||||
@@ -47,7 +47,7 @@ See the [wiki](https://sliver.sh/docs?name=Compile+from+Source).
|
||||
|
||||
### Feedback
|
||||
|
||||
Please take a moment and fill out [our survey](https://forms.gle/SwVsHFNh24ChG58C6)
|
||||
Please take a moment and fill out [our survey](https://forms.gle/SwVsHFNh24ChG58C6).
|
||||
|
||||
### License - GPLv3
|
||||
|
||||
|
||||
+23
-15
@@ -1,18 +1,26 @@
|
||||
Client
|
||||
=======
|
||||
# client
|
||||
|
||||
This directory contains the client implementation, pretty much all of this code is also used by the server console.
|
||||
## Overview
|
||||
|
||||
__Important:__ No code in this directory can import any code from `server/`.
|
||||
Main command-line client for interacting with and administering Sliver servers. Provides the Cobra entrypoint and aggregates console, command, and transport subsystems.
|
||||
|
||||
* `assets/` - Static asset files and management code (e.g. client configs)
|
||||
* `cli/` - Command line interface implementation
|
||||
* `command/` - Console command implementations
|
||||
* `constants/` - Various shared constant values
|
||||
* `core/` - Client state management
|
||||
* `licenses/` - Open source licenses
|
||||
* `spin/` - Console spinner library
|
||||
* `tcpproxy/` - Local TCP proxy listener code
|
||||
* `transport/` - Wires the client to the server
|
||||
* `version/` - Version information
|
||||
* `main.go` - Entrypoint
|
||||
## Go Files
|
||||
|
||||
- `main.go` – Entry point that initializes the CLI, processes flags, and launches the interactive console.
|
||||
|
||||
## Sub-packages
|
||||
|
||||
- `assets/` – Manages embedded client asset manifests such as operator profiles, settings, and armory catalogs. Handles serialization, bundling, and lookup of static client metadata.
|
||||
- `cli/` – Defines the Cobra root command and CLI initialization for the Sliver client binary. Sets up persistent flags, environment bootstrapping, and command wiring.
|
||||
- `command/` – Shared registration glue, scaffolding, and helpers for Sliver client console command groups. Hosts common utilities for binding Cobra commands to RPC-backed actions.
|
||||
- `console/` – Renders the interactive console UI, logging, and terminal helpers for the client. Coordinates readline behavior, prompt styling, and message formatting.
|
||||
- `constants/` – Centralizes constants shared across the client runtime and command packages. Captures strings, flag names, and feature toggles used throughout the CLI.
|
||||
- `core/` – Maintains client application state, background workers, and RPC coordination. Orchestrates session tracking, event streams, and health checks.
|
||||
- `credentials/` – Credential management utilities including sniffers and import helpers for operators. Provides parsers, storage helpers, and output formatting for recovered secrets.
|
||||
- `licenses/` – Holds embedded license metadata bundled with the client distribution. Supplies license retrieval utilities used for attribution commands.
|
||||
- `overlord/` – Supervises long-running client jobs, scheduling, and task orchestration. Tracks job lifecycle events and exposes status updates to the console.
|
||||
- `packages/` – Deals with packaged extensions and module discovery for the client. Scans, validates, and caches extension manifests and assets.
|
||||
- `spin/` – Lightweight terminal spinner utilities used for progress feedback. Wraps spinner styles and timing helpers shared across commands.
|
||||
- `tcpproxy/` – Implements the local TCP proxy used for port forwarding from the client side. Manages listener lifecycles, connection pumps, and cleanup hooks.
|
||||
- `transport/` – Client-side transports and RPC wiring to communicate with Sliver servers. Builds authenticated gRPC clients, TLS dialers, and reconnect logic.
|
||||
- `version/` – Build-time version and semantic metadata for the client binary. Exposes git information, release channels, and helper formatters.
|
||||
+14
-2
@@ -1,3 +1,15 @@
|
||||
Assets
|
||||
======
|
||||
# client/assets
|
||||
|
||||
## Overview
|
||||
|
||||
Manages embedded client asset manifests such as operator profiles, settings, and armory catalogs. Handles serialization, bundling, and lookup of static client metadata. Core logic addresses aliases, armories, C2 profiles, and extensions within the assets package.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `aliases.go` – Provides helpers for discovering, installing, and reading alias manifests shipped with the client.
|
||||
- `armories.go` – Loads configured armory definitions and persists operator customizations.
|
||||
- `assets.go` – Central entry point that exposes asset directories, lazy initialization, and filesystem utilities.
|
||||
- `c2profiles.go` – Embeds default HTTP C2 profile templates and exposes lookup utilities.
|
||||
- `config.go` – Tracks client configuration paths and manages persistence of runtime options.
|
||||
- `extensions.go` – Handles embedded extension manifests and supports lookup by command name.
|
||||
- `settings.go` – Stores default console settings and manages serialization to disk.
|
||||
+12
-25
@@ -35,7 +35,7 @@ type NameValueProbability struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Probability int `json:"probability"`
|
||||
Methods []string
|
||||
Method string `json:"method"`
|
||||
}
|
||||
|
||||
// HTTPC2ImplantConfig - Implant configuration options
|
||||
@@ -57,30 +57,17 @@ type HTTPC2ImplantConfig struct {
|
||||
NonceQueryArgChars string `json:"nonce_query_args"`
|
||||
URLParameters []NameValueProbability `json:"url_parameters"`
|
||||
Headers []NameValueProbability `json:"headers"`
|
||||
NonceQueryLength int `json:"nonce_query_length"`
|
||||
NonceMode string `json:"nonce_mode"`
|
||||
|
||||
MaxFiles int `json:"max_files"`
|
||||
MinFiles int `json:"min_files"`
|
||||
MaxPaths int `json:"max_paths"`
|
||||
MinPaths int `json:"min_paths"`
|
||||
MaxFileGen int `json:"max_files"`
|
||||
MinFileGen int `json:"min_files"`
|
||||
MaxPathGen int `json:"max_paths"`
|
||||
MinPathGen int `json:"min_paths"`
|
||||
MaxPathLength int `json:"max_path_length"`
|
||||
MinPathLength int `json:"min_path_length"`
|
||||
|
||||
// Stager files and paths
|
||||
StagerFileExt string `json:"stager_file_ext"`
|
||||
StagerFiles []string `json:"stager_files"`
|
||||
StagerPaths []string `json:"stager_paths"`
|
||||
|
||||
// Poll files and paths
|
||||
PollFileExt string `json:"poll_file_ext"`
|
||||
PollFiles []string `json:"poll_files"`
|
||||
PollPaths []string `json:"poll_paths"`
|
||||
|
||||
// Session files and paths
|
||||
StartSessionFileExt string `json:"start_session_file_ext"`
|
||||
SessionFileExt string `json:"session_file_ext"`
|
||||
SessionFiles []string `json:"session_files"`
|
||||
SessionPaths []string `json:"session_paths"`
|
||||
|
||||
// Close session files and paths
|
||||
CloseFileExt string `json:"close_file_ext"`
|
||||
CloseFiles []string `json:"close_files"`
|
||||
ClosePaths []string `json:"close_paths"`
|
||||
Extensions []string `json:"extensions"`
|
||||
Files []string `json:"files"`
|
||||
Paths []string `json:"paths"`
|
||||
}
|
||||
+13
-3
@@ -1,4 +1,14 @@
|
||||
CLI
|
||||
===
|
||||
# client/cli
|
||||
|
||||
This package implements the Sliver client cli.
|
||||
## Overview
|
||||
|
||||
Defines the Cobra root command and CLI initialization for the Sliver client binary. Sets up persistent flags, environment bootstrapping, and command wiring. Core logic addresses console, implant, import, and version within the cli package.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `cli.go` – Builds the root Cobra command, wires global flags, and starts the console UI.
|
||||
- `config.go` – Parses CLI configuration files and environment variables used during startup.
|
||||
- `console.go` – Launches the interactive console mode and handles profile selection.
|
||||
- `implant.go` – Implements CLI entry points for implant-specific operations without launching the console.
|
||||
- `import.go` – Provides import routines for bringing external state into the client (e.g., implants or loot).
|
||||
- `version.go` – Prints version/build information for the CLI binary.
|
||||
+62
-11
@@ -1,14 +1,65 @@
|
||||
Command
|
||||
=======
|
||||
# client/command
|
||||
|
||||
This package contains all of the client command implementations that are shared between the client and the server console.
|
||||
## Overview
|
||||
|
||||
### Developers
|
||||
Shared registration glue, scaffolding, and helpers for Sliver client console command groups. Hosts common utilities for binding Cobra commands to RPC-backed actions. Core logic addresses sliver within the command package.
|
||||
|
||||
General guidance on the structure of this package:
|
||||
* One command per file and the name of the file should reflect the command it implements (or there about, trivial commands can go into the same file). This makes it easy to find where a command implementation lives within a package or to search by file name if it is not clear which package implements a given command.
|
||||
* The root command, and reused code should go into the file named after the command
|
||||
* For example, code shared between the `generate` and the `regenerate` command should go in `generate.go`, and any `regenerate` specific code should go in `regenerate.go`
|
||||
* Command entrypoint functions should have the suffix `Cmd` e.g., `GenerateCmd` is the entrypoint for `generate`
|
||||
* Command entrypoints should always a function signature of `func (ctx *grumble.Context, con *console.SliverConsoleClient)`
|
||||
* Functions that are only ever exported for other commands to use should go in a `helpers.go`, if the function is used internally and exported follow the guidance above on shared code.
|
||||
## Go Files
|
||||
|
||||
- `command.go` – Provides helpers for binding Cobra commands, flag sets, and visibility filters into the client command tree.
|
||||
- `server.go` – Defines the server menu composition, wiring each server-side command group onto the root console structure at runtime.
|
||||
- `sliver.go` – Builds the implant/Sliver menu, attaching per-target command groups and loading alias/extension manifests before exposure.
|
||||
|
||||
## Sub-packages
|
||||
|
||||
- `alias/` – Implements the 'alias' command group for the Sliver client console.
|
||||
- `armory/` – Implements the 'armory' command group for the Sliver client console.
|
||||
- `backdoor/` – Implements the 'backdoor' command group for the Sliver client console.
|
||||
- `beacons/` – Implements the 'beacons' command group for the Sliver client console.
|
||||
- `builders/` – Implements the 'builders' command group for the Sliver client console.
|
||||
- `c2profiles/` – Implements the 'c2profiles' command group for the Sliver client console.
|
||||
- `certificates/` – Implements the 'certificates' command group for the Sliver client console.
|
||||
- `clean/` – Implements the 'clean' command group for the Sliver client console.
|
||||
- `completers/` – Implements the 'completers' command group for the Sliver client console.
|
||||
- `crack/` – Implements the 'crack' command group for the Sliver client console.
|
||||
- `creds/` – Implements the 'creds' command group for the Sliver client console.
|
||||
- `cursed/` – Implements the 'cursed' command group for the Sliver client console.
|
||||
- `dllhijack/` – Implements the 'dllhijack' command group for the Sliver client console.
|
||||
- `environment/` – Implements the 'environment' command group for the Sliver client console.
|
||||
- `exec/` – Implements the 'exec' command group for the Sliver client console.
|
||||
- `exit/` – Implements the 'exit' command group for the Sliver client console.
|
||||
- `extensions/` – Implements the 'extensions' command group for the Sliver client console.
|
||||
- `filesystem/` – Implements the 'filesystem' command group for the Sliver client console.
|
||||
- `flags/` – Implements the 'flags' command group for the Sliver client console.
|
||||
- `generate/` – Implements the 'generate' command group for the Sliver client console.
|
||||
- `help/` – Implements the 'help' command group for the Sliver client console.
|
||||
- `hosts/` – Implements the 'hosts' command group for the Sliver client console.
|
||||
- `info/` – Implements the 'info' command group for the Sliver client console.
|
||||
- `jobs/` – Implements the 'jobs' command group for the Sliver client console.
|
||||
- `kill/` – Implements the 'kill' command group for the Sliver client console.
|
||||
- `licenses/` – Implements the 'licenses' command group for the Sliver client console.
|
||||
- `loot/` – Implements the 'loot' command group for the Sliver client console.
|
||||
- `monitor/` – Implements the 'monitor' command group for the Sliver client console.
|
||||
- `network/` – Implements the 'network' command group for the Sliver client console.
|
||||
- `operators/` – Implements the 'operators' command group for the Sliver client console.
|
||||
- `pivots/` – Implements the 'pivots' command group for the Sliver client console.
|
||||
- `portfwd/` – Implements the 'portfwd' command group for the Sliver client console.
|
||||
- `privilege/` – Implements the 'privilege' command group for the Sliver client console.
|
||||
- `processes/` – Implements the 'processes' command group for the Sliver client console.
|
||||
- `reaction/` – Implements the 'reaction' command group for the Sliver client console.
|
||||
- `reconfig/` – Implements the 'reconfig' command group for the Sliver client console.
|
||||
- `registry/` – Implements the 'registry' command group for the Sliver client console.
|
||||
- `rportfwd/` – Implements the 'rportfwd' command group for the Sliver client console.
|
||||
- `screenshot/` – Implements the 'screenshot' command group for the Sliver client console.
|
||||
- `sessions/` – Implements the 'sessions' command group for the Sliver client console.
|
||||
- `settings/` – Implements the 'settings' command group for the Sliver client console.
|
||||
- `shell/` – Implements the 'shell' command group for the Sliver client console.
|
||||
- `shikata-ga-nai/` – Implements the 'shikata-ga-nai' command group for the Sliver client console.
|
||||
- `socks/` – Implements the 'socks' command group for the Sliver client console.
|
||||
- `taskmany/` – Implements the 'taskmany' command group for the Sliver client console.
|
||||
- `tasks/` – Implements the 'tasks' command group for the Sliver client console.
|
||||
- `update/` – Implements the 'update' command group for the Sliver client console.
|
||||
- `use/` – Implements the 'use' command group for the Sliver client console.
|
||||
- `wasm/` – Implements the 'wasm' command group for the Sliver client console.
|
||||
- `websites/` – Implements the 'websites' command group for the Sliver client console.
|
||||
- `wireguard/` – Implements the 'wireguard' command group for the Sliver client console.
|
||||
@@ -1,11 +1,14 @@
|
||||
Alias
|
||||
===========
|
||||
# client/command/alias
|
||||
|
||||
Wraps external DLLs/tool in Sliver console commands.
|
||||
## Overview
|
||||
|
||||
Implements the 'alias' command group for the Sliver client console. Handlers map Cobra invocations to alias workflows such as install, load, and remove.
|
||||
|
||||
## Go Files
|
||||
|
||||
### Format
|
||||
|
||||
* `alias-dir/`
|
||||
* * `manifest.json` -
|
||||
- `alias.go` – Implements runtime alias management, printing installed aliases and exposing tab-completion helpers.
|
||||
- `alias_test.go` *(tests)* – Exercises manifest parsing logic to ensure alias metadata is interpreted correctly.
|
||||
- `commands.go` – Wires Cobra commands for listing, installing, loading, and removing aliases into the client console.
|
||||
- `install.go` – Handles installing alias bundles from directories or archives, writing manifests and payload artifacts to disk.
|
||||
- `load.go` – Loads alias manifests, validates target compatibility, and registers commands against the active console.
|
||||
- `remove.go` – Removes installed aliases, prompting for confirmation and deleting associated on-disk assets.
|
||||
@@ -114,7 +114,7 @@ func InstallFromFile(aliasGzFilePath string, aliasName string, promptToOverwrite
|
||||
} else {
|
||||
errorMsg = fmt.Sprintf("Failed to parse %s: %s\n", ManifestFileName, err)
|
||||
}
|
||||
con.PrintErrorf(errorMsg)
|
||||
con.PrintErrorf("%s", errorMsg)
|
||||
return nil
|
||||
}
|
||||
installPath := filepath.Join(assets.GetAliasesDir(), filepath.Base(manifest.CommandName))
|
||||
|
||||
@@ -311,7 +311,7 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverClient, args []strin
|
||||
} else if !aliasManifest.IsReflective {
|
||||
msgStr = " Arguments are limited to 256 characters when using the default fork/exec model for non-reflective PE payloads.\n"
|
||||
}
|
||||
con.PrintWarnf(msgStr)
|
||||
con.PrintWarnf("%s", msgStr)
|
||||
confirm := false
|
||||
prompt := &survey.Confirm{Message: "Do you want to continue?"}
|
||||
survey.AskOne(prompt, &confirm, nil)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# client/command/armory
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'armory' command group for the Sliver client console. Handlers map Cobra invocations to armory workflows such as install, manage, parsers, and search.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `armory.go` – Maintains the armory cache lifecycle, fetching package metadata, verifying signatures, and presenting bundle listings.
|
||||
- `armory_test.go` *(tests)* – Placeholder for armory command tests; currently used to keep the package's test harness wired up.
|
||||
- `commands.go` – Declares the Cobra command hierarchy for armory actions and binds shared flag/completion plumbing.
|
||||
- `install.go` – Resolves dependencies and installs aliases or extensions from cached metadata, prompting when overwriting existing packages.
|
||||
- `manage.go` – Implements management helpers for viewing, adding, verifying, and persisting armory configurations.
|
||||
- `parsers.go` – Provides parsers and HTTP helpers for retrieving armory indexes and packages, including Minisign verification.
|
||||
- `search.go` – Implements the regex-driven search command that filters cached armory packages.
|
||||
- `update.go` – Calculates available package updates, presents options to the user, and orchestrates update installation.
|
||||
@@ -1,4 +1,10 @@
|
||||
Backdoor
|
||||
========
|
||||
# client/command/backdoor
|
||||
|
||||
Implements command related to `backdoor`
|
||||
## Overview
|
||||
|
||||
Implements the 'backdoor' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `backdoor.go` – Implements the RPC workflow that backdoors a remote binary with Sliver shellcode for the active session.
|
||||
- `commands.go` – Registers the Cobra command, binds flags/completions, and restricts usage to applicable targets.
|
||||
@@ -1,4 +1,14 @@
|
||||
Beacons
|
||||
========
|
||||
# client/command/beacons
|
||||
|
||||
This package implements the beacons command, which can be used to list and interact with beacons.
|
||||
## Overview
|
||||
|
||||
Implements the 'beacons' command group for the Sliver client console. Handlers map Cobra invocations to beacons workflows such as prune, RM, and watch.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `beacons.go` – Retrieves beacon inventories and renders them in tabular form with optional filtering.
|
||||
- `commands.go` – Declares the beacons command set, binds flags/completions, and wires subcommands like prune, rm, and watch.
|
||||
- `helpers.go` – Provides helper RPC wrappers for selecting, fetching, and listing beacons.
|
||||
- `prune.go` – Implements the prune routine that removes stale beacon entries via the backend API.
|
||||
- `rm.go` – Removes a specific beacon by ID, coordinating confirmation and RPC teardown.
|
||||
- `watch.go` – Streams beacon events in a watch loop, handling cancellation and console interaction.
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/builders
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'builders' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `builders.go` – Fetches external builder metadata and formats it for console display.
|
||||
- `commands.go` – Registers the builders CLI command with its flags and completion helpers.
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/c2profiles
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'c2profiles' command group for the Sliver client console. Handlers map Cobra invocations to c2profiles workflows such as C2 profiles.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `c2profiles.go` – Implements listing, import/export, and generation routines for HTTP C2 profiles, including protobuf/JSON conversion helpers.
|
||||
- `commands.go` – Binds the c2profiles command suite with flag handling and completions for profile management operations.
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
@@ -67,7 +66,6 @@ func C2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []string)
|
||||
}
|
||||
|
||||
func ImportC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
protocols := []string{constants.HttpStr, constants.HttpsStr}
|
||||
profileName, _ := cmd.Flags().GetString("name")
|
||||
if profileName == "" {
|
||||
con.PrintErrorf("Invalid c2 profile name\n")
|
||||
@@ -103,29 +101,6 @@ func ImportC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []st
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
confirm := false
|
||||
prompt := &survey.Confirm{Message: "Restart HTTP/S jobs?"}
|
||||
survey.AskOne(prompt, &confirm)
|
||||
if confirm {
|
||||
var restartJobReq clientpb.RestartJobReq
|
||||
jobs, err := con.Rpc.GetJobs(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
// reload jobs to include new profile
|
||||
for _, job := range jobs.Active {
|
||||
if job != nil && slices.Contains(protocols, job.Name) {
|
||||
restartJobReq.JobIDs = append(restartJobReq.JobIDs, job.ID)
|
||||
}
|
||||
}
|
||||
|
||||
_, err = con.Rpc.RestartJobs(context.Background(), &restartJobReq)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExportC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
@@ -201,23 +176,6 @@ func GenerateC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []
|
||||
return
|
||||
}
|
||||
|
||||
c2Profiles, err := con.Rpc.GetHTTPC2Profiles(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
var extensions []string
|
||||
for _, c2profile := range c2Profiles.Configs {
|
||||
confProfile, err := con.Rpc.GetHTTPC2ProfileByName(context.Background(), &clientpb.C2ProfileReq{Name: c2profile.Name})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
extensions = append(extensions, confProfile.ImplantConfig.StagerFileExtension)
|
||||
extensions = append(extensions, confProfile.ImplantConfig.StartSessionFileExtension)
|
||||
}
|
||||
|
||||
config, err := C2ConfigToJSON(profileName, profile)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
@@ -243,7 +201,7 @@ func GenerateC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []
|
||||
}
|
||||
urls := strings.Split(string(fileContent), "\n")
|
||||
|
||||
jsonProfile, err := updateC2Profile(extensions, config, urls)
|
||||
jsonProfile, err := updateC2Profile(config, urls)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
@@ -264,26 +222,26 @@ func GenerateC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []
|
||||
}
|
||||
con.Println("C2 profile generated and saved as ", profileName)
|
||||
} else {
|
||||
PrintC2Profiles(profile, con)
|
||||
PrintC2Profiles(C2ConfigToProtobuf(profileName, jsonProfile), con)
|
||||
}
|
||||
}
|
||||
|
||||
// convert protobuf to json
|
||||
func C2ConfigToJSON(profileName string, profile *clientpb.HTTPC2Config) (*assets.HTTPC2Config, error) {
|
||||
implantConfig := assets.HTTPC2ImplantConfig{
|
||||
UserAgent: profile.ImplantConfig.UserAgent,
|
||||
ChromeBaseVersion: int(profile.ImplantConfig.ChromeBaseVersion),
|
||||
MacOSVersion: profile.ImplantConfig.MacOSVersion,
|
||||
NonceQueryArgChars: profile.ImplantConfig.NonceQueryArgChars,
|
||||
MaxFiles: int(profile.ImplantConfig.MaxFiles),
|
||||
MinFiles: int(profile.ImplantConfig.MinFiles),
|
||||
MaxPaths: int(profile.ImplantConfig.MaxPaths),
|
||||
MinPaths: int(profile.ImplantConfig.MinFiles),
|
||||
StagerFileExt: profile.ImplantConfig.StagerFileExtension,
|
||||
PollFileExt: profile.ImplantConfig.PollFileExtension,
|
||||
StartSessionFileExt: profile.ImplantConfig.StartSessionFileExtension,
|
||||
SessionFileExt: profile.ImplantConfig.SessionFileExtension,
|
||||
CloseFileExt: profile.ImplantConfig.CloseFileExtension,
|
||||
UserAgent: profile.ImplantConfig.UserAgent,
|
||||
ChromeBaseVersion: int(profile.ImplantConfig.ChromeBaseVersion),
|
||||
MacOSVersion: profile.ImplantConfig.MacOSVersion,
|
||||
NonceQueryArgChars: profile.ImplantConfig.NonceQueryArgChars,
|
||||
NonceQueryLength: int(profile.ImplantConfig.NonceQueryLength),
|
||||
NonceMode: profile.ImplantConfig.NonceMode,
|
||||
MaxFileGen: int(profile.ImplantConfig.MaxFileGen),
|
||||
MinFileGen: int(profile.ImplantConfig.MinFileGen),
|
||||
MaxPathGen: int(profile.ImplantConfig.MaxPathGen),
|
||||
MinPathGen: int(profile.ImplantConfig.MinFileGen),
|
||||
MaxPathLength: int(profile.ImplantConfig.MaxPathLength),
|
||||
MinPathLength: int(profile.ImplantConfig.MinPathLength),
|
||||
Extensions: profile.ImplantConfig.Extensions,
|
||||
}
|
||||
|
||||
var headers []assets.NameValueProbability
|
||||
@@ -292,6 +250,7 @@ func C2ConfigToJSON(profileName string, profile *clientpb.HTTPC2Config) (*assets
|
||||
Name: header.Name,
|
||||
Value: header.Value,
|
||||
Probability: int(header.Probability),
|
||||
Method: header.Method,
|
||||
})
|
||||
}
|
||||
implantConfig.Headers = headers
|
||||
@@ -307,50 +266,19 @@ func C2ConfigToJSON(profileName string, profile *clientpb.HTTPC2Config) (*assets
|
||||
implantConfig.URLParameters = urlParameters
|
||||
|
||||
var (
|
||||
stagerFiles []string
|
||||
pollFiles []string
|
||||
sessionFiles []string
|
||||
closeFiles []string
|
||||
stagerPaths []string
|
||||
pollPaths []string
|
||||
sessionPaths []string
|
||||
closePaths []string
|
||||
files []string
|
||||
paths []string
|
||||
)
|
||||
|
||||
for _, pathSegment := range profile.ImplantConfig.PathSegments {
|
||||
if pathSegment.IsFile {
|
||||
switch pathSegment.SegmentType {
|
||||
case 0:
|
||||
pollFiles = append(pollFiles, pathSegment.Value)
|
||||
case 1:
|
||||
sessionFiles = append(sessionFiles, pathSegment.Value)
|
||||
case 2:
|
||||
closeFiles = append(closeFiles, pathSegment.Value)
|
||||
case 3:
|
||||
stagerFiles = append(stagerFiles, pathSegment.Value)
|
||||
}
|
||||
files = append(files, pathSegment.Value)
|
||||
} else {
|
||||
switch pathSegment.SegmentType {
|
||||
case 0:
|
||||
pollPaths = append(pollPaths, pathSegment.Value)
|
||||
case 1:
|
||||
sessionPaths = append(sessionPaths, pathSegment.Value)
|
||||
case 2:
|
||||
closePaths = append(closePaths, pathSegment.Value)
|
||||
case 3:
|
||||
stagerPaths = append(stagerPaths, pathSegment.Value)
|
||||
}
|
||||
paths = append(paths, pathSegment.Value)
|
||||
}
|
||||
}
|
||||
|
||||
implantConfig.PollFiles = pollFiles
|
||||
implantConfig.SessionFiles = sessionFiles
|
||||
implantConfig.CloseFiles = closeFiles
|
||||
implantConfig.StagerFiles = stagerFiles
|
||||
implantConfig.PollPaths = pollPaths
|
||||
implantConfig.SessionPaths = sessionPaths
|
||||
implantConfig.ClosePaths = closePaths
|
||||
implantConfig.StagerPaths = stagerPaths
|
||||
implantConfig.Files = files
|
||||
implantConfig.Paths = paths
|
||||
|
||||
var serverHeaders []assets.NameValueProbability
|
||||
for _, header := range profile.ServerConfig.Headers {
|
||||
@@ -358,6 +286,7 @@ func C2ConfigToJSON(profileName string, profile *clientpb.HTTPC2Config) (*assets
|
||||
Name: header.Name,
|
||||
Value: header.Value,
|
||||
Probability: int(header.Probability),
|
||||
Method: header.Method,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -388,101 +317,66 @@ func C2ConfigToProtobuf(profileName string, config *assets.HTTPC2Config) *client
|
||||
pathSegments := []*clientpb.HTTPC2PathSegment{}
|
||||
|
||||
// files
|
||||
for _, poll := range config.ImplantConfig.PollFiles {
|
||||
for _, file := range config.ImplantConfig.Files {
|
||||
pathSegments = append(pathSegments, &clientpb.HTTPC2PathSegment{
|
||||
IsFile: true,
|
||||
SegmentType: 0,
|
||||
Value: poll,
|
||||
IsFile: true,
|
||||
Value: file,
|
||||
})
|
||||
}
|
||||
|
||||
for _, session := range config.ImplantConfig.SessionFiles {
|
||||
for _, path := range config.ImplantConfig.Paths {
|
||||
pathSegments = append(pathSegments, &clientpb.HTTPC2PathSegment{
|
||||
IsFile: true,
|
||||
SegmentType: 1,
|
||||
Value: session,
|
||||
IsFile: false,
|
||||
Value: path,
|
||||
})
|
||||
}
|
||||
|
||||
for _, close := range config.ImplantConfig.CloseFiles {
|
||||
pathSegments = append(pathSegments, &clientpb.HTTPC2PathSegment{
|
||||
IsFile: true,
|
||||
SegmentType: 2,
|
||||
Value: close,
|
||||
for _, clientHeader := range config.ImplantConfig.Headers {
|
||||
httpC2Headers = append(httpC2Headers, &clientpb.HTTPC2Header{
|
||||
Method: clientHeader.Method,
|
||||
Name: clientHeader.Name,
|
||||
Value: clientHeader.Value,
|
||||
Probability: int32(clientHeader.Probability),
|
||||
})
|
||||
}
|
||||
|
||||
for _, stager := range config.ImplantConfig.StagerFiles {
|
||||
pathSegments = append(pathSegments, &clientpb.HTTPC2PathSegment{
|
||||
IsFile: true,
|
||||
SegmentType: 3,
|
||||
Value: stager,
|
||||
})
|
||||
}
|
||||
|
||||
// paths
|
||||
for _, poll := range config.ImplantConfig.PollPaths {
|
||||
pathSegments = append(pathSegments, &clientpb.HTTPC2PathSegment{
|
||||
IsFile: false,
|
||||
SegmentType: 0,
|
||||
Value: poll,
|
||||
})
|
||||
}
|
||||
|
||||
for _, session := range config.ImplantConfig.SessionPaths {
|
||||
pathSegments = append(pathSegments, &clientpb.HTTPC2PathSegment{
|
||||
IsFile: false,
|
||||
SegmentType: 1,
|
||||
Value: session,
|
||||
})
|
||||
}
|
||||
|
||||
for _, close := range config.ImplantConfig.ClosePaths {
|
||||
pathSegments = append(pathSegments, &clientpb.HTTPC2PathSegment{
|
||||
IsFile: false,
|
||||
SegmentType: 2,
|
||||
Value: close,
|
||||
})
|
||||
}
|
||||
|
||||
for _, stager := range config.ImplantConfig.StagerPaths {
|
||||
pathSegments = append(pathSegments, &clientpb.HTTPC2PathSegment{
|
||||
IsFile: false,
|
||||
SegmentType: 3,
|
||||
Value: stager,
|
||||
for _, urlParameter := range config.ImplantConfig.URLParameters {
|
||||
httpC2UrlParameters = append(httpC2UrlParameters, &clientpb.HTTPC2URLParameter{
|
||||
Method: urlParameter.Method,
|
||||
Name: urlParameter.Name,
|
||||
Value: urlParameter.Value,
|
||||
Probability: int32(urlParameter.Probability),
|
||||
})
|
||||
}
|
||||
|
||||
implantConfig := &clientpb.HTTPC2ImplantConfig{
|
||||
UserAgent: config.ImplantConfig.UserAgent,
|
||||
ChromeBaseVersion: int32(config.ImplantConfig.ChromeBaseVersion),
|
||||
MacOSVersion: config.ImplantConfig.MacOSVersion,
|
||||
NonceQueryArgChars: config.ImplantConfig.NonceQueryArgChars,
|
||||
ExtraURLParameters: httpC2UrlParameters,
|
||||
Headers: httpC2Headers,
|
||||
MaxFiles: int32(config.ImplantConfig.MaxFiles),
|
||||
MinFiles: int32(config.ImplantConfig.MinFiles),
|
||||
MaxPaths: int32(config.ImplantConfig.MaxPaths),
|
||||
MinPaths: int32(config.ImplantConfig.MinFiles),
|
||||
StagerFileExtension: config.ImplantConfig.StagerFileExt,
|
||||
PollFileExtension: config.ImplantConfig.PollFileExt,
|
||||
StartSessionFileExtension: config.ImplantConfig.StartSessionFileExt,
|
||||
SessionFileExtension: config.ImplantConfig.SessionFileExt,
|
||||
CloseFileExtension: config.ImplantConfig.CloseFileExt,
|
||||
PathSegments: pathSegments,
|
||||
UserAgent: config.ImplantConfig.UserAgent,
|
||||
ChromeBaseVersion: int32(config.ImplantConfig.ChromeBaseVersion),
|
||||
MacOSVersion: config.ImplantConfig.MacOSVersion,
|
||||
NonceQueryArgChars: config.ImplantConfig.NonceQueryArgChars,
|
||||
NonceQueryLength: int32(config.ImplantConfig.NonceQueryLength),
|
||||
NonceMode: config.ImplantConfig.NonceMode,
|
||||
ExtraURLParameters: httpC2UrlParameters,
|
||||
Headers: httpC2Headers,
|
||||
MaxFileGen: int32(config.ImplantConfig.MaxFileGen),
|
||||
MinFileGen: int32(config.ImplantConfig.MinFileGen),
|
||||
MaxPathGen: int32(config.ImplantConfig.MaxPathGen),
|
||||
MinPathGen: int32(config.ImplantConfig.MinPathGen),
|
||||
MaxPathLength: int32(config.ImplantConfig.MaxPathLength),
|
||||
MinPathLength: int32(config.ImplantConfig.MinPathLength),
|
||||
Extensions: config.ImplantConfig.Extensions,
|
||||
PathSegments: pathSegments,
|
||||
}
|
||||
|
||||
// Server Config
|
||||
serverHeaders := []*clientpb.HTTPC2Header{}
|
||||
for _, serverHeader := range config.ServerConfig.Headers {
|
||||
for _, method := range serverHeader.Methods {
|
||||
serverHeaders = append(serverHeaders, &clientpb.HTTPC2Header{
|
||||
Method: method,
|
||||
Name: serverHeader.Name,
|
||||
Value: serverHeader.Value,
|
||||
Probability: int32(serverHeader.Probability),
|
||||
})
|
||||
}
|
||||
serverHeaders = append(serverHeaders, &clientpb.HTTPC2Header{
|
||||
Method: serverHeader.Method,
|
||||
Name: serverHeader.Name,
|
||||
Value: serverHeader.Value,
|
||||
Probability: int32(serverHeader.Probability),
|
||||
})
|
||||
}
|
||||
|
||||
serverCookies := []*clientpb.HTTPC2Cookie{}
|
||||
@@ -525,7 +419,7 @@ func PrintC2Profiles(profile *clientpb.HTTPC2Config, con *console.SliverClient)
|
||||
|
||||
var serverHeaders []string
|
||||
for _, header := range profile.ServerConfig.Headers {
|
||||
serverHeaders = append(serverHeaders, header.Value)
|
||||
serverHeaders = append(serverHeaders, header.Name)
|
||||
}
|
||||
tw.AppendRow(table.Row{
|
||||
"Server Headers",
|
||||
@@ -550,7 +444,7 @@ func PrintC2Profiles(profile *clientpb.HTTPC2Config, con *console.SliverClient)
|
||||
|
||||
var clientHeaders []string
|
||||
for _, header := range profile.ImplantConfig.Headers {
|
||||
clientHeaders = append(clientHeaders, header.Value)
|
||||
clientHeaders = append(clientHeaders, header.Name)
|
||||
}
|
||||
tw.AppendRow(table.Row{
|
||||
"Client Headers",
|
||||
@@ -581,96 +475,65 @@ func PrintC2Profiles(profile *clientpb.HTTPC2Config, con *console.SliverClient)
|
||||
"Nonce query arg chars",
|
||||
profile.ImplantConfig.NonceQueryArgChars,
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Nonce query length",
|
||||
profile.ImplantConfig.NonceQueryLength,
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Nonce mode",
|
||||
profile.ImplantConfig.NonceMode,
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Max files",
|
||||
profile.ImplantConfig.MaxFiles,
|
||||
profile.ImplantConfig.MaxFileGen,
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Min files",
|
||||
profile.ImplantConfig.MinFiles,
|
||||
profile.ImplantConfig.MinFileGen,
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Max paths",
|
||||
profile.ImplantConfig.MaxPaths,
|
||||
profile.ImplantConfig.MaxPathGen,
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Min paths",
|
||||
profile.ImplantConfig.MinPaths,
|
||||
profile.ImplantConfig.MinPathGen,
|
||||
})
|
||||
|
||||
tw.AppendRow(table.Row{
|
||||
"Stager file extension",
|
||||
profile.ImplantConfig.StagerFileExtension,
|
||||
"Max path length",
|
||||
profile.ImplantConfig.MaxPathLength,
|
||||
})
|
||||
|
||||
tw.AppendRow(table.Row{
|
||||
"Start session file extension",
|
||||
profile.ImplantConfig.StartSessionFileExtension,
|
||||
"Min path length",
|
||||
profile.ImplantConfig.MinPathLength,
|
||||
})
|
||||
|
||||
tw.AppendRow(table.Row{
|
||||
"Session file extension",
|
||||
profile.ImplantConfig.SessionFileExtension,
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Poll file extension",
|
||||
profile.ImplantConfig.PollFileExtension,
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Close file extension",
|
||||
profile.ImplantConfig.CloseFileExtension,
|
||||
"File extensions",
|
||||
strings.Join(profile.ImplantConfig.Extensions, ","),
|
||||
})
|
||||
|
||||
var (
|
||||
pollPaths []string
|
||||
pollFiles []string
|
||||
sessionPaths []string
|
||||
sessionFiles []string
|
||||
closePaths []string
|
||||
closeFiles []string
|
||||
paths []string
|
||||
files []string
|
||||
)
|
||||
for _, segment := range profile.ImplantConfig.PathSegments {
|
||||
if segment.IsFile {
|
||||
switch segment.SegmentType {
|
||||
case 0:
|
||||
pollFiles = append(pollFiles, segment.Value)
|
||||
case 1:
|
||||
sessionFiles = append(sessionFiles, segment.Value)
|
||||
case 2:
|
||||
closeFiles = append(closeFiles, segment.Value)
|
||||
}
|
||||
files = append(files, segment.Value)
|
||||
} else {
|
||||
switch segment.SegmentType {
|
||||
case 0:
|
||||
pollPaths = append(pollPaths, segment.Value)
|
||||
case 1:
|
||||
sessionPaths = append(sessionPaths, segment.Value)
|
||||
case 2:
|
||||
closePaths = append(closePaths, segment.Value)
|
||||
}
|
||||
paths = append(paths, segment.Value)
|
||||
}
|
||||
}
|
||||
|
||||
tw.AppendRow(table.Row{
|
||||
"Poll paths",
|
||||
strings.Join(pollPaths[:], ","),
|
||||
"Paths",
|
||||
strings.Join(paths[:], ",")[:50] + "...",
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Poll files",
|
||||
strings.Join(pollFiles[:], ","),
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Session paths",
|
||||
strings.Join(sessionPaths[:], ","),
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Session files",
|
||||
strings.Join(sessionFiles[:], ","),
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Close paths",
|
||||
strings.Join(closePaths[:], ","),
|
||||
})
|
||||
tw.AppendRow(table.Row{
|
||||
"Close files",
|
||||
strings.Join(closeFiles[:], ","),
|
||||
"Files",
|
||||
strings.Join(files[:], ",")[:50] + "...",
|
||||
})
|
||||
|
||||
con.Println(tw.Render())
|
||||
@@ -693,14 +556,13 @@ func selectC2Profile(c2profiles []*clientpb.HTTPC2Config) string {
|
||||
return c2profile
|
||||
}
|
||||
|
||||
func updateC2Profile(usedExtensions []string, template *assets.HTTPC2Config, urls []string) (*assets.HTTPC2Config, error) {
|
||||
func updateC2Profile(template *assets.HTTPC2Config, urls []string) (*assets.HTTPC2Config, error) {
|
||||
// update the template with the urls
|
||||
|
||||
var (
|
||||
paths []string
|
||||
filenames []string
|
||||
extensions []string
|
||||
filteredExtensions []string
|
||||
paths []string
|
||||
filenames []string
|
||||
extensions []string
|
||||
)
|
||||
|
||||
for _, urlPath := range urls {
|
||||
@@ -729,23 +591,13 @@ func updateC2Profile(usedExtensions []string, template *assets.HTTPC2Config, url
|
||||
slices.Sort(extensions)
|
||||
extensions = slices.Compact(extensions)
|
||||
|
||||
for _, extension := range extensions {
|
||||
if !slices.Contains(usedExtensions, extension) {
|
||||
filteredExtensions = append(filteredExtensions, extension)
|
||||
}
|
||||
}
|
||||
|
||||
slices.Sort(paths)
|
||||
paths = slices.Compact(paths)
|
||||
|
||||
slices.Sort(filenames)
|
||||
filenames = slices.Compact(filenames)
|
||||
|
||||
// 5 is arbitrarily used as a minimum value, it only has to be 5 for the extensions, the others can be lower
|
||||
if len(filteredExtensions) < 5 {
|
||||
return nil, fmt.Errorf("got %d unused extensions, need at least 5", len(filteredExtensions))
|
||||
}
|
||||
|
||||
// 5 is arbitrarily used as a minimum value
|
||||
if len(paths) < 5 {
|
||||
return nil, fmt.Errorf("got %d paths need at least 5", len(paths))
|
||||
}
|
||||
@@ -754,53 +606,8 @@ func updateC2Profile(usedExtensions []string, template *assets.HTTPC2Config, url
|
||||
return nil, fmt.Errorf("got %d paths need at least 5", len(filenames))
|
||||
}
|
||||
|
||||
// shuffle extensions
|
||||
for i := len(extensions) - 1; i > 0; i-- {
|
||||
j := rand.Intn(i + 1)
|
||||
extensions[i], extensions[j] = extensions[j], extensions[i]
|
||||
}
|
||||
|
||||
template.ImplantConfig.PollFileExt = extensions[0]
|
||||
template.ImplantConfig.StagerFileExt = extensions[1]
|
||||
template.ImplantConfig.StartSessionFileExt = extensions[2]
|
||||
template.ImplantConfig.SessionFileExt = extensions[3]
|
||||
template.ImplantConfig.CloseFileExt = extensions[4]
|
||||
|
||||
// randomly distribute the paths and filenames into the different segment types
|
||||
template.ImplantConfig.CloseFiles = []string{}
|
||||
template.ImplantConfig.SessionFiles = []string{}
|
||||
template.ImplantConfig.PollFiles = []string{}
|
||||
template.ImplantConfig.StagerFiles = []string{}
|
||||
template.ImplantConfig.ClosePaths = []string{}
|
||||
template.ImplantConfig.SessionPaths = []string{}
|
||||
template.ImplantConfig.PollPaths = []string{}
|
||||
template.ImplantConfig.StagerPaths = []string{}
|
||||
|
||||
for _, path := range paths {
|
||||
switch rand.Intn(4) {
|
||||
case 0:
|
||||
template.ImplantConfig.PollPaths = append(template.ImplantConfig.PollPaths, path)
|
||||
case 1:
|
||||
template.ImplantConfig.SessionPaths = append(template.ImplantConfig.SessionPaths, path)
|
||||
case 2:
|
||||
template.ImplantConfig.ClosePaths = append(template.ImplantConfig.ClosePaths, path)
|
||||
case 3:
|
||||
template.ImplantConfig.StagerPaths = append(template.ImplantConfig.StagerPaths, path)
|
||||
}
|
||||
}
|
||||
|
||||
for _, filename := range filenames {
|
||||
switch rand.Intn(4) {
|
||||
case 0:
|
||||
template.ImplantConfig.PollFiles = append(template.ImplantConfig.PollFiles, filename)
|
||||
case 1:
|
||||
template.ImplantConfig.SessionFiles = append(template.ImplantConfig.SessionFiles, filename)
|
||||
case 2:
|
||||
template.ImplantConfig.CloseFiles = append(template.ImplantConfig.CloseFiles, filename)
|
||||
case 3:
|
||||
template.ImplantConfig.StagerFiles = append(template.ImplantConfig.StagerFiles, filename)
|
||||
}
|
||||
}
|
||||
|
||||
template.ImplantConfig.Extensions = extensions
|
||||
template.ImplantConfig.Paths = paths
|
||||
template.ImplantConfig.Files = filenames
|
||||
return template, nil
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/certificates
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'certificates' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `certificates.go` – Retrieves certificate metadata from the server, formats expiration status, and prints results to the console.
|
||||
- `commands.go` – Registers the certificates command and binds the flags needed to query certificate inventories.
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/command/clean
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'clean' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `clean.go` – Defines the clean command and its helpers that purge local build artifacts, cached profiles, and stale sessions.
|
||||
@@ -1,4 +1,9 @@
|
||||
Completers
|
||||
===========
|
||||
# client/command/completers
|
||||
|
||||
This package contains general purpose completers for the console, note that some package also contain their own package-specific completers.
|
||||
## Overview
|
||||
|
||||
Implements the 'completers' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `completers.go` – Provides reusable carapace completion helpers for selecting client interfaces and proxy endpoints.
|
||||
@@ -0,0 +1,12 @@
|
||||
# client/command/crack
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'crack' command group for the Sliver client console. Handlers map Cobra invocations to crack workflows such as crack files.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Defines the crack command hierarchy, attaching operations for stations and file management.
|
||||
- `crack-files.go` – Manages cracking asset uploads, listings, and removals, handling streaming transfers and chunking.
|
||||
- `crack.go` – Implements station status reporting, health checks, and list rendering for distributed cracking nodes.
|
||||
- `helpers.go` – Supplies completion helpers and byte formatting utilities for crack subcommands.
|
||||
@@ -0,0 +1,14 @@
|
||||
# client/command/creds
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'creds' command group for the Sliver client console. Handlers map Cobra invocations to creds workflows such as ADD, hash types, RM, and select.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `add.go` – Adds credentials to the client store via interactive or flag-based input.
|
||||
- `commands.go` – Registers credential management commands and subcommands.
|
||||
- `creds.go` – Lists stored credentials and formats them for display.
|
||||
- `hash-types.go` – Enumerates supported hash types and their identifiers.
|
||||
- `rm.go` – Removes credentials by ID or filter from the store.
|
||||
- `select.go` – Selects credentials for use in other workflows, updating defaults.
|
||||
@@ -1,3 +1,17 @@
|
||||
# Cursed
|
||||
# client/command/cursed
|
||||
|
||||
Cursed is a Sliver Chrome/Electron post-exploitation tool kit based on/integrated with [CursedChrome](https://github.com/mandatoryprogrammer/CursedChrome). Code injection is performed via the [DevTools protocol](https://chromedevtools.github.io/devtools-protocol/).
|
||||
## Overview
|
||||
|
||||
Implements the 'cursed' command group for the Sliver client console. Handlers map Cobra invocations to cursed workflows such as cursed chrome, cursed console, cursed cookies, and cursed edge.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Exposes the cursed command suite and binds individual subcommands for supported targets.
|
||||
- `cursed-chrome.go` – Launches or hijacks Chrome debugging sessions, locating executables and wiring remote control.
|
||||
- `cursed-console.go` – Provides the interactive cursed console experience atop Chrome DevTools sessions.
|
||||
- `cursed-cookies.go` – Fetches and displays browser cookies from an active cursed session.
|
||||
- `cursed-edge.go` – Mirrors the Chrome workflow for Microsoft Edge, including process discovery logic.
|
||||
- `cursed-electron.go` – Drives cursed interactions with arbitrary Electron apps, validating binaries and starting injected sessions.
|
||||
- `cursed-rm.go` – Removes cursed sessions from the client cache and tears down associated resources.
|
||||
- `cursed-screenshot.go` – Captures screenshots from a cursed browser context via DevTools APIs.
|
||||
- `cursed.go` – Manages the cursed process registry, selection helpers, and remote debugger configuration defaults.
|
||||
@@ -21,9 +21,10 @@ package cursed
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/overlord"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -46,24 +47,24 @@ func CursedCookiesCmd(cmd *cobra.Command, con *console.SliverClient, args []stri
|
||||
if len(cookies) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
saveFile, _ := cmd.Flags().GetString("save")
|
||||
if saveFile == "" {
|
||||
saveFile = fmt.Sprintf("cookies-%s.json", time.Now().Format("20060102150405"))
|
||||
}
|
||||
jsonCookies := []string{}
|
||||
for _, cookie := range cookies {
|
||||
jsonCookie, err := cookie.MarshalJSON()
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to marshal cookie: %s\n", err)
|
||||
continue
|
||||
}
|
||||
jsonCookies = append(jsonCookies, string(jsonCookie))
|
||||
|
||||
jsonBytes, err := json.MarshalIndent(cookies, "", " ")
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to marshal cookies: %s\n", err)
|
||||
return
|
||||
}
|
||||
err = os.WriteFile(saveFile, []byte(strings.Join(jsonCookies, "\n")), 0o600)
|
||||
|
||||
err = os.WriteFile(saveFile, jsonBytes, 0o600)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to save cookies: %s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
con.PrintInfof("Saved to %s", saveFile)
|
||||
con.Println()
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
DLL Hijack
|
||||
===========
|
||||
# client/command/dllhijack
|
||||
|
||||
Implements command related to `dllhijack`.
|
||||
## Overview
|
||||
|
||||
Implements the 'dllhijack' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the dllhijack command, its flags, and completions for selecting remote DLL targets.
|
||||
- `dllhijack.go` – Performs the RPC call that plants a Sliver DLL alongside a target executable for hijacking.
|
||||
@@ -1,4 +1,12 @@
|
||||
Environment
|
||||
===========
|
||||
# client/command/environment
|
||||
|
||||
Contains command implementations for manipulating remote environment variables.
|
||||
## Overview
|
||||
|
||||
Implements the 'environment' command group for the Sliver client console. Handlers map Cobra invocations to environment workflows such as GET, SET, and unset.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares environment command variations and wires subcommands for get/set/unset operations with shared flags.
|
||||
- `get.go` – Invokes the RPC to retrieve environment variables and prints the results for sessions or beacons.
|
||||
- `set.go` – Handles setting environment variables remotely, including beacon callback handling and result formatting.
|
||||
- `unset.go` – Removes environment variables on the remote target and reports task outcomes back to the user.
|
||||
@@ -1,4 +1,19 @@
|
||||
Exec
|
||||
====
|
||||
# client/command/exec
|
||||
|
||||
Implements execution related commands like `execute`, `execute-shellcode`, `execute-assembly`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'exec' command group for the Sliver client console. Handlers map Cobra invocations to exec workflows such as execute assembly, execute shellcode, execute, and migrate.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the exec command family and binds shared flags across execution techniques.
|
||||
- `execute-assembly.go` – Uploads .NET assemblies and triggers in-memory execution, handling results and loot capture.
|
||||
- `execute-shellcode.go` – Executes raw shellcode via RPC, supporting interactive injection and task result printing.
|
||||
- `execute.go` – Runs arbitrary commands, streams combined stdout/stderr, and persists output as loot when requested.
|
||||
- `migrate.go` – Implements process migration, moving implants into new host processes and reporting completion.
|
||||
- `msf-inject.go` – Coordinates Metasploit payload injection tasks and prints remote execution responses.
|
||||
- `msf.go` – Launches Metasploit jobs on targets and tracks their beacon callbacks.
|
||||
- `psexec.go` – Provides PsExec-style remote service deployment using generated binaries and random filenames.
|
||||
- `sideload.go` – Executes unmanaged DLL exports in a remote process and summarizes task output.
|
||||
- `spawndll.go` – Spawns new processes with DLL injection, capturing returned handles and statuses.
|
||||
- `ssh.go` – Runs remote commands over SSH, sourcing credentials from loot and presenting command output.
|
||||
@@ -49,7 +49,7 @@ func MsfInjectCmd(cmd *cobra.Command, con *console.SliverClient, args []string)
|
||||
return
|
||||
}
|
||||
if pid == -1 {
|
||||
con.PrintErrorf("Invalid pid '%s', see `help %s`\n", lhost, consts.MsfInjectStr)
|
||||
con.PrintErrorf("Invalid pid '%d', see `help %s`\n", pid, consts.MsfInjectStr)
|
||||
return
|
||||
}
|
||||
var goos string
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/command/exit
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'exit' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `exit.go` – Implements the client exit command, ensuring cleanup before terminating the console.
|
||||
@@ -1,67 +1,16 @@
|
||||
Extensions
|
||||
===========
|
||||
# client/command/extensions
|
||||
|
||||
Allows to load and execute 3rd party extensions.
|
||||
## Overview
|
||||
|
||||
Extensions directory structures can be arbitrary, however in the root of the directory or .tar.gz there
|
||||
must be a `extension.json` or a `alias.json` file. All paths are relative to the manifest/root directory,
|
||||
parent directories are not allowed. Only files listed in the manifest are copied, any other files will
|
||||
be ignored.
|
||||
Implements the 'extensions' command group for the Sliver client console. Handlers map Cobra invocations to extensions workflows such as argparser, install, list, and load.
|
||||
|
||||
```shell
|
||||
/path/to/extension/folder/
|
||||
├── extension.json
|
||||
└── windows
|
||||
│ └── extension.x86.dll
|
||||
│ └── extension.x64.dll
|
||||
└── linux
|
||||
│ └── extension.x86.so
|
||||
│ └── extension.x64.so
|
||||
└── darwin
|
||||
└── extension.x86.dylib
|
||||
└── extension.x64.dylib
|
||||
```
|
||||
## Go Files
|
||||
|
||||
Here's an example manifest (i.e., the `extension.json` or a `alias.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "foo",
|
||||
"version": "1.0.0",
|
||||
"extension_author": "ac1d-burn",
|
||||
"original_author": "zer0-cool",
|
||||
"repo_url": "https://github.com/foo/bar",
|
||||
"help": "Help for foo command",
|
||||
"entrypoint": "RunFoo",
|
||||
"init" :"NimMain",
|
||||
"depends_on": "bar",
|
||||
"files": [
|
||||
{
|
||||
"os": "windows",
|
||||
"arch": "amd64",
|
||||
"path": "extension.x64.o",
|
||||
}
|
||||
],
|
||||
"arguments": [
|
||||
{"name": "pid", "type": "int", "desc": "pid", "optional": false},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The structure is the following one:
|
||||
|
||||
- `name`: name of the extension, which will also be the name of the command in the sliver client
|
||||
- `help`: the documentation for the new command
|
||||
- `entrypoint`: the name of the exported function to call
|
||||
- `files`: a list of object pointing to the extensions files to load for each architectures and operating systems
|
||||
- `init`: the initialization function name (if relevant, can be omitted)
|
||||
- `arguments`: an optional list of objects (for DLLs), but mandatory for BOFs
|
||||
- `depends_on`: the name of an extension required by the current extension (won't load if the dependency is not loaded)
|
||||
|
||||
The `type` of an argument can be one of the following:
|
||||
|
||||
- `string`: regular ASCII string
|
||||
- `wstring`: string that will be UTF16 encoded
|
||||
- `int`: will be parsed as a 32 bit unsigned integer
|
||||
- `short`: will be parsed as a 16 bit unsigned integer
|
||||
- `file`: a string to a file path on the client side which content will be passed to the BOF
|
||||
- `argparser.go` – Builds argument buffers for extensions, including BOF-specific marshaling and validation.
|
||||
- `commands.go` – Declares the extensions command tree and binds subcommands for list, install, load, and remove actions.
|
||||
- `extensions.go` – Manages installed/temporary extension manifests, printing metadata and supplying completers.
|
||||
- `extensions_test.go` *(tests)* – Verifies manifest parsing and conversion routines to guard against format regressions.
|
||||
- `install.go` – Installs extension bundles from directories or archives, handling overwrite prompts and asset extraction.
|
||||
- `list.go` – Queries the server for matching extensions and renders results categorized by hash or type.
|
||||
- `load.go` – Loads extension binaries for the active target, registers generated commands, and dispatches execution RPCs.
|
||||
- `remove.go` – Removes installed extensions, coordinating manifest lookups and filesystem cleanup.
|
||||
@@ -0,0 +1,413 @@
|
||||
package extensions
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// ParseFlagArgumentsToBuffer parses flag-style arguments based on extension manifest
|
||||
// and converts them to a BOF-compatible binary buffer
|
||||
func ParseFlagArgumentsToBuffer(_ *cobra.Command, args []string, _ string, ext *ExtCommand) ([]byte, error) {
|
||||
// Create a flag set and parse the arguments
|
||||
fs, stringValues, wstringValues, intValues, shortValues, fileValues, err := bofSetupAndParseFlags(args, ext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Print debug information about parsed flags
|
||||
//bofDebugPrintParsedFlags(fs, ext, stringValues, wstringValues, intValues, shortValues, fileValues)
|
||||
|
||||
// Initialize the BOF arguments buffer
|
||||
argsBuffer := core.BOFArgsBuffer{
|
||||
Buffer: new(bytes.Buffer),
|
||||
}
|
||||
|
||||
// Process arguments and build the buffer
|
||||
missingRequiredArgs, err := bofProcessArgumentsToBuffer(fs, ext, argsBuffer,
|
||||
stringValues, wstringValues, intValues, shortValues, fileValues)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return error if we have missing required arguments
|
||||
if len(missingRequiredArgs) > 0 {
|
||||
return nil, fmt.Errorf("required arguments %s were not provided", strings.Join(missingRequiredArgs, ", "))
|
||||
}
|
||||
|
||||
// Get the final binary buffer
|
||||
parsedArgs, err := argsBuffer.GetBuffer()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get buffer: %v", err)
|
||||
}
|
||||
|
||||
return parsedArgs, nil
|
||||
}
|
||||
|
||||
// bofSetupAndParseFlags creates a flag set, defines expected flags based on the extension manifest,
|
||||
// and parses the provided arguments
|
||||
func bofSetupAndParseFlags(args []string, ext *ExtCommand) (*flag.FlagSet,
|
||||
map[string]*string, map[string]*string, map[string]*int, map[string]*int, map[string]*string, error) {
|
||||
|
||||
// Create a new FlagSet
|
||||
fs := flag.NewFlagSet("sliver-bof", flag.ContinueOnError)
|
||||
|
||||
// Maps to store flag value pointers
|
||||
stringValues := make(map[string]*string)
|
||||
intValues := make(map[string]*int)
|
||||
shortValues := make(map[string]*int)
|
||||
fileValues := make(map[string]*string) // Path to file data
|
||||
wstringValues := make(map[string]*string)
|
||||
|
||||
// Define expected flags based on manifest arguments
|
||||
for _, arg := range ext.Arguments {
|
||||
flagName := arg.Name
|
||||
flagDesc := arg.Desc
|
||||
|
||||
switch arg.Type {
|
||||
case "string":
|
||||
stringValues[flagName] = fs.String(flagName, "", flagDesc)
|
||||
case "wstring":
|
||||
wstringValues[flagName] = fs.String(flagName, "", flagDesc)
|
||||
case "int", "integer":
|
||||
intValues[flagName] = fs.Int(flagName, 0, flagDesc)
|
||||
case "short":
|
||||
shortValues[flagName] = fs.Int(flagName, 0, flagDesc)
|
||||
case "file":
|
||||
fileValues[flagName] = fs.String(flagName, "", flagDesc)
|
||||
default:
|
||||
return nil, nil, nil, nil, nil, nil, fmt.Errorf("unsupported argument type: %s", arg.Type)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the arguments
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return nil, nil, nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
return fs, stringValues, wstringValues, intValues, shortValues, fileValues, nil
|
||||
}
|
||||
|
||||
// bofProcessArgumentsToBuffer processes each argument and adds its value to the buffer
|
||||
// Returns a list of missing required arguments and any error encountered
|
||||
func bofProcessArgumentsToBuffer(fs *flag.FlagSet, ext *ExtCommand, argsBuffer core.BOFArgsBuffer,
|
||||
stringValues, wstringValues map[string]*string,
|
||||
intValues, shortValues map[string]*int,
|
||||
fileValues map[string]*string) ([]string, error) {
|
||||
|
||||
missingRequiredArgs := make([]string, 0)
|
||||
|
||||
for _, argDef := range ext.Arguments {
|
||||
var provided bool
|
||||
var err error
|
||||
|
||||
// Process based on argument type
|
||||
switch argDef.Type {
|
||||
case "string":
|
||||
provided, err = bofProcessStringArg(fs, argDef, stringValues, argsBuffer)
|
||||
case "wstring":
|
||||
provided, err = bofProcessWStringArg(fs, argDef, wstringValues, argsBuffer)
|
||||
case "int", "integer":
|
||||
provided, err = bofProcessIntArg(fs, argDef, intValues, argsBuffer)
|
||||
case "short":
|
||||
provided, err = bofProcessShortArg(fs, argDef, shortValues, argsBuffer)
|
||||
case "file":
|
||||
provided, err = bofProcessFileArg(fs, argDef, fileValues, argsBuffer)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If argument not provided, handle according to rules
|
||||
if !provided {
|
||||
if argDef.Optional {
|
||||
// Try to apply default or type-appropriate zero value
|
||||
err = bofApplyDefaultValue(argDef, argsBuffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Required argument was not provided
|
||||
missingRequiredArgs = append(missingRequiredArgs, "`"+argDef.Name+"`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return missingRequiredArgs, nil
|
||||
}
|
||||
|
||||
// bofProcessStringArg processes a string argument
|
||||
func bofProcessStringArg(fs *flag.FlagSet, argDef *extensionArgument, stringValues map[string]*string,
|
||||
argsBuffer core.BOFArgsBuffer) (bool, error) {
|
||||
|
||||
ptr := stringValues[argDef.Name]
|
||||
flagWasSet := *ptr != "" && bofFlagWasProvided(fs, argDef.Name)
|
||||
|
||||
if flagWasSet {
|
||||
err := argsBuffer.AddString(*ptr)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to add string argument %s: %v", argDef.Name, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// bofProcessWStringArg processes a wide string argument
|
||||
func bofProcessWStringArg(fs *flag.FlagSet, argDef *extensionArgument, wstringValues map[string]*string,
|
||||
argsBuffer core.BOFArgsBuffer) (bool, error) {
|
||||
|
||||
ptr := wstringValues[argDef.Name]
|
||||
flagWasSet := *ptr != "" && bofFlagWasProvided(fs, argDef.Name)
|
||||
|
||||
if flagWasSet {
|
||||
err := argsBuffer.AddWString(*ptr)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to add wstring argument %s: %v", argDef.Name, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// bofProcessIntArg processes an integer argument
|
||||
func bofProcessIntArg(fs *flag.FlagSet, argDef *extensionArgument, intValues map[string]*int,
|
||||
argsBuffer core.BOFArgsBuffer) (bool, error) {
|
||||
|
||||
ptr := intValues[argDef.Name]
|
||||
flagWasSet := bofFlagWasProvided(fs, argDef.Name)
|
||||
|
||||
if flagWasSet {
|
||||
err := argsBuffer.AddInt(uint32(*ptr))
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to add int argument %s: %v", argDef.Name, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// bofProcessShortArg processes a short integer argument
|
||||
func bofProcessShortArg(fs *flag.FlagSet, argDef *extensionArgument, shortValues map[string]*int,
|
||||
argsBuffer core.BOFArgsBuffer) (bool, error) {
|
||||
|
||||
ptr := shortValues[argDef.Name]
|
||||
flagWasSet := bofFlagWasProvided(fs, argDef.Name)
|
||||
|
||||
if flagWasSet {
|
||||
err := argsBuffer.AddShort(uint16(*ptr))
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to add short argument %s: %v", argDef.Name, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// bofProcessFileArg processes a file argument
|
||||
func bofProcessFileArg(fs *flag.FlagSet, argDef *extensionArgument, fileValues map[string]*string,
|
||||
argsBuffer core.BOFArgsBuffer) (bool, error) {
|
||||
|
||||
ptr := fileValues[argDef.Name]
|
||||
flagWasSet := *ptr != "" && bofFlagWasProvided(fs, argDef.Name)
|
||||
|
||||
if flagWasSet {
|
||||
// Validate file exists and read it
|
||||
data, err := os.ReadFile(*ptr)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error reading file for argument %s: %v", argDef.Name, err)
|
||||
}
|
||||
err = argsBuffer.AddData(data)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to add file data for argument %s: %v", argDef.Name, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// bofApplyDefaultValue applies a default value based on the argument definition
|
||||
func bofApplyDefaultValue(argDef *extensionArgument, argsBuffer core.BOFArgsBuffer) error {
|
||||
// Try to use default value from manifest if available
|
||||
if argDef.Default != nil {
|
||||
switch argDef.Type {
|
||||
case "string":
|
||||
// Handle string default - could be string literal or numeric in JSON
|
||||
defaultVal, ok := argDef.Default.(string)
|
||||
if !ok {
|
||||
// Try to convert from other types
|
||||
defaultVal = fmt.Sprintf("%v", argDef.Default)
|
||||
}
|
||||
err := argsBuffer.AddString(defaultVal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default string: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:%s (default)\n", argDef.Name, defaultVal)
|
||||
|
||||
case "wstring":
|
||||
// Handle wstring default
|
||||
defaultVal, ok := argDef.Default.(string)
|
||||
if !ok {
|
||||
defaultVal = fmt.Sprintf("%v", argDef.Default)
|
||||
}
|
||||
err := argsBuffer.AddWString(defaultVal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default wstring: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:%s (default)\n", argDef.Name, defaultVal)
|
||||
|
||||
case "int", "integer":
|
||||
// Handle int default - could be number or string in JSON
|
||||
var defaultInt uint32
|
||||
|
||||
// Try as number first
|
||||
numVal, ok := argDef.Default.(float64) // JSON unmarshals numbers as float64
|
||||
if ok {
|
||||
defaultInt = uint32(numVal)
|
||||
} else {
|
||||
// Try as string
|
||||
strVal, ok := argDef.Default.(string)
|
||||
if ok {
|
||||
val, err := strconv.ParseUint(strVal, 10, 32)
|
||||
if err == nil {
|
||||
defaultInt = uint32(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := argsBuffer.AddInt(defaultInt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default int: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:%d (default)\n", argDef.Name, defaultInt)
|
||||
|
||||
case "short":
|
||||
// Handle short default - could be number or string in JSON
|
||||
var defaultShort uint16
|
||||
|
||||
// Try as number first
|
||||
numVal, ok := argDef.Default.(float64) // JSON unmarshals numbers as float64
|
||||
if ok {
|
||||
defaultShort = uint16(numVal)
|
||||
} else {
|
||||
// Try as string
|
||||
strVal, ok := argDef.Default.(string)
|
||||
if ok {
|
||||
val, err := strconv.ParseUint(strVal, 10, 16)
|
||||
if err == nil {
|
||||
defaultShort = uint16(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := argsBuffer.AddShort(defaultShort)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default short: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:%d (default)\n", argDef.Name, defaultShort)
|
||||
|
||||
case "file":
|
||||
// Default for file doesn't really make sense, but handle for completeness
|
||||
err := argsBuffer.AddData([]byte{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default file data: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:<empty> (default)\n", argDef.Name)
|
||||
}
|
||||
} else {
|
||||
// No default specified in manifest, use type-appropriate zero values
|
||||
switch argDef.Type {
|
||||
case "string":
|
||||
err := argsBuffer.AddString("")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default string: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:<empty> (default)\n", argDef.Name)
|
||||
|
||||
case "wstring":
|
||||
err := argsBuffer.AddWString("")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default wstring: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:<empty> (default)\n", argDef.Name)
|
||||
|
||||
case "int", "integer":
|
||||
err := argsBuffer.AddInt(0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default int: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:0 (default)\n", argDef.Name)
|
||||
|
||||
case "short":
|
||||
err := argsBuffer.AddShort(0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default short: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:0 (default)\n", argDef.Name)
|
||||
|
||||
case "file":
|
||||
// Empty data for optional file
|
||||
err := argsBuffer.AddData([]byte{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add default file data: %v", err)
|
||||
}
|
||||
fmt.Printf(" -%s:<empty> (default)\n", argDef.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bofDebugPrintParsedFlags prints information about the parsed flags
|
||||
func bofDebugPrintParsedFlags(fs *flag.FlagSet, ext *ExtCommand,
|
||||
stringValues map[string]*string,
|
||||
wstringValues map[string]*string,
|
||||
intValues map[string]*int,
|
||||
shortValues map[string]*int,
|
||||
fileValues map[string]*string) {
|
||||
|
||||
fmt.Println("parsed flags:")
|
||||
|
||||
for _, arg := range ext.Arguments {
|
||||
flagName := arg.Name
|
||||
wasProvided := bofFlagWasProvided(fs, flagName)
|
||||
|
||||
if wasProvided {
|
||||
switch arg.Type {
|
||||
case "string":
|
||||
fmt.Printf(" -%s:%s\n", flagName, *stringValues[flagName])
|
||||
case "wstring":
|
||||
fmt.Printf(" -%s:%s\n", flagName, *wstringValues[flagName])
|
||||
case "int", "integer":
|
||||
fmt.Printf(" -%s:%d\n", flagName, *intValues[flagName])
|
||||
case "short":
|
||||
fmt.Printf(" -%s:%d\n", flagName, *shortValues[flagName])
|
||||
case "file":
|
||||
fmt.Printf(" -%s:%s\n", flagName, *fileValues[flagName])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bofFlagWasProvided checks if a flag was explicitly set
|
||||
func bofFlagWasProvided(fs *flag.FlagSet, name string) bool {
|
||||
provided := false
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
if f.Name == name {
|
||||
provided = true
|
||||
}
|
||||
})
|
||||
return provided
|
||||
}
|
||||
@@ -1,34 +1,28 @@
|
||||
package extensions
|
||||
|
||||
import (
|
||||
"github.com/bishopfox/sliver/client/command/flags"
|
||||
"github.com/bishopfox/sliver/client/command/help"
|
||||
"github.com/bishopfox/sliver/client/command/use"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/rsteube/carapace"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// Commands returns the “ command and its subcommands.
|
||||
// Commands returns the 'extensions' command and its subcommands.
|
||||
func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
extensionCmd := &cobra.Command{
|
||||
Use: consts.ExtensionsStr,
|
||||
Short: "Manage extensions",
|
||||
Long: help.GetHelpFor([]string{consts.ExtensionsStr}),
|
||||
GroupID: consts.ExecutionHelpGroup,
|
||||
GroupID: consts.GenericHelpGroup,
|
||||
Run: func(cmd *cobra.Command, _ []string) {
|
||||
ExtensionsCmd(cmd, con)
|
||||
},
|
||||
}
|
||||
|
||||
extensionCmd.AddCommand(&cobra.Command{
|
||||
Use: consts.ListStr,
|
||||
Short: "List extensions loaded in the current session or beacon",
|
||||
Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.ListStr}),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ExtensionsListCmd(cmd, con, args)
|
||||
},
|
||||
})
|
||||
|
||||
extensionLoadCmd := &cobra.Command{
|
||||
Use: consts.LoadStr,
|
||||
Short: "Temporarily load an extension from a local directory",
|
||||
@@ -66,3 +60,30 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
|
||||
return []*cobra.Command{extensionCmd}
|
||||
}
|
||||
|
||||
func SliverCommands(con *console.SliverClient) []*cobra.Command {
|
||||
extensionCmd := &cobra.Command{
|
||||
Use: consts.ExtensionsStr,
|
||||
Short: "Manage extensions",
|
||||
Long: help.GetHelpFor([]string{consts.ExtensionsStr}),
|
||||
GroupID: consts.InfoHelpGroup,
|
||||
Annotations: flags.RestrictTargets(consts.SessionCmdsFilter), // restrict to session targets since we cannot `list` "loaded" extensions from beacon mode
|
||||
}
|
||||
|
||||
listCmd := &cobra.Command{
|
||||
Use: consts.ListStr,
|
||||
Short: "List extensions loaded in the current session",
|
||||
Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.ListStr}),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ExtensionsListCmd(cmd, con, args)
|
||||
},
|
||||
}
|
||||
flags.Bind("use", false, listCmd, func(f *pflag.FlagSet) {
|
||||
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
|
||||
})
|
||||
extensionCmd.AddCommand(listCmd)
|
||||
|
||||
carapace.Gen(listCmd).PositionalCompletion(use.BeaconAndSessionIDCompleter(con))
|
||||
|
||||
return []*cobra.Command{extensionCmd}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/assets"
|
||||
@@ -35,7 +36,7 @@ import (
|
||||
|
||||
// ExtensionsCmd - List information about installed extensions.
|
||||
func ExtensionsCmd(cmd *cobra.Command, con *console.SliverClient) {
|
||||
if 0 < len(getInstalledManifests()) {
|
||||
if len(GetAllExtensionManifests()) > 0 {
|
||||
PrintExtensions(con)
|
||||
} else {
|
||||
con.PrintInfof("No extensions installed, use the 'armory' command to automatically install some\n")
|
||||
@@ -67,8 +68,12 @@ func PrintExtensions(con *console.SliverClient) {
|
||||
for _, extension := range loadedExtensions {
|
||||
//for _, extension := range extensionm.ExtCommand {
|
||||
installed := ""
|
||||
if _, ok := installedManifests[extension.Manifest.Name]; ok {
|
||||
installed = "✅"
|
||||
//if _, ok := installedManifests[extension.Manifest.Name]; ok {
|
||||
for _, installedManifest := range installedManifests {
|
||||
if extension.Manifest.RootPath == installedManifest.RootPath {
|
||||
installed = "✅"
|
||||
break
|
||||
}
|
||||
}
|
||||
tw.AppendRow(table.Row{
|
||||
extension.Manifest.Name,
|
||||
@@ -97,6 +102,9 @@ func extensionPlatforms(extension *ExtCommand) []string {
|
||||
return keys
|
||||
}
|
||||
|
||||
// getInstalledManifests - Returns a mapping of extension names to their parsed manifest objects.
|
||||
// Reads all installed extension manifests from disk, ignoring any that cannot be read or parsed.
|
||||
// The returned manifests have their RootPath set to the directory containing their manifest file.
|
||||
func getInstalledManifests() map[string]*ExtensionManifest {
|
||||
manifestPaths := assets.GetInstalledExtensionManifests()
|
||||
installedManifests := map[string]*ExtensionManifest{}
|
||||
@@ -110,11 +118,48 @@ func getInstalledManifests() map[string]*ExtensionManifest {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
manifest.RootPath = filepath.Dir(manifestPath)
|
||||
installedManifests[manifest.Name] = manifest
|
||||
}
|
||||
return installedManifests
|
||||
}
|
||||
|
||||
// getTemporarilyLoadedManifests returns a map of extension manifests that are currently
|
||||
// loaded into memory but not permanently installed. The map is keyed by the manifest's
|
||||
// Name field.
|
||||
func getTemporarilyLoadedManifests() map[string]*ExtensionManifest {
|
||||
tempManifests := map[string]*ExtensionManifest{}
|
||||
for name, manifest := range loadedManifests {
|
||||
tempManifests[name] = manifest
|
||||
}
|
||||
return tempManifests
|
||||
}
|
||||
|
||||
// GetAllExtensionManifests returns a combined list of manifest file paths from
|
||||
// both installed and temporarily loaded extensions
|
||||
func GetAllExtensionManifests() []string {
|
||||
manifestPaths := make(map[string]struct{}) // use map for deduplication
|
||||
|
||||
// Add installed manifests
|
||||
for _, manifest := range getInstalledManifests() {
|
||||
manifestPath := filepath.Join(manifest.RootPath, ManifestFileName)
|
||||
manifestPaths[manifestPath] = struct{}{}
|
||||
}
|
||||
|
||||
// Add temporarily loaded manifests
|
||||
for _, manifest := range getTemporarilyLoadedManifests() {
|
||||
manifestPath := filepath.Join(manifest.RootPath, ManifestFileName)
|
||||
manifestPaths[manifestPath] = struct{}{}
|
||||
}
|
||||
|
||||
// Convert to slice
|
||||
paths := make([]string, 0, len(manifestPaths))
|
||||
for path := range manifestPaths {
|
||||
paths = append(paths, path)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
// ExtensionsCommandNameCompleter - Completer for installed extensions command names.
|
||||
func ExtensionsCommandNameCompleter(con *console.SliverClient) carapace.Action {
|
||||
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
|
||||
|
||||
@@ -43,7 +43,22 @@ func ExtensionsInstallCmd(cmd *cobra.Command, con *console.SliverClient, args []
|
||||
InstallFromDir(extLocalPath, true, con, strings.HasSuffix(extLocalPath, ".tar.gz"))
|
||||
}
|
||||
|
||||
// Install an extension from a directory
|
||||
// InstallFromDir installs a Sliver extension from either a local directory or gzipped archive.
|
||||
// It reads the extension manifest, validates it, and copies all required files to the extensions
|
||||
// directory. If an extension with the same name already exists, it can optionally prompt for
|
||||
// overwrite confirmation.
|
||||
//
|
||||
// Parameters:
|
||||
// - extLocalPath: Path to the source directory or gzipped archive containing the extension
|
||||
// - promptToOverwrite: If true, prompts for confirmation before overwriting existing extension
|
||||
// - con: Sliver console client for displaying status and error messages
|
||||
// - isGz: Whether the source is a gzipped archive (true) or directory (false)
|
||||
//
|
||||
// The function will return early with error messages printed to console if:
|
||||
// - The manifest cannot be read or parsed
|
||||
// - Required directories cannot be created
|
||||
// - File copy operations fail
|
||||
// - User declines overwrite when prompted
|
||||
func InstallFromDir(extLocalPath string, promptToOverwrite bool, con *console.SliverClient, isGz bool) {
|
||||
var manifestData []byte
|
||||
var err error
|
||||
@@ -64,8 +79,15 @@ func InstallFromDir(extLocalPath string, promptToOverwrite bool, con *console.Sl
|
||||
return
|
||||
}
|
||||
|
||||
// Use package name if available, otherwise use extension name
|
||||
// (Note, for v1 manifests this will actually be command_name)
|
||||
packageID := manifestF.Name
|
||||
if manifestF.PackageName != "" {
|
||||
packageID = manifestF.PackageName
|
||||
}
|
||||
|
||||
//create repo path
|
||||
minstallPath := filepath.Join(assets.GetExtensionsDir(), filepath.Base(manifestF.Name))
|
||||
minstallPath := filepath.Join(assets.GetExtensionsDir(), filepath.Base(packageID))
|
||||
if _, err := os.Stat(minstallPath); !os.IsNotExist(err) {
|
||||
if promptToOverwrite {
|
||||
con.PrintInfof("Extension '%s' already exists", manifestF.Name)
|
||||
|
||||
@@ -20,12 +20,111 @@ package extensions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// ExtensionMatch holds the details of a matched extension
|
||||
|
||||
type ExtensionMatch struct {
|
||||
CommandName string
|
||||
Hash string
|
||||
BinPath string
|
||||
}
|
||||
|
||||
// FindExtensionMatches searches through loaded extensions for matching hashes
|
||||
// Returns a map of hash to ExtensionMatch (match will be nil if hash wasn't found)
|
||||
func FindExtensionMatches(targetHashes []string) map[string]*ExtensionMatch {
|
||||
results := make(map[string]*ExtensionMatch)
|
||||
pathCache := make(map[string]*ExtensionMatch)
|
||||
|
||||
// Initialize results map with all target hashes
|
||||
for _, hash := range targetHashes {
|
||||
results[hash] = nil
|
||||
}
|
||||
|
||||
// Search for matches
|
||||
for _, extCmd := range loadedExtensions {
|
||||
if extCmd == nil || len(extCmd.Files) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, file := range extCmd.Files {
|
||||
fullPath := filepath.Join(extCmd.Manifest.RootPath, file.Path)
|
||||
|
||||
// Check cache first
|
||||
var match *ExtensionMatch
|
||||
if cached, exists := pathCache[fullPath]; exists {
|
||||
match = cached
|
||||
} else {
|
||||
// Calculate hash if not cached
|
||||
fileData, err := os.ReadFile(fullPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
hashBytes := sha256.Sum256(fileData)
|
||||
fileHash := hex.EncodeToString(hashBytes[:])
|
||||
|
||||
match = &ExtensionMatch{
|
||||
CommandName: extCmd.CommandName,
|
||||
Hash: fileHash,
|
||||
BinPath: fullPath,
|
||||
}
|
||||
pathCache[fullPath] = match
|
||||
}
|
||||
|
||||
if slices.Contains(targetHashes, match.Hash) {
|
||||
results[match.Hash] = match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// PrintExtensionMatches prints the extension matches in a formatted table
|
||||
func PrintExtensionMatches(matches map[string]*ExtensionMatch, con *console.SliverClient) {
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.AppendHeader(table.Row{
|
||||
"Command Name",
|
||||
"Sha256 Hash",
|
||||
"Bin Path",
|
||||
})
|
||||
tw.SortBy([]table.SortBy{
|
||||
{Name: "Command Name", Mode: table.Asc},
|
||||
})
|
||||
|
||||
for hash, match := range matches {
|
||||
if match != nil {
|
||||
tw.AppendRow(table.Row{
|
||||
match.CommandName,
|
||||
hash,
|
||||
match.BinPath,
|
||||
})
|
||||
} else {
|
||||
tw.AppendRow(table.Row{
|
||||
"",
|
||||
hash,
|
||||
"",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
con.Println(tw.Render())
|
||||
}
|
||||
|
||||
// ExtensionsListCmd - List all extension loaded on the active session/beacon.
|
||||
func ExtensionsListCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
session := con.ActiveTarget.GetSessionInteractive()
|
||||
@@ -45,10 +144,12 @@ func ExtensionsListCmd(cmd *cobra.Command, con *console.SliverClient, args []str
|
||||
con.PrintErrorf("%s\n", extList.Response.Err)
|
||||
return
|
||||
}
|
||||
if len(extList.Names) > 0 {
|
||||
con.PrintInfof("Loaded extensions:\n")
|
||||
for _, ext := range extList.Names {
|
||||
con.Printf("- %s\n", ext)
|
||||
}
|
||||
|
||||
if len(extList.Names) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
con.PrintInfof("Loaded extensions:\n\n")
|
||||
matches := FindExtensionMatches(extList.Names)
|
||||
PrintExtensionMatches(matches, con)
|
||||
}
|
||||
@@ -80,6 +80,7 @@ type ExtensionManifest_ struct {
|
||||
|
||||
type ExtensionManifest struct {
|
||||
Name string `json:"name"`
|
||||
PackageName string `json:"package_name"`
|
||||
Version string `json:"version"`
|
||||
ExtensionAuthor string `json:"extension_author"`
|
||||
OriginalAuthor string `json:"original_author"`
|
||||
@@ -115,17 +116,24 @@ type extensionFile struct {
|
||||
}
|
||||
|
||||
type extensionArgument struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Desc string `json:"desc"`
|
||||
Optional bool `json:"optional"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Desc string `json:"desc"`
|
||||
Optional bool `json:"optional"`
|
||||
Default interface{} `json:"default,omitempty"`
|
||||
}
|
||||
|
||||
func (e *ExtCommand) getFileForTarget(targetOS string, targetArch string) (string, error) {
|
||||
filePath := ""
|
||||
for _, extFile := range e.Files {
|
||||
if targetOS == extFile.OS && targetArch == extFile.Arch {
|
||||
filePath = path.Join(assets.GetExtensionsDir(), e.Manifest.Name, extFile.Path)
|
||||
if e.Manifest.RootPath != "" {
|
||||
// Use RootPath for temporarily loaded extensions
|
||||
filePath = path.Join(e.Manifest.RootPath, extFile.Path)
|
||||
} else {
|
||||
// Fall back to extensions dir for installed extensions
|
||||
filePath = path.Join(assets.GetExtensionsDir(), e.Manifest.Name, extFile.Path)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -140,10 +148,19 @@ func (e *ExtCommand) getFileForTarget(targetOS string, targetArch string) (strin
|
||||
return filePath, nil
|
||||
}
|
||||
|
||||
// ExtensionLoadCmd - Load extension command.
|
||||
// ExtensionLoadCmd - Temporarily installs an extension from a local directory into the client.
|
||||
// The extension must contain a valid manifest file. If commands from the extension
|
||||
// already exist, the user will be prompted to overwrite them.
|
||||
func ExtensionLoadCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
dirPath := args[0]
|
||||
// dirPath := ctx.Args.String("dir-path")
|
||||
|
||||
// Add directory check
|
||||
fileInfo, err := os.Stat(dirPath)
|
||||
if err != nil || !fileInfo.IsDir() {
|
||||
con.PrintErrorf("Path is not a directory: %s\n", dirPath)
|
||||
return
|
||||
}
|
||||
|
||||
manifest, err := LoadExtensionManifest(filepath.Join(dirPath, ManifestFileName))
|
||||
if err != nil {
|
||||
return
|
||||
@@ -165,7 +182,11 @@ func ExtensionLoadCmd(cmd *cobra.Command, con *console.SliverClient, args []stri
|
||||
}
|
||||
}
|
||||
|
||||
// LoadExtensionManifest - Parse extension files.
|
||||
// LoadExtensionManifest loads and parses an extension manifest file from the given path.
|
||||
// It registers each command defined in the manifest into the loadedExtensions map
|
||||
// and registers the complete manifest into loadedManifests. A single manifest may
|
||||
// contain multiple extension commands. The manifest's RootPath is set to its containing
|
||||
// directory. Returns the parsed manifest and any errors encountered.
|
||||
func LoadExtensionManifest(manifestPath string) (*ExtensionManifest, error) {
|
||||
data, err := os.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
@@ -279,15 +300,20 @@ func validManifest(manifest *ExtensionManifest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtensionRegisterCommand - Register a new extension command
|
||||
// ExtensionRegisterCommand adds an extension command to the cobra command system.
|
||||
// It validates the extension's arguments, updates the loadedExtensions map, and
|
||||
// creates a cobra.Command with proper usage text, help documentation, and argument
|
||||
// handling. The command is added as a subcommand to the provided parent cobra.Command.
|
||||
// Arguments are displayed in the help text as uppercase, with optional args in square
|
||||
// brackets. The help text includes sections for command usage, description, and detailed
|
||||
// argument specifications.
|
||||
func ExtensionRegisterCommand(extCmd *ExtCommand, cmd *cobra.Command, con *console.SliverClient) {
|
||||
if errInvalidArgs := checkExtensionArgs(extCmd); errInvalidArgs != nil {
|
||||
con.PrintErrorf(errInvalidArgs.Error())
|
||||
con.PrintErrorf("%s", errInvalidArgs.Error())
|
||||
return
|
||||
}
|
||||
|
||||
loadedExtensions[extCmd.CommandName] = extCmd
|
||||
//helpMsg := extCmd.Help
|
||||
|
||||
usage := strings.Builder{}
|
||||
usage.WriteString(extCmd.CommandName)
|
||||
@@ -339,9 +365,9 @@ func ExtensionRegisterCommand(extCmd *ExtCommand, cmd *cobra.Command, con *conso
|
||||
|
||||
// Command
|
||||
extensionCmd := &cobra.Command{
|
||||
Use: usage.String(), //extCmd.CommandName,
|
||||
//Short: helpMsg.String(), doesn't appear to be used?
|
||||
Long: help.FormatHelpTmpl(longHelp.String()),
|
||||
Use: usage.String(),
|
||||
Short: extCmd.Help,
|
||||
Long: help.FormatHelpTmpl(longHelp.String()),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
runExtensionCmd(cmd, con, args)
|
||||
},
|
||||
@@ -559,11 +585,11 @@ func runExtensionCmd(cmd *cobra.Command, con *console.SliverClient, args []strin
|
||||
extName = ext.DependsOn
|
||||
entryPoint = loadedExtensions[extName].Entrypoint // should exist at this point
|
||||
} else {
|
||||
// Regular DLL
|
||||
extensionArgs, err = getExtArgs(cmd, args, binPath, ext)
|
||||
if err != nil {
|
||||
con.PrintErrorf("ext args error: %s\n", err)
|
||||
return
|
||||
// Regular DLL - Just join the arguments with spaces
|
||||
if len(args) > 0 {
|
||||
extensionArgs = []byte(strings.Join(args, " "))
|
||||
} else {
|
||||
extensionArgs = []byte{}
|
||||
}
|
||||
extName = ext.CommandName
|
||||
entryPoint = ext.Entrypoint
|
||||
@@ -659,7 +685,7 @@ func PrintExtOutput(extName string, commandName string, outputSchema *packages.O
|
||||
}
|
||||
}
|
||||
if callExtension.Response != nil && callExtension.Response.Err != "" {
|
||||
con.PrintErrorf(callExtension.Response.Err)
|
||||
con.PrintErrorf("%s", callExtension.Response.Err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -771,7 +797,7 @@ func getBOFArgs(cmd *cobra.Command, args []string, binPath string, ext *ExtComma
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsedArgs, err := getExtArgs(cmd, args, binPath, ext)
|
||||
parsedArgs, err := ParseFlagArgumentsToBuffer(cmd, args, binPath, ext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -829,7 +855,7 @@ func makeExtensionArgCompleter(extCmd *ExtCommand, _ *cobra.Command, comps *cara
|
||||
usage += " (optional)"
|
||||
}
|
||||
|
||||
actions = append(actions, action.Usage(usage))
|
||||
actions = append(actions, action.Usage("%s", usage))
|
||||
}
|
||||
|
||||
comps.PositionalCompletion(actions...)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/assets"
|
||||
@@ -86,12 +87,35 @@ func RemoveExtensionByManifestName(manifestName string, con *console.SliverClien
|
||||
return false, errors.New("command name is required")
|
||||
}
|
||||
if man, ok := loadedManifests[manifestName]; ok {
|
||||
//foudn the manifest
|
||||
//delet it
|
||||
extPath := filepath.Join(assets.GetExtensionsDir(), filepath.Base(manifestName))
|
||||
// Found the manifest
|
||||
var extPath string
|
||||
if man.RootPath != "" {
|
||||
// Use RootPath for temporarily loaded extensions
|
||||
extPath = man.RootPath
|
||||
} else {
|
||||
// Fall back to extensions dir for installed extensions
|
||||
extPath = filepath.Join(assets.GetExtensionsDir(), filepath.Base(manifestName))
|
||||
}
|
||||
|
||||
if _, err := os.Stat(extPath); os.IsNotExist(err) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// If path is outside extensions directory, prompt for confirmation
|
||||
if !strings.HasPrefix(extPath, assets.GetExtensionsDir()) {
|
||||
confirm := false
|
||||
prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' extension directory from filesystem?", manifestName)}
|
||||
survey.AskOne(prompt, &confirm)
|
||||
if !confirm {
|
||||
// Skip the forceRemoveAll but continue with the rest
|
||||
delete(loadedManifests, manifestName)
|
||||
for _, cmd := range man.ExtCommand {
|
||||
delete(loadedExtensions, cmd.CommandName)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
forceRemoveAll(extPath)
|
||||
delete(loadedManifests, manifestName)
|
||||
for _, cmd := range man.ExtCommand {
|
||||
|
||||
@@ -1,4 +1,28 @@
|
||||
Filesystem
|
||||
==========
|
||||
# client/command/filesystem
|
||||
|
||||
This package implements file system commands such as `ls`, `cd`, `rm`, `download`, `upload`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'filesystem' command group for the Sliver client console. Handlers map Cobra invocations to filesystem workflows such as CAT, CD, chmod, and chown.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `cat.go` – Downloads remote files and prints contents locally with optional ANSI colorization.
|
||||
- `cd.go` – Changes the working directory of the active session or beacon.
|
||||
- `chmod.go` – Adjusts remote file permissions via RPC for Unix-like targets.
|
||||
- `chown.go` – Alters remote file ownership metadata where supported.
|
||||
- `chtimes.go` – Updates remote file access and modification timestamps.
|
||||
- `commands.go` – Assembles the filesystem command group and wires each file operation subcommand.
|
||||
- `cp.go` – Copies files on the remote target, handling overwrite prompts and path validation.
|
||||
- `download.go` – Retrieves files from the target and writes them to the local loot directory.
|
||||
- `grep.go` – Runs server-side grep equivalents with pattern, highlight, and streaming options.
|
||||
- `head.go` – Streams the first bytes or lines of a remote file.
|
||||
- `ls.go` – Lists directory contents with filtering, sorting, and long-format support.
|
||||
- `memfiles-add.go` – Uploads file data into in-memory implants for later retrieval.
|
||||
- `memfiles-list.go` – Enumerates in-memory file entries stored on the implant.
|
||||
- `memfiles-rm.go` – Removes staged in-memory files from the implant cache.
|
||||
- `mkdir.go` – Creates directories on the remote system, with recursive creation if requested.
|
||||
- `mount.go` – Mounts remote filesystem paths for live browsing through the client.
|
||||
- `mv.go` – Moves or renames remote files and directories.
|
||||
- `pwd.go` – Prints the current working directory of the active target.
|
||||
- `rm.go` – Deletes remote files or directories with optional recursive behavior.
|
||||
- `upload.go` – Transfers local files to the target and sets desired permissions.
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/chroma/formatters"
|
||||
"github.com/alecthomas/chroma/lexers"
|
||||
@@ -72,16 +73,16 @@ func CatCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintCat(download, cmd, con)
|
||||
PrintCat(filePath, download, cmd, con)
|
||||
})
|
||||
con.PrintAsyncResponse(download.Response)
|
||||
} else {
|
||||
PrintCat(download, cmd, con)
|
||||
PrintCat(filePath, download, cmd, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintCat - Print the download to stdout.
|
||||
func PrintCat(download *sliverpb.Download, cmd *cobra.Command, con *console.SliverClient) {
|
||||
func PrintCat(originalFileName string, download *sliverpb.Download, cmd *cobra.Command, con *console.SliverClient) {
|
||||
var (
|
||||
lootDownload bool = true
|
||||
err error
|
||||
@@ -108,6 +109,9 @@ func PrintCat(download *sliverpb.Download, cmd *cobra.Command, con *console.Sliv
|
||||
con.Printf("\n")
|
||||
}
|
||||
}
|
||||
if !strings.Contains(download.Path, originalFileName) {
|
||||
con.PrintInfof("Supplied pattern %s matched file %s\n\n", originalFileName, download.Path)
|
||||
}
|
||||
if color, _ := cmd.Flags().GetBool("colorize-output"); color {
|
||||
if err = colorize(download); err != nil {
|
||||
con.Println(string(download.Data))
|
||||
|
||||
@@ -295,7 +295,7 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
f.StringP("file-type", "F", "", "force a specific file type (binary/text) if looting (optional)")
|
||||
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
|
||||
f.Int64P("bytes", "b", 0, "Grab the first number of bytes from the file")
|
||||
f.Int64P("lines", "l", 0, "Grab the first number of lines from the file")
|
||||
f.Int64P("lines", "l", 10, "Grab the first number of lines from the file")
|
||||
})
|
||||
carapace.Gen(headCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the file to print"))
|
||||
|
||||
@@ -322,7 +322,7 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
f.StringP("file-type", "F", "", "force a specific file type (binary/text) if looting (optional)")
|
||||
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
|
||||
f.Int64P("bytes", "b", 0, "Grab the last number of bytes from the file")
|
||||
f.Int64P("lines", "l", 0, "Grab the last number of lines from the file")
|
||||
f.Int64P("lines", "l", 10, "Grab the last number of lines from the file")
|
||||
})
|
||||
carapace.Gen(tailCmd).PositionalCompletion(carapace.ActionValues().Usage("path to the file to print"))
|
||||
|
||||
|
||||
@@ -97,9 +97,7 @@ func prettifyDownloadName(path string) string {
|
||||
filteredString = multipleUnderscoreRegex.ReplaceAllString(filteredString, "_")
|
||||
|
||||
// If there is an underscore at the front of the filename, strip that off
|
||||
if strings.HasPrefix(filteredString, "_") {
|
||||
filteredString = filteredString[1:]
|
||||
}
|
||||
filteredString, _ = strings.CutPrefix(filteredString, "_")
|
||||
|
||||
return filteredString
|
||||
}
|
||||
@@ -118,7 +116,15 @@ func HandleDownloadResponse(download *sliverpb.Download, cmd *cobra.Command, arg
|
||||
}
|
||||
}
|
||||
|
||||
remotePath := args[0]
|
||||
// Use download.Path because a glob matching a single file on the remote will not have the
|
||||
// correct file name - the filename will contain the globs if we use the path from the user
|
||||
// On non-Windows systems, filepath.Base will not see backslashes, so we will replace them
|
||||
// on systems that do not use backslashes as path separators
|
||||
remotePath := download.Path
|
||||
if strings.Contains(download.Path, "\\") && string(os.PathSeparator) != "\\" {
|
||||
remotePath = strings.ReplaceAll(download.Path, "\\", "/")
|
||||
}
|
||||
|
||||
var localPath string
|
||||
if len(args) == 1 {
|
||||
localPath = "."
|
||||
|
||||
@@ -63,7 +63,7 @@ func HeadCmd(cmd *cobra.Command, con *console.SliverClient, args []string, head
|
||||
} else {
|
||||
operationName = "bytes"
|
||||
}
|
||||
} else if cmd.Flags().Changed("lines") {
|
||||
} else {
|
||||
fetchBytes = false
|
||||
fetchSize, _ = cmd.Flags().GetInt64("lines")
|
||||
if fetchSize < 0 {
|
||||
@@ -76,9 +76,6 @@ func HeadCmd(cmd *cobra.Command, con *console.SliverClient, args []string, head
|
||||
} else {
|
||||
operationName = "lines"
|
||||
}
|
||||
} else {
|
||||
con.PrintErrorf("A number of bytes or a number of lines must be specified.")
|
||||
return
|
||||
}
|
||||
|
||||
ctrl := make(chan bool)
|
||||
@@ -118,10 +115,10 @@ func HeadCmd(cmd *cobra.Command, con *console.SliverClient, args []string, head
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintCat(download, cmd, con)
|
||||
PrintCat(filePath, download, cmd, con)
|
||||
})
|
||||
con.PrintAsyncResponse(download.Response)
|
||||
} else {
|
||||
PrintCat(download, cmd, con)
|
||||
PrintCat(filePath, download, cmd, con)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/command/flags
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'flags' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `flags.go` – Provides shared helpers for binding Cobra flag sets, target filters, and carapace completions to commands.
|
||||
@@ -1,5 +1,24 @@
|
||||
Generate
|
||||
========
|
||||
# client/command/generate
|
||||
|
||||
Implements command related to implant generation such as `generate`, `regenerate`, `profiles`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'generate' command group for the Sliver client console. Handlers map Cobra invocations to generate workflows such as canaries, generate beacon, generate info, and implants RM.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `canaries.go` – Lists DNS canaries, filters burned entries, and prints status tables.
|
||||
- `commands.go` – Defines the generate command hierarchy spanning implant, profile, and canary tooling.
|
||||
- `generate-beacon.go` – Builds staged beacons from profile/flag inputs and triggers compilation via RPC.
|
||||
- `generate-info.go` – Displays build configuration details for a generated implant artifact.
|
||||
- `generate.go` – Orchestrates implant compilation pipelines, parsing C2 flags and selecting targets/builders.
|
||||
- `helpers.go` – Supplies completions, helper lookups, and binary retrieval utilities used across generate commands.
|
||||
- `implants-rm.go` – Deletes stored implant builds from the server catalog.
|
||||
- `implants-stage.go` – Uploads generated implants into staging slots for later deployment.
|
||||
- `implants.go` – Lists implant builds, filters them, and resolves selected build metadata.
|
||||
- `profiles-generate.go` – Generates new implant profiles from templates and selected options.
|
||||
- `profiles-new.go` – Creates empty implant profiles populated with default settings.
|
||||
- `profiles-rm.go` – Removes saved implant profiles and confirms deletion state.
|
||||
- `profiles-stage.go` – Stages implant profiles to facilitate rapid build operations.
|
||||
- `profiles.go` – Lists profiles, prints detailed info, and resolves profile selections for other commands.
|
||||
- `regenerate.go` – Rebuilds implants from existing configuration IDs without re-specifying flags.
|
||||
- `traffic-encoders.go` – Manages generation of HTTP/DNS traffic encoder assets for implants.
|
||||
@@ -48,30 +48,6 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
|
||||
generateCmd.AddCommand(generateBeaconCmd)
|
||||
|
||||
generateStagerCmd := &cobra.Command{
|
||||
Use: consts.MsfStagerStr,
|
||||
Short: "Generate a stager using Metasploit (requires local Metasploit installation)",
|
||||
Long: help.GetHelpFor([]string{consts.MsfStagerStr}),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
GenerateStagerCmd(cmd, con, args)
|
||||
},
|
||||
}
|
||||
flags.Bind("stager", false, generateStagerCmd, func(f *pflag.FlagSet) {
|
||||
f.StringP("os", "o", "windows", "operating system")
|
||||
f.StringP("arch", "a", "amd64", "cpu architecture")
|
||||
f.StringP("lhost", "L", "", "Listening host")
|
||||
f.Uint32P("lport", "l", 8443, "Listening port")
|
||||
f.StringP("protocol", "r", "tcp", "Staging protocol (tcp/http/https)")
|
||||
f.StringP("format", "f", "raw", "Output format (msfvenom formats, see help generate msf-stager for the list)")
|
||||
f.StringP("badchars", "b", "", "bytes to exclude from stage shellcode")
|
||||
f.StringP("save", "s", "", "directory to save the generated stager to")
|
||||
f.StringP("advanced", "d", "", "Advanced options for the stager using URI query syntax (option1=value1&option2=value2...)")
|
||||
})
|
||||
flags.BindFlagCompletions(generateStagerCmd, func(comp *carapace.ActionMap) {
|
||||
(*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant")
|
||||
})
|
||||
generateCmd.AddCommand(generateStagerCmd)
|
||||
|
||||
generateInfoCmd := &cobra.Command{
|
||||
Use: consts.CompilerInfoStr,
|
||||
Short: "Get information about the server's compiler",
|
||||
@@ -167,6 +143,8 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
flags.Bind("profiles", false, profilesGenerateCmd, func(f *pflag.FlagSet) {
|
||||
f.StringP("save", "s", "", "directory/file to the binary to")
|
||||
f.BoolP("disable-sgn", "G", false, "disable shikata ga nai shellcode encoder")
|
||||
f.StringP("name", "n", "", "Implant name")
|
||||
|
||||
})
|
||||
flags.BindFlagCompletions(profilesGenerateCmd, func(comp *carapace.ActionMap) {
|
||||
(*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant")
|
||||
@@ -331,7 +309,7 @@ func coreImplantFlags(name string, cmd *cobra.Command) {
|
||||
f.BoolP("evasion", "e", false, "enable evasion features (e.g. overwrite user space hooks)")
|
||||
f.BoolP("skip-symbols", "l", false, "skip symbol obfuscation")
|
||||
f.BoolP("disable-sgn", "G", false, "disable shikata ga nai shellcode encoder")
|
||||
|
||||
f.StringP("exports", "v", "StartW,VoidFunc,DllInstall,DllRegisterServer,DllUnregisterServer", "comma separated list of exports to include in the binary")
|
||||
f.StringP("canary", "c", "", "canary domain(s)")
|
||||
|
||||
// C2 channels
|
||||
@@ -377,6 +355,7 @@ func coreImplantFlagCompletions(cmd *cobra.Command, con *console.SliverClient) {
|
||||
(*comp)["format"] = FormatCompleter()
|
||||
(*comp)["save"] = carapace.ActionFiles().Tag("directory/file to save implant")
|
||||
(*comp)["traffic-encoders"] = TrafficEncodersCompleter(con).UniqueList(",")
|
||||
(*comp)["c2profile"] = HTTPC2Completer(con)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func GenerateBeaconCmd(cmd *cobra.Command, con *console.SliverClient, args []str
|
||||
save, _ = os.Getwd()
|
||||
}
|
||||
if external, _ := cmd.Flags().GetBool("external-builder"); !external {
|
||||
compile(config, save, con)
|
||||
compile(name, config, save, con)
|
||||
} else {
|
||||
externalBuild(name, config, save, con)
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
package generate
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2022 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// GenerateStagerCmd - Generate a stager using Metasploit.
|
||||
func GenerateStagerCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
var stageProto clientpb.StageProtocol
|
||||
lhost, _ := cmd.Flags().GetString("lhost")
|
||||
if lhost == "" {
|
||||
con.PrintErrorf("Please specify a listening host")
|
||||
return
|
||||
}
|
||||
match, err := regexp.MatchString(`^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$`, lhost)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !match {
|
||||
addr, err := net.LookupHost(lhost)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error resolving %s: %v\n", lhost, err)
|
||||
return
|
||||
}
|
||||
if len(addr) > 1 {
|
||||
prompt := &survey.Select{
|
||||
Message: "Select an address",
|
||||
Options: addr,
|
||||
}
|
||||
err := survey.AskOne(prompt, &lhost)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %v\n", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
lhost = addr[0]
|
||||
}
|
||||
}
|
||||
lport, _ := cmd.Flags().GetUint32("lport")
|
||||
stageOS, _ := cmd.Flags().GetString("os")
|
||||
arch, _ := cmd.Flags().GetString("arch")
|
||||
proto, _ := cmd.Flags().GetString("protocol")
|
||||
format, _ := cmd.Flags().GetString("format")
|
||||
badChars, _ := cmd.Flags().GetString("badchars")
|
||||
save, _ := cmd.Flags().GetString("save")
|
||||
advOptions, _ := cmd.Flags().GetString("advanced")
|
||||
|
||||
bChars := make([]string, 0)
|
||||
if len(badChars) > 0 {
|
||||
for _, b := range strings.Split(badChars, " ") {
|
||||
bChars = append(bChars, fmt.Sprintf("\\x%s", b))
|
||||
}
|
||||
}
|
||||
|
||||
switch proto {
|
||||
case "tcp":
|
||||
stageProto = clientpb.StageProtocol_TCP
|
||||
case "http":
|
||||
stageProto = clientpb.StageProtocol_HTTP
|
||||
case "https":
|
||||
stageProto = clientpb.StageProtocol_HTTPS
|
||||
default:
|
||||
con.PrintErrorf("%s staging protocol not supported\n", proto)
|
||||
return
|
||||
}
|
||||
|
||||
ctrl := make(chan bool)
|
||||
con.SpinUntil("Generating stager, please wait ...", ctrl)
|
||||
stageFile, err := con.Rpc.MsfStage(context.Background(), &clientpb.MsfStagerReq{
|
||||
Arch: arch,
|
||||
BadChars: bChars,
|
||||
Format: format,
|
||||
Host: lhost,
|
||||
Port: lport,
|
||||
Protocol: stageProto,
|
||||
OS: stageOS,
|
||||
AdvOptions: advOptions,
|
||||
})
|
||||
ctrl <- true
|
||||
<-ctrl
|
||||
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error: %v - Please make sure Metasploit framework >= v6.2 is installed and msfvenom/msfconsole are in your PATH", err)
|
||||
return
|
||||
}
|
||||
|
||||
if save != "" || format == "raw" {
|
||||
saveTo, err := saveLocation(save, stageFile.GetFile().GetName(), con)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = os.WriteFile(saveTo, stageFile.GetFile().GetData(), 0o700)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to write to: %s\n", saveTo)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("Sliver implant stager saved to: %s\n", saveTo)
|
||||
} else {
|
||||
con.PrintInfof("Here's your stager:\n")
|
||||
con.Println(string(stageFile.GetFile().GetData()))
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ func GenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
save, _ = os.Getwd()
|
||||
}
|
||||
if external, _ := cmd.Flags().GetBool("external-builder"); !external {
|
||||
compile(config, save, con)
|
||||
compile(name, config, save, con)
|
||||
} else {
|
||||
_, err := externalBuild(name, config, save, con)
|
||||
if err != nil {
|
||||
@@ -290,6 +290,15 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
|
||||
isShellcode := false
|
||||
sgnEnabled := false
|
||||
|
||||
var exports []string
|
||||
exportsArg, _ := cmd.Flags().GetString("exports")
|
||||
if exportsArg == "" {
|
||||
con.PrintErrorf("Shared libraries need at least one export\n")
|
||||
return "", nil
|
||||
} else {
|
||||
exports = strings.Split(exportsArg, ",")
|
||||
}
|
||||
|
||||
format, _ := cmd.Flags().GetString("format")
|
||||
runAtLoad := false
|
||||
var configFormat clientpb.OutputFormat
|
||||
@@ -364,6 +373,8 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
|
||||
c2Profile = consts.DefaultC2Profile
|
||||
}
|
||||
|
||||
// exports if its a shared library
|
||||
|
||||
config := &clientpb.ImplantConfig{
|
||||
GOOS: targetOS,
|
||||
GOARCH: targetArch,
|
||||
@@ -395,6 +406,7 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
|
||||
IsSharedLib: isSharedLib,
|
||||
IsService: isService,
|
||||
IsShellcode: isShellcode,
|
||||
Exports: exports,
|
||||
|
||||
RunAtLoad: runAtLoad,
|
||||
NetGoEnabled: netGo,
|
||||
@@ -905,7 +917,7 @@ func externalBuild(name string, config *clientpb.ImplantConfig, save string, con
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func compile(config *clientpb.ImplantConfig, save string, con *console.SliverClient) (*commonpb.File, error) {
|
||||
func compile(name string, config *clientpb.ImplantConfig, save string, con *console.SliverClient) (*commonpb.File, error) {
|
||||
if config.IsBeacon {
|
||||
interval := time.Duration(config.BeaconInterval)
|
||||
con.PrintInfof("Generating new %s/%s beacon implant binary (%v)\n", config.GOOS, config.GOARCH, interval)
|
||||
@@ -923,6 +935,7 @@ func compile(config *clientpb.ImplantConfig, save string, con *console.SliverCli
|
||||
con.SpinUntil("Compiling, please wait ...", ctrl)
|
||||
|
||||
generated, err := con.Rpc.Generate(context.Background(), &clientpb.GenerateReq{
|
||||
Name: name,
|
||||
Config: config,
|
||||
})
|
||||
ctrl <- true
|
||||
|
||||
@@ -36,6 +36,8 @@ func ProfilesGenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []s
|
||||
con.PrintErrorf("No profile name specified\n")
|
||||
return
|
||||
}
|
||||
|
||||
implantName, _ := cmd.Flags().GetString("name")
|
||||
save, _ := cmd.Flags().GetString("save")
|
||||
if save == "" {
|
||||
save, _ = os.Getwd()
|
||||
@@ -46,7 +48,7 @@ func ProfilesGenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []s
|
||||
if SGNDisabled, _ := cmd.Flags().GetBool("disable-sgn"); SGNDisabled {
|
||||
profile.Config.SGNEnabled = !SGNDisabled
|
||||
}
|
||||
_, err := compile(profile.Config, save, con)
|
||||
_, err := compile(implantName, profile.Config, save, con)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
Help
|
||||
====
|
||||
# client/command/help
|
||||
|
||||
This package contains all of the long-form command help templates that are displayed when a user types `help <cmd>`
|
||||
## Overview
|
||||
|
||||
Implements the 'help' command group for the Sliver client console. Handlers map Cobra invocations to help workflows such as long help.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `help.go` – Houses the legacy grouped help implementation for the console, kept for reference and future reuse.
|
||||
- `long-help.go` – Stores long-form help templates and utilities for formatting command documentation.
|
||||
@@ -45,7 +45,6 @@ var (
|
||||
consts.InfoStr: infoHelp,
|
||||
consts.UseStr: useHelp,
|
||||
consts.GenerateStr: generateHelp,
|
||||
consts.MsfStagerStr: generateStagerHelp,
|
||||
consts.StageListenerStr: stageListenerHelp,
|
||||
|
||||
consts.MsfStr: msfHelp,
|
||||
@@ -196,33 +195,6 @@ Execution limits can be used to restrict the execution of a Sliver implant to ma
|
||||
Due to the large number of options and C2s this can be a lot of typing. If you'd like to have a reusable a Sliver config
|
||||
see 'help profiles new'. All "generate" flags can be saved into a profile, you can view existing profiles with the "profiles"
|
||||
command.
|
||||
`
|
||||
generateStagerHelp = `[[.Bold]]Command:[[.Normal]] generate msf-stager <options>
|
||||
[[.Bold]]About:[[.Normal]] Generate a new sliver stager shellcode and saves the output to the cwd or a path specified with --save, or to stdout using --format.
|
||||
|
||||
[[.Bold]][[.Underline]]++ Bad Characters ++[[.Normal]]
|
||||
Bad characters must be specified like this for single bytes:
|
||||
|
||||
generate msf-stager -b 00
|
||||
|
||||
And like this for multiple bytes:
|
||||
|
||||
generate msf-stager -b '00 0a cc'
|
||||
|
||||
[[.Bold]][[.Underline]]++ Output Formats ++[[.Normal]]
|
||||
You can use the --format flag to print out the shellcode to stdout, in one of the following transform formats:
|
||||
[[.Bold]]bash c csharp dw dword hex java js_be js_le num perl pl powershell ps1 py python raw rb ruby sh vbapplication vbscript[[.Normal]]
|
||||
|
||||
[[.Bold]][[.Underline]]++ Advanced Options ++[[.Normal]]
|
||||
If there are any advanced options you need to pass to msfvenom, you can use the --advanced flag to provide them. They must be provided in URI query format: option1=value1&option2=value2 and so on.
|
||||
The full list of advanced options is available using "show advanced" in msf for the payload corresponding to the chosen protocol:
|
||||
TCP: meterpreter/reverse_tcp
|
||||
HTTP: custom/reverse_winhttp
|
||||
HTTPS: custom/reverse_winhttps
|
||||
|
||||
Example:
|
||||
To tell the stager to use the proxy proxy.corp.com:8080 with the user name "corp_drone" and password "MyPassword", you would pass the following string to --advanced:
|
||||
HttpProxyHost=proxy.corp.com&HttpProxyPort=8080&HttpProxyUser=corp_drone&HttpProxyPass=MyPassword
|
||||
`
|
||||
stageListenerHelp = `[[.Bold]]Command:[[.Normal]] stage-listener <options>
|
||||
[[.Bold]]About:[[.Normal]] Starts a stager listener bound to a Sliver profile.
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
Hosts
|
||||
======
|
||||
# client/command/hosts
|
||||
|
||||
Command to access and manage host information.
|
||||
## Overview
|
||||
|
||||
Implements the 'hosts' command group for the Sliver client console. Handlers map Cobra invocations to hosts workflows such as hosts IOC RM, hosts IOC, and hosts RM.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Sets up the hosts command suite and its IOC management subcommands.
|
||||
- `hosts-ioc-rm.go` – Removes stored indicators of compromise for a host via RPC.
|
||||
- `hosts-ioc.go` – Lists and prints host IOC data retrieved from the server.
|
||||
- `hosts-rm.go` – Deletes hosts from inventory and confirms removal operations.
|
||||
- `hosts.go` – Displays host summaries, filters by query, and renders tabular output.
|
||||
@@ -1,4 +1,11 @@
|
||||
Info
|
||||
====
|
||||
# client/command/info
|
||||
|
||||
Implements session information commands like `info`, `print`, `whoami`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'info' command group for the Sliver client console. Handlers map Cobra invocations to info workflows such as ping.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers information-oriented commands and binds them into the console.
|
||||
- `info.go` – Queries detailed session or beacon metadata and prints rich status tables.
|
||||
- `ping.go` – Sends ping requests to implants to test connectivity and round-trip latency.
|
||||
@@ -1,4 +1,16 @@
|
||||
Jobs
|
||||
=====
|
||||
# client/command/jobs
|
||||
|
||||
Implements commands related to starting/killing jobs like `jobs` and starting C2 listeners (`mtls`, `http`, etc.)
|
||||
## Overview
|
||||
|
||||
Implements the 'jobs' command group for the Sliver client console. Handlers map Cobra invocations to jobs workflows such as DNS, HTTP, HTTPS, and mTLS.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares the jobs command tree and wires transport-specific subcommands.
|
||||
- `dns.go` – Lists, starts, and stops DNS listener jobs via RPC.
|
||||
- `http.go` – Manages HTTP listener jobs, including creation and teardown.
|
||||
- `https.go` – Handles HTTPS listener lifecycle operations with certificate options.
|
||||
- `jobs.go` – Provides common utilities for rendering job tables and selecting listener IDs.
|
||||
- `mtls.go` – Controls mTLS listener jobs and prints connection details.
|
||||
- `stage.go` – Manages staging servers for delivering payloads to new implants.
|
||||
- `wg.go` – Configures and monitors WireGuard listener jobs for C2 traffic.
|
||||
@@ -48,7 +48,6 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
flags.Bind("mTLS listener", false, mtlsCmd, func(f *pflag.FlagSet) {
|
||||
f.StringP("lhost", "L", "", "interface to bind server to")
|
||||
f.Uint32P("lport", "l", generate.DefaultMTLSLPort, "tcp listen port")
|
||||
f.BoolP("persistent", "p", false, "make persistent across restarts")
|
||||
})
|
||||
|
||||
// Wireguard
|
||||
@@ -66,7 +65,6 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
f.Uint32P("lport", "l", generate.DefaultWGLPort, "udp listen port")
|
||||
f.Uint32P("nport", "n", generate.DefaultWGNPort, "virtual tun interface listen port")
|
||||
f.Uint32P("key-port", "x", generate.DefaultWGKeyExPort, "virtual tun interface key exchange port")
|
||||
f.BoolP("persistent", "p", false, "make persistent across restarts")
|
||||
})
|
||||
|
||||
// DNS
|
||||
@@ -85,7 +83,6 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
f.StringP("lhost", "L", "", "interface to bind server to")
|
||||
f.Uint32P("lport", "l", generate.DefaultDNSLPort, "udp listen port")
|
||||
f.BoolP("disable-otp", "D", false, "disable otp authentication")
|
||||
f.BoolP("persistent", "p", false, "make persistent across restarts")
|
||||
})
|
||||
|
||||
// HTTP
|
||||
@@ -106,7 +103,6 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
f.BoolP("disable-otp", "D", false, "disable otp authentication")
|
||||
f.StringP("long-poll-timeout", "T", "1s", "server-side long poll timeout")
|
||||
f.StringP("long-poll-jitter", "J", "2s", "server-side long poll jitter")
|
||||
f.BoolP("persistent", "p", false, "make persistent across restarts")
|
||||
})
|
||||
|
||||
// HTTPS
|
||||
@@ -132,8 +128,6 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
f.StringP("key", "k", "", "PEM encoded private key file")
|
||||
f.BoolP("lets-encrypt", "e", false, "attempt to provision a let's encrypt certificate")
|
||||
f.BoolP("disable-randomized-jarm", "E", false, "disable randomized jarm fingerprints")
|
||||
|
||||
f.BoolP("persistent", "p", false, "make persistent across restarts")
|
||||
})
|
||||
flags.BindFlagCompletions(httpsCmd, func(comp *carapace.ActionMap) {
|
||||
(*comp)["cert"] = carapace.ActionFiles().Tag("certificate file")
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/kill
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'kill' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the kill command and binds timeout/target flags.
|
||||
- `kill.go` – Terminates sessions or beacons on the server, handling confirmations and output messaging.
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
@@ -74,6 +75,16 @@ func KillSession(session *clientpb.Session, cmd *cobra.Command, con *console.Sli
|
||||
timeout, _ := cmd.Flags().GetInt64("timeout")
|
||||
force, _ := cmd.Flags().GetBool("force")
|
||||
|
||||
// remove any active socks proxies
|
||||
socks := core.SocksProxies.List()
|
||||
if len(socks) != 0 {
|
||||
for _, p := range socks {
|
||||
if p.SessionID == session.ID {
|
||||
core.SocksProxies.Remove(p.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err := con.Rpc.Kill(context.Background(), &sliverpb.KillReq{
|
||||
Request: &commonpb.Request{
|
||||
SessionID: session.ID,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# client/command/licenses
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'licenses' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Displays third-party license information through a dedicated console command.
|
||||
@@ -1,5 +1,16 @@
|
||||
Loot
|
||||
=====
|
||||
# client/command/loot
|
||||
|
||||
Client loot command implementations
|
||||
## Overview
|
||||
|
||||
Implements the 'loot' command group for the Sliver client console. Handlers map Cobra invocations to loot workflows such as fetch, local, remote, and rename.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares the loot command tree and binds fetch/local/removal subcommands.
|
||||
- `fetch.go` – Downloads remote loot artifacts and writes them to local storage.
|
||||
- `helpers.go` – Provides helper functions for lookup, filtering, and formatting loot entries.
|
||||
- `local.go` – Lists, inspects, and opens loot stored on the client filesystem.
|
||||
- `loot.go` – Shows remote loot inventory and renders summaries.
|
||||
- `remote.go` – Interacts with server-side loot, supporting filtering and detail views.
|
||||
- `rename.go` – Renames loot items while synchronizing local and remote metadata.
|
||||
- `rm.go` – Deletes loot entries from the server or local cache with confirmation prompts.
|
||||
@@ -1,5 +1,12 @@
|
||||
Monitor
|
||||
========
|
||||
# client/command/monitor
|
||||
|
||||
Contains `monitor` related command implementations.
|
||||
## Overview
|
||||
|
||||
Implements the 'monitor' command group for the Sliver client console. Handlers map Cobra invocations to monitor workflows such as start and stop.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the monitor command suite for live session monitoring.
|
||||
- `config.go` – Parses monitor configuration flags and resolves target selections.
|
||||
- `start.go` – Starts monitoring jobs and streams event output to the console.
|
||||
- `stop.go` – Stops active monitor jobs and reports termination status.
|
||||
@@ -1,4 +1,11 @@
|
||||
Network
|
||||
========
|
||||
# client/command/network
|
||||
|
||||
Network related command implementations such as `netstat` and `ifconfig`
|
||||
## Overview
|
||||
|
||||
Implements the 'network' command group for the Sliver client console. Handlers map Cobra invocations to network workflows such as ifconfig and netstat.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers network inspection commands for implants.
|
||||
- `ifconfig.go` – Retrieves and prints interface configuration details from the target.
|
||||
- `netstat.go` – Displays remote socket listings similar to netstat output.
|
||||
@@ -1,6 +1,10 @@
|
||||
Operators
|
||||
==========
|
||||
# client/command/operators
|
||||
|
||||
Operator related command implementations.
|
||||
## Overview
|
||||
|
||||
__NOTE:__ Some operator-related commands are server-side only and are located instead in `server/console`
|
||||
Implements the 'operators' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares the operators command and binds associated flags.
|
||||
- `operators.go` – Lists operators connected to the server and prints session details.
|
||||
@@ -1,5 +1,15 @@
|
||||
Pivots
|
||||
=======
|
||||
# client/command/pivots
|
||||
|
||||
Pivot related command implementations, pivots are specifically for pivoting C2 traffic (not to be confused with port forwarding)
|
||||
## Overview
|
||||
|
||||
Implements the 'pivots' command group for the Sliver client console. Handlers map Cobra invocations to pivots workflows such as details, graph, start, and stop.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Declares the pivots command family and ties start/stop operations together.
|
||||
- `details.go` – Prints detailed information about a specific pivot chain.
|
||||
- `graph.go` – Renders pivot relationships as ASCII graphs for situational awareness.
|
||||
- `helpers.go` – Supplies shared RPC helpers and completions used across pivot commands.
|
||||
- `pivots.go` – Lists pivot sessions and summarizes their status.
|
||||
- `start.go` – Initiates new pivot listeners or routes for the active target.
|
||||
- `stop.go` – Stops running pivots and cleans up resources on the implant.
|
||||
@@ -1,7 +1,12 @@
|
||||
Portfwd
|
||||
========
|
||||
# client/command/portfwd
|
||||
|
||||
In-band port forwarding related command implementations.
|
||||
## Overview
|
||||
|
||||
__NOTE:__ WireGuard port forwarding commands are located in `client/command/wireguard`
|
||||
Implements the 'portfwd' command group for the Sliver client console. Handlers map Cobra invocations to portfwd workflows such as portfwd ADD and portfwd RM.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Sets up the port forwarding command suite.
|
||||
- `portfwd-add.go` – Adds new local-to-remote port forwarders on the active session.
|
||||
- `portfwd-rm.go` – Removes configured port forwarders by ID.
|
||||
- `portfwd.go` – Lists existing port forwards and renders their configuration.
|
||||
@@ -1,5 +1,15 @@
|
||||
Privilege
|
||||
==========
|
||||
# client/command/privilege
|
||||
|
||||
Commands related to manipulation of operating system privileges, such as Windows Tokens.
|
||||
## Overview
|
||||
|
||||
Implements the 'privilege' command group for the Sliver client console. Handlers map Cobra invocations to privilege workflows such as getprivs, getsystem, impersonate, and make token.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers privilege escalation commands and binds platform restrictions.
|
||||
- `getprivs.go` – Queries and prints token privileges for the current user context.
|
||||
- `getsystem.go` – Attempts to obtain SYSTEM privileges via built-in escalation techniques.
|
||||
- `impersonate.go` – Handles impersonation of other logon sessions using available tokens.
|
||||
- `make-token.go` – Creates new logon tokens with supplied credentials for the implant.
|
||||
- `rev2self.go` – Reverts impersonation back to the implant's original security context.
|
||||
- `runas.go` – Runs commands under alternate credentials or integrity levels through runas-like workflows.
|
||||
@@ -1,4 +1,14 @@
|
||||
Processes
|
||||
==========
|
||||
# client/command/processes
|
||||
|
||||
Commands for manipulating remote processes, e.g. `ps`, `terminate`, etc.
|
||||
## Overview
|
||||
|
||||
Implements the 'processes' command group for the Sliver client console. Handlers map Cobra invocations to processes workflows such as procdump, PS, pstree, and terminate.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Creates the processes command suite and binds subcommands for inspection and control.
|
||||
- `procdump.go` – Dumps process memory to loot for forensic analysis via RPC tasks.
|
||||
- `ps.go` – Lists active processes on the target with filtering options.
|
||||
- `pstree.go` – Renders process hierarchies as a tree view.
|
||||
- `services.go` – Enumerates Windows services and their states.
|
||||
- `terminate.go` – Terminates processes by PID with confirmation messaging.
|
||||
@@ -25,11 +25,12 @@ func Commands(con *console.SliverClient) []*cobra.Command {
|
||||
flags.Bind("", false, psCmd, func(f *pflag.FlagSet) {
|
||||
f.IntP("pid", "p", -1, "filter based on pid")
|
||||
f.StringP("exe", "e", "", "filter based on executable name")
|
||||
f.StringP("owner", "o", "", "filter based on owner")
|
||||
f.BoolP("print-cmdline", "c", false, "print command line arguments")
|
||||
f.StringP("owner", "o", "", "filter based on owner, must request full process metadata (-f)")
|
||||
f.BoolP("print-cmdline", "c", false, "print command line arguments, must request full process metadata (-f)")
|
||||
f.BoolP("overflow", "O", false, "overflow terminal width (display truncated rows)")
|
||||
f.IntP("skip-pages", "S", 0, "skip the first n page(s)")
|
||||
f.BoolP("tree", "T", false, "print process tree")
|
||||
f.BoolP("full", "f", false, "show full process metadata (owner, architecture, session information) -- may trigger EDR")
|
||||
|
||||
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
|
||||
})
|
||||
|
||||
@@ -100,6 +100,13 @@ var knownSecurityTools = map[string][]string{
|
||||
"CrAmTray.exe": {console.Red, "Cybereason ActiveProbe"}, // Cybereason ActiveProbe
|
||||
"CrsSvc.exe": {console.Red, "Cybereason ActiveProbe"}, // Cybereason ActiveProbe
|
||||
"CybereasonAV.exe": {console.Red, "Cybereason ActiveProbe"}, // Cybereason ActiveProbe
|
||||
"cortex-xdr-payload.exe": {console.Red, "Palo Alto Cortex"}, // Cortex XDR - offline triage
|
||||
"cysandbox.exe": {console.Red, "Palo Alto Cortex"}, // Cortex XDR - sandbox
|
||||
"cyuserservice.exe": {console.Red, "Palo Alto Cortex"}, // Cortex XDR - user service
|
||||
"cywscsvc.exe": {console.Red, "Palo Alto Cortex"}, // Cortex XDR - security center service
|
||||
"tlaworker.exe": {console.Red, "Palo Alto Cortex"}, // Cortex XDR - local analysis worker
|
||||
"AEEngine.exe": {console.Red, "Faronics Anti-Executable"}, // Faronics Anti-Executable - security service
|
||||
"Antiexecutable.exe": {console.Red, "Faronics Anti-Executable"}, // Faronics Anti-Executable - gui and tray icon
|
||||
}
|
||||
|
||||
// PsCmd - List processes on the remote system
|
||||
@@ -108,14 +115,45 @@ func PsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ownerFilter, _ := cmd.Flags().GetString("owner")
|
||||
cmdLine, _ := cmd.Flags().GetBool("print-cmdline")
|
||||
tree, _ := cmd.Flags().GetBool("tree")
|
||||
fullInfo, _ := cmd.Flags().GetBool("full")
|
||||
|
||||
if tree && fullInfo {
|
||||
con.PrintWarnf("Process tree and full process metadata were requested. " +
|
||||
"Full process metadata is not necessary for the process tree, so the request for full process metadata will be ignored.\n\n")
|
||||
fullInfo = false
|
||||
}
|
||||
|
||||
if ownerFilter != "" && !fullInfo {
|
||||
con.PrintErrorf("Filtering on process owner was requested, but full process metadata was not requested. Re-run the command, and specify the -f flag.\n")
|
||||
return
|
||||
}
|
||||
|
||||
if cmdLine && !fullInfo {
|
||||
con.PrintErrorf("Process command line arguments were requested, but full process metadata was not requested. Re-run the command, and specify the -f flag.\n")
|
||||
return
|
||||
}
|
||||
|
||||
// Get OS information
|
||||
os := getOS(session, beacon)
|
||||
|
||||
/*
|
||||
Because a full list can trigger EDR on some platforms,
|
||||
namely Windows, filtering of the process list must be
|
||||
done on the implant side.
|
||||
*/
|
||||
ps, err := con.Rpc.Ps(context.Background(), &sliverpb.PsReq{
|
||||
Request: con.ActiveTarget.Request(cmd),
|
||||
FullInfo: fullInfo,
|
||||
Request: con.ActiveTarget.Request(cmd),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
os := getOS(session, beacon)
|
||||
|
||||
if ps.Response != nil && ps.Response.Async {
|
||||
con.AddBeaconCallback(ps.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, ps)
|
||||
@@ -123,7 +161,7 @@ func PsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintPS(os, ps, false, cmd.Flags(), con)
|
||||
PrintPS(os, ps, false, fullInfo, cmd.Flags(), con)
|
||||
products := findKnownSecurityProducts(ps)
|
||||
if 0 < len(products) {
|
||||
con.Println()
|
||||
@@ -132,7 +170,7 @@ func PsCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
})
|
||||
con.PrintAsyncResponse(ps.Response)
|
||||
} else {
|
||||
PrintPS(os, ps, true, cmd.Flags(), con)
|
||||
PrintPS(os, ps, true, fullInfo, cmd.Flags(), con)
|
||||
products := findKnownSecurityProducts(ps)
|
||||
if 0 < len(products) {
|
||||
con.Println()
|
||||
@@ -151,7 +189,7 @@ func getOS(session *clientpb.Session, beacon *clientpb.Beacon) string {
|
||||
}
|
||||
|
||||
// PrintPS - Prints the process list
|
||||
func PrintPS(os string, ps *sliverpb.Ps, interactive bool, flags *pflag.FlagSet, con *console.SliverClient) {
|
||||
func PrintPS(os string, ps *sliverpb.Ps, interactive bool, fullInfo bool, flags *pflag.FlagSet, con *console.SliverClient) {
|
||||
pidFilter, _ := flags.GetInt("pid")
|
||||
exeFilter, _ := flags.GetString("exe")
|
||||
ownerFilter, _ := flags.GetString("owner")
|
||||
@@ -180,15 +218,25 @@ func PrintPS(os string, ps *sliverpb.Ps, interactive bool, flags *pflag.FlagSet,
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
|
||||
defaultInfo := table.Row{"pid", "ppid", "executable"}
|
||||
|
||||
switch os {
|
||||
case "windows":
|
||||
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "arch", "executable", "session"})
|
||||
if fullInfo {
|
||||
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "arch", "executable", "session"})
|
||||
} else {
|
||||
tw.AppendHeader(defaultInfo)
|
||||
}
|
||||
case "darwin":
|
||||
fallthrough
|
||||
case "linux":
|
||||
fallthrough
|
||||
default:
|
||||
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "arch", "executable"})
|
||||
if fullInfo {
|
||||
tw.AppendHeader(table.Row{"pid", "ppid", "owner", "arch", "executable"})
|
||||
} else {
|
||||
tw.AppendHeader(defaultInfo)
|
||||
}
|
||||
}
|
||||
|
||||
cmdLine, _ := flags.GetBool("print-cmdline")
|
||||
@@ -202,7 +250,7 @@ func PrintPS(os string, ps *sliverpb.Ps, interactive bool, flags *pflag.FlagSet,
|
||||
if ownerFilter != "" && !strings.Contains(strings.ToLower(proc.Owner), strings.ToLower(ownerFilter)) {
|
||||
continue
|
||||
}
|
||||
row := procRow(tw, proc, cmdLine, con)
|
||||
row := procRow(proc, cmdLine, fullInfo, con)
|
||||
tw.AppendRow(row)
|
||||
}
|
||||
tw.SortBy([]table.SortBy{
|
||||
@@ -230,7 +278,7 @@ func findKnownSecurityProducts(ps *sliverpb.Ps) []string {
|
||||
}
|
||||
|
||||
// procRow - Stylizes the process information
|
||||
func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console.SliverClient) table.Row {
|
||||
func procRow(proc *commonpb.Process, cmdLine bool, fullInfo bool, con *console.SliverClient) table.Row {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
|
||||
color := console.Normal
|
||||
@@ -247,7 +295,7 @@ func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console
|
||||
var row table.Row
|
||||
switch session.GetOS() {
|
||||
case "windows":
|
||||
if cmdLine {
|
||||
if cmdLine && fullInfo {
|
||||
var args string
|
||||
if len(proc.CmdLine) >= 1 {
|
||||
args = strings.Join(proc.CmdLine, " ")
|
||||
@@ -263,13 +311,21 @@ func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID),
|
||||
}
|
||||
} else {
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Architecture),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID),
|
||||
if fullInfo {
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Architecture),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID),
|
||||
}
|
||||
} else {
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
|
||||
}
|
||||
}
|
||||
}
|
||||
case "darwin":
|
||||
@@ -277,7 +333,7 @@ func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console
|
||||
case "linux":
|
||||
fallthrough
|
||||
default:
|
||||
if cmdLine {
|
||||
if cmdLine && fullInfo {
|
||||
var args string
|
||||
if len(proc.CmdLine) >= 2 {
|
||||
args = strings.Join(proc.CmdLine, " ")
|
||||
@@ -292,12 +348,20 @@ func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console
|
||||
fmt.Sprintf(color+"%s"+console.Normal, args),
|
||||
}
|
||||
} else {
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Architecture),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
|
||||
if fullInfo {
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Owner),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Architecture),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
|
||||
}
|
||||
} else {
|
||||
row = table.Row{
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Pid),
|
||||
fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid),
|
||||
fmt.Sprintf(color+"%s"+console.Normal, proc.Executable),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
Reaction
|
||||
=========
|
||||
# client/command/reaction
|
||||
|
||||
Commands to set a reaction, or unset a reaction. Reactions allow the operator to automate commands in response to event(s).
|
||||
## Overview
|
||||
|
||||
Implements the 'reaction' command group for the Sliver client console. Handlers map Cobra invocations to reaction workflows such as reload, save, SET, and unset.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Wires the reaction command set for automations and triggers.
|
||||
- `helpers.go` – Supplies shared lookup and persistence helpers for reaction rules.
|
||||
- `reaction.go` – Lists existing reactions and displays their trigger conditions.
|
||||
- `reload.go` – Reloads reaction definitions from disk into the client runtime.
|
||||
- `save.go` – Persists in-memory reaction definitions back to disk.
|
||||
- `set.go` – Creates or modifies reaction rules interactively.
|
||||
- `unset.go` – Removes configured reaction rules from the store.
|
||||
@@ -1,4 +1,11 @@
|
||||
Reconfig
|
||||
=========
|
||||
# client/command/reconfig
|
||||
|
||||
Commands used to reconfigure beacon/session times and metadata
|
||||
## Overview
|
||||
|
||||
Implements the 'reconfig' command group for the Sliver client console. Handlers map Cobra invocations to reconfig workflows such as rename.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the reconfig command and attaches subcommands such as rename.
|
||||
- `reconfig.go` – Shows current implant configuration and prompts for updates.
|
||||
- `rename.go` – Renames implants or beacons on the server for easier identification.
|
||||
@@ -1,4 +1,14 @@
|
||||
Registry
|
||||
========
|
||||
# client/command/registry
|
||||
|
||||
Commands for manipulating the Windows registry.
|
||||
## Overview
|
||||
|
||||
Implements the 'registry' command group for the Sliver client console. Handlers map Cobra invocations to registry workflows such as REG create, REG delete, REG list, and REG read.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Exposes registry management commands for Windows targets.
|
||||
- `reg-create.go` – Creates new registry keys or values remotely.
|
||||
- `reg-delete.go` – Deletes registry keys/values with confirmation messaging.
|
||||
- `reg-list.go` – Enumerates registry subkeys and values for a provided path.
|
||||
- `reg-read.go` – Reads and prints registry value data.
|
||||
- `reg-write.go` – Writes registry values with type handling for supported data kinds.
|
||||
@@ -0,0 +1,12 @@
|
||||
# client/command/rportfwd
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'rportfwd' command group for the Sliver client console. Handlers map Cobra invocations to rportfwd workflows such as portfwd ADD, portfwd RM, and portfwd.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers reverse port forwarding commands tied to implant callbacks.
|
||||
- `portfwd-add.go` – Adds new reverse port forwards from remote hosts back to the operator.
|
||||
- `portfwd-rm.go` – Removes reverse port forwards by identifier.
|
||||
- `portfwd.go` – Lists active reverse port forwards and summarizes their endpoints.
|
||||
@@ -1,5 +1,10 @@
|
||||
Screenshot
|
||||
===========
|
||||
# client/command/screenshot
|
||||
|
||||
Screenshot command implementation.
|
||||
## Overview
|
||||
|
||||
Implements the 'screenshot' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the screenshot command and binds output options.
|
||||
- `screenshot.go` – Requests a screenshot from the implant and saves or displays the resulting image.
|
||||
@@ -19,6 +19,7 @@ package command
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/bishopfox/sliver/client/command/alias"
|
||||
@@ -31,6 +32,7 @@ import (
|
||||
"github.com/bishopfox/sliver/client/command/crack"
|
||||
"github.com/bishopfox/sliver/client/command/creds"
|
||||
"github.com/bishopfox/sliver/client/command/exit"
|
||||
"github.com/bishopfox/sliver/client/command/extensions"
|
||||
"github.com/bishopfox/sliver/client/command/generate"
|
||||
"github.com/bishopfox/sliver/client/command/hosts"
|
||||
"github.com/bishopfox/sliver/client/command/info"
|
||||
@@ -43,6 +45,7 @@ import (
|
||||
"github.com/bishopfox/sliver/client/command/sessions"
|
||||
"github.com/bishopfox/sliver/client/command/settings"
|
||||
sgn "github.com/bishopfox/sliver/client/command/shikata-ga-nai"
|
||||
"github.com/bishopfox/sliver/client/command/socks"
|
||||
"github.com/bishopfox/sliver/client/command/taskmany"
|
||||
"github.com/bishopfox/sliver/client/command/update"
|
||||
"github.com/bishopfox/sliver/client/command/use"
|
||||
@@ -90,6 +93,7 @@ func ServerCommands(con *client.SliverClient, serverCmds func() []*cobra.Command
|
||||
licenses.Commands,
|
||||
settings.Commands,
|
||||
alias.Commands,
|
||||
extensions.Commands,
|
||||
armory.Commands,
|
||||
update.Commands,
|
||||
operators.Commands,
|
||||
@@ -105,6 +109,7 @@ func ServerCommands(con *client.SliverClient, serverCmds func() []*cobra.Command
|
||||
websites.Commands,
|
||||
wireguard.Commands,
|
||||
c2profiles.Commands,
|
||||
socks.RootCommands,
|
||||
)
|
||||
|
||||
// Payloads
|
||||
@@ -129,6 +134,26 @@ func ServerCommands(con *client.SliverClient, serverCmds func() []*cobra.Command
|
||||
|
||||
// [ Post-command declaration setup ]-----------------------------------------
|
||||
|
||||
// Load Extensions
|
||||
// Similar to the SliverCommand loading, without adding the commands to the
|
||||
// Server command tree. This is done to ensure that the extensions are loaded
|
||||
// before the server is started, so that the extensions are registered.
|
||||
extensionManifests := extensions.GetAllExtensionManifests()
|
||||
for _, manifest := range extensionManifests {
|
||||
_, err := extensions.LoadExtensionManifest(manifest)
|
||||
// Absorb error in case there's no extensions manifest
|
||||
if err != nil {
|
||||
//con doesn't appear to be initialised here?
|
||||
//con.PrintErrorf("Failed to load extension: %s", err)
|
||||
fmt.Printf("Failed to load extension: %s\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
//for _, ext := range mext.ExtCommand {
|
||||
// extensions.ExtensionRegisterCommand(ext, sliver, con)
|
||||
//}
|
||||
}
|
||||
|
||||
// Everything below this line should preferably not be any command binding
|
||||
// (although you can do so without fear). If there are any final modifications
|
||||
// to make to the server menu command tree, it time to do them here.
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
Sessions
|
||||
=========
|
||||
# client/command/sessions
|
||||
|
||||
Session related command implementations.
|
||||
## Overview
|
||||
|
||||
Implements the 'sessions' command group for the Sliver client console. Handlers map Cobra invocations to sessions workflows such as background, close, interactive, and prune.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `background.go` – Sends interactive sessions to the background while keeping them connected.
|
||||
- `close.go` – Closes sessions cleanly via RPC.
|
||||
- `commands.go` – Assembles the sessions command hierarchy and subcommands.
|
||||
- `helpers.go` – Provides lookup utilities and prompt helpers for session selection.
|
||||
- `interactive.go` – Brings sessions into the foreground interactive console.
|
||||
- `prune.go` – Removes disconnected or dead sessions from the server inventory.
|
||||
- `sessions.go` – Lists active sessions and renders tabular summaries.
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/client/core"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -35,6 +36,16 @@ func CloseSessionCmd(cmd *cobra.Command, con *console.SliverClient, args []strin
|
||||
return
|
||||
}
|
||||
|
||||
// remove any active socks proxies
|
||||
socks := core.SocksProxies.List()
|
||||
if len(socks) != 0 {
|
||||
for _, p := range socks {
|
||||
if p.SessionID == session.ID {
|
||||
core.SocksProxies.Remove(p.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close the session
|
||||
_, err := con.Rpc.CloseSession(context.Background(), &sliverpb.CloseSession{
|
||||
Request: con.ActiveTarget.Request(cmd),
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
Style
|
||||
======
|
||||
# client/command/settings
|
||||
|
||||
Defines terminal interface styles.
|
||||
## Overview
|
||||
|
||||
Implements the 'settings' command group for the Sliver client console. Handlers map Cobra invocations to settings workflows such as beacons, opsec, and tables.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `beacons.go` – Configures beacon polling, jitter, and other runtime options.
|
||||
- `commands.go` – Registers the settings command namespace and attaches subcommands.
|
||||
- `opsec.go` – Manages operational security settings like auto tasks and notifications.
|
||||
- `settings.go` – Lists and updates general client settings persisted to disk.
|
||||
- `tables.go` – Adjusts table formatting preferences for console output.
|
||||
@@ -1,5 +1,12 @@
|
||||
Shell
|
||||
======
|
||||
# client/command/shell
|
||||
|
||||
Implements the interactive `shell` command.
|
||||
## Overview
|
||||
|
||||
Implements the 'shell' command group for the Sliver client console. Handlers map Cobra invocations to shell workflows such as filter reader generic and filter reader windows.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Exposes the interactive shell command and binds its options.
|
||||
- `filter-reader_generic.go` – Provides output filtering for shell streams on POSIX targets.
|
||||
- `filter-reader_windows.go` – Implements CRLF-aware filtering and decoding for Windows shell sessions.
|
||||
- `shell.go` – Launches interactive command shells over RPC and manages IO loops.
|
||||
@@ -0,0 +1,10 @@
|
||||
# client/command/shikata-ga-nai
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'shikata-ga-nai' command group for the Sliver client console. Handlers map Cobra invocations to shikata ga nai workflows such as SGN.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers shikata-ga-nai encoder commands for payload generation.
|
||||
- `sgn.go` – Interfaces with the SGN service to build XOR polymorphic payloads and prints results.
|
||||
@@ -87,6 +87,7 @@ func SliverCommands(con *client.SliverClient) console.Commands {
|
||||
screenshot.Commands,
|
||||
environment.Commands,
|
||||
registry.Commands,
|
||||
extensions.SliverCommands,
|
||||
)
|
||||
|
||||
// [ Filesystem ]
|
||||
@@ -127,9 +128,7 @@ func SliverCommands(con *client.SliverClient) console.Commands {
|
||||
bind(consts.AliasHelpGroup)
|
||||
|
||||
// [ Extensions ]
|
||||
bind(consts.ExtensionHelpGroup,
|
||||
extensions.Commands,
|
||||
)
|
||||
bind(consts.ExtensionHelpGroup)
|
||||
|
||||
// [ Post-command declaration setup ]----------------------------------------
|
||||
|
||||
@@ -144,7 +143,7 @@ func SliverCommands(con *client.SliverClient) console.Commands {
|
||||
}
|
||||
|
||||
// Load Extensions
|
||||
extensionManifests := assets.GetInstalledExtensionManifests()
|
||||
extensionManifests := extensions.GetAllExtensionManifests()
|
||||
for _, manifest := range extensionManifests {
|
||||
mext, err := extensions.LoadExtensionManifest(manifest)
|
||||
// Absorb error in case there's no extensions manifest
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# client/command/socks
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'socks' command group for the Sliver client console. Handlers map Cobra invocations to socks workflows such as rootcommands, socks start, and socks stop.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers SOCKS proxy commands within the client console.
|
||||
- `rootCommands.go` – Provides shared root-level wiring for SOCKS commands used in multiple menus.
|
||||
- `socks-start.go` – Starts local SOCKS proxy listeners tied to implants.
|
||||
- `socks-stop.go` – Stops running SOCKS proxies and frees ports.
|
||||
- `socks.go` – Lists SOCKS proxies and prints their connection details.
|
||||
@@ -0,0 +1,46 @@
|
||||
package socks
|
||||
|
||||
import (
|
||||
"github.com/bishopfox/sliver/client/command/flags"
|
||||
"github.com/bishopfox/sliver/client/command/help"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/rsteube/carapace"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// Commands returns the “ command and its subcommands.
|
||||
func RootCommands(con *console.SliverClient) []*cobra.Command {
|
||||
socksCmd := &cobra.Command{
|
||||
Use: consts.Socks5Str,
|
||||
Short: "In-band SOCKS5 Proxy",
|
||||
Long: help.GetHelpFor([]string{consts.Socks5Str}),
|
||||
GroupID: consts.NetworkHelpGroup,
|
||||
Annotations: flags.RestrictTargets(consts.SessionCmdsFilter),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
SocksCmd(cmd, con, args)
|
||||
},
|
||||
}
|
||||
flags.Bind("", true, socksCmd, func(f *pflag.FlagSet) {
|
||||
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
|
||||
})
|
||||
|
||||
socksStopCmd := &cobra.Command{
|
||||
Use: consts.StopStr,
|
||||
Short: "Stop a SOCKS5 proxy",
|
||||
Long: help.GetHelpFor([]string{consts.Socks5Str}),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
SocksStopCmd(cmd, con, args)
|
||||
},
|
||||
}
|
||||
socksCmd.AddCommand(socksStopCmd)
|
||||
flags.Bind("", false, socksStopCmd, func(f *pflag.FlagSet) {
|
||||
f.Uint64P("id", "i", 0, "id of portfwd to remove")
|
||||
})
|
||||
flags.BindFlagCompletions(socksStopCmd, func(comp *carapace.ActionMap) {
|
||||
(*comp)["id"] = SocksIDCompleter(con)
|
||||
})
|
||||
|
||||
return []*cobra.Command{socksCmd}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ func SocksCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
return socks[i].ID < socks[j].ID
|
||||
})
|
||||
|
||||
session := con.ActiveTarget.GetSession()
|
||||
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.AppendHeader(table.Row{
|
||||
@@ -52,6 +54,10 @@ func SocksCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
"Passwords",
|
||||
})
|
||||
for _, p := range socks {
|
||||
// if we're in an active session, just display socks proxies for the session
|
||||
if session != nil && session.ID != p.SessionID {
|
||||
continue
|
||||
}
|
||||
tw.AppendRow(table.Row{p.ID, p.SessionID, p.BindAddr, p.Username, p.Password})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
Taskmany
|
||||
========
|
||||
This package implements the `taskmany` command, which is used to task multiple beacons or sessions at once
|
||||
# client/command/taskmany
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'taskmany' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `taskmany.go` – Batches task execution across multiple sessions or beacons using shared parameters.
|
||||
@@ -1,5 +1,13 @@
|
||||
Tasks
|
||||
=======
|
||||
# client/command/tasks
|
||||
|
||||
Manage and interact with Beacon tasks
|
||||
## Overview
|
||||
|
||||
Implements the 'tasks' command group for the Sliver client console. Handlers map Cobra invocations to tasks workflows such as fetch and tasks cancel.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers task management commands for viewing and controlling job history.
|
||||
- `fetch.go` – Downloads task artifacts and output generated by implants.
|
||||
- `helpers.go` – Provides shared utilities for task lookups, formatting, and completion.
|
||||
- `tasks-cancel.go` – Cancels queued or running tasks targeting implants.
|
||||
- `tasks.go` – Lists recent tasks with filters for status and target.
|
||||
@@ -628,8 +628,11 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverClient) {
|
||||
f.BoolP("overflow", "O", false, "overflow terminal width (display truncated rows)")
|
||||
f.IntP("skip-pages", "S", 0, "skip the first n page(s)")
|
||||
f.BoolP("tree", "T", false, "print process tree")
|
||||
f.BoolP("full", "f", false, "show full process info (owner, command line, session information, may trigger EDR), default true on all non-Windows OSs, false on Windows")
|
||||
|
||||
processes.PrintPS(beacon.OS, ps, true, f, con)
|
||||
fullInfo := beacon.OS != "windows"
|
||||
|
||||
processes.PrintPS(beacon.OS, ps, true, fullInfo, f, con)
|
||||
|
||||
case sliverpb.MsgTerminateReq:
|
||||
terminate := &sliverpb.Terminate{}
|
||||
|
||||
@@ -50,6 +50,9 @@ func TasksCancelCmd(cmd *cobra.Command, con *console.SliverClient, args []string
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
// Request and response content is not needed for cancelling a task
|
||||
task.Request = nil
|
||||
task.Response = nil
|
||||
}
|
||||
|
||||
if task != nil {
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
Update
|
||||
======
|
||||
# client/command/update
|
||||
|
||||
Implements the `update` command
|
||||
## Overview
|
||||
|
||||
Implements the 'update' command group for the Sliver client console.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers the update command for checking new releases.
|
||||
- `update.go` – Contacts the update endpoint and reports available client/server versions.
|
||||
@@ -1,4 +1,12 @@
|
||||
Use
|
||||
====
|
||||
# client/command/use
|
||||
|
||||
This package implements the `use` command, which is used to select active sessions/beacons.
|
||||
## Overview
|
||||
|
||||
Implements the 'use' command group for the Sliver client console. Handlers map Cobra invocations to use workflows such as beacons and sessions.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `beacons.go` – Switches the active target to a selected beacon.
|
||||
- `commands.go` – Registers the use command and subcommands for session selection.
|
||||
- `sessions.go` – Sets the active session context for subsequent commands.
|
||||
- `use.go` – Implements shared helper logic for switching targets and updating prompts.
|
||||
@@ -0,0 +1,11 @@
|
||||
# client/command/wasm
|
||||
|
||||
## Overview
|
||||
|
||||
Implements the 'wasm' command group for the Sliver client console. Handlers map Cobra invocations to wasm workflows such as memfs.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers WebAssembly-related commands.
|
||||
- `memfs.go` – Manages the WASM in-memory filesystem cache for implants.
|
||||
- `wasm.go` – Lists installed WASM modules and orchestrates execution requests.
|
||||
@@ -1,4 +1,14 @@
|
||||
Websites
|
||||
========
|
||||
# client/command/websites
|
||||
|
||||
Commands related to managing `website`'s
|
||||
## Overview
|
||||
|
||||
Implements the 'websites' command group for the Sliver client console. Handlers map Cobra invocations to websites workflows such as websites ADD content, websites RM content, websites RM, and websites update content.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers website management commands for hosted phishing content.
|
||||
- `websites-add-content.go` – Uploads new site content (files or strings) to the server.
|
||||
- `websites-rm-content.go` – Removes specific content entries from a hosted site.
|
||||
- `websites-rm.go` – Deletes entire website definitions from the server.
|
||||
- `websites-update-content.go` – Replaces or updates existing hosted content assets.
|
||||
- `websites.go` – Lists configured websites and prints their metadata.
|
||||
@@ -1,7 +1,16 @@
|
||||
WireGuard
|
||||
==========
|
||||
# client/command/wireguard
|
||||
|
||||
This package implements commands related to WireGuard functionality such as `wg-socks` and `wg-portfwd`
|
||||
## Overview
|
||||
|
||||
__NOTE:__ Listener code for WireGuard (and all other protocols) is located in the `client/command/jobs` package
|
||||
Implements the 'wireguard' command group for the Sliver client console. Handlers map Cobra invocations to wireguard workflows such as WG config, WG portfwd ADD, WG portfwd RM, and WG portfwd.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `commands.go` – Registers WireGuard-centric commands and their subcommands.
|
||||
- `wg-config.go` – Generates and displays WireGuard configuration files for implants.
|
||||
- `wg-portfwd-add.go` – Adds WireGuard-based port forwarding rules.
|
||||
- `wg-portfwd-rm.go` – Removes WireGuard port forwarding entries.
|
||||
- `wg-portfwd.go` – Lists WireGuard forwarding rules with status information.
|
||||
- `wg-socks-start.go` – Starts SOCKS proxies over WireGuard tunnels.
|
||||
- `wg-socks-stop.go` – Stops WireGuard-backed SOCKS proxies.
|
||||
- `wg-socks.go` – Lists SOCKS proxies running over WireGuard connections.
|
||||
@@ -1,4 +1,10 @@
|
||||
Console (Client)
|
||||
=================
|
||||
# client/console
|
||||
|
||||
Contains the entrypoint for the console client
|
||||
## Overview
|
||||
|
||||
Renders the interactive console UI, logging, and terminal helpers for the client. Coordinates readline behavior, prompt styling, and message formatting.
|
||||
|
||||
## Go Files
|
||||
|
||||
- `console.go` – Implements the interactive console, prompt rendering, and RPC client integration.
|
||||
- `log.go` – Provides structured logging utilities and output filters tailored to the console experience.
|
||||
Loaded 100 of 3763 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user