Skip to content

Commit

Permalink
Merge branch 'master' into fix_externalbuild_encoderids
Browse files Browse the repository at this point in the history
  • Loading branch information
rkervella authored May 22, 2024
2 parents 69bcf72 + 292f41c commit 550700d
Show file tree
Hide file tree
Showing 269 changed files with 15,852 additions and 8,641 deletions.
222 changes: 214 additions & 8 deletions client/command/c2profiles/c2profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@ package c2profiles
import (
"context"
"encoding/json"
"fmt"
"io"
"math/rand"
"net/url"
"os"
"path"
"path/filepath"
"strings"

"github.com/AlecAivazis/survey/v2"
Expand Down Expand Up @@ -154,7 +159,13 @@ func ExportC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []st
return
}

jsonProfile, err := C2ConfigToJSON(profileName, profile)
config, err := C2ConfigToJSON(profileName, profile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}

jsonProfile, err := json.Marshal(config)
if err != nil {
con.PrintErrorf("%s\n", err)
return
Expand All @@ -169,8 +180,96 @@ func ExportC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []st
con.Println(profileName, "C2 profile exported to ", filepath)
}

func GenerateC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {

// load template to use as starting point
template, err := cmd.Flags().GetString("template")
if err != nil {
con.PrintErrorf("%s\n", err)
return
}

profileName, _ := cmd.Flags().GetString("name")
if profileName == "" {
con.PrintErrorf("Invalid c2 profile name\n")
return
}

profile, err := con.Rpc.GetHTTPC2ProfileByName(context.Background(), &clientpb.C2ProfileReq{Name: template})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}

c2Profiles, err := con.Rpc.GetHTTPC2Profiles(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}

var extensions []string
for _, c2profile := range c2Profiles.Configs {
confProfile, err := con.Rpc.GetHTTPC2ProfileByName(context.Background(), &clientpb.C2ProfileReq{Name: c2profile.Name})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
extensions = append(extensions, confProfile.ImplantConfig.StagerFileExtension)
extensions = append(extensions, confProfile.ImplantConfig.StartSessionFileExtension)
}

config, err := C2ConfigToJSON(profileName, profile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}

// read urls files and replace segments
filepath, err := cmd.Flags().GetString("file")
if err != nil {
con.PrintErrorf("%s\n", err)
return
}

urlsFile, err := os.Open(filepath)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
fileContent, err := io.ReadAll(urlsFile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
urls := strings.Split(string(fileContent), "\n")

jsonProfile, err := updateC2Profile(extensions, config, urls)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}

// save or display config
importC2Profile, err := cmd.Flags().GetBool("import")
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
if importC2Profile {
httpC2ConfigReq := clientpb.HTTPC2ConfigReq{C2Config: C2ConfigToProtobuf(profileName, jsonProfile)}
_, err = con.Rpc.SaveHTTPC2Profile(context.Background(), &httpC2ConfigReq)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Println("C2 profile generated and saved as ", profileName)
} else {
PrintC2Profiles(profile, con)
}
}

