Skip to content

Commit

Permalink
update no-consolation script
Browse files Browse the repository at this point in the history
  • Loading branch information
S4ntiagoP committed Apr 21, 2024
1 parent 29717e1 commit 660cbfa
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 25 deletions.
Binary file modified NoConsolation/bin/NoConsolation.x64.o
Binary file not shown.
Binary file modified NoConsolation/bin/NoConsolation.x86.o
Binary file not shown.
99 changes: 74 additions & 25 deletions NoConsolation/no-consolation.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@

import os
from havoc import Demon, RegisterCommand
from datetime import datetime

def is_windows_path(path):
return re.match(r'^[a-zA-Z]:\\', path) is not None

def is_linux_path(path):
return re.match(r'^/[a-zA-Z]', path) is not None

def is_pe_name(path):
return re.match(r'^[a-zA-Z].*\.exe', path) is not None

def noconsolation_parse_params( demon, params ):
packer = Packer()

Expand All @@ -20,6 +24,13 @@ def noconsolation_parse_params( demon, params ):
alloc_console = False
close_handles = False
free_libs = False
cmdline = None
cmdwline = None
pename = None
dont_save = False
list_pes = False
unload_pe = None
name_set = False
timeout = 60
path_set = False
path = ''
Expand Down Expand Up @@ -66,15 +77,29 @@ def noconsolation_parse_params( demon, params ):
close_handles = True
elif param == '--free-libraries' or param == '-fl':
free_libs = True
elif param == '--dont-save' or param == '-ds':
dont_save = True
elif param == '--list-pes' or param == '-lpe':
list_pes = True
elif param == '--unload-pe' or param == '-upe':
skip = True
if i + 1 >= num_params:
demon.ConsoleWrite( demon.CONSOLE_ERROR, "missing --unload-pe value" )
return None, None
unload_pe = params[i + 1]
elif os.path.exists( param ) or is_windows_path( param ):
path_set = True
path = param
break
elif local is False and os.path.exists( param ) is False and is_linux_path( param ):
demon.ConsoleWrite( demon.CONSOLE_INFO, f"Specified executable {path} does not exist" )
return None, None
elif local is False and is_pe_name( params[ i ] ):
pename = params[ i ]
name_set = True
break
elif param == '--help' or param == '-h':
demon.ConsoleWrite( demon.CONSOLE_INFO, "Usage: noconsolation [--local] [--timeout 60] [-k] [--method funcname] [-w] [--no-output] [--alloc-console] [--close-handles] [--free-libraries] /path/to/binary.exe arg1 arg2" )
demon.ConsoleWrite( demon.CONSOLE_INFO, "Usage: noconsolation [--local] [--timeout 60] [-k] [--method funcname] [-w] [--no-output] [--alloc-console] [--close-handles] [--free-libraries] [--dont-save] [--list-pes] [--unload-pe pename] /path/to/binary.exe arg1 arg2" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " --local, -l Optional. The binary should be loaded from the target Windows machine" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " --timeout NUM_SECONDS, -t NUM_SECONDS Optional. The number of seconds you wish to wait for the PE to complete running. Default 60 seconds. Set to 0 to disable" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " -k Optional. Overwrite the PE headers" )
Expand All @@ -84,7 +109,10 @@ def noconsolation_parse_params( demon, params ):
demon.ConsoleWrite( demon.CONSOLE_INFO, " --alloc-console, -ac Optional. Allocate a console. This will spawn a new process" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " --close-handles, -ch Optional. Close Pipe handles once finished. If PowerShell was already ran, this will break the output for PowerShell in the future" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " --free-libraries, -fl Optional. Free all loaded DLLs" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " /path/to/binary.exe Required. Full path to the windows EXE/DLL you wish you run inside Beacon" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " --dont-save, -ds Optional. Do not save this binary in memory" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " --list-pes, -lpe Optional. List all PEs that have been loaded in memory" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " --unload-pe PE_NAME, -upe PE_NAME Optional. Unload from memory a PE" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " /path/to/binary.exe Required. Full path to the windows EXE/DLL you wish you run inside Beacon. If already loaded, you can simply specify the binary name." )
demon.ConsoleWrite( demon.CONSOLE_INFO, " ARG1 ARG2 Optional. Parameters for the PE. Must be provided after the path" )
demon.ConsoleWrite( demon.CONSOLE_INFO, "" )
demon.ConsoleWrite( demon.CONSOLE_INFO, " Example: noconsolation --local C:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe $ExecutionContext.SessionState.LanguageMode" )
Expand All @@ -95,40 +123,56 @@ def noconsolation_parse_params( demon, params ):
demon.ConsoleWrite( demon.CONSOLE_INFO, f"invalid argument: {param}" )
return None, None

