diff --git a/Loader/Loader.go b/Loader/Loader.go index 33b2d6a..df3b751 100644 --- a/Loader/Loader.go +++ b/Loader/Loader.go @@ -65,7 +65,7 @@ type Beacon_SSL struct { var num_Profile int var Post bool -func GenerateOptions(stage, sleeptime, jitter, useragent, uri, customuri, beacon_PE, processinject_min_alloc, Post_EX_Process_Name, metadata, injector, ansible, Host, Profile, ProfilePath, outFile, custom_cert, cert_password, CDN, CDN_Value, datajitter, Keylogger string, Forwarder bool) { +func GenerateOptions(stage, sleeptime, jitter, useragent, uri, customuri, customuriGET, customuriPOST, beacon_PE, processinject_min_alloc, Post_EX_Process_Name, metadata, injector, ansible, Host, Profile, ProfilePath, outFile, custom_cert, cert_password, CDN, CDN_Value, datajitter, Keylogger string, Forwarder bool) { Beacon_Com := &Beacon_Com{} Beacon_Stage_p1 := &Beacon_Stage_p1{} Beacon_Stage_p2 := &Beacon_Stage_p2{} @@ -80,7 +80,7 @@ func GenerateOptions(stage, sleeptime, jitter, useragent, uri, customuri, beacon fmt.Println("[*] Preparing Varibles...") HostStageMessage, Beacon_Com.Variables = GenerateComunication(stage, sleeptime, jitter, useragent, datajitter) Beacon_PostEX.Variables = GeneratePostProcessName(Post_EX_Process_Name, Keylogger) - Beacon_GETPOST.Variables = GenerateHTTPVaribles(Host, metadata, uri, customuri, CDN, CDN_Value, Profile, Forwarder) + Beacon_GETPOST.Variables = GenerateHTTPVaribles(Host, metadata, uri, customuri, customuriGET, customuriPOST, CDN, CDN_Value, Profile, Forwarder) Beacon_Stage_p2.Variables = GeneratePE(beacon_PE) Process_Inject.Variables = GenerateProcessInject(processinject_min_alloc, injector) Beacon_GETPOST_Profile.Variables, Beacon_SSL.Variables = GenerateProfile(Profile, CDN, CDN_Value, cert_password, custom_cert, ProfilePath, Host) @@ -166,7 +166,7 @@ func GenerateComunication(stage, sleeptime, jitter, useragent, datajitter string num_agent, _ := strconv.Atoi(Utils.GenerateNumer(51, 65)) Beacon_Com.Variables["useragent"] = Struct.Useragent_list[num_agent] } else { - log.Fatal("Error: Please provide a Useragent option") + Beacon_Com.Variables["useragent"] = useragent } } if useragent == "" { @@ -199,7 +199,7 @@ func GeneratePostProcessName(Post_EX_Process_Name, Keylogger string) map[string] return Beacon_PostEX.Variables } -func GenerateHTTPVaribles(Host, metadata, uri, customuri, CDN, CDN_Value, Profile string, Forwarder bool) map[string]string { +func GenerateHTTPVaribles(Host, metadata, uri, customuri, customuriGET, customuriPOST, CDN, CDN_Value, Profile string, Forwarder bool) map[string]string { Beacon_GETPOST := &Beacon_GETPOST{} Beacon_GETPOST.Variables = make(map[string]string) Beacon_GETPOST.Variables["Host"] = Host @@ -221,11 +221,29 @@ func GenerateHTTPVaribles(Host, metadata, uri, customuri, CDN, CDN_Value, Profil } else { log.Fatal("Error: Please provide a valid metadata option") } + if customuri != "0" { + if customuriGET != "0" || customuriPOST != "0" { + log.Fatal("Error: Using customuri with either of customuriGET or customuriPOST is not supported") + } + } + if (customuriGET != "0" && customuriPOST == "0") || (customuriGET == "0" && customuriPOST != "0") { + log.Fatal("Error: When using CustomuriGET/CustomuriPOST, both must be sepecified") + } if uri == "" { Post = false uri := customuri + if customuriGET != "0" && customuriPOST != "0" { + uri = customuriGET + fmt.Println("[*] GET URI base: " + uri) + } + Beacon_GETPOST.Variables["HTTP_GET_URI"] = Utils.GenerateURIValues(1, num_Profile, Post, uri) Post = true + if customuriGET != "0" && customuriPOST != "0" { + uri = customuriPOST + fmt.Println("[*] POST URI base: " + uri) + } + Beacon_GETPOST.Variables["HTTP_POST_URI"] = Utils.GenerateURIValues(1, num_Profile, Post, uri) } @@ -233,8 +251,16 @@ func GenerateHTTPVaribles(Host, metadata, uri, customuri, CDN, CDN_Value, Profil num_uri, _ := strconv.Atoi(uri) Post = false uri := customuri + if customuriGET != "0" && customuriPOST != "0" { + uri = customuriGET + fmt.Println("[*] GET URI base: " + uri) + } Beacon_GETPOST.Variables["HTTP_GET_URI"] = Utils.GenerateURIValues(num_uri, num_Profile, Post, uri) Post = true + if customuriGET != "0" && customuriPOST != "0" { + uri = customuriPOST + fmt.Println("[*] POST URI base: " + uri) + } Beacon_GETPOST.Variables["HTTP_POST_URI"] = Utils.GenerateURIValues(num_uri, num_Profile, Post, uri) } if CDN != "" { @@ -323,6 +349,7 @@ func GenerateProfile(Profile, CDN, CDN_Value, cert_password, custom_cert, Profil CNAME := "\rhttps-certificate {\rset CN \"" + hostname + "\"; #Common Name" Beacon_SSL.Variables["Cert"] = CNAME + Struct.Cert[num_Profile-1] Beacon_GETPOST_Profile.Variables["Profile"] = Struct.HTTP_GET_POST_list[(num_Profile - 1)] + fmt.Println("[!] Self Signed SSL Cerificate Used") } else if num_Profile == 6 { if CDN == "" { log.Fatal("Error: Please provide a CDN value in order to use AzureEdge profiles") @@ -335,7 +362,6 @@ func GenerateProfile(Profile, CDN, CDN_Value, cert_password, custom_cert, Profil } Beacon_SSL.Variables["Cert"] = Struct.Cert[4] Beacon_GETPOST_Profile.Variables["Profile"] = Struct.HTTP_GET_POST_list[(num_Profile - 1)] - } else if num_Profile == 5 || num_Profile == 7 { if cert_password == "" { log.Fatal("Error: Please provide a Password value to use this profile") @@ -346,16 +372,23 @@ func GenerateProfile(Profile, CDN, CDN_Value, cert_password, custom_cert, Profil Beacon_SSL.Variables["Cert"] = Struct.Cert[4] Beacon_GETPOST_Profile.Variables["Profile"] = Struct.HTTP_GET_POST_list[(num_Profile - 1)] } else if num_Profile == 8 { - if cert_password == "" { + if cert_password == "" && custom_cert == "" { + CNAME := "\rhttps-certificate {\rset CN \"" + hostname + "\"; #Common Name" + Beacon_SSL.Variables["Cert"] = CNAME + Struct.Cert[0] + fmt.Println("[!] Self Signed SSL Cerificate Used") + } + if cert_password == "" && custom_cert != "" { log.Fatal("Error: Please provide a Password value to use this profile") } - if custom_cert == "" { + if custom_cert == "" && cert_password != "" { log.Fatal("Error: Please provide a Keystore value to use this profile") } - Beacon_SSL.Variables["Cert"] = Struct.Cert[4] + if cert_password != "" && custom_cert != "" { + Beacon_SSL.Variables["Cert"] = Struct.Cert[4] + } Beacon_GETPOST_Profile.Variables["Profile"] = Utils.Readfile(ProfilePath) } else { - log.Fatal("Error: Please provide a Profile number less the 7 option") + log.Fatal("Error: Please provide a Profile number of 8 or less") } } if custom_cert != "" && cert_password != "" { diff --git a/README.md b/README.md index dcb4c5a..7fc8128 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,11 @@ Usage of ./SourcePoint: -CDN-Value string CDN cookie value (typically used for AzureEdge profiles) -Customuri string - The base URI for custom HTTP GET/POST profile (default "0") + The base URI for custom HTTP GET/POST profile (default "0") - Cannot be used with CustomuriGET or CustomuriPOST + -CustomuriGET string + The base URI for custom HTTP GET profile (default "0") - Must be used with CustomuriPOST + -CustomuriPOST string + The base URI for custom HTTP POST profile (default "0") - Must be used with CustomuriGET -Datajitter string Appends a value to HTTP-Get and HTTP-Post server output (default "50") -Forwarder @@ -148,6 +152,7 @@ Usage of ./SourcePoint: [*] Win6.3 [*] Linux [*] Mac + [*] Custom - Whatever string you specify will be used as the user agent -Yaml string Path to the Yaml config file ``` @@ -209,23 +214,23 @@ This part of your profile controls how the beacon handles post-exploitation modu ### Profiles -Currently SourcePoint provides you with 6 baked in options for HTTP/HTTPS traffic profiles, based on existing profiles. Of these 6, 4 of them are influenced by and based on: +Currently SourcePoint provides you with 7 baked in options for HTTP/HTTPS traffic profiles, based on existing profiles. Of these 6, 4 of them are influenced by and based on: * Microsoft Window's Update Communication * Slack's Message Communication * Gotomeeting's Active Meeting Communication * Microsoft Outlook's Email Communication -2 of the profile options (5, 6 and 7) are designed specifically for: +3 of the profile options (5, 6 and 7) are designed specifically for: * Cloudfront.net * AzureEdge.net -The last option (7) is designed to input a custom profile. This option is designed to allow an operator to utilize a completely custom traffic profile. There are many cases where a completely unique traffic profile will yield high success rather than one of these. This also allows operators to still utilize SourcePoint's malleability features with their go-to or favorite traffic profile. As this allows for unique profiles it’s important to ensure you tweak and adjust the profile for SourcePoint to work. At a minimum: +The last option (8) is designed to input a custom profile. This option is designed to allow an operator to utilize a completely custom traffic profile. There are many cases where a completely unique traffic profile will yield high success rather than one of these. This also allows operators to still utilize SourcePoint's malleability features with their go-to or favorite traffic profile. As this allows for unique profiles it’s important to ensure you tweak and adjust the profile for SourcePoint to work. At a minimum: * Replace - `header "Host" "acme.com";` with `header "Host" "{{.Variables.Host}}";` * Replace - `/pathtolegitpage/` under the GET field with `{{.Variables.HTTP_GET_URI}}` * Replace - `/pathtolegitpage/` under the POST field with `{{.Variables.HTTP_POST_URI}}` -To do so, use the following options `-CustomURI` and `-ProfilePath` along with `-Profile 7`. While developing a profile, it’s highly recommended to use the native ./c2lint to verify everything is working. +To do so, use the following options `-Customuri` and `-ProfilePath` along with `-Profile 8`. To use a different URI base for GET and POST, `-CustomuriGET` and `-CustomuriPOST` should be used in place of `-Customuri`. While developing a profile, it’s highly recommended to use the native ./c2lint to verify everything is working. ## Sample Yaml Configs diff --git a/SourcePoint.go b/SourcePoint.go index 7ca4df9..6fac776 100644 --- a/SourcePoint.go +++ b/SourcePoint.go @@ -18,6 +18,8 @@ type FlagOptions struct { useragent string uri string customuri string + customuriGET string + customuriPOST string beacon_PE string processinject_min_alloc string Post_EX_Process_Name string @@ -56,6 +58,8 @@ type conf struct { Sleep string `yaml:"Sleep"` Uri string `yaml:"Uri"` Customuri string `yaml:"Customuri"` + CustomuriGET string `yaml:"CustomuriGET"` + CustomuriPOST string `yaml:"CustomuriPOST"` CDN string `yaml:"CDN"` CDN_Value string `yaml:"CDN_Value"` Useragent string `yaml:"Useragent"` @@ -91,7 +95,9 @@ func options() *FlagOptions { [*] Linux [*] Mac`) uri := flag.String("Uri", "", "The number URIs a profile for beacons to choose from") - customuri := flag.String("Customuri", "0", "The base URI for custom HTTP GET/POST profile") + customuri := flag.String("Customuri", "0", "The base URI for custom HTTP GET/POST profile - Cannot be used with CustomuriGET or CustomuriPOST") + customuriGET := flag.String("CustomuriGET", "0", "The base URI for custom HTTP GET profile - Must be used with CustomuriPOST") + customuriPOST := flag.String("CustomuriPOST", "0", "The base URI for custom HTTP POST profile - Must be used with CustomuriGET") beacon_PE := flag.String("PE_Clone", "", `PE file beacon will mimic (Use the number): [1] srv.dll [2] ActivationManager.dll @@ -174,7 +180,7 @@ func options() *FlagOptions { Forwarder := flag.Bool("Forwarder", false, "Enabled the X-forwarded-For header (Good for when your C2 is behind a redirector)") Yaml := flag.String("Yaml", "", "Path to the Yaml config file") flag.Parse() - return &FlagOptions{stage: *stage, sleeptime: *sleeptime, jitter: *jitter, useragent: *useragent, uri: *uri, customuri: *customuri, beacon_PE: *beacon_PE, processinject_min_alloc: *processinject_min_alloc, Post_EX_Process_Name: *Post_EX_Process_Name, metadata: *metadata, injector: *injector, Host: *Host, Profile: *Profile, ProfilePath: *ProfilePath, outFile: *outFile, custom_cert: *custom_cert, cert_password: *cert_password, CDN: *CDN, CDN_Value: *CDN_Value, Yaml: *Yaml, Datajitter: *Datajitter, Keylogger: *Keylogger, Forwarder: *Forwarder} + return &FlagOptions{stage: *stage, sleeptime: *sleeptime, jitter: *jitter, useragent: *useragent, uri: *uri, customuri: *customuri, customuriGET: *customuriGET, customuriPOST: *customuriPOST, beacon_PE: *beacon_PE, processinject_min_alloc: *processinject_min_alloc, Post_EX_Process_Name: *Post_EX_Process_Name, metadata: *metadata, injector: *injector, Host: *Host, Profile: *Profile, ProfilePath: *ProfilePath, outFile: *outFile, custom_cert: *custom_cert, cert_password: *cert_password, CDN: *CDN, CDN_Value: *CDN_Value, Yaml: *Yaml, Datajitter: *Datajitter, Keylogger: *Keylogger, Forwarder: *Forwarder} } @@ -209,6 +215,8 @@ func main() { opt.sleeptime = c.Sleep opt.uri = c.Uri opt.customuri = c.Customuri + opt.customuri = c.CustomuriGET + opt.customuri = c.CustomuriPOST opt.CDN = c.CDN opt.useragent = c.Useragent opt.ProfilePath = c.ProfilePath @@ -224,6 +232,6 @@ func main() { log.Fatal("Error: Please provide the hostname, IP or enable ansible mode") } - Loader.GenerateOptions(opt.stage, opt.sleeptime, opt.jitter, opt.useragent, opt.uri, opt.customuri, opt.beacon_PE, opt.processinject_min_alloc, opt.Post_EX_Process_Name, opt.metadata, opt.injector, opt.ansible, opt.Host, opt.Profile, opt.ProfilePath, opt.outFile, opt.custom_cert, opt.cert_password, opt.CDN, opt.CDN_Value, opt.Datajitter, opt.Keylogger, opt.Forwarder) + Loader.GenerateOptions(opt.stage, opt.sleeptime, opt.jitter, opt.useragent, opt.uri, opt.customuri, opt.customuriGET, opt.customuriPOST, opt.beacon_PE, opt.processinject_min_alloc, opt.Post_EX_Process_Name, opt.metadata, opt.injector, opt.ansible, opt.Host, opt.Profile, opt.ProfilePath, opt.outFile, opt.custom_cert, opt.cert_password, opt.CDN, opt.CDN_Value, opt.Datajitter, opt.Keylogger, opt.Forwarder) } diff --git a/Utils/Utils.go b/Utils/Utils.go index eb20daf..6e33522 100644 --- a/Utils/Utils.go +++ b/Utils/Utils.go @@ -123,7 +123,7 @@ func GenerateURIValues(numb int, profile_type int, Post bool, customuri string) } } if profile_type == 8 { - baseuri = "//" + baseuri = "" + customuri + "" } if profile_type == 9 { baseuri = "" + customuri + ""