example_client.py
Here is an example client that handles some more commands and includes a catch-all handler for unhandled commands.
It can be found in the file scripts/example_client.py
but is also listed here for convenience.
#!/usr/bin/env python3
#
# Example beacon client
#
# Run with:
# $ python3 example_client.py --help
#
# Recommended to do a dry run first to see how it will connect using which parameters:
# $ python3 example_client.py <beacon_file> -n
#
# Then run it for real in verbose mode:
# $ python3 example_client.py <beacon_file> -v
#
from io import BytesIO
import textwrap
from dissect.cobaltstrike.client import HttpBeaconClient, BeaconCallback, BeaconCommand, parse_commandline_options
from dissect.cobaltstrike.client import CallbackOutputMessage
from dissect.cobaltstrike.utils import p32be, u32be
client = HttpBeaconClient()
@client.handle(None)
def on_empty_task(task):
client.logger.debug("Received empty task.")
@client.catch_all()
def catch_all(task):
orly = "\n".join(
[
",___,",
"{O,o}",
"|)``)",
"O RLY?",
"",
]
)
return CallbackOutputMessage(textwrap.indent(orly, "\t"))
@client.handle(BeaconCommand.COMMAND_FILE_LIST)
def on_file_list(task):
# Parse task data for file listing
with BytesIO(task.data) as data:
req_no = u32be(data.read(4))
size = u32be(data.read(4))
folder = data.read(size).decode()
# Create file list response buffer
buffer = "\n".join(
[
folder,
"{type}\t{size}\t{date}\t{name}".format(type="D", size=0, date="04/10 2022 13:33:37", name="."),
"{type}\t{size}\t{date}\t{name}".format(type="D", size=0, date="04/10 2022 13:33:37", name=".."),
"{type}\t{size}\t{date}\t{name}".format(type="D", size=0, date="04/10 2022 13:33:37", name="srsly?"),
"{type}\t{size}\t{date}\t{name}".format(type="F", size=36, date="04/10 2022 13:33:37", name="flag.txt"),
]
)
# <request_number>|buffer|<zero termination>
buffer = p32be(req_no) + buffer.encode() + p32be(0)
return BeaconCallback.CALLBACK_PENDING, buffer
@client.handle(BeaconCommand.COMMAND_DOWNLOAD)
def on_download(task):
# from https://github.com/desaster/kippo
nowai = "\n".join(
[
" ___ ",
" {o,o}",
" (__(|",
' -"-"-',
"NO WAI!",
"",
]
)
fid = 100
size = len(nowai)
file_name = b"flag.txt"
client.send_callback(BeaconCallback.CALLBACK_FILE, p32be(fid) + p32be(size) + file_name + p32be(0))
client.send_callback(BeaconCallback.CALLBACK_FILE_WRITE, p32be(fid) + nowai.encode() + p32be(0))
client.send_callback(BeaconCallback.CALLBACK_FILE_CLOSE, p32be(fid) + p32be(0))
@client.handle(BeaconCommand.COMMAND_SLEEP)
def on_sleep(task):
with BytesIO(task.data) as data:
client.sleeptime = u32be(data.read(4))
client.jitter = u32be(data.read(4))
client.logger.info("Set new sleeptime: %u, jitter: %u", client.sleeptime, client.jitter)
@client.handle(BeaconCommand.COMMAND_PWD)
def on_pwd(task):
cwd = f"C:\\Users\\{client.user}\\Documents\\"
return BeaconCallback.CALLBACK_PWD, cwd.encode() + p32be(0)
if __name__ == "__main__":
args, options = parse_commandline_options(
defaults=dict(
user="O RLY?",
computer="YA RLY",
)
)
client.run(**options)