if path_set is False:
# allow users to close all handles without having to run a PE
if unload_pe is None and list_pes is False and name_set is False and path_set is False and close_handles is False:
demon.ConsoleWrite( demon.CONSOLE_INFO, "PE path not provided" )
return None, None

if os.path.exists(path) is False and local is False:
if path_set is True and os.path.exists(path) is False and local is False:
demon.ConsoleWrite( demon.CONSOLE_INFO, f"Specified executable {path} does not exist" )
return None, None

if local is False:
pename = path.split("/")[-1]
if path_set is True and list_pes is True:
demon.ConsoleWrite( demon.CONSOLE_INFO, "The option --list-pes must be ran alone" )
return None, None

try:
with open(path, 'rb') as f:
pebytes = f.read()
except:
demon.ConsoleWrite( demon.CONSOLE_INFO, f"could not read PE" )
return None, None
if unload_pe is not None and list_pes is True:
demon.ConsoleWrite( demon.CONSOLE_INFO, "The option --list-pes must be ran alone" )
return None, None

if len(pebytes) == 0:
demon.ConsoleWrite( demon.CONSOLE_INFO, f"The PE is empty" )
return None, None
if unload_pe is not None and path_set is True:
demon.ConsoleWrite( demon.CONSOLE_INFO, "The option --unload-pe must be ran alone" )
return None, None

if path_set:
if local is False:
pename = path.split("/")[-1]

path = ''
else:
pename = path.split("\\")[-1]
try:
with open(path, 'rb') as f:
pebytes = f.read()
except:
demon.ConsoleWrite( demon.CONSOLE_INFO, f"could not read PE" )
return None, None

if len(pebytes) == 0:
demon.ConsoleWrite( demon.CONSOLE_INFO, f"The PE is empty" )
return None, None

path = ''
else:
pename = path.split("\\")[-1]

# Iterate through args given
cmdline = pename
for y in range(i + 1, len(params)):
arg = params[ y ]
arg = arg.replace('\\"', '"')
if path_set or name_set:
# Iterate through args given
cmdline = pename
for y in range(i + 1, len(params)):
arg = params[ y ]
arg = arg.replace('\\"', '"')

cmdline = f'{cmdline} {arg}'
cmdline = f'{cmdline} {arg}'

packer.addstr(pename)
packer.addbytes(pebytes)
packer.addstr(path)
packer.addbool(local)
Expand All @@ -142,6 +186,11 @@ def noconsolation_parse_params( demon, params ):
packer.addbool(alloc_console)
packer.addbool(close_handles)
packer.addbool(free_libs)
packer.addbool(dont_save)
packer.addbool(list_pes)
packer.addstr(unload_pe)
packer.addstr("<unknown user>")
packer.addstr(datetime.now().strftime('%H:%M:%S %Y-%m-%d'))

return packer.getbuffer(), pename

Expand All @@ -165,4 +214,4 @@ def noconsolation( demonID, *params ):

return TaskID

RegisterCommand( noconsolation, "", "noconsolation", "Execute a PE inline", 0, "[--local] [--timeout 60] [-k] [--method funcname] [-w] [--no-output] [--alloc-console] [--close-handles] [--free-libraries] /path/to/binary.exe arg1 arg2", "--local C:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe $ExecutionContext.SessionState.LanguageMode" )
RegisterCommand( noconsolation, "", "noconsolation", "Execute a PE inline", 0, "[--local] [--timeout 60] [-k] [--method funcname] [-w] [--no-output] [--alloc-console] [--close-handles] [--free-libraries] [--dont-save] [--list-pes] [--unload-pe pename] /path/to/binary.exe arg1 arg2", "--local C:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe $ExecutionContext.SessionState.LanguageMode" )

0 comments on commit 660cbfa

Please sign in to comment.