Skip to content

Commit

Permalink
make donut install conditional so we can support arm machines. add wa… (
Browse files Browse the repository at this point in the history
BC-SECURITY#721)

* make donut install conditional so we can support arm machines. add warnings when donut is invoked but not installed

* post-merge fix
  • Loading branch information
vinnybod authored Nov 5, 2023
1 parent 4ba4bab commit b8151b4
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 13 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added automatic tasking for sysinfo for stageless agents (@Cx01N)
- Updated listeners to consistently use port 80 and 443 for HTTP traffic by default (@Cx01N)
- Remove unneeded condition statement from all listeners (@Vinnybod)
- Make the installation of donut conditional on architecture since it doesn't work on ARM (@Vinnybod)
- When donut is invoked but not installed, give a useful warning (@Vinnybod)

## [5.7.3] - 2023-10-17

Expand Down
26 changes: 21 additions & 5 deletions empire/server/common/stagers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@
import subprocess
import zipfile
from itertools import cycle
from typing import Optional, Tuple

try:
import donut
except ModuleNotFoundError:
donut = None

import donut
import macholib.MachO

from empire.server.core.db import models
Expand Down Expand Up @@ -179,7 +184,7 @@ def generate_powershell_exe(

def generate_powershell_shellcode(
self, posh_code, arch="both", dot_net_version="net40"
):
) -> Tuple[Optional[str], Optional[str]]:
"""
Generate powershell shellcode using donut python module
"""
Expand All @@ -191,8 +196,14 @@ def generate_powershell_shellcode(
arch_type = 3

directory = self.generate_powershell_exe(posh_code, dot_net_version)

if not donut:
err = "module donut-shellcode not installed. It is only supported on x86."
log.warning(err, exc_info=True)
return None, err

shellcode = donut.create(file=directory, arch=arch_type)
return shellcode
return shellcode, None

def generate_exe_oneliner(
self, language, obfuscate, obfuscation_command, encode, listener_name
Expand Down Expand Up @@ -270,7 +281,7 @@ def generate_python_exe(

def generate_python_shellcode(
self, posh_code, arch="both", dot_net_version="net40"
):
) -> Tuple[Optional[str], Optional[str]]:
"""
Generate ironpython shellcode using donut python module
"""
Expand All @@ -281,9 +292,14 @@ def generate_python_shellcode(
elif arch == "both":
arch_type = 3

if not donut:
err = "module donut-shellcode not installed. It is only supported on x86."
log.warning(err, exc_info=True)
return None, err

directory = self.generate_python_exe(posh_code, dot_net_version)
shellcode = donut.create(file=directory, arch=arch_type)
return shellcode
return shellcode, None

def generate_macho(self, launcherCode):
"""
Expand Down
16 changes: 14 additions & 2 deletions empire/server/modules/csharp/ProcessInjection.Covenant.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from typing import Dict

import donut
try:
import donut
except ModuleNotFoundError:
donut = None

import yaml

from empire.server.common import helpers
Expand Down Expand Up @@ -48,9 +52,11 @@ def generate(
return handle_error_message("[!] Invalid listener: " + listener_name)

if language.lower() == "powershell":
shellcode = main_menu.stagers.generate_powershell_shellcode(
shellcode, err = main_menu.stagers.generate_powershell_shellcode(
launcher, arch=arch, dot_net_version=dot_net_version
)
if err:
return handle_error_message(err)

elif language.lower() == "csharp":
if arch == "x86":
Expand All @@ -60,6 +66,12 @@ def generate(
elif arch == "both":
arch_type = 3
directory = f"{main_menu.installPath}/csharp/Covenant/Data/Tasks/CSharp/Compiled/{dot_net_version}/{launcher}.exe"

if not donut:
return handle_error_message(
"module donut-shellcode not installed. It is only supported on x86."
)

shellcode = donut.create(file=directory, arch=arch_type)

elif language.lower() == "ironpython":
Expand Down
5 changes: 4 additions & 1 deletion empire/server/modules/powershell/management/shinject.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ def generate(
return handle_error_message("[!] Error in launcher generation.")
else:
launcher_code = launcher.split(" ")[-1]
sc = main_menu.stagers.generate_powershell_shellcode(
sc, err = main_menu.stagers.generate_powershell_shellcode(
launcher_code, arch
)
if err:
return handle_error_message(err)

encoded_sc = helpers.encode_base64(sc)

script_end = '\nInvoke-Shellcode -ProcessID {} -Shellcode $([Convert]::FromBase64String("{}")) -Force'.format(
Expand Down
22 changes: 19 additions & 3 deletions empire/server/stagers/windows/shellcode.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import logging

import donut
try:
import donut
except ModuleNotFoundError:
donut = None

from empire.server.utils.module_util import handle_error_message

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -142,9 +147,12 @@ def generate(self):
return "[!] Error in launcher command generation."

if language.lower() == "powershell":
shellcode = self.mainMenu.stagers.generate_powershell_shellcode(
shellcode, err = self.mainMenu.stagers.generate_powershell_shellcode(
launcher, arch=arch, dot_net_version=dot_net_version
)
if err:
return handle_error_message(err)

return shellcode

elif language.lower() == "csharp":
Expand All @@ -155,14 +163,22 @@ def generate(self):
elif arch == "both":
arch_type = 3

if not donut:
return handle_error_message(
"module donut-shellcode not installed. It is only supported on x86."
)

directory = f"{self.mainMenu.installPath}/csharp/Covenant/Data/Tasks/CSharp/Compiled/{dot_net_version}/{launcher}.exe"
shellcode = donut.create(file=directory, arch=arch_type)
return shellcode

elif language.lower() == "python":
shellcode = self.mainMenu.stagers.generate_python_shellcode(
shellcode, err = self.mainMenu.stagers.generate_python_shellcode(
launcher, arch=arch, dot_net_version=dot_net_version
)
if err:
return handle_error_message(err)

return shellcode

else:
Expand Down
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pyvnc = {git = "https://github.com/BC-SECURITY/pyVNC.git"}
python-socketio = {extras = ["client"], version = "^5.10.0"}
Flask = "^2.3.3"
pysecretsocks = {git = "https://github.com/BC-SECURITY/PySecretSOCKS.git", rev = "da5be0e"}
donut-shellcode = "^1.0.2"
donut-shellcode = { version = "^1.0.2", markers = "platform_machine == 'x86_64' or platform_machine == 'amd64'" }
python-obfuscator = "^0.0.2"
pyinstaller = "^5.13.2"
md2pdf = {git = "https://github.com/bc-security/md2pdf", rev = "48d5a46"}
Expand Down

0 comments on commit b8151b4

Please sign in to comment.