// convert protobuf to json
func C2ConfigToJSON(profileName string, profile *clientpb.HTTPC2Config) ([]byte, error) {
func C2ConfigToJSON(profileName string, profile *clientpb.HTTPC2Config) (*assets.HTTPC2Config, error) {
implantConfig := assets.HTTPC2ImplantConfig{
UserAgent: profile.ImplantConfig.UserAgent,
ChromeBaseVersion: int(profile.ImplantConfig.ChromeBaseVersion),
Expand Down Expand Up @@ -278,12 +377,7 @@ func C2ConfigToJSON(profileName string, profile *clientpb.HTTPC2Config) ([]byte,
ServerConfig: serverConfig,
}

jsonConfig, err := json.Marshal(config)
if err != nil {
return nil, err
}

return jsonConfig, nil
return &config, nil
}

// convert json to protobuf
Expand Down Expand Up @@ -598,3 +692,115 @@ func selectC2Profile(c2profiles []*clientpb.HTTPC2Config) string {

return c2profile
}

func updateC2Profile(usedExtensions []string, template *assets.HTTPC2Config, urls []string) (*assets.HTTPC2Config, error) {
// update the template with the urls

var (
paths []string
filenames []string
extensions []string
filteredExtensions []string
)

for _, urlPath := range urls {
parsedURL, err := url.Parse(urlPath)
if err != nil {
fmt.Println("Error parsing URL:", err)
continue
}

dir, file := path.Split(parsedURL.Path)
dir = strings.Trim(dir, "/")
if dir != "" {
paths = append(paths, strings.Split(dir, "/")...)
}

if file != "" {
fileName := strings.TrimSuffix(file, filepath.Ext(file))
filenames = append(filenames, fileName)
ext := strings.TrimPrefix(filepath.Ext(file), ".")
if ext != "" {
extensions = append(extensions, ext)
}
}
}

slices.Sort(extensions)
extensions = slices.Compact(extensions)

for _, extension := range extensions {
if !slices.Contains(usedExtensions, extension) {
filteredExtensions = append(filteredExtensions, extension)
}
}

slices.Sort(paths)
paths = slices.Compact(paths)

slices.Sort(filenames)
filenames = slices.Compact(filenames)

// 5 is arbitrarily used as a minimum value, it only has to be 5 for the extensions, the others can be lower
if len(filteredExtensions) < 5 {
return nil, fmt.Errorf("got %d unused extensions, need at least 5", len(filteredExtensions))
}

if len(paths) < 5 {
return nil, fmt.Errorf("got %d paths need at least 5", len(paths))
}

if len(filenames) < 5 {
return nil, fmt.Errorf("got %d paths need at least 5", len(filenames))
}

// shuffle extensions
for i := len(extensions) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
extensions[i], extensions[j] = extensions[j], extensions[i]
}

template.ImplantConfig.PollFileExt = extensions[0]
template.ImplantConfig.StagerFileExt = extensions[1]
template.ImplantConfig.StartSessionFileExt = extensions[2]
template.ImplantConfig.SessionFileExt = extensions[3]
template.ImplantConfig.CloseFileExt = extensions[4]

// randomly distribute the paths and filenames into the different segment types
template.ImplantConfig.CloseFiles = []string{}
template.ImplantConfig.SessionFiles = []string{}
template.ImplantConfig.PollFiles = []string{}
template.ImplantConfig.StagerFiles = []string{}
template.ImplantConfig.ClosePaths = []string{}
template.ImplantConfig.SessionPaths = []string{}
template.ImplantConfig.PollPaths = []string{}
template.ImplantConfig.StagerPaths = []string{}

for _, path := range paths {
switch rand.Intn(4) {
case 0:
template.ImplantConfig.PollPaths = append(template.ImplantConfig.PollPaths, path)
case 1:
template.ImplantConfig.SessionPaths = append(template.ImplantConfig.SessionPaths, path)
case 2:
template.ImplantConfig.ClosePaths = append(template.ImplantConfig.ClosePaths, path)
case 3:
template.ImplantConfig.StagerPaths = append(template.ImplantConfig.StagerPaths, path)
}
}

for _, filename := range filenames {
switch rand.Intn(4) {
case 0:
template.ImplantConfig.PollFiles = append(template.ImplantConfig.PollFiles, filename)
case 1:
template.ImplantConfig.SessionFiles = append(template.ImplantConfig.SessionFiles, filename)
case 2:
template.ImplantConfig.CloseFiles = append(template.ImplantConfig.CloseFiles, filename)
case 3:
template.ImplantConfig.StagerFiles = append(template.ImplantConfig.StagerFiles, filename)
}
}

return template, nil
}
26 changes: 25 additions & 1 deletion client/command/c2profiles/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ func Commands(con *console.SliverClient) []*cobra.Command {
flags.Bind(consts.ExportC2ProfileStr, false, exportC2ProfileCmd, func(f *pflag.FlagSet) {
f.StringP("file", "f", "", "Path to file to export C2 configuration to")
f.StringP("name", "n", consts.DefaultC2Profile, "HTTP C2 Profile name")

})
flags.BindFlagCompletions(exportC2ProfileCmd, func(comp *carapace.ActionMap) {
(*comp)["name"] = generate.HTTPC2Completer(con)
})

C2ProfileCmd := &cobra.Command{
Expand All @@ -58,6 +60,28 @@ func Commands(con *console.SliverClient) []*cobra.Command {
flags.BindFlagCompletions(C2ProfileCmd, func(comp *carapace.ActionMap) {
(*comp)["name"] = generate.HTTPC2Completer(con)
})

generateC2ProfileCmd := &cobra.Command{
Use: consts.C2GenerateStr,
Short: "Generate a C2 Profile from a list of urls",
Long: help.GetHelpFor([]string{consts.C2ProfileStr + "." + consts.C2GenerateStr}),
Run: func(cmd *cobra.Command, args []string) {
GenerateC2ProfileCmd(cmd, con, args)
},
}

flags.Bind(consts.GenerateStr, false, generateC2ProfileCmd, func(f *pflag.FlagSet) {
f.StringP("file", "f", "", "Path to file containing URL list, /hello/there.txt one per line")
f.BoolP("import", "i", false, "Import the generated profile after creation")
f.StringP("name", "n", "", "HTTP C2 Profile name to save C2Profile as")
f.StringP("template", "t", consts.DefaultC2Profile, "HTTP C2 Profile to use as a template for the new profile")
})

flags.BindFlagCompletions(generateC2ProfileCmd, func(comp *carapace.ActionMap) {
(*comp)["template"] = generate.HTTPC2Completer(con)
})

C2ProfileCmd.AddCommand(generateC2ProfileCmd)
C2ProfileCmd.AddCommand(importC2ProfileCmd)
C2ProfileCmd.AddCommand(exportC2ProfileCmd)

Expand Down
5 changes: 5 additions & 0 deletions client/command/help/long-help.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ var (

// HTTP C2
consts.C2ProfileStr: c2ProfilesHelp,
consts.C2ProfileStr + sep + consts.C2GenerateStr: c2GenerateHelp,
}

jobsHelp = `[[.Bold]]Command:[[.Normal]] jobs <options>
Expand Down Expand Up @@ -1296,6 +1297,10 @@ Sliver uses the same hash identifiers as Hashcat (use the #):
C2ProfileImportStr = `[[.Bold]]Command:[[.Normal]] Import
[[.Bold]]About:[[.Normal]] Load custom HTTP C2 profiles.
`
c2GenerateHelp = `[[.Bold]]Command:[[.Normal]] C2 Profile generate
[[.Bold]]About:[[.Normal]] Generate C2 profile using a file containing urls.
Optionaly import profile or use another profile as a base template for the new profile.
`

grepHelp = `[[.Bold]]Command:[[.Normal]] grep [flags / options] <search pattern> <path>
[[.Bold]]About:[[.Normal]] Search a file or path for a search pattern
Expand Down
1 change: 1 addition & 0 deletions client/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ const (
TasksStr = "tasks"
CancelStr = "cancel"
GenerateStr = "generate"
C2GenerateStr = "generate"
RegenerateStr = "regenerate"
CompilerInfoStr = "info"
MsfStagerStr = "msf-stager"
Expand Down
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ require (
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
github.com/tetratelabs/wazero v1.7.1
github.com/tetratelabs/wazero v1.7.2
github.com/things-go/go-socks5 v0.0.5
github.com/ulikunitz/xz v0.5.12
github.com/xlab/treeprint v1.2.0
Expand All @@ -64,7 +64,7 @@ require (
gorm.io/gorm v1.25.10
gvisor.dev/gvisor v0.0.0-20240306221502-ee1e1f6070e3
modernc.org/sqlite v1.29.9
tailscale.com v1.64.2
tailscale.com v1.66.3
)

require (
Expand Down Expand Up @@ -95,8 +95,7 @@ require (
github.com/aws/smithy-go v1.19.0 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/coreos/go-iptables v0.7.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
github.com/demisto/goxforce v0.0.0-20160322194047-db8357535b1d // indirect
Expand All @@ -107,6 +106,7 @@ require (
github.com/gaissmai/bart v0.4.1 // indirect
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
Expand All @@ -116,7 +116,7 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/nftables v0.1.1-0.20230115205135-9aa6fdf5a28c // indirect
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect
github.com/gorilla/csrf v1.7.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
Expand Down Expand Up @@ -165,7 +165,7 @@ require (
github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 // indirect
github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 // indirect
github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 // indirect
github.com/tailscale/wireguard-go v0.0.0-20231121184858-cc193a0b3272 // indirect
github.com/tailscale/wireguard-go v0.0.0-20240429185444-03c5a0ccf754 // indirect
github.com/tcnksm/go-httpstat v0.2.0 // indirect
github.com/thedevsaddam/gojsonq/v2 v2.5.2 // indirect
github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e // indirect
Expand Down
Loading

0 comments on commit 550700d

Please sign in to comment.