Compare commits

..
21 changed files with 5498 additions and 10216 deletions

No files matched your search

+1 -1
View File
@@ -9,7 +9,7 @@
# STAGE: base
## Compiles Sliver for use
FROM golang:1.22.5 AS base
FROM golang:1.23.5 AS base
### Base packages
RUN apt-get update --fix-missing && apt-get -y install \
+11 -32
View File
@@ -1,28 +1,34 @@
package extensions
import (
"github.com/bishopfox/sliver/client/command/flags"
"github.com/bishopfox/sliver/client/command/help"
"github.com/bishopfox/sliver/client/command/use"
"github.com/bishopfox/sliver/client/console"
consts "github.com/bishopfox/sliver/client/constants"
"github.com/rsteube/carapace"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
// Commands returns the 'extensions' command and its subcommands.
// Commands returns the “ command and its subcommands.
func Commands(con *console.SliverClient) []*cobra.Command {
extensionCmd := &cobra.Command{
Use: consts.ExtensionsStr,
Short: "Manage extensions",
Long: help.GetHelpFor([]string{consts.ExtensionsStr}),
GroupID: consts.GenericHelpGroup,
GroupID: consts.ExecutionHelpGroup,
Run: func(cmd *cobra.Command, _ []string) {
ExtensionsCmd(cmd, con)
},
}
extensionCmd.AddCommand(&cobra.Command{
Use: consts.ListStr,
Short: "List extensions loaded in the current session or beacon",
Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.ListStr}),
Run: func(cmd *cobra.Command, args []string) {
ExtensionsListCmd(cmd, con, args)
},
})
extensionLoadCmd := &cobra.Command{
Use: consts.LoadStr,
Short: "Temporarily load an extension from a local directory",
@@ -60,30 +66,3 @@ func Commands(con *console.SliverClient) []*cobra.Command {
return []*cobra.Command{extensionCmd}
}
func SliverCommands(con *console.SliverClient) []*cobra.Command {
extensionCmd := &cobra.Command{
Use: consts.ExtensionsStr,
Short: "Manage extensions",
Long: help.GetHelpFor([]string{consts.ExtensionsStr}),
GroupID: consts.InfoHelpGroup,
Annotations: flags.RestrictTargets(consts.SessionCmdsFilter), // restrict to session targets since we cannot `list` "loaded" extensions from beacon mode
}
listCmd := &cobra.Command{
Use: consts.ListStr,
Short: "List extensions loaded in the current session",
Long: help.GetHelpFor([]string{consts.ExtensionsStr, consts.ListStr}),
Run: func(cmd *cobra.Command, args []string) {
ExtensionsListCmd(cmd, con, args)
},
}
flags.Bind("use", false, listCmd, func(f *pflag.FlagSet) {
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
})
extensionCmd.AddCommand(listCmd)
carapace.Gen(listCmd).PositionalCompletion(use.BeaconAndSessionIDCompleter(con))
return []*cobra.Command{extensionCmd}
}
+3 -48
View File
@@ -22,7 +22,6 @@ import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/bishopfox/sliver/client/assets"
@@ -36,7 +35,7 @@ import (
// ExtensionsCmd - List information about installed extensions.
func ExtensionsCmd(cmd *cobra.Command, con *console.SliverClient) {
if len(GetAllExtensionManifests()) > 0 {
if 0 < len(getInstalledManifests()) {
PrintExtensions(con)
} else {
con.PrintInfof("No extensions installed, use the 'armory' command to automatically install some\n")
@@ -68,12 +67,8 @@ func PrintExtensions(con *console.SliverClient) {
for _, extension := range loadedExtensions {
//for _, extension := range extensionm.ExtCommand {
installed := ""
//if _, ok := installedManifests[extension.Manifest.Name]; ok {
for _, installedManifest := range installedManifests {
if extension.Manifest.RootPath == installedManifest.RootPath {
installed = "✅"
break
}
if _, ok := installedManifests[extension.Manifest.Name]; ok {
installed = "✅"
}
tw.AppendRow(table.Row{
extension.Manifest.Name,
@@ -102,9 +97,6 @@ func extensionPlatforms(extension *ExtCommand) []string {
return keys
}
// getInstalledManifests - Returns a mapping of extension names to their parsed manifest objects.
// Reads all installed extension manifests from disk, ignoring any that cannot be read or parsed.
// The returned manifests have their RootPath set to the directory containing their manifest file.
func getInstalledManifests() map[string]*ExtensionManifest {
manifestPaths := assets.GetInstalledExtensionManifests()
installedManifests := map[string]*ExtensionManifest{}
@@ -118,48 +110,11 @@ func getInstalledManifests() map[string]*ExtensionManifest {
if err != nil {
continue
}
manifest.RootPath = filepath.Dir(manifestPath)
installedManifests[manifest.Name] = manifest
}
return installedManifests
}
// getTemporarilyLoadedManifests returns a map of extension manifests that are currently
// loaded into memory but not permanently installed. The map is keyed by the manifest's
// Name field.
func getTemporarilyLoadedManifests() map[string]*ExtensionManifest {
tempManifests := map[string]*ExtensionManifest{}
for name, manifest := range loadedManifests {
tempManifests[name] = manifest
}
return tempManifests
}
// GetAllExtensionManifests returns a combined list of manifest file paths from
// both installed and temporarily loaded extensions
func GetAllExtensionManifests() []string {
manifestPaths := make(map[string]struct{}) // use map for deduplication
// Add installed manifests
for _, manifest := range getInstalledManifests() {
manifestPath := filepath.Join(manifest.RootPath, ManifestFileName)
manifestPaths[manifestPath] = struct{}{}
}
// Add temporarily loaded manifests
for _, manifest := range getTemporarilyLoadedManifests() {
manifestPath := filepath.Join(manifest.RootPath, ManifestFileName)
manifestPaths[manifestPath] = struct{}{}
}
// Convert to slice
paths := make([]string, 0, len(manifestPaths))
for path := range manifestPaths {
paths = append(paths, path)
}
return paths
}
// ExtensionsCommandNameCompleter - Completer for installed extensions command names.
func ExtensionsCommandNameCompleter(con *console.SliverClient) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
+2 -24
View File
@@ -43,22 +43,7 @@ func ExtensionsInstallCmd(cmd *cobra.Command, con *console.SliverClient, args []
InstallFromDir(extLocalPath, true, con, strings.HasSuffix(extLocalPath, ".tar.gz"))
}
// InstallFromDir installs a Sliver extension from either a local directory or gzipped archive.
// It reads the extension manifest, validates it, and copies all required files to the extensions
// directory. If an extension with the same name already exists, it can optionally prompt for
// overwrite confirmation.
//
// Parameters:
// - extLocalPath: Path to the source directory or gzipped archive containing the extension
// - promptToOverwrite: If true, prompts for confirmation before overwriting existing extension
// - con: Sliver console client for displaying status and error messages
// - isGz: Whether the source is a gzipped archive (true) or directory (false)
//
// The function will return early with error messages printed to console if:
// - The manifest cannot be read or parsed
// - Required directories cannot be created
// - File copy operations fail
// - User declines overwrite when prompted
// Install an extension from a directory
func InstallFromDir(extLocalPath string, promptToOverwrite bool, con *console.SliverClient, isGz bool) {
var manifestData []byte
var err error
@@ -79,15 +64,8 @@ func InstallFromDir(extLocalPath string, promptToOverwrite bool, con *console.Sl
return
}
// Use package name if available, otherwise use extension name
// (Note, for v1 manifests this will actually be command_name)
packageID := manifestF.Name
if manifestF.PackageName != "" {
packageID = manifestF.PackageName
}
//create repo path
minstallPath := filepath.Join(assets.GetExtensionsDir(), filepath.Base(packageID))
minstallPath := filepath.Join(assets.GetExtensionsDir(), filepath.Base(manifestF.Name))
if _, err := os.Stat(minstallPath); !os.IsNotExist(err) {
if promptToOverwrite {
con.PrintInfof("Extension '%s' already exists", manifestF.Name)
+5 -111
View File
@@ -20,116 +20,12 @@ package extensions
import (
"context"
"crypto/sha256"
"encoding/hex"
"os"
"path/filepath"
"github.com/bishopfox/sliver/client/command/settings"
"github.com/bishopfox/sliver/client/console"
"github.com/bishopfox/sliver/protobuf/sliverpb"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
)
// ExtensionMatch holds the details of a matched extension
type ExtensionMatch struct {
CommandName string
Hash string
BinPath string
}
// FindExtensionMatches searches through loaded extensions for matching hashes
// Returns a map of hash to ExtensionMatch (match will be nil if hash wasn't found)
func FindExtensionMatches(targetHashes []string) map[string]*ExtensionMatch {
results := make(map[string]*ExtensionMatch)
pathCache := make(map[string]*ExtensionMatch)
// Initialize results map with all target hashes
for _, hash := range targetHashes {
results[hash] = nil
}
// Search for matches
for targetHash := range results {
for _, extCmd := range loadedExtensions {
if extCmd == nil || len(extCmd.Files) == 0 {
continue
}
for _, file := range extCmd.Files {
fullPath := filepath.Join(extCmd.Manifest.RootPath, file.Path)
// Check cache first
var match *ExtensionMatch
if cached, exists := pathCache[fullPath]; exists {
match = cached
} else {
// Calculate hash if not cached
fileData, err := os.ReadFile(fullPath)
if err != nil {
continue
}
hashBytes := sha256.Sum256(fileData)
fileHash := hex.EncodeToString(hashBytes[:])
match = &ExtensionMatch{
CommandName: extCmd.CommandName,
Hash: fileHash,
BinPath: fullPath,
}
pathCache[fullPath] = match
}
if match.Hash == targetHash {
results[targetHash] = match
break
}
}
if results[targetHash] != nil {
break
}
}
}
return results
}
// PrintExtensionMatches prints the extension matches in a formatted table
func PrintExtensionMatches(matches map[string]*ExtensionMatch, con *console.SliverClient) {
tw := table.NewWriter()
tw.SetStyle(settings.GetTableStyle(con))
tw.AppendHeader(table.Row{
"Command Name",
"Sha256 Hash",
"Bin Path",
})
tw.SortBy([]table.SortBy{
{Name: "Command Name", Mode: table.Asc},
})
for hash, match := range matches {
if match != nil {
tw.AppendRow(table.Row{
match.CommandName,
hash,
match.BinPath,
})
} else {
tw.AppendRow(table.Row{
"",
hash,
"",
})
}
}
con.Println(tw.Render())
}
// ExtensionsListCmd - List all extension loaded on the active session/beacon.
func ExtensionsListCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
session := con.ActiveTarget.GetSessionInteractive()
@@ -149,12 +45,10 @@ func ExtensionsListCmd(cmd *cobra.Command, con *console.SliverClient, args []str
con.PrintErrorf("%s\n", extList.Response.Err)
return
}
if len(extList.Names) == 0 {
return
if len(extList.Names) > 0 {
con.PrintInfof("Loaded extensions:\n")
for _, ext := range extList.Names {
con.Printf("- %s\n", ext)
}
}
con.PrintInfof("Loaded extensions:\n\n")
matches := FindExtensionMatches(extList.Names)
PrintExtensionMatches(matches, con)
}
+9 -34
View File
@@ -80,7 +80,6 @@ type ExtensionManifest_ struct {
type ExtensionManifest struct {
Name string `json:"name"`
PackageName string `json:"package_name"`
Version string `json:"version"`
ExtensionAuthor string `json:"extension_author"`
OriginalAuthor string `json:"original_author"`
@@ -126,13 +125,7 @@ func (e *ExtCommand) getFileForTarget(targetOS string, targetArch string) (strin
filePath := ""
for _, extFile := range e.Files {
if targetOS == extFile.OS && targetArch == extFile.Arch {
if e.Manifest.RootPath != "" {
// Use RootPath for temporarily loaded extensions
filePath = path.Join(e.Manifest.RootPath, extFile.Path)
} else {
// Fall back to extensions dir for installed extensions
filePath = path.Join(assets.GetExtensionsDir(), e.Manifest.Name, extFile.Path)
}
filePath = path.Join(assets.GetExtensionsDir(), e.Manifest.Name, extFile.Path)
break
}
}
@@ -147,19 +140,10 @@ func (e *ExtCommand) getFileForTarget(targetOS string, targetArch string) (strin
return filePath, nil
}
// ExtensionLoadCmd - Temporarily installs an extension from a local directory into the client.
// The extension must contain a valid manifest file. If commands from the extension
// already exist, the user will be prompted to overwrite them.
// ExtensionLoadCmd - Load extension command.
func ExtensionLoadCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
dirPath := args[0]
// Add directory check
fileInfo, err := os.Stat(dirPath)
if err != nil || !fileInfo.IsDir() {
con.PrintErrorf("Path is not a directory: %s\n", dirPath)
return
}
// dirPath := ctx.Args.String("dir-path")
manifest, err := LoadExtensionManifest(filepath.Join(dirPath, ManifestFileName))
if err != nil {
return
@@ -181,11 +165,7 @@ func ExtensionLoadCmd(cmd *cobra.Command, con *console.SliverClient, args []stri
}
}
// LoadExtensionManifest loads and parses an extension manifest file from the given path.
// It registers each command defined in the manifest into the loadedExtensions map
// and registers the complete manifest into loadedManifests. A single manifest may
// contain multiple extension commands. The manifest's RootPath is set to its containing
// directory. Returns the parsed manifest and any errors encountered.
// LoadExtensionManifest - Parse extension files.
func LoadExtensionManifest(manifestPath string) (*ExtensionManifest, error) {
data, err := os.ReadFile(manifestPath)
if err != nil {
@@ -299,13 +279,7 @@ func validManifest(manifest *ExtensionManifest) error {
return nil
}
// ExtensionRegisterCommand adds an extension command to the cobra command system.
// It validates the extension's arguments, updates the loadedExtensions map, and
// creates a cobra.Command with proper usage text, help documentation, and argument
// handling. The command is added as a subcommand to the provided parent cobra.Command.
// Arguments are displayed in the help text as uppercase, with optional args in square
// brackets. The help text includes sections for command usage, description, and detailed
// argument specifications.
// ExtensionRegisterCommand - Register a new extension command
func ExtensionRegisterCommand(extCmd *ExtCommand, cmd *cobra.Command, con *console.SliverClient) {
if errInvalidArgs := checkExtensionArgs(extCmd); errInvalidArgs != nil {
con.PrintErrorf(errInvalidArgs.Error())
@@ -313,6 +287,7 @@ func ExtensionRegisterCommand(extCmd *ExtCommand, cmd *cobra.Command, con *conso
}
loadedExtensions[extCmd.CommandName] = extCmd
//helpMsg := extCmd.Help
usage := strings.Builder{}
usage.WriteString(extCmd.CommandName)
@@ -364,9 +339,9 @@ func ExtensionRegisterCommand(extCmd *ExtCommand, cmd *cobra.Command, con *conso
// Command
extensionCmd := &cobra.Command{
Use: usage.String(),
Short: extCmd.Help,
Long: help.FormatHelpTmpl(longHelp.String()),
Use: usage.String(), //extCmd.CommandName,
//Short: helpMsg.String(), doesn't appear to be used?
Long: help.FormatHelpTmpl(longHelp.String()),
Run: func(cmd *cobra.Command, args []string) {
runExtensionCmd(cmd, con, args)
},
+3 -27
View File
@@ -23,7 +23,6 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/bishopfox/sliver/client/assets"
@@ -87,35 +86,12 @@ func RemoveExtensionByManifestName(manifestName string, con *console.SliverClien
return false, errors.New("command name is required")
}
if man, ok := loadedManifests[manifestName]; ok {
// Found the manifest
var extPath string
if man.RootPath != "" {
// Use RootPath for temporarily loaded extensions
extPath = man.RootPath
} else {
// Fall back to extensions dir for installed extensions
extPath = filepath.Join(assets.GetExtensionsDir(), filepath.Base(manifestName))
}
//foudn the manifest
//delet it
extPath := filepath.Join(assets.GetExtensionsDir(), filepath.Base(manifestName))
if _, err := os.Stat(extPath); os.IsNotExist(err) {
return true, nil
}
// If path is outside extensions directory, prompt for confirmation
if !strings.HasPrefix(extPath, assets.GetExtensionsDir()) {
confirm := false
prompt := &survey.Confirm{Message: fmt.Sprintf("Remove '%s' extension directory from filesystem?", manifestName)}
survey.AskOne(prompt, &confirm)
if !confirm {
// Skip the forceRemoveAll but continue with the rest
delete(loadedManifests, manifestName)
for _, cmd := range man.ExtCommand {
delete(loadedExtensions, cmd.CommandName)
}
return true, nil
}
}
forceRemoveAll(extPath)
delete(loadedManifests, manifestName)
for _, cmd := range man.ExtCommand {
-23
View File
@@ -19,7 +19,6 @@ package command
*/
import (
"fmt"
"os"
"github.com/bishopfox/sliver/client/command/alias"
@@ -32,7 +31,6 @@ import (
"github.com/bishopfox/sliver/client/command/crack"
"github.com/bishopfox/sliver/client/command/creds"
"github.com/bishopfox/sliver/client/command/exit"
"github.com/bishopfox/sliver/client/command/extensions"
"github.com/bishopfox/sliver/client/command/generate"
"github.com/bishopfox/sliver/client/command/hosts"
"github.com/bishopfox/sliver/client/command/info"
@@ -93,7 +91,6 @@ func ServerCommands(con *client.SliverClient, serverCmds func() []*cobra.Command
licenses.Commands,
settings.Commands,
alias.Commands,
extensions.Commands,
armory.Commands,
update.Commands,
operators.Commands,
@@ -134,26 +131,6 @@ func ServerCommands(con *client.SliverClient, serverCmds func() []*cobra.Command
// [ Post-command declaration setup ]-----------------------------------------
// Load Extensions
// Similar to the SliverCommand loading, without adding the commands to the
// Server command tree. This is done to ensure that the extensions are loaded
// before the server is started, so that the extensions are registered.
extensionManifests := extensions.GetAllExtensionManifests()
for _, manifest := range extensionManifests {
_, err := extensions.LoadExtensionManifest(manifest)
// Absorb error in case there's no extensions manifest
if err != nil {
//con doesn't appear to be initialised here?
//con.PrintErrorf("Failed to load extension: %s", err)
fmt.Printf("Failed to load extension: %s\n", err)
continue
}
//for _, ext := range mext.ExtCommand {
// extensions.ExtensionRegisterCommand(ext, sliver, con)
//}
}
// Everything below this line should preferably not be any command binding
// (although you can do so without fear). If there are any final modifications
// to make to the server menu command tree, it time to do them here.
+4 -3
View File
@@ -87,7 +87,6 @@ func SliverCommands(con *client.SliverClient) console.Commands {
screenshot.Commands,
environment.Commands,
registry.Commands,
extensions.SliverCommands,
)
// [ Filesystem ]
@@ -128,7 +127,9 @@ func SliverCommands(con *client.SliverClient) console.Commands {
bind(consts.AliasHelpGroup)
// [ Extensions ]
bind(consts.ExtensionHelpGroup)
bind(consts.ExtensionHelpGroup,
extensions.Commands,
)
// [ Post-command declaration setup ]----------------------------------------
@@ -143,7 +144,7 @@ func SliverCommands(con *client.SliverClient) console.Commands {
}
// Load Extensions
extensionManifests := extensions.GetAllExtensionManifests()
extensionManifests := assets.GetInstalledExtensionManifests()
for _, manifest := range extensionManifests {
mext, err := extensions.LoadExtensionManifest(manifest)
// Absorb error in case there's no extensions manifest
+2 -2
View File
@@ -20,8 +20,8 @@ set -e
# Creates the static go asset archives
GO_VER="1.22.5"
GARBLE_VER="1.22.5"
GO_VER="1.23.5"
GARBLE_VER="1.23.5"
ZIG_VER="0.13.0"
SGN_VER="0.0.3"
File diff suppressed because it is too large. Load diff
+1
View File
@@ -187,6 +187,7 @@ message ImplantConfig {
bool NetGoEnabled = 151;
bool TrafficEncodersEnabled = 152;
repeated string TrafficEncoders = 153;
string Extension = 154;
repeated commonpb.File Assets = 200;
}
+58 -149
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.25.3
// protoc-gen-go v1.36.3
// protoc v5.29.3
// source: commonpb/common.proto
package commonpb
@@ -21,18 +21,16 @@ const (
)
type Empty struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Empty) Reset() {
*x = Empty{}
if protoimpl.UnsafeEnabled {
mi := &file_commonpb_common_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
mi := &file_commonpb_common_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Empty) String() string {
@@ -43,7 +41,7 @@ func (*Empty) ProtoMessage() {}
func (x *Empty) ProtoReflect() protoreflect.Message {
mi := &file_commonpb_common_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -60,23 +58,20 @@ func (*Empty) Descriptor() ([]byte, []int) {
// Request - Common fields used in all gRPC requests
type Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Async bool `protobuf:"varint,1,opt,name=Async,proto3" json:"Async,omitempty"`
Timeout int64 `protobuf:"varint,2,opt,name=Timeout,proto3" json:"Timeout,omitempty"`
BeaconID string `protobuf:"bytes,8,opt,name=BeaconID,proto3" json:"BeaconID,omitempty"`
SessionID string `protobuf:"bytes,9,opt,name=SessionID,proto3" json:"SessionID,omitempty"`
unknownFields protoimpl.UnknownFields
Async bool `protobuf:"varint,1,opt,name=Async,proto3" json:"Async,omitempty"`
Timeout int64 `protobuf:"varint,2,opt,name=Timeout,proto3" json:"Timeout,omitempty"`
BeaconID string `protobuf:"bytes,8,opt,name=BeaconID,proto3" json:"BeaconID,omitempty"`
SessionID string `protobuf:"bytes,9,opt,name=SessionID,proto3" json:"SessionID,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *Request) Reset() {
*x = Request{}
if protoimpl.UnsafeEnabled {
mi := &file_commonpb_common_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
mi := &file_commonpb_common_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Request) String() string {
@@ -87,7 +82,7 @@ func (*Request) ProtoMessage() {}
func (x *Request) ProtoReflect() protoreflect.Message {
mi := &file_commonpb_common_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -135,23 +130,20 @@ func (x *Request) GetSessionID() string {
// only used when the implant needs to return an error to the server.
// Client<->Server comms should use normal gRPC error handling.
type Response struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Err string `protobuf:"bytes,1,opt,name=Err,proto3" json:"Err,omitempty"`
Async bool `protobuf:"varint,2,opt,name=Async,proto3" json:"Async,omitempty"`
BeaconID string `protobuf:"bytes,8,opt,name=BeaconID,proto3" json:"BeaconID,omitempty"`
TaskID string `protobuf:"bytes,9,opt,name=TaskID,proto3" json:"TaskID,omitempty"`
unknownFields protoimpl.UnknownFields
Err string `protobuf:"bytes,1,opt,name=Err,proto3" json:"Err,omitempty"`
Async bool `protobuf:"varint,2,opt,name=Async,proto3" json:"Async,omitempty"`
BeaconID string `protobuf:"bytes,8,opt,name=BeaconID,proto3" json:"BeaconID,omitempty"`
TaskID string `protobuf:"bytes,9,opt,name=TaskID,proto3" json:"TaskID,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *Response) Reset() {
*x = Response{}
if protoimpl.UnsafeEnabled {
mi := &file_commonpb_common_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
mi := &file_commonpb_common_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Response) String() string {
@@ -162,7 +154,7 @@ func (*Response) ProtoMessage() {}
func (x *Response) ProtoReflect() protoreflect.Message {
mi := &file_commonpb_common_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -207,21 +199,18 @@ func (x *Response) GetTaskID() string {
// File - A basic file data type
type File struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"`
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *File) Reset() {
*x = File{}
if protoimpl.UnsafeEnabled {
mi := &file_commonpb_common_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
mi := &file_commonpb_common_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *File) String() string {
@@ -232,7 +221,7 @@ func (*File) ProtoMessage() {}
func (x *File) ProtoReflect() protoreflect.Message {
mi := &file_commonpb_common_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -263,26 +252,23 @@ func (x *File) GetData() []byte {
// Process - A basic process data type
type Process struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Pid int32 `protobuf:"varint,1,opt,name=Pid,proto3" json:"Pid,omitempty"`
Ppid int32 `protobuf:"varint,2,opt,name=Ppid,proto3" json:"Ppid,omitempty"`
Executable string `protobuf:"bytes,3,opt,name=Executable,proto3" json:"Executable,omitempty"`
Owner string `protobuf:"bytes,4,opt,name=Owner,proto3" json:"Owner,omitempty"`
Architecture string `protobuf:"bytes,7,opt,name=Architecture,proto3" json:"Architecture,omitempty"`
SessionID int32 `protobuf:"varint,5,opt,name=SessionID,proto3" json:"SessionID,omitempty"`
CmdLine []string `protobuf:"bytes,6,rep,name=CmdLine,proto3" json:"CmdLine,omitempty"`
unknownFields protoimpl.UnknownFields
Pid int32 `protobuf:"varint,1,opt,name=Pid,proto3" json:"Pid,omitempty"`
Ppid int32 `protobuf:"varint,2,opt,name=Ppid,proto3" json:"Ppid,omitempty"`
Executable string `protobuf:"bytes,3,opt,name=Executable,proto3" json:"Executable,omitempty"`
Owner string `protobuf:"bytes,4,opt,name=Owner,proto3" json:"Owner,omitempty"`
Architecture string `protobuf:"bytes,7,opt,name=Architecture,proto3" json:"Architecture,omitempty"`
SessionID int32 `protobuf:"varint,5,opt,name=SessionID,proto3" json:"SessionID,omitempty"`
CmdLine []string `protobuf:"bytes,6,rep,name=CmdLine,proto3" json:"CmdLine,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *Process) Reset() {
*x = Process{}
if protoimpl.UnsafeEnabled {
mi := &file_commonpb_common_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
mi := &file_commonpb_common_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Process) String() string {
@@ -293,7 +279,7 @@ func (*Process) ProtoMessage() {}
func (x *Process) ProtoReflect() protoreflect.Message {
mi := &file_commonpb_common_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -359,21 +345,18 @@ func (x *Process) GetCmdLine() []string {
// EnvVar - Environment variable K/V
type EnvVar struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Key string `protobuf:"bytes,1,opt,name=Key,proto3" json:"Key,omitempty"`
Value string `protobuf:"bytes,2,opt,name=Value,proto3" json:"Value,omitempty"`
unknownFields protoimpl.UnknownFields
Key string `protobuf:"bytes,1,opt,name=Key,proto3" json:"Key,omitempty"`
Value string `protobuf:"bytes,2,opt,name=Value,proto3" json:"Value,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *EnvVar) Reset() {
*x = EnvVar{}
if protoimpl.UnsafeEnabled {
mi := &file_commonpb_common_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
mi := &file_commonpb_common_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *EnvVar) String() string {
@@ -384,7 +367,7 @@ func (*EnvVar) ProtoMessage() {}
func (x *EnvVar) ProtoReflect() protoreflect.Message {
mi := &file_commonpb_common_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -470,7 +453,7 @@ func file_commonpb_common_proto_rawDescGZIP() []byte {
}
var file_commonpb_common_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_commonpb_common_proto_goTypes = []interface{}{
var file_commonpb_common_proto_goTypes = []any{
(*Empty)(nil), // 0: commonpb.Empty
(*Request)(nil), // 1: commonpb.Request
(*Response)(nil), // 2: commonpb.Response
@@ -491,80 +474,6 @@ func file_commonpb_common_proto_init() {
if File_commonpb_common_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_commonpb_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Empty); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_commonpb_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_commonpb_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Response); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_commonpb_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*File); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_commonpb_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Process); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_commonpb_common_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EnvVar); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
+15 -32
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.25.3
// protoc-gen-go v1.36.3
// protoc v5.29.3
// source: dnspb/dns.proto
package dnspb
@@ -92,25 +92,22 @@ func (DNSMessageType) EnumDescriptor() ([]byte, []int) {
//
// [Type TOTP]: ID field is used for the TOTP code
type DNSMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Type DNSMessageType `protobuf:"varint,1,opt,name=Type,proto3,enum=dnspb.DNSMessageType" json:"Type,omitempty"`
ID uint32 `protobuf:"varint,2,opt,name=ID,proto3" json:"ID,omitempty"` // 8 bit message id + 24 bit dns session ID
Start uint32 `protobuf:"varint,3,opt,name=Start,proto3" json:"Start,omitempty"` // Bytes start at
Stop uint32 `protobuf:"varint,4,opt,name=Stop,proto3" json:"Stop,omitempty"` // Bytes stop at
Size uint32 `protobuf:"varint,5,opt,name=Size,proto3" json:"Size,omitempty"` // Total size
Data []byte `protobuf:"bytes,6,opt,name=Data,proto3" json:"Data,omitempty"` // Actual data
unknownFields protoimpl.UnknownFields
Type DNSMessageType `protobuf:"varint,1,opt,name=Type,proto3,enum=dnspb.DNSMessageType" json:"Type,omitempty"`
ID uint32 `protobuf:"varint,2,opt,name=ID,proto3" json:"ID,omitempty"` // 8 bit message id + 24 bit dns session ID
Start uint32 `protobuf:"varint,3,opt,name=Start,proto3" json:"Start,omitempty"` // Bytes start at
Stop uint32 `protobuf:"varint,4,opt,name=Stop,proto3" json:"Stop,omitempty"` // Bytes stop at
Size uint32 `protobuf:"varint,5,opt,name=Size,proto3" json:"Size,omitempty"` // Total size
Data []byte `protobuf:"bytes,6,opt,name=Data,proto3" json:"Data,omitempty"` // Actual data
sizeCache protoimpl.SizeCache
}
func (x *DNSMessage) Reset() {
*x = DNSMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_dnspb_dns_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
mi := &file_dnspb_dns_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DNSMessage) String() string {
@@ -121,7 +118,7 @@ func (*DNSMessage) ProtoMessage() {}
func (x *DNSMessage) ProtoReflect() protoreflect.Message {
mi := &file_dnspb_dns_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -221,7 +218,7 @@ func file_dnspb_dns_proto_rawDescGZIP() []byte {
var file_dnspb_dns_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_dnspb_dns_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_dnspb_dns_proto_goTypes = []interface{}{
var file_dnspb_dns_proto_goTypes = []any{
(DNSMessageType)(0), // 0: dnspb.DNSMessageType
(*DNSMessage)(nil), // 1: dnspb.DNSMessage
}
@@ -239,20 +236,6 @@ func file_dnspb_dns_proto_init() {
if File_dnspb_dns_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_dnspb_dns_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DNSMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
+3 -3
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.25.3
// protoc-gen-go v1.36.3
// protoc v5.29.3
// source: rpcpb/services.proto
package rpcpb
@@ -724,7 +724,7 @@ var file_rpcpb_services_proto_rawDesc = []byte{
0x70, 0x63, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_rpcpb_services_proto_goTypes = []interface{}{
var file_rpcpb_services_proto_goTypes = []any{
(*commonpb.Empty)(nil), // 0: commonpb.Empty
(*clientpb.ClientLogData)(nil), // 1: clientpb.ClientLogData
(*sliverpb.KillReq)(nil), // 2: sliverpb.KillReq
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+1 -4
View File
@@ -241,10 +241,7 @@ func (b *Builder) handleBuildEvent(event *clientpb.Event) {
return
}
fileName := filepath.Base(extConfig.Build.Name)
if extConfig.Config.GOOS == "windows" {
fileName += ".exe"
}
fileName := filepath.Base(extConfig.Build.Name) + extConfig.Config.Extension
builderLog.Infof("Uploading '%s' to server ...", extConfig.Build.Name)
_, err = b.rpc.GenerateExternalSaveBuild(context.Background(), &clientpb.ExternalImplantBinary{
+4 -2
View File
@@ -136,8 +136,7 @@ func ImplantBuildFromProtobuf(ib *clientpb.ImplantBuild) *ImplantBuild {
WGImplantPrivKey: ib.WGImplantPrivKey,
WGServerPubKey: ib.WGServerPubKey,
Stage: ib.Stage,
}
Stage: ib.Stage}
return &build
}
@@ -207,6 +206,7 @@ type ImplantConfig struct {
NetGoEnabled bool
TrafficEncodersEnabled bool
Assets []EncoderAsset
Extension string
}
// BeforeCreate - GORM hook
@@ -284,6 +284,7 @@ func (ic *ImplantConfig) ToProtobuf() *clientpb.ImplantConfig {
IncludeNamePipe: ic.IncludeNamePipe,
IncludeWG: ic.IncludeWG,
IncludeTCP: ic.IncludeTCP,
Extension: ic.Extension,
}
if ic.ImplantProfileID != nil {
@@ -505,6 +506,7 @@ func ImplantConfigFromProtobuf(pbConfig *clientpb.ImplantConfig) *ImplantConfig
Name: pbAsset.Name,
})
}
cfg.Extension = pbConfig.Extension
return &cfg
}
+16
View File
@@ -33,6 +33,22 @@ func SliverExternal(name string, config *clientpb.ImplantConfig) (*clientpb.Exte
config.IncludeNamePipe = models.IsC2Enabled([]string{"namedpipe"}, config.C2)
config.IncludeTCP = models.IsC2Enabled([]string{"tcppivot"}, config.C2)
// set file extension for external builds
if config.IsSharedLib {
switch config.GOOS {
case WINDOWS:
config.Extension = ".dll"
case DARWIN:
config.Extension = ".dylib"
case LINUX:
config.Extension = ".so"
}
} else {
if config.GOOS == WINDOWS {
config.Extension = ".exe"
}
}
build, err := GenerateConfig(name, config)
if err != nil {
return nil, err
+7 -1
View File
@@ -154,6 +154,11 @@ func (rpc *Server) Regenerate(ctx context.Context, req *clientpb.RegenerateReq)
return nil, status.Error(codes.InvalidArgument, "invalid implant name")
}
config, err := db.ImplantConfigByID(build.ImplantConfigID)
if err != nil {
return nil, err
}
fileData, err := generate.ImplantFileFromBuild(build)
if err != nil {
return nil, err
@@ -161,7 +166,7 @@ func (rpc *Server) Regenerate(ctx context.Context, req *clientpb.RegenerateReq)
return &clientpb.Generate{
File: &commonpb.File{
Name: build.Name,
Name: build.Name + config.Extension,
Data: fileData,
},
}, nil
@@ -384,6 +389,7 @@ func (rpc *Server) GenerateExternalSaveBuild(ctx context.Context, req *clientpb.
rcpGenLog.Errorf("Failed to write implant binary to temp file: %s", err)
return nil, status.Error(codes.Internal, "Failed to write implant binary to temp file")
}
rpcLog.Infof("Saving external build '%s' from %s", req.Name, tmpFile.Name())
err = generate.ImplantBuildSave(implantBuild, implantConfig, tmpFile.Name())
if err != nil {