2015-08-14 14:18:52 +00:00
#!/usr/bin/env python2
#This must be one of the first imports or else we get threading error on completion
from gevent import monkey
monkey . patch_all ( )
from gevent . pool import Pool
2015-11-08 22:27:33 +00:00
from gevent import joinall , sleep
2015-08-16 13:53:08 +00:00
2015-11-03 10:22:58 +00:00
from core . logger import *
2016-01-17 05:33:11 +00:00
from core . greenlets import main_greenlet
2015-11-03 10:22:58 +00:00
from core . settings import init_args
2015-11-08 22:27:33 +00:00
from core . servers . mimikatz import http_server , https_server
2015-11-03 10:22:58 +00:00
from argparse import RawTextHelpFormatter
from netaddr import IPAddress , IPRange , IPNetwork , AddrFormatError
from logging import DEBUG
2015-08-14 14:18:52 +00:00
2015-11-03 10:22:58 +00:00
import re
import argparse
import sys
import os
2015-11-08 22:27:33 +00:00
2016-01-17 05:33:11 +00:00
VERSION = ' 2.3 '
CODENAME = ' \' Pink Bubbles \' '
2015-08-14 14:18:52 +00:00
2015-11-04 17:03:39 +00:00
if sys . platform == ' linux2 ' :
if os . geteuid ( ) is not 0 :
2016-01-17 05:33:11 +00:00
print_error ( ' I needz r00tz! ' )
sys . exit ( 1 )
2015-11-04 17:03:39 +00:00
2015-11-03 10:22:58 +00:00
parser = argparse . ArgumentParser ( description = """
2015-08-28 19:38:50 +00:00
______ . ______ ___ ______ __ ___ . ___ ___ . ___ . ______ _______ ___ ___ _______ ______
/ | | _ \ / \ / | | | / / | \/ | / \ | _ \ | ____ | \ \ / / | ____ | / |
| , - - - - ' | |_) | / ^ \ | ,---- ' | ' / | \ / | / ^ \ | |_) | | |__ \ V / | |__ | ,---- '
| | | / / / _ \ \ | | | < | | \/ | | / / _ \ \ | ___ / | __ | > < | __ | | |
| ` - - - - . | | \ \- - - - . / _____ \ | ` - - - - . | . \ | | | | / _____ \ | | | | ____ / . \ | | ____ | ` - - - - .
\______ | | _ | ` . _____ | / __ / \__ \ \______ | | __ | \__ \ | __ | | __ | / __ / \__ \ | _ | | _______ | / __ / \__ \ | _______ | \______ |
2015-11-10 08:57:04 +00:00
Swiss army knife for pentesting Windows / Active Directory environments | @byt3bl33d3r
2015-08-28 19:38:50 +00:00
2015-11-10 08:57:04 +00:00
Powered by Impacket https : / / github . com / CoreSecurity / impacket ( @agsolino )
2015-08-28 19:38:50 +00:00
2015-11-10 08:57:04 +00:00
Inspired by :
@ShawnDEvans ' s smbmap https://github.com/ShawnDEvans/smbmap
@gojhonny ' s CredCrack https://github.com/gojhonny/CredCrack
@pentestgeek ' s smbexec https://github.com/pentestgeek/smbexec
{ } : { }
2016-01-17 05:33:11 +00:00
{ } : { }
2015-11-08 22:27:33 +00:00
""" .format(red( ' Version ' ),
yellow ( VERSION ) ,
2016-01-07 06:28:31 +00:00
red ( ' Codename ' ) ,
2015-11-08 22:27:33 +00:00
yellow ( CODENAME ) ) ,
2015-11-03 10:22:58 +00:00
formatter_class = RawTextHelpFormatter ,
2016-01-14 02:21:04 +00:00
version = ' {} - {} ' . format ( VERSION , CODENAME ) ,
2015-11-03 10:22:58 +00:00
epilog = ' There \' s been an awakening... have you felt it? ' )
2016-01-17 05:33:11 +00:00
parser . add_argument ( " target " , nargs = ' * ' , type = str , help = " The target IP, range, CIDR identifier, hostname, FQDN or list or file containg a list of targets " )
2015-11-20 01:13:32 +00:00
parser . add_argument ( " -t " , type = int , dest = " threads " , default = 100 , help = " Set how many concurrent threads to use (defaults to 100) " )
2015-11-03 10:22:58 +00:00
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 ' )
parser . add_argument ( " -C " , metavar = " COMBO_FILE " , dest = ' combo_file ' , type = str , default = None , help = " Combo file containing a list of domain \\ username:password or username:password entries " )
parser . add_argument ( ' -k ' , action = " store " , dest = ' aesKey ' , metavar = " HEX_KEY " , help = ' AES key to use for Kerberos Authentication (128 or 256 bits) ' )
parser . add_argument ( " -d " , metavar = " DOMAIN " , dest = ' domain ' , default = None , help = " Domain name " )
2015-11-10 08:57:04 +00:00
parser . add_argument ( " -n " , metavar = ' NAMESPACE ' , dest = ' namespace ' , default = ' //./root/cimv2 ' , help = ' WMI Namespace (default: //./root/cimv2) ' )
2015-11-03 10:22:58 +00:00
parser . add_argument ( " -s " , metavar = " SHARE " , dest = ' share ' , default = " C$ " , help = " Specify a share (default: C$) " )
parser . add_argument ( ' --kerb ' , action = " store_true " , dest = ' kerb ' , help = ' Use Kerberos authentication. Grabs credentials from ccache file (KRB5CCNAME) based on target parameters ' )
parser . add_argument ( " --port " , dest = ' port ' , type = int , choices = { 139 , 445 } , default = 445 , help = " SMB port (default: 445) " )
2015-11-09 06:39:37 +00:00
parser . add_argument ( " --server " , choices = { ' http ' , ' https ' } , default = ' http ' , help = ' Use the selected server (defaults to http) ' )
2015-11-21 02:47:40 +00:00
parser . add_argument ( " --server-port " , metavar = ' PORT ' , type = int , help = ' Start the server on the specified port ' )
2015-11-20 06:04:54 +00:00
#How much fail can we limit? can we fail at failing to limit? da da da dum
parser . add_argument ( " --fail-limit " , metavar = ' LIMIT ' , type = int , default = None , help = ' The max number of failed login attempts allowed per host (default: None) ' )
parser . add_argument ( " --gfail-limit " , metavar = ' LIMIT ' , type = int , default = None , help = ' The max number of failed login attempts allowed globally (default: None) ' )
2015-11-03 10:22:58 +00:00
parser . add_argument ( " --verbose " , action = ' store_true ' , dest = ' verbose ' , help = " Enable verbose output " )
rgroup = parser . add_argument_group ( " Credential Gathering " , " Options for gathering credentials " )
rgroup . add_argument ( " --sam " , action = ' store_true ' , help = ' Dump SAM hashes from target systems ' )
2015-11-08 22:27:33 +00:00
rgroup . add_argument ( " --lsa " , action = ' store_true ' , help = ' Dump LSA secrets from target systems ' )
2015-12-11 07:24:43 +00:00
rgroup . add_argument ( " --gpp-passwords " , action = ' store_true ' , help = ' Retrieve plaintext passwords and other information for accounts pushed through Group Policy Preferences ' )
2015-11-08 22:27:33 +00:00
rgroup . add_argument ( " --ntds " , choices = { ' vss ' , ' drsuapi ' , ' ninja ' } , help = " Dump the NTDS.dit from target DCs using the specifed method \n (drsuapi is the fastest) " )
2015-11-10 08:57:04 +00:00
rgroup . add_argument ( " --ntds-history " , action = ' store_true ' , help = ' Dump NTDS.dit password history ' )
rgroup . add_argument ( " --ntds-pwdLastSet " , action = ' store_true ' , help = ' Shows the pwdLastSet attribute for each NTDS.dit account ' )
2015-11-03 10:22:58 +00:00
rgroup . add_argument ( " --mimikatz " , action = ' store_true ' , help = ' Run Invoke-Mimikatz (sekurlsa::logonpasswords) on target systems ' )
2015-11-09 03:11:18 +00:00
rgroup . add_argument ( " --mimikatz-cmd " , metavar = ' MIMIKATZ_CMD ' , help = ' Run Invoke-Mimikatz with the specified command ' )
rgroup . add_argument ( " --enable-wdigest " , action = ' store_true ' , help = " Creates the ' UseLogonCredential ' registry key enabling WDigest cred dumping on Windows >= 8.1 " )
2015-11-03 10:22:58 +00:00
rgroup . add_argument ( " --disable-wdigest " , action = ' store_true ' , help = " Deletes the ' UseLogonCredential ' registry key " )
egroup = parser . add_argument_group ( " Mapping/Enumeration " , " Options for Mapping/Enumerating " )
2015-11-08 22:27:33 +00:00
egroup . add_argument ( " --shares " , action = " store_true " , dest = " enum_shares " , help = " List shares " )
2015-11-03 10:22:58 +00:00
egroup . add_argument ( ' --check-uac ' , action = ' store_true ' , dest = ' check_uac ' , help = ' Checks UAC status ' )
egroup . add_argument ( " --sessions " , action = ' store_true ' , dest = ' enum_sessions ' , help = ' Enumerate active sessions ' )
egroup . add_argument ( ' --disks ' , action = ' store_true ' , dest = ' enum_disks ' , help = ' Enumerate disks ' )
egroup . add_argument ( " --users " , action = ' store_true ' , dest = ' enum_users ' , help = ' Enumerate users ' )
2015-11-08 22:27:33 +00:00
egroup . add_argument ( " --rid-brute " , nargs = ' ? ' , const = 4000 , metavar = ' MAX_RID ' , dest = ' rid_brute ' , help = ' Enumerate users by bruteforcing RID \' s (defaults to 4000) ' )
2015-11-03 10:22:58 +00:00
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 ' )
2015-11-20 01:13:32 +00:00
egroup . add_argument ( " --powerview " , metavar = ' POWERVIEW_CMD ' , dest = ' powerview ' , help = ' Run the specified PowerView command ' )
2015-11-03 10:22:58 +00:00
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 " )
sgroup . add_argument ( " --spider " , metavar = ' FOLDER ' , nargs = ' ? ' , const = ' . ' , type = str , help = ' Folder to spider (defaults to top level directory) ' )
sgroup . add_argument ( " --content " , dest = ' search_content ' , action = ' store_true ' , help = ' Enable file content searching ' )
sgroup . add_argument ( " --exclude-dirs " , type = str , metavar = ' DIR_LIST ' , default = ' ' , dest = ' exclude_dirs ' , help = ' Directories to exclude from spidering ' )
sgroup . add_argument ( " --pattern " , type = str , help = ' Pattern to search for in folders, filenames and file content ' )
sgroup . add_argument ( " --patternfile " , type = str , help = ' File containing patterns to search for in folders, filenames and file content ' )
sgroup . add_argument ( " --depth " , type = int , default = 10 , help = ' Spider recursion depth (default: 10) ' )
cgroup = parser . add_argument_group ( " Command Execution " , " Options for executing commands " )
2015-11-09 03:11:18 +00:00
cgroup . add_argument ( ' --execm ' , choices = { " wmi " , " smbexec " , " atexec " } , default = " wmi " , help = " Method to execute the command (default: wmi) " )
2015-11-20 04:13:46 +00:00
cgroup . add_argument ( ' --force-ps32 ' , action = ' store_true ' , dest = ' force_ps32 ' , help = ' Force all PowerShell code/commands to run in a 32bit process ' )
2015-11-08 22:27:33 +00:00
cgroup . add_argument ( ' --no-output ' , action = ' store_true ' , dest = ' no_output ' , help = ' Do not retrieve command output ' )
2015-11-03 10:22:58 +00:00
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 ' )
xgroup = parser . add_argument_group ( " Shellcode/EXE/DLL/Meterpreter Injection " , " Options for injecting Shellcode/EXE/DLL/Meterpreter in memory using PowerShell " )
xgroup . add_argument ( " --inject " , choices = { ' shellcode ' , ' exe ' , ' dll ' , ' met_reverse_https ' , ' met_reverse_http ' } , help = ' Inject Shellcode, EXE, DLL or Meterpreter ' )
xgroup . add_argument ( " --path " , type = str , help = ' Path to the Shellcode/EXE/DLL you want to inject on the target systems (ignored if injecting Meterpreter) ' )
xgroup . add_argument ( ' --procid ' , type = int , help = ' Process ID to inject the Shellcode/EXE/DLL/Meterpreter into (if omitted, will inject within the running PowerShell process) ' )
xgroup . add_argument ( " --exeargs " , type = str , help = ' Arguments to pass to the EXE being reflectively loaded (ignored if not injecting an EXE) ' )
xgroup . add_argument ( " --met-options " , nargs = 2 , metavar = ( ' LHOST ' , ' LPORT ' ) , dest = ' met_options ' , help = ' Meterpreter options (ignored if not injecting Meterpreter) ' )
bgroup = parser . add_argument_group ( " Filesystem Interaction " , " Options for interacting with filesystems " )
bgroup . add_argument ( " --list " , metavar = ' PATH ' , nargs = ' ? ' , const = ' . ' , type = str , help = ' List contents of a directory (defaults to top level directory) ' )
2015-11-21 03:20:42 +00:00
bgroup . add_argument ( " --download " , nargs = 2 , metavar = ( ' SRC ' , ' DST ' ) , help = " Download a file from the remote systems " )
2015-11-03 10:22:58 +00:00
bgroup . add_argument ( " --upload " , nargs = 2 , metavar = ( ' SRC ' , ' DST ' ) , help = " Upload a file to the remote systems " )
bgroup . add_argument ( " --delete " , metavar = " PATH " , help = " Delete a remote file " )
2015-11-20 04:13:46 +00:00
wgroup = parser . add_argument_group ( " Service Interaction " , " Options for interacting with Windows services " )
wgroup . add_argument ( " --service " , choices = { ' list ' , ' start ' , ' stop ' , ' delete ' , ' status ' , ' config ' , ' create ' , ' change ' } )
wgroup . add_argument ( " --name " , dest = ' service_name ' , metavar = ' NAME ' , help = ' Service name ' )
wgroup . add_argument ( " --display " , dest = ' service_display_name ' , metavar = ' NAME ' , help = ' Service display name ' )
wgroup . add_argument ( " --bin-path " , dest = ' service_bin_path ' , metavar = ' PATH ' , help = ' Binary path ' )
wgroup . add_argument ( " --service-type " , metavar = ' TYPE ' , help = ' Service type ' )
wgroup . add_argument ( " --start-type " , metavar = ' TYPE ' , help = ' Service start type ' )
wgroup . add_argument ( " --start-name " , metavar = ' NAME ' , help = ' Name of the account under which the service should run ' )
wgroup . add_argument ( " --start-pass " , metavar = ' PASS ' , help = ' Password of the account whose name was specified with the --start-name parameter ' )
2016-01-17 05:33:11 +00:00
mgroup = parser . add_argument_group ( " MSSQL Interaction " , " Options for interacting with MSSQL DB ' s " )
mgroup . add_argument ( " --mssql " , nargs = ' ? ' , const = ' ' , metavar = ' QUERY ' , help = ' Authenticate with the provided credentials against the MSSQL service, optionally execute the specified query ' )
mgroup . add_argument ( " --mssql-port " , default = 1433 , metavar = ' PORT ' , help = ' MSSQL service port (default: 1433) ' )
mgroup . add_argument ( " --mssql-instance " , action = ' store_true ' , help = ' Enumerate the MSSQL intances on the target hosts ' )
mgroup . add_argument ( " --enable-xpcmdshell " , action = ' store_true ' , help = ' Enable xp_cmdshell on target DB \' s ' )
mgroup . add_argument ( " --disable-xpcmdshell " , action = ' store_true ' , help = ' Disable xp_cmdshell on target DB \' s ' )
mgroup . add_argument ( " --xp-cmd " , metavar = ' COMMAND ' , help = ' Execute the specified command using xp_cmdshell ' )
2015-11-03 10:22:58 +00:00
if len ( sys . argv ) == 1 :
parser . print_help ( )
sys . exit ( 1 )
args = parser . parse_args ( )
patterns = [ ]
targets = [ ]
2015-11-21 02:33:55 +00:00
if args . server == ' http ' :
if args . server_port :
args . http_port = args . server_port
else :
args . server_port = 80
if args . server == ' https ' :
if args . server_port :
args . https_port = args . server_port
else :
args . server_port = 443
2015-11-03 10:22:58 +00:00
init_args ( args )
if args . verbose :
2016-01-17 05:33:11 +00:00
setup_logger ( ' _ ' . join ( args . target ) , DEBUG )
2015-11-03 10:22:58 +00:00
else :
2016-01-17 05:33:11 +00:00
setup_logger ( ' _ ' . join ( args . target ) )
2015-11-03 10:22:58 +00:00
###################### Just a bunch of error checking to make sure everythings good to go ######################
if args . inject :
if not args . inject . startswith ( ' met_ ' ) :
if not args . path :
print_error ( " You must specify a ' --path ' to the Shellcode/EXE/DLL to inject " )
shutdown ( 1 )
2015-09-13 17:39:39 +00:00
2015-11-03 10:22:58 +00:00
elif args . path :
if not os . path . exists ( args . path ) :
print_error ( ' Unable to find Shellcode/EXE/DLL at specified path ' )
shutdown ( 1 )
2015-08-14 14:18:52 +00:00
2015-11-03 10:22:58 +00:00
elif args . inject . startswith ( ' met_ ' ) :
if not args . met_options :
print_error ( " You must specify Meterpreter ' s handler options using ' --met-options ' " )
shutdown ( 1 )
2015-11-01 20:27:42 +00:00
2015-11-03 10:22:58 +00:00
if args . spider :
if not args . pattern and not args . patternfile :
print_error ( " You must specify a --pattern or --patternfile " )
shutdown ( 1 )
2015-11-01 20:27:42 +00:00
2015-11-03 10:22:58 +00:00
if args . patternfile :
if not os . path . exists ( args . patternfile ) :
print_error ( " Unable to find pattern file at specified path " )
shutdown ( 1 )
2015-11-01 20:27:42 +00:00
2015-11-03 10:22:58 +00:00
for line in args . patternfile . readlines ( ) :
line = line . rstrip ( )
patterns . append ( re . compile ( line , re . IGNORECASE ) )
2015-08-19 14:33:56 +00:00
2015-11-03 10:22:58 +00:00
patterns . extend ( re . compile ( patt , re . IGNORECASE ) for patt in args . pattern . split ( ' , ' ) )
2015-09-13 17:39:39 +00:00
2015-11-03 10:22:58 +00:00
args . pattern = patterns
args . exclude_dirs = args . exclude_dirs . split ( ' , ' )
2015-10-08 01:34:05 +00:00
2015-11-03 10:22:58 +00:00
if args . combo_file and not os . path . exists ( args . combo_file ) :
print_error ( ' Unable to find combo file at specified path ' )
shutdown ( 1 )
2015-09-28 21:08:14 +00:00
2015-11-20 04:13:46 +00:00
if args . service :
if args . service in [ ' start ' , ' stop ' , ' delete ' , ' status ' , ' config ' , ' change ' ] :
2015-12-20 17:24:17 +00:00
if not args . service_name :
2015-11-20 04:13:46 +00:00
print_error ( ' You must specify a --name ' )
shutdown ( 1 )
elif args . service == ' create ' :
if not args . service_name or not args . service_display_name or not args . service_bin_path :
print_error ( ' You must specify --name, --display and --bin-path ' )
shutdown ( 1 )
2015-11-10 08:57:04 +00:00
if args . ntds_history or args . ntds_pwdLastSet :
if not args . ntds :
print_error ( ' --ntds-history and --ntds-pwdLastSet require --ntds ' )
shutdown ( 1 )
2015-11-03 10:22:58 +00:00
################################################################################################################
2015-08-29 10:05:27 +00:00
2016-01-17 05:33:11 +00:00
def populate_targets ( target ) :
2015-11-03 10:22:58 +00:00
if ' - ' in target :
ip_range = target . split ( ' - ' )
try :
hosts = IPRange ( ip_range [ 0 ] , ip_range [ 1 ] )
except AddrFormatError :
2016-01-07 05:07:19 +00:00
try :
start_ip = IPAddress ( ip_range [ 0 ] )
2015-08-29 10:05:27 +00:00
2016-01-07 05:07:19 +00:00
start_ip_words = list ( start_ip . words )
start_ip_words [ - 1 ] = ip_range [ 1 ]
start_ip_words = [ str ( v ) for v in start_ip_words ]
2015-08-29 10:05:27 +00:00
2016-01-07 05:07:19 +00:00
end_ip = IPAddress ( ' . ' . join ( start_ip_words ) )
2015-08-29 10:05:27 +00:00
2016-01-17 05:33:11 +00:00
t = IPRange ( start_ip , end_ip )
2016-01-07 05:07:19 +00:00
except AddrFormatError :
2016-01-17 05:33:11 +00:00
t = target
2015-08-29 10:05:27 +00:00
else :
2016-01-07 05:07:19 +00:00
try :
2016-01-17 05:33:11 +00:00
t = IPNetwork ( target )
2016-01-07 05:07:19 +00:00
except AddrFormatError :
2016-01-17 05:33:11 +00:00
t = target
if type ( t ) == IPNetwork or type ( t ) == IPRange :
targets . extend ( list ( t ) )
else :
targets . append ( t )
for target in args . target :
if os . path . exists ( target ) :
with open ( target , ' r ' ) as target_file :
for target_entry in target_file :
populate_targets ( target_entry )
else :
populate_targets ( target )
2015-08-19 14:17:08 +00:00
2015-12-11 07:24:43 +00:00
if args . mimikatz or args . powerview or args . gpp_passwords or args . mimikatz_cmd or args . inject or args . ntds == ' ninja ' :
2015-11-03 10:22:58 +00:00
if args . server == ' http ' :
2015-11-21 02:33:55 +00:00
http_server ( args . server_port )
2015-09-13 17:39:39 +00:00
2015-11-03 10:22:58 +00:00
elif args . server == ' https ' :
2015-11-21 02:33:55 +00:00
https_server ( args . server_port )
2015-10-23 01:20:07 +00:00
2015-11-03 10:22:58 +00:00
def concurrency ( targets ) :
2015-11-08 22:27:33 +00:00
'''
Open all the greenlet ( as supposed to redlet ? ? ) threads
Whoever came up with that name has a fetish for traffic lights
'''
2015-11-03 10:22:58 +00:00
try :
pool = Pool ( args . threads )
2016-01-17 05:33:11 +00:00
jobs = [ pool . spawn ( main_greenlet , str ( target ) ) for target in targets ]
2015-11-03 10:22:58 +00:00
joinall ( jobs )
except KeyboardInterrupt :
shutdown ( 0 )
2015-08-14 14:18:52 +00:00
2015-11-03 10:22:58 +00:00
concurrency ( targets )
2015-08-17 16:40:10 +00:00
2015-12-11 07:24:43 +00:00
if args . mimikatz or args . powerview or args . gpp_passwords or args . mimikatz_cmd or args . inject or args . ntds == ' ninja ' :
2015-11-03 10:22:58 +00:00
try :
while True :
sleep ( 1 )
except KeyboardInterrupt :
shutdown ( 0 )