1
1
2
2
import os
3
3
from havoc import Demon , RegisterCommand
4
+ from datetime import datetime
4
5
5
6
def is_windows_path (path ):
6
7
return re .match (r'^[a-zA-Z]:\\' , path ) is not None
7
8
8
9
def is_linux_path (path ):
9
10
return re .match (r'^/[a-zA-Z]' , path ) is not None
10
11
12
+ def is_pe_name (path ):
13
+ return re .match (r'^[a-zA-Z].*\.exe' , path ) is not None
14
+
11
15
def noconsolation_parse_params ( demon , params ):
12
16
packer = Packer ()
13
17
@@ -20,6 +24,13 @@ def noconsolation_parse_params( demon, params ):
20
24
alloc_console = False
21
25
close_handles = False
22
26
free_libs = False
27
+ cmdline = None
28
+ cmdwline = None
29
+ pename = None
30
+ dont_save = False
31
+ list_pes = False
32
+ unload_pe = None
33
+ name_set = False
23
34
timeout = 60
24
35
path_set = False
25
36
path = ''
@@ -66,15 +77,29 @@ def noconsolation_parse_params( demon, params ):
66
77
close_handles = True
67
78
elif param == '--free-libraries' or param == '-fl' :
68
79
free_libs = True
80
+ elif param == '--dont-save' or param == '-ds' :
81
+ dont_save = True
82
+ elif param == '--list-pes' or param == '-lpe' :
83
+ list_pes = True
84
+ elif param == '--unload-pe' or param == '-upe' :
85
+ skip = True
86
+ if i + 1 >= num_params :
87
+ demon .ConsoleWrite ( demon .CONSOLE_ERROR , "missing --unload-pe value" )
88
+ return None , None
89
+ unload_pe = params [i + 1 ]
69
90
elif os .path .exists ( param ) or is_windows_path ( param ):
70
91
path_set = True
71
92
path = param
72
93
break
73
94
elif local is False and os .path .exists ( param ) is False and is_linux_path ( param ):
74
95
demon .ConsoleWrite ( demon .CONSOLE_INFO , f"Specified executable { path } does not exist" )
75
96
return None , None
97
+ elif local is False and is_pe_name ( params [ i ] ):
98
+ pename = params [ i ]
99
+ name_set = True
100
+ break
76
101
elif param == '--help' or param == '-h' :
77
- 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" )
102
+ 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" )
78
103
demon .ConsoleWrite ( demon .CONSOLE_INFO , " --local, -l Optional. The binary should be loaded from the target Windows machine" )
79
104
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" )
80
105
demon .ConsoleWrite ( demon .CONSOLE_INFO , " -k Optional. Overwrite the PE headers" )
@@ -84,7 +109,10 @@ def noconsolation_parse_params( demon, params ):
84
109
demon .ConsoleWrite ( demon .CONSOLE_INFO , " --alloc-console, -ac Optional. Allocate a console. This will spawn a new process" )
85
110
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" )
86
111
demon .ConsoleWrite ( demon .CONSOLE_INFO , " --free-libraries, -fl Optional. Free all loaded DLLs" )
87
- demon .ConsoleWrite ( demon .CONSOLE_INFO , " /path/to/binary.exe Required. Full path to the windows EXE/DLL you wish you run inside Beacon" )
112
+ demon .ConsoleWrite ( demon .CONSOLE_INFO , " --dont-save, -ds Optional. Do not save this binary in memory" )
113
+ demon .ConsoleWrite ( demon .CONSOLE_INFO , " --list-pes, -lpe Optional. List all PEs that have been loaded in memory" )
114
+ demon .ConsoleWrite ( demon .CONSOLE_INFO , " --unload-pe PE_NAME, -upe PE_NAME Optional. Unload from memory a PE" )
115
+ 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." )
88
116
demon .ConsoleWrite ( demon .CONSOLE_INFO , " ARG1 ARG2 Optional. Parameters for the PE. Must be provided after the path" )
89
117
demon .ConsoleWrite ( demon .CONSOLE_INFO , "" )
90
118
demon .ConsoleWrite ( demon .CONSOLE_INFO , " Example: noconsolation --local C:\\ windows\\ system32\\ windowspowershell\\ v1.0\\ powershell.exe $ExecutionContext.SessionState.LanguageMode" )
@@ -95,40 +123,56 @@ def noconsolation_parse_params( demon, params ):
95
123
demon .ConsoleWrite ( demon .CONSOLE_INFO , f"invalid argument: { param } " )
96
124
return None , None
97
125
98
- if path_set is False :
126
+ # allow users to close all handles without having to run a PE
127
+ 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 :
99
128
demon .ConsoleWrite ( demon .CONSOLE_INFO , "PE path not provided" )
100
129
return None , None
101
130
102
- if os .path .exists (path ) is False and local is False :
131
+ if path_set is True and os .path .exists (path ) is False and local is False :
103
132
demon .ConsoleWrite ( demon .CONSOLE_INFO , f"Specified executable { path } does not exist" )
104
133
return None , None
105
134
106
- if local is False :
107
- pename = path .split ("/" )[- 1 ]
135
+ if path_set is True and list_pes is True :
136
+ demon .ConsoleWrite ( demon .CONSOLE_INFO , "The option --list-pes must be ran alone" )
137
+ return None , None
108
138
109
- try :
110
- with open (path , 'rb' ) as f :
111
- pebytes = f .read ()
112
- except :
113
- demon .ConsoleWrite ( demon .CONSOLE_INFO , f"could not read PE" )
114
- return None , None
139
+ if unload_pe is not None and list_pes is True :
140
+ demon .ConsoleWrite ( demon .CONSOLE_INFO , "The option --list-pes must be ran alone" )
141
+ return None , None
115
142
116
- if len (pebytes ) == 0 :
117
- demon .ConsoleWrite ( demon .CONSOLE_INFO , f"The PE is empty" )
118
- return None , None
143
+ if unload_pe is not None and path_set is True :
144
+ demon .ConsoleWrite ( demon .CONSOLE_INFO , "The option --unload-pe must be ran alone" )
145
+ return None , None
146
+
147
+ if path_set :
148
+ if local is False :
149
+ pename = path .split ("/" )[- 1 ]
119
150
120
- path = ''
121
- else :
122
- pename = path .split ("\\ " )[- 1 ]
151
+ try :
152
+ with open (path , 'rb' ) as f :
153
+ pebytes = f .read ()
154
+ except :
155
+ demon .ConsoleWrite ( demon .CONSOLE_INFO , f"could not read PE" )
156
+ return None , None
157
+
158
+ if len (pebytes ) == 0 :
159
+ demon .ConsoleWrite ( demon .CONSOLE_INFO , f"The PE is empty" )
160
+ return None , None
161
+
162
+ path = ''
163
+ else :
164
+ pename = path .split ("\\ " )[- 1 ]
123
165
124
- # Iterate through args given
125
- cmdline = pename
126
- for y in range (i + 1 , len (params )):
127
- arg = params [ y ]
128
- arg = arg .replace ('\\ "' , '"' )
166
+ if path_set or name_set :
167
+ # Iterate through args given
168
+ cmdline = pename
169
+ for y in range (i + 1 , len (params )):
170
+ arg = params [ y ]
171
+ arg = arg .replace ('\\ "' , '"' )
129
172
130
- cmdline = f'{ cmdline } { arg } '
173
+ cmdline = f'{ cmdline } { arg } '
131
174
175
+ packer .addstr (pename )
132
176
packer .addbytes (pebytes )
133
177
packer .addstr (path )
134
178
packer .addbool (local )
@@ -142,6 +186,11 @@ def noconsolation_parse_params( demon, params ):
142
186
packer .addbool (alloc_console )
143
187
packer .addbool (close_handles )
144
188
packer .addbool (free_libs )
189
+ packer .addbool (dont_save )
190
+ packer .addbool (list_pes )
191
+ packer .addstr (unload_pe )
192
+ packer .addstr ("<unknown user>" )
193
+ packer .addstr (datetime .now ().strftime ('%H:%M:%S %Y-%m-%d' ))
145
194
146
195
return packer .getbuffer (), pename
147
196
@@ -165,4 +214,4 @@ def noconsolation( demonID, *params ):
165
214
166
215
return TaskID
167
216
168
- 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" )
217
+ 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 commit comments