Skip to content

Commit

Permalink
5.0 Download API (#290)
Browse files Browse the repository at this point in the history
  • Loading branch information
vinnybod authored Feb 20, 2022
1 parent 44c659e commit 1c5fa05
Show file tree
Hide file tree
Showing 31 changed files with 650 additions and 476 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ empire/client/generated-stagers

empire/server/v2/api/static/*
starkiller-dist.tar.gz

empire/test/downloads
44 changes: 24 additions & 20 deletions empire/server/common/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
from builtins import object, str
from datetime import datetime, timezone

from pydispatch import dispatcher
# from pydispatch import dispatcher
from sqlalchemy import and_, func, or_, update
from sqlalchemy.orm import Session, undefer
from zlib_wrapper import decompress
Expand Down Expand Up @@ -317,6 +317,8 @@ def save_file(
sessionID = nameid

lang = self.get_language_db(sessionID)

# todo this doesn't work for non-windows. All files are stored flat.
parts = path.split("\\")

# construct the appropriate save path
Expand Down Expand Up @@ -1156,7 +1158,7 @@ def handle_agent_staging(
sessionID
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
return "ERROR: Invalid PowerShell public key"

elif language.lower() == "python":
Expand All @@ -1165,7 +1167,7 @@ def handle_agent_staging(
sessionID
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
return "Error: Invalid Python key post format from %s" % (sessionID)
else:
try:
Expand All @@ -1175,7 +1177,7 @@ def handle_agent_staging(
sessionID
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
return "Error: Invalid Python key post format from {}".format(
sessionID
)
Expand All @@ -1192,7 +1194,7 @@ def handle_agent_staging(
sessionID, clientIP
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))

delay = listenerOptions["DefaultDelay"]["Value"]
jitter = listenerOptions["DefaultJitter"]["Value"]
Expand Down Expand Up @@ -1228,7 +1230,7 @@ def handle_agent_staging(
sessionID, clientIP, language
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
return "ERROR: invalid language: {}".format(language)

elif meta == "STAGE2":
Expand All @@ -1249,7 +1251,7 @@ def handle_agent_staging(
)
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
# remove the agent from the cache/database
self.mainMenu.agents.remove_agent_db(sessionID)
return (
Expand All @@ -1263,7 +1265,7 @@ def handle_agent_staging(
):
message = "[!] Invalid nonce returned from {}".format(sessionID)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
# remove the agent from the cache/database
self.mainMenu.agents.remove_agent_db(sessionID)
return "ERROR: Invalid nonce returned from %s" % (sessionID)
Expand All @@ -1272,7 +1274,7 @@ def handle_agent_staging(
sessionID, message
)
signal = json.dumps({"print": False, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))

listener = str(parts[1], "utf-8")
domainname = str(parts[2], "utf-8")
Expand All @@ -1299,7 +1301,7 @@ def handle_agent_staging(
)
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
# remove the agent from the cache/database
self.mainMenu.agents.remove_agent_db(sessionID)
return (
Expand Down Expand Up @@ -1348,7 +1350,7 @@ def handle_agent_staging(
sessionID, clientIP
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))

agent = self.mainMenu.agents.get_agent_for_socket(sessionID)
hooks.run_hooks(
Expand Down Expand Up @@ -1390,7 +1392,7 @@ def handle_agent_staging(
sessionID, clientIP, meta
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))

def handle_agent_data(
self,
Expand All @@ -1411,7 +1413,7 @@ def handle_agent_data(
len(routingPacket)
)
signal = json.dumps({"print": False, "message": message})
dispatcher.send(signal, sender="empire")
# dispatcher.send(signal, sender="empire")
return None

if isinstance(routingPacket, str):
Expand All @@ -1431,7 +1433,7 @@ def handle_agent_data(
)
)
signal = json.dumps({"print": False, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
dataToReturn.append(
(
language,
Expand All @@ -1453,7 +1455,7 @@ def handle_agent_data(
sessionID
)
signal = json.dumps({"print": False, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
dataToReturn.append(
("", "ERROR: sessionID %s not in cache!" % (sessionID))
)
Expand All @@ -1463,7 +1465,7 @@ def handle_agent_data(
sessionID
)
signal = json.dumps({"print": False, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
dataToReturn.append(
(
language,
Expand All @@ -1478,7 +1480,7 @@ def handle_agent_data(
)
)
signal = json.dumps({"print": False, "message": message})
dispatcher.send(signal, sender="agents/{}".format(sessionID))
# dispatcher.send(signal, sender="agents/{}".format(sessionID))
dataToReturn.append(
(
language,
Expand Down Expand Up @@ -1912,7 +1914,9 @@ def process_agent_packet(

# attach file to tasking
download = models.Download(
location=final_save_path, size=os.path.getsize(final_save_path)
location=final_save_path,
filename=final_save_path.split("/")[-1],
size=os.path.getsize(final_save_path),
)
db.add(download)
db.flush()
Expand All @@ -1930,7 +1934,7 @@ def process_agent_packet(
)
)
signal = json.dumps({"print": True, "message": message})
dispatcher.send(signal, sender="agents/{}".format(self.sessionID))
# dispatcher.send(signal, sender="agents/{}".format(self.sessionID))
return

with open(savePath, "a+") as f:
Expand Down Expand Up @@ -2061,7 +2065,7 @@ def process_agent_packet(
self.save_agent_log(session_id, data)
message = "[+] Updated comms for {} to {}".format(session_id, listener_name)
signal = json.dumps({"print": False, "message": message})
dispatcher.send(signal, sender="agents/{}".format(session_id))
# dispatcher.send(signal, sender="agents/{}".format(session_id))

elif response_name == "TASK_UPDATE_LISTENERNAME":
# The agent listener name variable has been updated agent side
Expand Down
5 changes: 3 additions & 2 deletions empire/server/common/empire.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@

from prompt_toolkit import HTML, PromptSession
from prompt_toolkit.patch_stdout import patch_stdout
from pydispatch import dispatcher

# from pydispatch import dispatcher
from sqlalchemy import and_, func, or_

from empire.server.common import hooks_internal
Expand Down Expand Up @@ -447,7 +448,7 @@ def preobfuscate_modules(self, obfuscation_command, reobfuscate=False):
"obfuscated_file": os.path.basename(file),
}
)
dispatcher.send(signal, sender="empire")
# dispatcher.send(signal, sender="empire")
else:
print(
helpers.color(
Expand Down
5 changes: 3 additions & 2 deletions empire/server/common/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

import json

from pydispatch import dispatcher

from empire.server.database import models
from empire.server.database.base import SessionLocal

# from pydispatch import dispatcher


# from empire.server.common import db # used in the disabled TODO below

################################################################################
Expand Down
19 changes: 13 additions & 6 deletions empire/server/common/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,13 @@
"""
from __future__ import division, print_function

import json

from future import standard_library

standard_library.install_aliases()
import base64
import binascii
import datetime
import fnmatch
import hashlib
import json
import numbers
import os
import random
import re
Expand All @@ -66,7 +63,6 @@

import iptools
import netifaces
from past.utils import old_div

###############################################################
#
Expand Down Expand Up @@ -658,6 +654,17 @@ def get_file_datetime():
return datetime.now().strftime("%Y-%m-%d_%H-%M-%S")


def old_div(a, b):
"""
Equivalent to ``a / b`` on Python 2 without ``from __future__ import
division``.
"""
if isinstance(a, numbers.Integral) and isinstance(b, numbers.Integral):
return a // b
else:
return a / b


def get_file_size(file):
"""
Returns a string with the file size and highest rating.
Expand Down
4 changes: 2 additions & 2 deletions empire/server/common/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
import threading
from http.server import BaseHTTPRequestHandler

from pydispatch import dispatcher

# Empire imports
from . import helpers

# from pydispatch import dispatcher


def default_page(path_to_html_file="empty"):
if path_to_html_file == "empty":
Expand Down
5 changes: 3 additions & 2 deletions empire/server/common/packets.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@
import struct
import sys

from pydispatch import dispatcher

# Empire imports
from . import encryption

# from pydispatch import dispatcher


# 0 -> error
# 1-99 -> standard functionality
# 100-199 -> dynamic functionality
Expand Down
3 changes: 0 additions & 3 deletions empire/server/common/pylnk.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@

from __future__ import print_function

from future import standard_library

standard_library.install_aliases()
import re
import time
from builtins import chr, object, range, str
Expand Down
2 changes: 1 addition & 1 deletion empire/server/common/stagers.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@

import donut
import macholib.MachO
from past.utils import old_div

from empire.server.database import models
from empire.server.database.base import SessionLocal

from . import helpers
from .helpers import old_div


class Stagers(object):
Expand Down
7 changes: 7 additions & 0 deletions empire/server/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@
Column("download_id", Integer, ForeignKey("downloads.id")),
)

# this doesn't actually join to anything atm, but is used for the filtering in api/v2/downloads
upload_download_assc = Table(
"upload_download_assc",
Base.metadata,
Column("download_id", Integer, ForeignKey("downloads.id")),
)


class User(Base):
__tablename__ = "users"
Expand Down
Loading

0 comments on commit 1c5fa05

Please sign in to comment.