Compare commits

...
Author SHA1 Message Date
Tim Makram Ghatas f0b078bcd1 add export command for c2 profiles 2024-04-02 22:28:47 +02:00
Ronan Kervella 9f4988e12a Merge pull request #1622 from BishopFox/bugfix_merge_issue
re-add deleted commands from bad merge for c2profiles and implant staging
2024-04-02 10:11:07 -07:00
3 changed files with 182 additions and 3 deletions

No files matched your search

+163
View File
@@ -123,6 +123,169 @@ func ImportC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []st
}
}
func ExportC2ProfileCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
filepath, _ := cmd.Flags().GetString("file")
if filepath == "" {
con.PrintErrorf("Missing file path\n")
return
}
profileName, _ := cmd.Flags().GetString("name")
if profileName == "" {
con.PrintErrorf("Invalid c2 profile name\n")
return
}
if profileName == constants.DefaultC2Profile {
httpC2Profiles, err := con.Rpc.GetHTTPC2Profiles(context.Background(), &commonpb.Empty{})
if err != nil {
con.PrintErrorf("failed to fetch HTTP C2 profiles: %s", err.Error())
return
}
if len(httpC2Profiles.Configs) != 1 {
profileName = selectC2Profile(httpC2Profiles.Configs)
}
}
profile, err := con.Rpc.GetHTTPC2ProfileByName(context.Background(), &clientpb.C2ProfileReq{Name: profileName})
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
jsonProfile, err := C2ConfigToJSON(profileName, profile)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
err = os.WriteFile(filepath, jsonProfile, 0644)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
con.Println(profileName, "C2 profile exported to ", filepath)
}
// convert protobuf to json
func C2ConfigToJSON(profileName string, profile *clientpb.HTTPC2Config) ([]byte, error) {
implantConfig := assets.HTTPC2ImplantConfig{
UserAgent: profile.ImplantConfig.UserAgent,
ChromeBaseVersion: int(profile.ImplantConfig.ChromeBaseVersion),
MacOSVersion: profile.ImplantConfig.MacOSVersion,
NonceQueryArgChars: profile.ImplantConfig.NonceQueryArgChars,
MaxFiles: int(profile.ImplantConfig.MaxFiles),
MinFiles: int(profile.ImplantConfig.MinFiles),
MaxPaths: int(profile.ImplantConfig.MaxPaths),
MinPaths: int(profile.ImplantConfig.MinFiles),
StagerFileExt: profile.ImplantConfig.StagerFileExtension,
PollFileExt: profile.ImplantConfig.PollFileExtension,
StartSessionFileExt: profile.ImplantConfig.StartSessionFileExtension,
SessionFileExt: profile.ImplantConfig.SessionFileExtension,
CloseFileExt: profile.ImplantConfig.CloseFileExtension,
}
var headers []assets.NameValueProbability
for _, header := range profile.ImplantConfig.Headers {
headers = append(headers, assets.NameValueProbability{
Name: header.Name,
Value: header.Value,
Probability: int(header.Probability),
})
}
implantConfig.Headers = headers
var urlParameters []assets.NameValueProbability
for _, urlParameter := range profile.ImplantConfig.ExtraURLParameters {
urlParameters = append(urlParameters, assets.NameValueProbability{
Name: urlParameter.Name,
Value: urlParameter.Value,
Probability: int(urlParameter.Probability),
})
}
implantConfig.URLParameters = urlParameters
var (
stagerFiles []string
pollFiles []string
sessionFiles []string
closeFiles []string
stagerPaths []string
pollPaths []string
sessionPaths []string
closePaths []string
)
for _, pathSegment := range profile.ImplantConfig.PathSegments {
if pathSegment.IsFile {
switch pathSegment.SegmentType {
case 0:
pollFiles = append(pollFiles, pathSegment.Value)
case 1:
sessionFiles = append(sessionFiles, pathSegment.Value)
case 2:
closeFiles = append(closeFiles, pathSegment.Value)
case 3:
stagerFiles = append(stagerFiles, pathSegment.Value)
}
} else {
switch pathSegment.SegmentType {
case 0:
pollPaths = append(pollPaths, pathSegment.Value)
case 1:
sessionPaths = append(sessionPaths, pathSegment.Value)
case 2:
closePaths = append(closePaths, pathSegment.Value)
case 3:
stagerPaths = append(stagerPaths, pathSegment.Value)
}
}
}
implantConfig.PollFiles = pollFiles
implantConfig.SessionFiles = sessionFiles
implantConfig.CloseFiles = closeFiles
implantConfig.StagerFiles = stagerFiles
implantConfig.PollPaths = pollPaths
implantConfig.SessionPaths = sessionPaths
implantConfig.ClosePaths = closePaths
implantConfig.StagerPaths = stagerPaths
var serverHeaders []assets.NameValueProbability
for _, header := range profile.ServerConfig.Headers {
serverHeaders = append(serverHeaders, assets.NameValueProbability{
Name: header.Name,
Value: header.Value,
Probability: int(header.Probability),
})
}
var serverCookies []string
for _, cookie := range profile.ServerConfig.Cookies {
serverCookies = append(serverCookies, cookie.Name)
}
serverConfig := assets.HTTPC2ServerConfig{
RandomVersionHeaders: profile.ServerConfig.RandomVersionHeaders,
Headers: serverHeaders,
Cookies: serverCookies,
}
config := assets.HTTPC2Config{
ImplantConfig: implantConfig,
ServerConfig: serverConfig,
}
jsonConfig, err := json.Marshal(config)
if err != nil {
return nil, err
}
return jsonConfig, nil
}
// convert json to protobuf
func C2ConfigToProtobuf(profileName string, config *assets.HTTPC2Config) *clientpb.HTTPC2Config {
+18 -3
View File
@@ -14,7 +14,7 @@ import (
// Commands returns the “ command and its subcommands.
func Commands(con *console.SliverClient) []*cobra.Command {
ImportC2ProfileCmd := &cobra.Command{
importC2ProfileCmd := &cobra.Command{
Use: consts.ImportC2ProfileStr,
Short: "Import HTTP C2 profile",
Long: help.GetHelpFor([]string{consts.ImportC2ProfileStr}),
@@ -22,12 +22,26 @@ func Commands(con *console.SliverClient) []*cobra.Command {
ImportC2ProfileCmd(cmd, con, args)
},
}
flags.Bind(consts.ImportC2ProfileStr, false, ImportC2ProfileCmd, func(f *pflag.FlagSet) {
flags.Bind(consts.ImportC2ProfileStr, false, importC2ProfileCmd, func(f *pflag.FlagSet) {
f.StringP("name", "n", consts.DefaultC2Profile, "HTTP C2 Profile name")
f.StringP("file", "f", "", "Path to C2 configuration file to import")
f.BoolP("overwrite", "o", false, "Overwrite profile if it exists")
})
exportC2ProfileCmd := &cobra.Command{
Use: consts.ExportC2ProfileStr,
Short: "Export HTTP C2 profile",
Long: help.GetHelpFor([]string{consts.ExportC2ProfileStr}),
Run: func(cmd *cobra.Command, args []string) {
ExportC2ProfileCmd(cmd, con, args)
},
}
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")
})
C2ProfileCmd := &cobra.Command{
Use: consts.C2ProfileStr,
Short: "Display C2 profile details",
@@ -44,7 +58,8 @@ func Commands(con *console.SliverClient) []*cobra.Command {
flags.BindFlagCompletions(C2ProfileCmd, func(comp *carapace.ActionMap) {
(*comp)["name"] = generate.HTTPC2Completer(con)
})
C2ProfileCmd.AddCommand(ImportC2ProfileCmd)
C2ProfileCmd.AddCommand(importC2ProfileCmd)
C2ProfileCmd.AddCommand(exportC2ProfileCmd)
return []*cobra.Command{
C2ProfileCmd,
+1
View File
@@ -145,6 +145,7 @@ const (
TrafficEncodersStr = "traffic-encoders"
C2ProfileStr = "c2profiles"
ImportC2ProfileStr = "import"
ExportC2ProfileStr = "export"
// Generic.