mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-08 01:38:17 -10:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee2a72ff5f | ||
|
|
86507dc5c5 | ||
|
|
d2b43ebb9f | ||
|
|
3a0ce8b890 | ||
|
|
623579affb | ||
|
|
632eacf3fd | ||
|
|
6918743f03 | ||
|
|
5d333af798 | ||
|
|
68cddc1de2 | ||
|
|
8a04d8d882 | ||
|
|
1d9d5cf85a | ||
|
|
b0c3549b08 | ||
|
|
b044a4584b | ||
|
|
fb5bd84811 | ||
|
|
ae8444fc75 |
No files matched your search
@@ -22,7 +22,7 @@ jobs:
|
||||
git build-essential zlib1g zlib1g-dev wget zip unzip
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
go-version: "^1.21"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
go-version: "^1.21"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head of the pull request.
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
git build-essential zlib1g zlib1g-dev wget zip unzip
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
mingw-w64 binutils-mingw-w64 g++-mingw-w64 gcc-multilib
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
run: brew install mingw-w64
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
go-version: "^1.21"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Git Fetch Tags
|
||||
run: git fetch --prune --unshallow --tags -f
|
||||
|
||||
@@ -850,13 +850,13 @@ func externalBuild(name string, config *clientpb.ImplantConfig, save string, con
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
if parts[0] == externalImplantConfig.Config.ID {
|
||||
if parts[0] == externalImplantConfig.Build.ID {
|
||||
con.RemoveEventListener(listenerID)
|
||||
return nil, fmt.Errorf("external build failed: %s", parts[1])
|
||||
}
|
||||
|
||||
case consts.AcknowledgeBuildEvent:
|
||||
if string(event.Data) == externalImplantConfig.Config.ID {
|
||||
if string(event.Data) == externalImplantConfig.Build.ID {
|
||||
msgF = "External build acknowledged by builder (template: %s) ... %s"
|
||||
}
|
||||
|
||||
@@ -865,7 +865,7 @@ func externalBuild(name string, config *clientpb.ImplantConfig, save string, con
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
if parts[0] == externalImplantConfig.Config.ID {
|
||||
if parts[0] == externalImplantConfig.Build.ID {
|
||||
con.RemoveEventListener(listenerID)
|
||||
name = parts[1]
|
||||
waiting = false
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
)
|
||||
|
||||
// ImplantsStageCmd - Serve a previously generated build
|
||||
func ImplantsStageCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args []string) {
|
||||
builds, err := con.Rpc.ImplantBuilds(context.Background(), &commonpb.Empty{})
|
||||
if err != nil {
|
||||
con.PrintErrorf("Unable to load implant builds '%s'\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
options := []string{}
|
||||
for name, _ := range builds.Configs {
|
||||
options = append(options, name)
|
||||
}
|
||||
|
||||
prompt := &survey.MultiSelect{
|
||||
Message: "Select sessions and beacons to expose:",
|
||||
Options: options,
|
||||
}
|
||||
selected := []string{}
|
||||
survey.AskOne(prompt, &selected)
|
||||
|
||||
_, err = con.Rpc.StageImplantBuild(context.Background(), &clientpb.ImplantStageReq{Build: selected})
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to serve implant %s\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,7 @@ func PrintImplantBuilds(builds *clientpb.ImplantBuilds, filters ImplantBuildFilt
|
||||
"Debug",
|
||||
"C2 Config",
|
||||
"ID",
|
||||
"Stage",
|
||||
})
|
||||
tw.SortBy([]table.SortBy{
|
||||
{Name: "Name", Mode: table.Asc},
|
||||
@@ -126,6 +127,7 @@ func PrintImplantBuilds(builds *clientpb.ImplantBuilds, filters ImplantBuildFilt
|
||||
fmt.Sprintf("%v", config.Debug),
|
||||
fmt.Sprintf(config.HTTPC2ConfigName),
|
||||
fmt.Sprintf("%v", builds.ResourceIDs[sliverName].Value),
|
||||
fmt.Sprintf("%v", builds.Staged[sliverName]),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ func HTTPListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args
|
||||
pollTimeout, _ := cmd.Flags().GetString("long-poll-timeout")
|
||||
pollJitter, _ := cmd.Flags().GetString("long-poll-jitter")
|
||||
website, _ := cmd.Flags().GetString("website")
|
||||
staging, _ := cmd.Flags().GetBool("staging")
|
||||
|
||||
longPollTimeout, err := time.ParseDuration(pollTimeout)
|
||||
if err != nil {
|
||||
@@ -60,7 +59,6 @@ func HTTPListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args
|
||||
EnforceOTP: !disableOTP,
|
||||
LongPollTimeout: int64(longPollTimeout),
|
||||
LongPollJitter: int64(longPollJitter),
|
||||
Staging: staging,
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
|
||||
@@ -42,7 +42,6 @@ func HTTPSListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args
|
||||
website, _ := cmd.Flags().GetString("website")
|
||||
letsEncrypt, _ := cmd.Flags().GetBool("lets-encrypt")
|
||||
disableRandomize, _ := cmd.Flags().GetBool("disable-randomized-jarm")
|
||||
staging, _ := cmd.Flags().GetBool("staging")
|
||||
|
||||
longPollTimeout, err := time.ParseDuration(pollTimeout)
|
||||
if err != nil {
|
||||
@@ -76,7 +75,6 @@ func HTTPSListenerCmd(cmd *cobra.Command, con *console.SliverConsoleClient, args
|
||||
LongPollTimeout: int64(longPollTimeout),
|
||||
LongPollJitter: int64(longPollJitter),
|
||||
RandomizeJARM: !disableRandomize,
|
||||
Staging: staging,
|
||||
})
|
||||
con.Println()
|
||||
if err != nil {
|
||||
|
||||
@@ -1094,6 +1094,16 @@ func ServerCommands(con *client.SliverConsoleClient, serverCmds func() []*cobra.
|
||||
carapace.Gen(implantsRmCmd).PositionalCompletion(generate.ImplantBuildNameCompleter(con))
|
||||
implantBuildsCmd.AddCommand(implantsRmCmd)
|
||||
|
||||
implantStageCmd := &cobra.Command{
|
||||
Use: consts.StageStr,
|
||||
Short: "Serve a previously generated implant",
|
||||
Long: help.GetHelpFor([]string{consts.ImplantBuildsStr, consts.StageStr}),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
generate.ImplantsStageCmd(cmd, con, args)
|
||||
},
|
||||
}
|
||||
implantBuildsCmd.AddCommand(implantStageCmd)
|
||||
|
||||
canariesCmd := &cobra.Command{
|
||||
Use: consts.CanariesStr,
|
||||
Short: "List previously generated canaries",
|
||||
|
||||
@@ -240,6 +240,10 @@ func sessionStartup() {
|
||||
if connection != nil {
|
||||
err := sessionMainLoop(connection)
|
||||
if err != nil {
|
||||
if err == ErrTerminate {
|
||||
connection.Cleanup()
|
||||
return
|
||||
}
|
||||
connectionErrors++
|
||||
if transports.GetMaxConnectionErrors() < connectionErrors {
|
||||
return
|
||||
|
||||
+2133
-2039
File diff suppressed because it is too large.
Load diff
@@ -216,11 +216,12 @@ message TrafficEncoderTests {
|
||||
message ExternalImplantConfig {
|
||||
ImplantConfig Config = 1;
|
||||
ImplantBuild Build = 2;
|
||||
HTTPC2Config HTTPC2 = 3;
|
||||
}
|
||||
|
||||
message ExternalImplantBinary {
|
||||
string Name = 1;
|
||||
string ImplantConfigID = 2;
|
||||
string ImplantBuildID = 2;
|
||||
commonpb.File File = 3;
|
||||
}
|
||||
|
||||
@@ -228,6 +229,11 @@ message ExternalImplantBinary {
|
||||
message ImplantBuilds {
|
||||
map<string, ImplantConfig> Configs = 1;
|
||||
map<string, ResourceID> ResourceIDs = 2;
|
||||
map<string, bool> staged = 3;
|
||||
}
|
||||
|
||||
message ImplantStageReq {
|
||||
repeated string Build = 1;
|
||||
}
|
||||
|
||||
message ImplantBuild {
|
||||
@@ -254,6 +260,7 @@ message ImplantBuild {
|
||||
string MtlsCACert = 17;
|
||||
string MtlsCert = 18;
|
||||
string MtlsKey = 19;
|
||||
bool Stage = 20;
|
||||
}
|
||||
|
||||
message CompilerTarget {
|
||||
@@ -382,7 +389,6 @@ message HTTPListenerReq {
|
||||
int64 LongPollTimeout = 11;
|
||||
int64 LongPollJitter = 12;
|
||||
bool RandomizeJARM = 13; // Only valid with Secure = true
|
||||
bool Staging = 14;
|
||||
}
|
||||
|
||||
// Named Pipes Messages for pivoting
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v4.25.0
|
||||
// source: commonpb/common.proto
|
||||
|
||||
@@ -131,8 +131,9 @@ func (x *Request) GetSessionID() string {
|
||||
}
|
||||
|
||||
// Response - Common fields used in all gRPC responses. Note that the Err field
|
||||
// only used when the implant needs to return an error to the server.
|
||||
// Client<->Server comms should use normal gRPC error handling.
|
||||
//
|
||||
// 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v4.25.0
|
||||
// source: dnspb/dns.proto
|
||||
|
||||
@@ -87,12 +87,10 @@ func (DNSMessageType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_dnspb_dns_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
// NOTE: DNS is very space sensitive so certain fields are re-purposed
|
||||
// depending on the DNSMessageType as noted below:
|
||||
//
|
||||
//NOTE: DNS is very space sensitive so certain fields are re-purposed
|
||||
//depending on the DNSMessageType as noted below:
|
||||
//
|
||||
//[Type TOTP]: ID field is used for the TOTP code
|
||||
//
|
||||
// [Type TOTP]: ID field is used for the TOTP code
|
||||
type DNSMessage struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
||||
+1039
-1039
File diff suppressed because it is too large.
Load diff
@@ -57,8 +57,6 @@ service SliverRPC {
|
||||
// *** Stager Listener ***
|
||||
rpc StartTCPStagerListener(clientpb.StagerListenerReq)
|
||||
returns (clientpb.StagerListener);
|
||||
rpc StartHTTPStagerListener(clientpb.StagerListenerReq)
|
||||
returns (clientpb.StagerListener);
|
||||
|
||||
// *** Loot ***
|
||||
rpc LootAdd(clientpb.Loot) returns (clientpb.Loot);
|
||||
@@ -90,10 +88,12 @@ service SliverRPC {
|
||||
returns (clientpb.ExternalImplantConfig);
|
||||
rpc GenerateExternalSaveBuild(clientpb.ExternalImplantBinary)
|
||||
returns (commonpb.Empty);
|
||||
rpc GenerateExternalGetImplantConfig(clientpb.ImplantConfig)
|
||||
rpc GenerateExternalGetBuildConfig(clientpb.ImplantBuild)
|
||||
returns (clientpb.ExternalImplantConfig);
|
||||
rpc GenerateStage(clientpb.GenerateStageReq)
|
||||
returns (clientpb.Generate);
|
||||
rpc StageImplantBuild(clientpb.ImplantStageReq)
|
||||
returns (commonpb.Empty);
|
||||
|
||||
// *** HTTP C2 Profiles ***
|
||||
rpc GetHTTPC2Profiles(commonpb.Empty) returns (clientpb.HTTPC2Configs);
|
||||
|
||||
+568
-390
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v4.25.0
|
||||
// source: sliverpb/sliver.proto
|
||||
|
||||
@@ -173,7 +173,8 @@ func (PeerFailureType) EnumDescriptor() ([]byte, []int) {
|
||||
}
|
||||
|
||||
// Envelope - Used to encode implant<->server messages since we
|
||||
// cannot use gRPC due to the various transports used.
|
||||
//
|
||||
// cannot use gRPC due to the various transports used.
|
||||
type Envelope struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -746,7 +747,8 @@ func (x *CloseSession) GetRequest() *commonpb.Request {
|
||||
}
|
||||
|
||||
// Ping - Not ICMP, just sends a rount trip message to an implant to
|
||||
// see if it's still responding.
|
||||
//
|
||||
// see if it's still responding.
|
||||
type Ping struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -3439,7 +3441,8 @@ func (x *CurrentTokenOwner) GetResponse() *commonpb.Response {
|
||||
}
|
||||
|
||||
// InvokeGetSystemReq - Implant-side version of GetSystemReq, this message
|
||||
// contains the .Data based on the client's req.Config
|
||||
//
|
||||
// contains the .Data based on the client's req.Config
|
||||
type InvokeGetSystemReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
||||
+23
-49
@@ -31,12 +31,9 @@ import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/rpcpb"
|
||||
"github.com/bishopfox/sliver/server/codenames"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
"github.com/bishopfox/sliver/server/generate"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -113,16 +110,16 @@ func handleBuildEvent(externalBuilder *clientpb.Builder, event *clientpb.Event,
|
||||
return
|
||||
}
|
||||
|
||||
implantConfigID := parts[1]
|
||||
builderLog.Infof("Build event for implant config id: %s", implantConfigID)
|
||||
extConfig, err := rpc.GenerateExternalGetImplantConfig(context.Background(), &clientpb.ImplantConfig{
|
||||
ID: implantConfigID,
|
||||
implantBuildID := parts[1]
|
||||
builderLog.Infof("Build event for implant build id: %s", implantBuildID)
|
||||
extConfig, err := rpc.GenerateExternalGetBuildConfig(context.Background(), &clientpb.ImplantBuild{
|
||||
ID: implantBuildID,
|
||||
})
|
||||
if err != nil {
|
||||
builderLog.Errorf("Failed to get implant config: %s", err)
|
||||
builderLog.Errorf("Failed to get build config: %s", err)
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildFailedEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantConfigID, err.Error())),
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantBuildID, err.Error())),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -130,7 +127,7 @@ func handleBuildEvent(externalBuilder *clientpb.Builder, event *clientpb.Event,
|
||||
builderLog.Errorf("nil extConfig")
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildFailedEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantConfigID, "nil external config")),
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantBuildID, "nil external config")),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -139,7 +136,7 @@ func handleBuildEvent(externalBuilder *clientpb.Builder, event *clientpb.Event,
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildFailedEvent,
|
||||
Data: []byte(
|
||||
fmt.Sprintf("%s:%s", implantConfigID, fmt.Sprintf("unsupported target %s:%s/%s", extConfig.Config.Format, extConfig.Config.GOOS, extConfig.Config.GOARCH)),
|
||||
fmt.Sprintf("%s:%s", implantBuildID, fmt.Sprintf("unsupported target %s:%s/%s", extConfig.Config.Format, extConfig.Config.GOOS, extConfig.Config.GOARCH)),
|
||||
),
|
||||
})
|
||||
return
|
||||
@@ -148,60 +145,37 @@ func handleBuildEvent(externalBuilder *clientpb.Builder, event *clientpb.Event,
|
||||
builderLog.Warnf("Reject event, unsupported template '%s'", extConfig.Config.TemplateName)
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildFailedEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantConfigID, "Unsupported template")),
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantBuildID, "Unsupported template")),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
name, _ := codenames.GetCodename()
|
||||
err = util.AllowedName(name)
|
||||
if err != nil {
|
||||
builderLog.Errorf("Invalid implant name: %s", err)
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildFailedEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantConfigID, err.Error())),
|
||||
})
|
||||
return
|
||||
}
|
||||
extModel := models.ImplantConfigFromProtobuf(extConfig.Config)
|
||||
|
||||
// retrieve http c2 implant config
|
||||
httpC2Config, err := db.LoadHTTPC2ConfigByName(extConfig.Config.HTTPC2ConfigName)
|
||||
if err != nil {
|
||||
builderLog.Errorf("Unable to load HTTP C2 Configuration: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
builderLog.Infof("Building %s for %s/%s (format: %s)", name, extConfig.Config.GOOS, extConfig.Config.GOARCH, extConfig.Config.Format)
|
||||
builderLog.Infof("Building %s for %s/%s (format: %s)", extConfig.Build.Name, extConfig.Config.GOOS, extConfig.Config.GOARCH, extConfig.Config.Format)
|
||||
builderLog.Infof(" [c2] mtls:%t wg:%t http/s:%t dns:%t", extModel.IncludeMTLS, extModel.IncludeWG, extModel.IncludeHTTP, extModel.IncludeDNS)
|
||||
builderLog.Infof("[pivots] tcp:%t named-pipe:%t", extModel.IncludeTCP, extModel.IncludeNamePipe)
|
||||
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.AcknowledgeBuildEvent,
|
||||
Data: []byte(implantConfigID),
|
||||
Data: []byte(implantBuildID),
|
||||
})
|
||||
|
||||
build, err := generate.GenerateConfig(name, extConfig.Config)
|
||||
if err != nil {
|
||||
builderLog.Errorf("Failed to generate config: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
var fPath string
|
||||
switch extConfig.Config.Format {
|
||||
case clientpb.OutputFormat_SERVICE:
|
||||
fallthrough
|
||||
case clientpb.OutputFormat_EXECUTABLE:
|
||||
fPath, err = generate.SliverExecutable(name, build, extConfig.Config, httpC2Config.ImplantConfig)
|
||||
fPath, err = generate.SliverExecutable(extConfig.Build.Name, extConfig.Build, extConfig.Config, extConfig.HTTPC2.ImplantConfig)
|
||||
case clientpb.OutputFormat_SHARED_LIB:
|
||||
fPath, err = generate.SliverSharedLibrary(name, build, extConfig.Config, httpC2Config.ImplantConfig)
|
||||
fPath, err = generate.SliverSharedLibrary(extConfig.Build.Name, extConfig.Build, extConfig.Config, extConfig.HTTPC2.ImplantConfig)
|
||||
case clientpb.OutputFormat_SHELLCODE:
|
||||
fPath, err = generate.SliverShellcode(name, build, extConfig.Config, httpC2Config.ImplantConfig)
|
||||
fPath, err = generate.SliverShellcode(extConfig.Build.Name, extConfig.Build, extConfig.Config, extConfig.HTTPC2.ImplantConfig)
|
||||
default:
|
||||
builderLog.Errorf("invalid output format: %s", extConfig.Config.Format)
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildFailedEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantConfigID, err.Error())),
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantBuildID, err.Error())),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -209,7 +183,7 @@ func handleBuildEvent(externalBuilder *clientpb.Builder, event *clientpb.Event,
|
||||
builderLog.Errorf("Failed to generate sliver: %s", err)
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildFailedEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantConfigID, err.Error())),
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantBuildID, err.Error())),
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -220,20 +194,20 @@ func handleBuildEvent(externalBuilder *clientpb.Builder, event *clientpb.Event,
|
||||
builderLog.Errorf("Failed to read generated sliver: %s", err)
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildFailedEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantConfigID, err.Error())),
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantBuildID, err.Error())),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
fileName := filepath.Base(name)
|
||||
fileName := filepath.Base(extConfig.Build.Name)
|
||||
if extConfig.Config.GOOS == "windows" {
|
||||
fileName += ".exe"
|
||||
}
|
||||
|
||||
builderLog.Infof("Uploading '%s' to server ...", name)
|
||||
builderLog.Infof("Uploading '%s' to server ...", extConfig.Build.Name)
|
||||
_, err = rpc.GenerateExternalSaveBuild(context.Background(), &clientpb.ExternalImplantBinary{
|
||||
Name: name,
|
||||
ImplantConfigID: extConfig.Config.ID,
|
||||
Name: extConfig.Build.Name,
|
||||
ImplantBuildID: extConfig.Build.ID,
|
||||
File: &commonpb.File{
|
||||
Name: fileName,
|
||||
Data: data,
|
||||
@@ -243,13 +217,13 @@ func handleBuildEvent(externalBuilder *clientpb.Builder, event *clientpb.Event,
|
||||
builderLog.Errorf("Failed to save build: %s", err)
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildFailedEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantConfigID, err.Error())),
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantBuildID, err.Error())),
|
||||
})
|
||||
return
|
||||
}
|
||||
rpc.BuilderTrigger(context.Background(), &clientpb.Event{
|
||||
EventType: consts.ExternalBuildCompletedEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantConfigID, name)),
|
||||
Data: []byte(fmt.Sprintf("%s:%s", implantBuildID, extConfig.Build.Name)),
|
||||
})
|
||||
builderLog.Infof("All done, built and saved %s", fileName)
|
||||
}
|
||||
|
||||
+23
-32
@@ -122,7 +122,6 @@ type SliverHTTPC2 struct {
|
||||
HTTPServer *http.Server
|
||||
ServerConf *clientpb.HTTPListenerReq // Server config (user args)
|
||||
HTTPSessions *HTTPSessions
|
||||
SliverStage []byte // Sliver shellcode to serve during staging process
|
||||
Cleanup func()
|
||||
|
||||
c2Config []*clientpb.HTTPC2Config // C2 configs
|
||||
@@ -347,17 +346,15 @@ func (s *SliverHTTPC2) router() *mux.Router {
|
||||
s.ServerConf.LongPollJitter = int64(DefaultLongPollJitter)
|
||||
}
|
||||
|
||||
if s.ServerConf.Staging {
|
||||
// start stager handlers, extension are unique accross all profiles
|
||||
for _, c2Config := range c2Configs.Configs {
|
||||
// Can't force the user agent on the stager payload
|
||||
// Request from msf stager payload will look like:
|
||||
// GET /fonts/Inter-Medium.woff/B64_ENCODED_PAYLOAD_UUID
|
||||
router.HandleFunc(
|
||||
fmt.Sprintf("/{rpath:.*\\.%s[/]{0,1}.*$}", c2Config.ImplantConfig.StagerFileExtension),
|
||||
s.stagerHandler,
|
||||
).Methods(http.MethodGet)
|
||||
}
|
||||
// start stager handlers, extension are unique accross all profiles
|
||||
for _, c2Config := range c2Configs.Configs {
|
||||
// Can't force the user agent on the stager payload
|
||||
// Request from msf stager payload will look like:
|
||||
// GET /fonts/Inter-Medium.woff/B64_ENCODED_PAYLOAD_UUID
|
||||
router.HandleFunc(
|
||||
fmt.Sprintf("/{rpath:.*\\.%s[/]{0,1}.*$}", c2Config.ImplantConfig.StagerFileExtension),
|
||||
s.stagerHandler,
|
||||
).Methods(http.MethodGet)
|
||||
}
|
||||
|
||||
router.HandleFunc("/{rpath:.*}", s.mainHandler).Methods(http.MethodGet, http.MethodPost)
|
||||
@@ -760,13 +757,7 @@ func (s *SliverHTTPC2) closeHandler(resp http.ResponseWriter, req *http.Request)
|
||||
func (s *SliverHTTPC2) stagerHandler(resp http.ResponseWriter, req *http.Request) {
|
||||
nonce, _ := getNonceFromURL(req.URL)
|
||||
httpLog.Debug("Stager request")
|
||||
if len(s.SliverStage) != 0 {
|
||||
httpLog.Infof("Received staging request from %s", getRemoteAddr(req))
|
||||
s.noCacheHeader(resp)
|
||||
resp.Write(s.SliverStage)
|
||||
httpLog.Infof("Serving sliver shellcode (size %d) to %s", len(s.SliverStage), getRemoteAddr(req))
|
||||
resp.WriteHeader(http.StatusOK)
|
||||
} else if nonce != 0 {
|
||||
if nonce != 0 {
|
||||
resourceID, err := db.ResourceIDByValue(nonce)
|
||||
if err != nil {
|
||||
httpLog.Infof("No profile with id %#v", nonce)
|
||||
@@ -774,21 +765,21 @@ func (s *SliverHTTPC2) stagerHandler(resp http.ResponseWriter, req *http.Request
|
||||
return
|
||||
}
|
||||
build, _ := db.ImplantBuildByResourceID(resourceID.Value)
|
||||
payload, err := generate.ImplantFileFromBuild(build)
|
||||
if err != nil {
|
||||
httpLog.Infof("Unable to retrieve Implant build %s", build)
|
||||
s.defaultHandler(resp, req)
|
||||
return
|
||||
if build.Stage {
|
||||
payload, err := generate.ImplantFileFromBuild(build)
|
||||
if err != nil {
|
||||
httpLog.Infof("Unable to retrieve Implant build %s", build)
|
||||
s.defaultHandler(resp, req)
|
||||
return
|
||||
}
|
||||
httpLog.Infof("Received staging request from %s", getRemoteAddr(req))
|
||||
s.noCacheHeader(resp)
|
||||
resp.Write(payload)
|
||||
httpLog.Infof("Serving sliver shellcode (size %d) %s to %s", len(payload), resourceID.Name, getRemoteAddr(req))
|
||||
resp.WriteHeader(http.StatusOK)
|
||||
}
|
||||
httpLog.Infof("Received staging request from %s", getRemoteAddr(req))
|
||||
s.noCacheHeader(resp)
|
||||
resp.Write(payload)
|
||||
httpLog.Infof("Serving sliver shellcode (size %d) %s to %s", len(payload), resourceID.Name, getRemoteAddr(req))
|
||||
resp.WriteHeader(http.StatusOK)
|
||||
|
||||
} else {
|
||||
s.defaultHandler(resp, req)
|
||||
}
|
||||
s.defaultHandler(resp, req)
|
||||
}
|
||||
|
||||
func (s *SliverHTTPC2) getHTTPSession(req *http.Request) *HTTPSession {
|
||||
|
||||
@@ -263,64 +263,6 @@ func StartTCPStagerListenerJob(host string, port uint16, profileName string, she
|
||||
return job, nil
|
||||
}
|
||||
|
||||
// StartHTTPStagerListenerJob - Start an HTTP(S) stager payload listener
|
||||
func StartHTTPStagerListenerJob(req *clientpb.HTTPListenerReq, data []byte) (*core.Job, error) {
|
||||
server, err := StartHTTPListener(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name := constants.HttpStr
|
||||
if req.Secure {
|
||||
name = constants.HttpsStr
|
||||
}
|
||||
server.SliverStage = data
|
||||
job := &core.Job{
|
||||
ID: core.NextJobID(),
|
||||
Name: name,
|
||||
Description: fmt.Sprintf("Stager handler %s for domain %s", name, req.Domain),
|
||||
Protocol: constants.TCPListenerStr,
|
||||
Port: uint16(req.Port),
|
||||
JobCtrl: make(chan bool),
|
||||
}
|
||||
core.Jobs.Add(job)
|
||||
|
||||
cleanup := func(err error) {
|
||||
server.Cleanup()
|
||||
core.Jobs.Remove(job)
|
||||
core.EventBroker.Publish(core.Event{
|
||||
Job: job,
|
||||
EventType: consts.JobStoppedEvent,
|
||||
Err: err,
|
||||
})
|
||||
}
|
||||
once := &sync.Once{}
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
if server.ServerConf.Secure {
|
||||
if server.ServerConf.ACME {
|
||||
err = server.HTTPServer.ListenAndServeTLS("", "") // ACME manager pulls the certs under the hood
|
||||
} else {
|
||||
err = listenAndServeTLS(server.HTTPServer, req.Cert, req.Key)
|
||||
}
|
||||
} else {
|
||||
err = server.HTTPServer.ListenAndServe()
|
||||
}
|
||||
if err != nil {
|
||||
jobLog.Errorf("%s listener error %v", name, err)
|
||||
once.Do(func() { cleanup(err) })
|
||||
job.JobCtrl <- true // Cleanup other goroutine
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
<-job.JobCtrl
|
||||
once.Do(func() { cleanup(nil) })
|
||||
}()
|
||||
|
||||
return job, nil
|
||||
}
|
||||
|
||||
// Fuck'in Go - https://stackoverflow.com/questions/30815244/golang-https-server-passing-certfile-and-kyefile-in-terms-of-byte-array
|
||||
// basically the same as server.ListenAndServerTLS() but we can pass in byte slices instead of file paths
|
||||
func listenAndServeTLS(srv *http.Server, certPEMBlock, keyPEMBlock []byte) error {
|
||||
|
||||
+51
-10
@@ -115,6 +115,7 @@ func ImplantBuilds() (*clientpb.ImplantBuilds, error) {
|
||||
pbBuilds := &clientpb.ImplantBuilds{
|
||||
Configs: map[string]*clientpb.ImplantConfig{},
|
||||
ResourceIDs: map[string]*clientpb.ResourceID{},
|
||||
Staged: map[string]bool{},
|
||||
}
|
||||
for _, dbBuild := range builds {
|
||||
config, err := ImplantConfigByID(dbBuild.ImplantConfigID.String())
|
||||
@@ -128,6 +129,8 @@ func ImplantBuilds() (*clientpb.ImplantBuilds, error) {
|
||||
return nil, err
|
||||
}
|
||||
pbBuilds.ResourceIDs[dbBuild.Name] = resource
|
||||
|
||||
pbBuilds.Staged[dbBuild.Name] = dbBuild.Stage
|
||||
}
|
||||
|
||||
return pbBuilds, err
|
||||
@@ -135,25 +138,50 @@ func ImplantBuilds() (*clientpb.ImplantBuilds, error) {
|
||||
|
||||
// SaveImplantBuild
|
||||
func SaveImplantBuild(ib *clientpb.ImplantBuild) (*clientpb.ImplantBuild, error) {
|
||||
implantBuild := models.ImplantBuildFromProtobuf(ib)
|
||||
dbSession := Session()
|
||||
err := dbSession.Create(&implantBuild).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var implantBuild *models.ImplantBuild
|
||||
if ib.ID != "" {
|
||||
_, err := ImplantBuildByID(ib.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implantBuild = models.ImplantBuildFromProtobuf(ib)
|
||||
err = dbSession.Save(implantBuild).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
implantBuild = models.ImplantBuildFromProtobuf(ib)
|
||||
err := dbSession.Create(&implantBuild).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
return implantBuild.ToProtobuf(), nil
|
||||
}
|
||||
|
||||
// SaveImplantConfig
|
||||
func SaveImplantConfig(ic *clientpb.ImplantConfig) (*clientpb.ImplantConfig, error) {
|
||||
implantConfig := models.ImplantConfigFromProtobuf(ic)
|
||||
dbSession := Session()
|
||||
err := dbSession.Create(&implantConfig).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var implantConfig *models.ImplantConfig
|
||||
if ic.ID != "" {
|
||||
_, err := ImplantConfigByID(ic.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implantConfig = models.ImplantConfigFromProtobuf(ic)
|
||||
err = dbSession.Save(implantConfig).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
implantConfig = models.ImplantConfigFromProtobuf(ic)
|
||||
err := dbSession.Create(&implantConfig).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return implantConfig.ToProtobuf(), nil
|
||||
}
|
||||
|
||||
@@ -184,6 +212,19 @@ func ImplantBuildByResourceID(resourceID uint64) (*clientpb.ImplantBuild, error)
|
||||
return build.ToProtobuf(), nil
|
||||
}
|
||||
|
||||
// ImplantBuildByID - Fetch implant build from ID
|
||||
func ImplantBuildByID(id string) (*clientpb.ImplantBuild, error) {
|
||||
build := models.ImplantBuild{}
|
||||
uuid, _ := uuid.FromString(id)
|
||||
err := Session().Where(&models.ImplantBuild{
|
||||
ID: uuid,
|
||||
}).Find(&build).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return build.ToProtobuf(), nil
|
||||
}
|
||||
|
||||
// ImplantProfiles - Fetch a map of name<->profiles current in the database
|
||||
func ImplantProfiles() ([]*clientpb.ImplantProfile, error) {
|
||||
profiles := []*models.ImplantProfile{}
|
||||
|
||||
@@ -70,6 +70,8 @@ type ImplantBuild struct {
|
||||
// WireGuard
|
||||
WGImplantPrivKey string
|
||||
WGServerPubKey string
|
||||
|
||||
Stage bool
|
||||
}
|
||||
|
||||
// BeforeCreate - GORM hook
|
||||
@@ -104,6 +106,7 @@ func (ib *ImplantBuild) ToProtobuf() *clientpb.ImplantBuild {
|
||||
MtlsKey: ib.MtlsKey,
|
||||
WGImplantPrivKey: ib.WGImplantPrivKey,
|
||||
WGServerPubKey: ib.WGServerPubKey,
|
||||
Stage: ib.Stage,
|
||||
}
|
||||
return &build
|
||||
}
|
||||
@@ -133,6 +136,7 @@ func ImplantBuildFromProtobuf(ib *clientpb.ImplantBuild) *ImplantBuild {
|
||||
|
||||
WGImplantPrivKey: ib.WGImplantPrivKey,
|
||||
WGServerPubKey: ib.WGServerPubKey,
|
||||
Stage: ib.Stage,
|
||||
}
|
||||
return &build
|
||||
}
|
||||
|
||||
@@ -171,7 +171,6 @@ func (j *HTTPListener) ToProtobuf() *clientpb.HTTPListenerReq {
|
||||
LongPollTimeout: int64(j.LongPollTimeout),
|
||||
LongPollJitter: int64(j.LongPollJitter),
|
||||
RandomizeJARM: j.RandomizeJarm,
|
||||
Staging: j.Staging,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +234,6 @@ func ListenerJobFromProtobuf(pbListenerJob *clientpb.ListenerJob) *ListenerJob {
|
||||
LongPollTimeout: pbListenerJob.HTTPConf.LongPollTimeout,
|
||||
LongPollJitter: pbListenerJob.HTTPConf.LongPollJitter,
|
||||
RandomizeJarm: pbListenerJob.HTTPConf.RandomizeJARM,
|
||||
Staging: pbListenerJob.HTTPConf.Staging,
|
||||
}
|
||||
case constants.HttpsStr:
|
||||
cfg.HttpListener = HTTPListener{
|
||||
@@ -251,7 +249,6 @@ func ListenerJobFromProtobuf(pbListenerJob *clientpb.ListenerJob) *ListenerJob {
|
||||
LongPollTimeout: pbListenerJob.HTTPConf.LongPollTimeout,
|
||||
LongPollJitter: pbListenerJob.HTTPConf.LongPollJitter,
|
||||
RandomizeJarm: pbListenerJob.HTTPConf.RandomizeJARM,
|
||||
Staging: pbListenerJob.HTTPConf.Staging,
|
||||
}
|
||||
case constants.MtlsStr:
|
||||
cfg.MtlsListener = MtlsListener{
|
||||
|
||||
@@ -749,6 +749,8 @@ func GenerateConfig(name string, implantConfig *clientpb.ImplantConfig) (*client
|
||||
build.WGServerPubKey = serverPubKey
|
||||
}
|
||||
|
||||
build.Stage = false
|
||||
|
||||
return &build, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -20,16 +20,36 @@ package generate
|
||||
|
||||
import (
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
)
|
||||
|
||||
// SliverExternal - Generates the cryptographic keys for the implant but compiles no code
|
||||
func SliverExternal(name string, config *clientpb.ImplantConfig) (*clientpb.ExternalImplantConfig, error) {
|
||||
config.IncludeMTLS = models.IsC2Enabled([]string{"mtls"}, config.C2)
|
||||
config.IncludeWG = models.IsC2Enabled([]string{"wg"}, config.C2)
|
||||
config.IncludeHTTP = models.IsC2Enabled([]string{"http", "https"}, config.C2)
|
||||
config.IncludeDNS = models.IsC2Enabled([]string{"dns"}, config.C2)
|
||||
config.IncludeNamePipe = models.IsC2Enabled([]string{"namedpipe"}, config.C2)
|
||||
config.IncludeTCP = models.IsC2Enabled([]string{"tcppivot"}, config.C2)
|
||||
|
||||
build, err := GenerateConfig(name, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config, err = db.SaveImplantConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
build.ImplantConfigID = config.ID
|
||||
implantBuild, err := db.SaveImplantBuild(build)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &clientpb.ExternalImplantConfig{
|
||||
Config: config,
|
||||
Build: build,
|
||||
Build: implantBuild,
|
||||
}, nil
|
||||
}
|
||||
+40
-32
@@ -176,6 +176,22 @@ func (rpc *Server) ImplantBuilds(ctx context.Context, _ *commonpb.Empty) (*clien
|
||||
return builds, nil
|
||||
}
|
||||
|
||||
// StageImplantBuild - Serve a previously generated build
|
||||
func (rpc *Server) StageImplantBuild(ctx context.Context, req *clientpb.ImplantStageReq) (*commonpb.Empty, error) {
|
||||
err := db.Session().Model(&models.ImplantBuild{}).Where("Stage = ?", true).Update("Stage", false).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, name := range req.Build {
|
||||
err = db.Session().Model(&models.ImplantBuild{}).Where(&models.ImplantBuild{Name: name}).Update("Stage", true).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &commonpb.Empty{}, nil
|
||||
}
|
||||
|
||||
// Canaries - List existing canaries
|
||||
func (rpc *Server) Canaries(ctx context.Context, _ *commonpb.Empty) (*clientpb.Canaries, error) {
|
||||
dbCanaries, err := db.ListCanaries()
|
||||
@@ -339,7 +355,7 @@ func (rpc *Server) GenerateExternal(ctx context.Context, req *clientpb.ExternalG
|
||||
|
||||
core.EventBroker.Publish(core.Event{
|
||||
EventType: consts.ExternalBuildEvent,
|
||||
Data: []byte(fmt.Sprintf("%s:%s", req.BuilderName, config.ID)),
|
||||
Data: []byte(fmt.Sprintf("%s:%s", req.BuilderName, externalConfig.Build.ID)),
|
||||
})
|
||||
|
||||
return externalConfig, err
|
||||
@@ -347,22 +363,14 @@ func (rpc *Server) GenerateExternal(ctx context.Context, req *clientpb.ExternalG
|
||||
|
||||
// GenerateExternalSaveBuild - Allows an external builder to save the build to the server
|
||||
func (rpc *Server) GenerateExternalSaveBuild(ctx context.Context, req *clientpb.ExternalImplantBinary) (*commonpb.Empty, error) {
|
||||
implantConfig, err := db.ImplantConfigWithC2sByID(req.ImplantConfigID)
|
||||
implantBuild, err := db.ImplantBuildByID(req.ImplantBuildID)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid implant config id")
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid implant build id")
|
||||
}
|
||||
if implantConfig.TemplateName == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid payload name")
|
||||
}
|
||||
err = util.AllowedName(req.Name)
|
||||
|
||||
implantConfig, err := db.ImplantConfigWithC2sByID(implantBuild.ImplantConfigID)
|
||||
if err != nil {
|
||||
rpcLog.Errorf("Invalid build name: %s", err)
|
||||
return nil, ErrInvalidName
|
||||
}
|
||||
_, err = db.ImplantBuildByName(req.Name)
|
||||
if err == nil {
|
||||
rpcLog.Errorf("Build '%s' already exists!", req.Name)
|
||||
return nil, ErrBuildExists
|
||||
return nil, status.Error(codes.Internal, "invalid implant config id")
|
||||
}
|
||||
|
||||
tmpFile, err := os.CreateTemp(assets.GetRootAppDir(), "tmp-external-build-*")
|
||||
@@ -377,20 +385,7 @@ func (rpc *Server) GenerateExternalSaveBuild(ctx context.Context, req *clientpb.
|
||||
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())
|
||||
|
||||
implantConfig, err = generate.ImplantConfigSave(implantConfig)
|
||||
if err != nil {
|
||||
rpcLog.Errorf("Failed to save implant config: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
build, err := generate.GenerateConfig(req.Name, implantConfig)
|
||||
if err != nil {
|
||||
rpcLog.Errorf("Failed to generate implant config: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = generate.ImplantBuildSave(build, implantConfig, tmpFile.Name())
|
||||
err = generate.ImplantBuildSave(implantBuild, implantConfig, tmpFile.Name())
|
||||
if err != nil {
|
||||
rpcLog.Errorf("Failed to save external build: %s", err)
|
||||
return nil, err
|
||||
@@ -398,21 +393,34 @@ func (rpc *Server) GenerateExternalSaveBuild(ctx context.Context, req *clientpb.
|
||||
|
||||
core.EventBroker.Publish(core.Event{
|
||||
EventType: consts.BuildCompletedEvent,
|
||||
Data: []byte(req.Name),
|
||||
Data: []byte(implantBuild.Name),
|
||||
})
|
||||
|
||||
return &commonpb.Empty{}, nil
|
||||
}
|
||||
|
||||
// GenerateExternalGetImplantConfig - Get an implant config for external builder
|
||||
func (rpc *Server) GenerateExternalGetImplantConfig(ctx context.Context, req *clientpb.ImplantConfig) (*clientpb.ExternalImplantConfig, error) {
|
||||
implantConfig, err := db.ImplantConfigWithC2sByID(req.ID)
|
||||
func (rpc *Server) GenerateExternalGetBuildConfig(ctx context.Context, req *clientpb.ImplantBuild) (*clientpb.ExternalImplantConfig, error) {
|
||||
build, err := db.ImplantBuildByID(req.ID)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid implant config id")
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid implant build id")
|
||||
}
|
||||
|
||||
implantConfig, err := db.ImplantConfigWithC2sByID(build.ImplantConfigID)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "invalid implant config id")
|
||||
}
|
||||
|
||||
// retrieve http c2 implant config
|
||||
httpC2Config, err := db.LoadHTTPC2ConfigByName(implantConfig.HTTPC2ConfigName)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, fmt.Sprintf("Unable to load HTTP C2 Configuration: %s", err))
|
||||
}
|
||||
|
||||
return &clientpb.ExternalImplantConfig{
|
||||
Config: implantConfig,
|
||||
Build: build,
|
||||
HTTPC2: httpC2Config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
@@ -40,35 +39,6 @@ func (rpc *Server) StartTCPStagerListener(ctx context.Context, req *clientpb.Sta
|
||||
return &clientpb.StagerListener{JobID: uint32(job.ID)}, nil
|
||||
}
|
||||
|
||||
// StartHTTPStagerListener starts a HTTP(S) stager listener
|
||||
func (rpc *Server) StartHTTPStagerListener(ctx context.Context, req *clientpb.StagerListenerReq) (*clientpb.StagerListener, error) {
|
||||
host := req.GetHost()
|
||||
if !checkInterface(req.GetHost()) {
|
||||
host = "0.0.0.0"
|
||||
}
|
||||
|
||||
conf := &clientpb.HTTPListenerReq{
|
||||
Host: host,
|
||||
Port: req.Port,
|
||||
Domain: req.Host,
|
||||
Secure: false,
|
||||
}
|
||||
if req.GetProtocol() == clientpb.StageProtocol_HTTPS {
|
||||
conf.Secure = true
|
||||
conf.Key = req.Key
|
||||
conf.Cert = req.Cert
|
||||
conf.ACME = req.ACME
|
||||
}
|
||||
job, err := c2.StartHTTPStagerListenerJob(conf, req.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if job == nil {
|
||||
return nil, fmt.Errorf("job is nil")
|
||||
}
|
||||
return &clientpb.StagerListener{JobID: uint32(job.ID)}, err
|
||||
}
|
||||
|
||||
// checkInterface verifies if an IP address
|
||||
// is attached to an existing network interface
|
||||
func checkInterface(a string) bool {
|
||||
|
||||
Reference in new issue
Block a user