Skip to content

Commit

Permalink
Merge pull request #1459 from BishopFox/fix_external_build
Browse files Browse the repository at this point in the history
adapt external builds to support http c2 configuration and new build …
  • Loading branch information
moloch-- authored Nov 16, 2023
2 parents 3a0ce8b + d2b43eb commit 86507dc
Show file tree
Hide file tree
Showing 10 changed files with 2,358 additions and 2,321 deletions.
6 changes: 3 additions & 3 deletions client/command/generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

Expand All @@ -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
Expand Down
3,100 changes: 1,556 additions & 1,544 deletions protobuf/clientpb/client.pb.go

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion protobuf/clientpb/client.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
984 changes: 492 additions & 492 deletions protobuf/rpcpb/services.pb.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion protobuf/rpcpb/services.proto
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ 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);
Expand Down
376 changes: 188 additions & 188 deletions protobuf/rpcpb/services_grpc.pb.go

Large diffs are not rendered by default.

72 changes: 23 additions & 49 deletions server/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -113,24 +110,24 @@ 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
}
if extConfig == nil {
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
}
Expand All @@ -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
Expand All @@ -148,68 +145,45 @@ 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
}
if err != nil {
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
}
Expand All @@ -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,
Expand All @@ -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)
}
Expand Down
58 changes: 48 additions & 10 deletions server/db/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,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
}

Expand Down Expand Up @@ -187,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{}
Expand Down
22 changes: 21 additions & 1 deletion server/generate/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Loading

0 comments on commit 86507dc

Please sign in to comment.