Skip to content

Conversation

@terrorbyte
Copy link
Collaborator

@terrorbyte terrorbyte commented Oct 10, 2025

This adds support for adding explicit payload support to an exploit. This provides a few things:

  • Bring Your Own Payload (BYOP). Long awaited ability to support user provided payloads.
  • Payload type defined automatic flags
  • Ability to modify exploit flow for corner cases in specific implementation
  • Ability to change behavior for architecture
  • Exploit can define it's effects on the system and behavior that might allow flagging
  • Details output can now contain payload information and effect information

BYOP

Now when a payload adds support via config.AddPayload depending on the supported payloads. The file based (ELF, SO, .exe, .dll, webshell) types will add a -payload option that will automatically read a file from disk and add it to config.CustomPayload if the user uses the flag.

If the user uses one of the new payload.*Command types then -command flag will be available and config.CustomPayload will contain the value provided by that flag (or it can be accessed directly from the normal flag handling for the string type).

An example of how to define the code for this:

supportedPayload := []payload.Supported{
	{
		Types:   payload.GenericCommand,
		Arch:    payload.None,
		Effects: payload.NoEffects,
		Default: true,
	},
	{
		Types:   payload.LinuxELF,
		Arch:    payload.AMD64,
		Effects: payload.NoEffects,
	},
	{
		Types: payload.LinuxELF,
		Arch:  payload.ARM64,
		Effects: payload.Effects{
			payload.FileCreate: []string{"/var/www/html/pwnt", "/var/www/html/pwnt2"},
		},
	},
}
conf := config.NewRemoteExploit(
	config.ImplementedFeatures{AssetDetection: true, VersionScanning: false, Exploitation: true},
	config.CodeExecution, supportedC2,
	"", []string{""},
	[]string{""}, "CVE-2023-28324", "HTTP", 80)
conf.AddPayload(supportedPayload[:]...)

Now when the exploit is run the following options can be seen:

...
  -command string
    	Command to use for the exploit, an empty string will use the exploit default.
...
  -payload string
    	Path to load custom payload from, an empty string will use the exploit default.
  -payload-arch string
    	Payload architecture to use based on supported archs: none, amd64, arm64 (default "none")
  -payload-type string
    	Payload type to use based on supported types: GenericCommand, LinuxELF, LinuxELF (default "GenericCommand")
...

If a payload is defined with only one architecture -payload-arch will not show up and if only one payload type is defined -payload-type will also disappear. For example:

supportedPayload := []payload.Supported{
	{
		Types:   payload.GenericCommand,
		Arch:    payload.None,
		Effects: payload.Effects{
			payload.FileCreate: []string{"/var/www/html/pwnt", "/var/www/html/pwnt2"},
		},
	},
}
conf := config.NewRemoteExploit(
	config.ImplementedFeatures{AssetDetection: true, VersionScanning: false, Exploitation: true},
	config.CodeExecution, supportedC2,
	"", []string{""},
	[]string{""}, "CVE-2023-28324", "HTTP", 80)
conf.AddPayload(supportedPayload[:]...)

will yield the following flags with none of the others:

...
  -command string
    	Command to use for the exploit, an empty string will use the exploit default.
...

The developer can then handle the specific cases:

if conf.HasCustomPayload() {
	if conf.SelectedPayload.Type.IsCommand() {
		output.PrintfStatus("using '%s' in place of default", string(conf.CustomPayload))
	} else {
		output.PrintfStatus("using binary len %d in place of default", len(string(conf.CustomPayload)))
	}
}

Or if there is a complex case where more specificity is required:

switch conf.SelectedPayload.Types {
case payload.GenericCommand:
	output.PrintfStatus("adding GenericCommand")
	if conf.HasCustomPayload() {
                // Handle payload, ie any encoding or exploit specific bad chars
		output.PrintfStatus("using '%s' in place of default", string(conf.CustomPayload))
	}
        // Handle the normal default case
case payload.LinuxELF:
	output.PrintfStatus("adding LinuxELF")
	if conf.HasCustomPayload() {
                // Handle payload, ie any encoding or exploit specific bad chars
		output.PrintfStatus("using binary len %d in place of default", len(string(conf.CustomPayload)))
	}
        // Handle the normal default case
}

Payload and Exploit Effects

You can now define payload effects. The above example adds a list of payload effects if the default payload is used. An example of how this is now available in the details listing from the above example:

poptart:~/src/work/payload-test $ go run byop/byop.go -details
time=2025-10-10T10:38:43.694-06:00 level=SUCCESS msg="Implementation Details" ExploitType=CodeExecution AssetDetection=true VersionScanner=false Exploitation=true SupportedC2=[SimpleShellServer] SupportedPayloads="[GenericCommand (none): Effects -  LinuxELF (amd64): Effects -  LinuxELF (arm64): Effects - (FileCreate: /var/www/html/pwnt, /var/www/html/pwnt2)]" Vendor="" Products=[] CPE=[] CVE=CVE-2023-28324 Protocol=HTTP DefaultPort=80 CustomFlags="[{Name:command Type:string Default:} {Name:payload Type:string Default:} {Name:payload-type Type:string Default:GenericCommand} {Name:payload-arch Type:string Default:none}]"

This is part of #434

Undraft requirements:

  • - Add more docs and examples
  • - Separate out some of the logic to make it less complex in a single function
  • - Add tests
  • - Make the Effects string format better

@terrorbyte terrorbyte self-assigned this Oct 10, 2025
@terrorbyte terrorbyte added enhancement New feature or request proposal go Pull requests that update go code labels Oct 10, 2025
@terrorbyte terrorbyte force-pushed the feature/payload-types branch from ba81611 to c1c00eb Compare October 10, 2025 16:47
@terrorbyte terrorbyte force-pushed the feature/payload-types branch from 47a44c9 to 3f707e1 Compare October 30, 2025 21:47
@terrorbyte terrorbyte marked this pull request as ready for review October 30, 2025 21:55
@terrorbyte
Copy link
Collaborator Author

I'd like some comments on the effects strings formats as those feel very wrong. Something I considered was even turning them directly into JSON, which is nasty but a known format.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request go Pull requests that update go code proposal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants