Skip to content

Added Logic to Report Custom Exploit Flags #248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 7, 2024
Merged

Added Logic to Report Custom Exploit Flags #248

merged 1 commit into from
Oct 7, 2024

Conversation

j-baines
Copy link
Contributor

@j-baines j-baines commented Oct 4, 2024

Currently, one of our stated goals it to make interoperability with other software easy. One thing that breaks that is when an exploit defines command line parameters that aren't generally well known. What I don't mean is like "lhost", "rhost", "proxy", etc. Those are all well known and easily mapped out to specific exploit types.

I'm talking about this scenario. Consider our implementation for CVE-2024-45507:

func main() {
	httpServer := httpservefile.GetInstance()
	httpServer.CreateFlags()

	flag.StringVar(&httpServer.HTTPAddr, "httpAddr", "", "The address the HTTP server should bind to")
	flag.IntVar(&httpServer.HTTPPort, "httpPort", 8080, "The port the HTTP server should bind to")
	flag.StringVar(&globalHostname, "hostname", "localhost", "Hostname to use if not provided using rhost (default to rhost value or localhost)")

	supportedC2 := []c2.Impl{
		c2.SSLShellServer,
		c2.SimpleShellServer,
	}
	conf := config.NewRemoteExploit(
		config.ImplementedFeatures{AssetDetection: true, VersionScanning: true, Exploitation: true},
		config.CodeExecution, supportedC2, "Apache", []string{"OFBiz"},
		[]string{"cpe:2.3:a:apache:ofbiz"}, "CVE-2024-45507", "HTTP", 80)

	sploit := OFBizGroovyFetch{}
	exploit.RunProgram(sploit, conf)
}

Here we see the exploit define three flags. One of which is totally specific to the exploit (hostname) and two that are hooked into HTTPServeFile logic (we used httpservefile as the http server for this one... meta I actually like, but I digress).

From a "Let's use this programmatically to pwn the world" perspective, these are not great because (outside of the horrible --help menu) there is no way to discover them! So in this patch, I implement a way to bubble these three command line options into the --details view.

First, let me share our CVE-2024-45507 was redefined (the diff is sort of messy since I moved stuff, so this is likely easier):

func main() {
	supportedC2 := []c2.Impl{
		c2.SSLShellServer,
		c2.SimpleShellServer,
	}
	conf := config.NewRemoteExploit(
		config.ImplementedFeatures{AssetDetection: true, VersionScanning: true, Exploitation: true},
		config.CodeExecution, supportedC2, "Apache", []string{"OFBiz"},
		[]string{"cpe:2.3:a:apache:ofbiz"}, "CVE-2024-45507", "HTTP", 80)

	// This exploit requires an HTTP server so hijack the HTTPServeFile server
	httpServer := httpservefile.GetInstance()
	httpServer.CreateFlags()

	// Newer OFBiz requires the `host` field contain a hostname and not an IP address.
	// If the user provides a hostname using `rhost` we will use that, otherwise
	// we'll use this variable which is defaulted to `localhost` - the user can
	// alter it on the command line.
	conf.CreateStringFlag("hostname", "localhost", "Hostname to use if not provided using rhost (default to rhost value or localhost)")
	conf.CreateStringVarFlag(&httpServer.HTTPAddr, "httpAddr", "", "The address the HTTP server should bind to")
	conf.CreateIntVarFlag(&httpServer.HTTPPort, "httpPort", 8080, "The port the HTTP server should bind to")

	sploit := OFBizGroovyFetch{}
	exploit.RunProgram(sploit, conf)
}

Here you can see that instead of flag I'm using conf.Create*Flag. This actually eliminates the use of the globalHostname variable. Instead we using conf.GetStringFlag("hostname"):

 func (sploit OFBizGroovyFetch) CheckVersion(conf *config.Config) exploit.VersionCheckType {
-       hostname := globalHostname
+       hostname := conf.GetStringFlag("hostname")
        if net.ParseIP(conf.Rhost) == nil {
                hostname = conf.Rhost
        }
@@ -191,7 +184,7 @@ func hostXMLFile(filename string, cmd string) {
 
 func triggerExploit(conf *config.Config, decoratorURL string) bool {
        headers := map[string]string{
-               "Host": fmt.Sprintf("%s:%d", globalHostname, conf.Rport),
+               "Host": fmt.Sprintf("%s:%d", conf.GetStringFlag("hostname"), conf.Rport),
        }

Additionally, --details now knows all about these three variables and their types (see CustomFlags):

albinolobster@mournland:~/initial-access/feed/cve-2024-45507$ ./build/cve-2024-45507_linux-arm64 --details --log-json | jq
{
  "time": "2024-10-04T13:04:03.285376637-04:00",
  "level": "SUCCESS",
  "msg": "Implementation Details",
  "ExploitType": "CodeExecution",
  "AssetDetection": true,
  "VersionScanner": true,
  "Exploitation": true,
  "SupportedC2": [
    "SSLShellServer",
    "SimpleShellServer"
  ],
  "Vendor": "Apache",
  "Products": [
    "OFBiz"
  ],
  "CPE": [
    "cpe:2.3:a:apache:ofbiz"
  ],
  "CVE": "CVE-2024-45507",
  "Protocol": "HTTP",
  "DefaultPort": 80,
  "CustomFlags": [
    {
      "Name": "hostname",
      "Type": "string",
      "Default": "localhost"
    },
    {
      "Name": "httpAddr",
      "Type": "string",
      "Default": ""
    },
    {
      "Name": "httpPort",
      "Type": "int",
      "Default": "8080"
    }
  ]
}

The actual implementation in config.go is not actually all that different from how flag works. They go the extra mile to mask types (although at the end of the day, they still have to define get/set for every type anyways and require type-oriented function anyways), but otherwise no big surprises. The parameters are stored in maps in config.go for easy lookup... and that's about it.

@j-baines j-baines requested review from terrorbyte, wvu and j-shomo October 4, 2024 17:05
@j-baines j-baines linked an issue Oct 4, 2024 that may be closed by this pull request
@j-baines j-baines merged commit 80f1e79 into main Oct 7, 2024
3 checks passed
@j-baines j-baines deleted the param-details branch October 7, 2024 15:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Self-Documenting Params
1 participant