1# Copyright (c) 2003-2016 CORE Security Technologies
2#
3# This software is provided under under a slightly modified version
4# of the Apache Software License. See the accompanying LICENSE file
5# for more information.
6#
7# Author: Alberto Solino (@agsolino)
8#
9# Description:
10#   [MS-LSAT] Interface implementation
11#
12#   Best way to learn how to use these calls is to grab the protocol standard
13#   so you understand what the call does, and then read the test case located
14#   at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC
15#
16#   Some calls have helper functions, which makes it even easier to use.
17#   They are located at the end of this file.
18#   Helper functions start with "h"<name of the call>.
19#   There are test cases for them too.
20#
21from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRENUM, NDRPOINTER, NDRUniConformantArray
22from impacket.dcerpc.v5.dtypes import ULONG, LONG, PRPC_SID, RPC_UNICODE_STRING, LPWSTR, PRPC_UNICODE_STRING, NTSTATUS, \
23    NULL
24from impacket import nt_errors
25from impacket.uuid import uuidtup_to_bin
26from impacket.dcerpc.v5.enum import Enum
27from impacket.dcerpc.v5.lsad import LSAPR_HANDLE, LSAPR_ACL, SECURITY_DESCRIPTOR_CONTROL, LSAPR_SECURITY_DESCRIPTOR, \
28    PLSAPR_SECURITY_DESCRIPTOR, SECURITY_IMPERSONATION_LEVEL, SECURITY_CONTEXT_TRACKING_MODE, \
29    SECURITY_QUALITY_OF_SERVICE, LSAPR_OBJECT_ATTRIBUTES, LSAPR_TRUST_INFORMATION, PLSAPR_TRUST_INFORMATION_ARRAY, \
30    PRPC_UNICODE_STRING_ARRAY, LsarOpenPolicy2, LsarOpenPolicy, LsarClose, hLsarOpenPolicy2, hLsarOpenPolicy, hLsarClose
31from impacket.dcerpc.v5.samr import SID_NAME_USE
32from impacket.dcerpc.v5.rpcrt import DCERPCException
33
34MSRPC_UUID_LSAT  = uuidtup_to_bin(('12345778-1234-ABCD-EF00-0123456789AB','0.0'))
35
36class DCERPCSessionError(DCERPCException):
37    def __init__(self, error_string=None, error_code=None, packet=None):
38        DCERPCException.__init__(self, error_string, error_code, packet)
39
40    def __str__( self ):
41        key = self.error_code
42        if nt_errors.ERROR_MESSAGES.has_key(key):
43            error_msg_short = nt_errors.ERROR_MESSAGES[key][0]
44            error_msg_verbose = nt_errors.ERROR_MESSAGES[key][1]
45            return 'LSAT SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
46        else:
47            return 'LSAT SessionError: unknown error code: 0x%x' % self.error_code
48
49################################################################################
50# CONSTANTS
51################################################################################
52# 2.2.10 ACCESS_MASK
53POLICY_LOOKUP_NAMES             = 0x00000800
54
55################################################################################
56# STRUCTURES
57################################################################################
58# 2.2.12 LSAPR_REFERENCED_DOMAIN_LIST
59class LSAPR_REFERENCED_DOMAIN_LIST(NDRSTRUCT):
60    structure = (
61        ('Entries', ULONG),
62        ('Domains', PLSAPR_TRUST_INFORMATION_ARRAY),
63        ('MaxEntries', ULONG),
64    )
65
66class PLSAPR_REFERENCED_DOMAIN_LIST(NDRPOINTER):
67    referent = (
68        ('Data', LSAPR_REFERENCED_DOMAIN_LIST),
69    )
70
71# 2.2.14 LSA_TRANSLATED_SID
72class LSA_TRANSLATED_SID(NDRSTRUCT):
73    structure = (
74        ('Use', SID_NAME_USE),
75        ('RelativeId', ULONG),
76        ('DomainIndex', LONG),
77    )
78
79# 2.2.15 LSAPR_TRANSLATED_SIDS
80class LSA_TRANSLATED_SID_ARRAY(NDRUniConformantArray):
81    item = LSA_TRANSLATED_SID
82
83class PLSA_TRANSLATED_SID_ARRAY(NDRPOINTER):
84    referent = (
85        ('Data', LSA_TRANSLATED_SID_ARRAY),
86    )
87
88class LSAPR_TRANSLATED_SIDS(NDRSTRUCT):
89    structure = (
90        ('Entries', ULONG),
91        ('Sids', PLSA_TRANSLATED_SID_ARRAY),
92    )
93
94# 2.2.16 LSAP_LOOKUP_LEVEL
95class LSAP_LOOKUP_LEVEL(NDRENUM):
96    class enumItems(Enum):
97        LsapLookupWksta                = 1
98        LsapLookupPDC                  = 2
99        LsapLookupTDL                  = 3
100        LsapLookupGC                   = 4
101        LsapLookupXForestReferral      = 5
102        LsapLookupXForestResolve       = 6
103        LsapLookupRODCReferralToFullDC = 7
104
105# 2.2.17 LSAPR_SID_INFORMATION
106class LSAPR_SID_INFORMATION(NDRSTRUCT):
107    structure = (
108        ('Sid', PRPC_SID),
109    )
110
111# 2.2.18 LSAPR_SID_ENUM_BUFFER
112class LSAPR_SID_INFORMATION_ARRAY(NDRUniConformantArray):
113    item = LSAPR_SID_INFORMATION
114
115class PLSAPR_SID_INFORMATION_ARRAY(NDRPOINTER):
116    referent = (
117        ('Data', LSAPR_SID_INFORMATION_ARRAY),
118    )
119
120class LSAPR_SID_ENUM_BUFFER(NDRSTRUCT):
121    structure = (
122        ('Entries', ULONG),
123        ('SidInfo', PLSAPR_SID_INFORMATION_ARRAY),
124    )
125
126# 2.2.19 LSAPR_TRANSLATED_NAME
127class LSAPR_TRANSLATED_NAME(NDRSTRUCT):
128    structure = (
129        ('Use', SID_NAME_USE),
130        ('Name', RPC_UNICODE_STRING),
131        ('DomainIndex', LONG),
132    )
133
134# 2.2.20 LSAPR_TRANSLATED_NAMES
135class LSAPR_TRANSLATED_NAME_ARRAY(NDRUniConformantArray):
136    item = LSAPR_TRANSLATED_NAME
137
138class PLSAPR_TRANSLATED_NAME_ARRAY(NDRPOINTER):
139    referent = (
140        ('Data', LSAPR_TRANSLATED_NAME_ARRAY),
141    )
142
143class LSAPR_TRANSLATED_NAMES(NDRSTRUCT):
144    structure = (
145        ('Entries', ULONG),
146        ('Names', PLSAPR_TRANSLATED_NAME_ARRAY),
147    )
148
149# 2.2.21 LSAPR_TRANSLATED_NAME_EX
150class LSAPR_TRANSLATED_NAME_EX(NDRSTRUCT):
151    structure = (
152        ('Use', SID_NAME_USE),
153        ('Name', RPC_UNICODE_STRING),
154        ('DomainIndex', LONG),
155        ('Flags', ULONG),
156    )
157
158# 2.2.22 LSAPR_TRANSLATED_NAMES_EX
159class LSAPR_TRANSLATED_NAME_EX_ARRAY(NDRUniConformantArray):
160    item = LSAPR_TRANSLATED_NAME_EX
161
162class PLSAPR_TRANSLATED_NAME_EX_ARRAY(NDRPOINTER):
163    referent = (
164        ('Data', LSAPR_TRANSLATED_NAME_EX_ARRAY),
165    )
166
167class LSAPR_TRANSLATED_NAMES_EX(NDRSTRUCT):
168    structure = (
169        ('Entries', ULONG),
170        ('Names', PLSAPR_TRANSLATED_NAME_EX_ARRAY),
171    )
172
173# 2.2.23 LSAPR_TRANSLATED_SID_EX
174class LSAPR_TRANSLATED_SID_EX(NDRSTRUCT):
175    structure = (
176        ('Use', SID_NAME_USE),
177        ('RelativeId', ULONG),
178        ('DomainIndex', LONG),
179        ('Flags', ULONG),
180    )
181
182# 2.2.24 LSAPR_TRANSLATED_SIDS_EX
183class LSAPR_TRANSLATED_SID_EX_ARRAY(NDRUniConformantArray):
184    item = LSAPR_TRANSLATED_SID_EX
185
186class PLSAPR_TRANSLATED_SID_EX_ARRAY(NDRPOINTER):
187    referent = (
188        ('Data', LSAPR_TRANSLATED_SID_EX_ARRAY),
189    )
190
191class LSAPR_TRANSLATED_SIDS_EX(NDRSTRUCT):
192    structure = (
193        ('Entries', ULONG),
194        ('Sids', PLSAPR_TRANSLATED_SID_EX_ARRAY),
195    )
196
197# 2.2.25 LSAPR_TRANSLATED_SID_EX2
198class LSAPR_TRANSLATED_SID_EX2(NDRSTRUCT):
199    structure = (
200        ('Use', SID_NAME_USE),
201        ('Sid', PRPC_SID),
202        ('DomainIndex', LONG),
203        ('Flags', ULONG),
204    )
205
206# 2.2.26 LSAPR_TRANSLATED_SIDS_EX2
207class LSAPR_TRANSLATED_SID_EX2_ARRAY(NDRUniConformantArray):
208    item = LSAPR_TRANSLATED_SID_EX2
209
210class PLSAPR_TRANSLATED_SID_EX2_ARRAY(NDRPOINTER):
211    referent = (
212        ('Data', LSAPR_TRANSLATED_SID_EX2_ARRAY),
213    )
214
215class LSAPR_TRANSLATED_SIDS_EX2(NDRSTRUCT):
216    structure = (
217        ('Entries', ULONG),
218        ('Sids', PLSAPR_TRANSLATED_SID_EX2_ARRAY),
219    )
220
221class RPC_UNICODE_STRING_ARRAY(NDRUniConformantArray):
222    item = RPC_UNICODE_STRING
223
224################################################################################
225# RPC CALLS
226################################################################################
227# 3.1.4.4 LsarGetUserName (Opnum 45)
228class LsarGetUserName(NDRCALL):
229    opnum = 45
230    structure = (
231       ('SystemName', LPWSTR),
232       ('UserName', PRPC_UNICODE_STRING),
233       ('DomainName', PRPC_UNICODE_STRING),
234    )
235
236class LsarGetUserNameResponse(NDRCALL):
237    structure = (
238       ('UserName', PRPC_UNICODE_STRING),
239       ('DomainName', PRPC_UNICODE_STRING),
240       ('ErrorCode', NTSTATUS),
241    )
242
243# 3.1.4.5 LsarLookupNames4 (Opnum 77)
244class LsarLookupNames4(NDRCALL):
245    opnum = 77
246    structure = (
247       ('Count', ULONG),
248       ('Names', RPC_UNICODE_STRING_ARRAY),
249       ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2),
250       ('LookupLevel', LSAP_LOOKUP_LEVEL),
251       ('MappedCount', ULONG),
252       ('LookupOptions', ULONG),
253       ('ClientRevision', ULONG),
254    )
255
256class LsarLookupNames4Response(NDRCALL):
257    structure = (
258       ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST),
259       ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2),
260       ('MappedCount', ULONG),
261       ('ErrorCode', NTSTATUS),
262    )
263
264# 3.1.4.6 LsarLookupNames3 (Opnum 68)
265class LsarLookupNames3(NDRCALL):
266    opnum = 68
267    structure = (
268       ('PolicyHandle', LSAPR_HANDLE),
269       ('Count', ULONG),
270       ('Names', RPC_UNICODE_STRING_ARRAY),
271       ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2),
272       ('LookupLevel', LSAP_LOOKUP_LEVEL),
273       ('MappedCount', ULONG),
274       ('LookupOptions', ULONG),
275       ('ClientRevision', ULONG),
276    )
277
278class LsarLookupNames3Response(NDRCALL):
279    structure = (
280       ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST),
281       ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX2),
282       ('MappedCount', ULONG),
283       ('ErrorCode', NTSTATUS),
284    )
285
286# 3.1.4.7 LsarLookupNames2 (Opnum 58)
287class LsarLookupNames2(NDRCALL):
288    opnum = 58
289    structure = (
290       ('PolicyHandle', LSAPR_HANDLE),
291       ('Count', ULONG),
292       ('Names', RPC_UNICODE_STRING_ARRAY),
293       ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX),
294       ('LookupLevel', LSAP_LOOKUP_LEVEL),
295       ('MappedCount', ULONG),
296       ('LookupOptions', ULONG),
297       ('ClientRevision', ULONG),
298    )
299
300class LsarLookupNames2Response(NDRCALL):
301    structure = (
302       ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST),
303       ('TranslatedSids', LSAPR_TRANSLATED_SIDS_EX),
304       ('MappedCount', ULONG),
305       ('ErrorCode', NTSTATUS),
306    )
307
308# 3.1.4.8 LsarLookupNames (Opnum 14)
309class LsarLookupNames(NDRCALL):
310    opnum = 14
311    structure = (
312       ('PolicyHandle', LSAPR_HANDLE),
313       ('Count', ULONG),
314       ('Names', RPC_UNICODE_STRING_ARRAY),
315       ('TranslatedSids', LSAPR_TRANSLATED_SIDS),
316       ('LookupLevel', LSAP_LOOKUP_LEVEL),
317       ('MappedCount', ULONG),
318    )
319
320class LsarLookupNamesResponse(NDRCALL):
321    structure = (
322       ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST),
323       ('TranslatedSids', LSAPR_TRANSLATED_SIDS),
324       ('MappedCount', ULONG),
325       ('ErrorCode', NTSTATUS),
326    )
327
328# 3.1.4.9 LsarLookupSids3 (Opnum 76)
329class LsarLookupSids3(NDRCALL):
330    opnum = 76
331    structure = (
332       ('SidEnumBuffer', LSAPR_SID_ENUM_BUFFER),
333       ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX),
334       ('LookupLevel', LSAP_LOOKUP_LEVEL),
335       ('MappedCount', ULONG),
336       ('LookupOptions', ULONG),
337       ('ClientRevision', ULONG),
338    )
339
340class LsarLookupSids3Response(NDRCALL):
341    structure = (
342       ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST),
343       ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX),
344       ('MappedCount', ULONG),
345       ('ErrorCode', NTSTATUS),
346    )
347
348# 3.1.4.10 LsarLookupSids2 (Opnum 57)
349class LsarLookupSids2(NDRCALL):
350    opnum = 57
351    structure = (
352       ('PolicyHandle', LSAPR_HANDLE),
353       ('SidEnumBuffer', LSAPR_SID_ENUM_BUFFER),
354       ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX),
355       ('LookupLevel', LSAP_LOOKUP_LEVEL),
356       ('MappedCount', ULONG),
357       ('LookupOptions', ULONG),
358       ('ClientRevision', ULONG),
359    )
360
361class LsarLookupSids2Response(NDRCALL):
362    structure = (
363       ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST),
364       ('TranslatedNames', LSAPR_TRANSLATED_NAMES_EX),
365       ('MappedCount', ULONG),
366       ('ErrorCode', NTSTATUS),
367    )
368
369# 3.1.4.11 LsarLookupSids (Opnum 15)
370class LsarLookupSids(NDRCALL):
371    opnum = 15
372    structure = (
373       ('PolicyHandle', LSAPR_HANDLE),
374       ('SidEnumBuffer', LSAPR_SID_ENUM_BUFFER),
375       ('TranslatedNames', LSAPR_TRANSLATED_NAMES),
376       ('LookupLevel', LSAP_LOOKUP_LEVEL),
377       ('MappedCount', ULONG),
378    )
379
380class LsarLookupSidsResponse(NDRCALL):
381    structure = (
382       ('ReferencedDomains', PLSAPR_REFERENCED_DOMAIN_LIST),
383       ('TranslatedNames', LSAPR_TRANSLATED_NAMES),
384       ('MappedCount', ULONG),
385       ('ErrorCode', NTSTATUS),
386    )
387
388################################################################################
389# OPNUMs and their corresponding structures
390################################################################################
391OPNUMS = {
392 14 : (LsarLookupNames, LsarLookupNamesResponse),
393 15 : (LsarLookupSids, LsarLookupSidsResponse),
394 45 : (LsarGetUserName, LsarGetUserNameResponse),
395 57 : (LsarLookupSids2, LsarLookupSids2Response),
396 58 : (LsarLookupNames2, LsarLookupNames2Response),
397 68 : (LsarLookupNames3, LsarLookupNames3Response),
398 76 : (LsarLookupSids3, LsarLookupSids3Response),
399 77 : (LsarLookupNames4, LsarLookupNames4Response),
400}
401
402################################################################################
403# HELPER FUNCTIONS
404################################################################################
405def hLsarGetUserName(dce, userName = NULL, domainName = NULL):
406    request = LsarGetUserName()
407    request['SystemName'] = NULL
408    request['UserName'] = userName
409    request['DomainName'] = domainName
410    return dce.request(request)
411
412def hLsarLookupNames4(dce, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001):
413    request = LsarLookupNames4()
414    request['Count'] = len(names)
415    for name in names:
416        itemn = RPC_UNICODE_STRING()
417        itemn['Data'] = name
418        request['Names'].append(itemn)
419    request['TranslatedSids']['Sids'] = NULL
420    request['LookupLevel'] = lookupLevel
421    request['LookupOptions'] = lookupOptions
422    request['ClientRevision'] = clientRevision
423
424    return dce.request(request)
425
426def hLsarLookupNames3(dce, policyHandle, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001):
427    request = LsarLookupNames3()
428    request['PolicyHandle'] = policyHandle
429    request['Count'] = len(names)
430    for name in names:
431        itemn = RPC_UNICODE_STRING()
432        itemn['Data'] = name
433        request['Names'].append(itemn)
434    request['TranslatedSids']['Sids'] = NULL
435    request['LookupLevel'] = lookupLevel
436    request['LookupOptions'] = lookupOptions
437    request['ClientRevision'] = clientRevision
438
439    return dce.request(request)
440
441def hLsarLookupNames2(dce, policyHandle, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001):
442    request = LsarLookupNames2()
443    request['PolicyHandle'] = policyHandle
444    request['Count'] = len(names)
445    for name in names:
446        itemn = RPC_UNICODE_STRING()
447        itemn['Data'] = name
448        request['Names'].append(itemn)
449    request['TranslatedSids']['Sids'] = NULL
450    request['LookupLevel'] = lookupLevel
451    request['LookupOptions'] = lookupOptions
452    request['ClientRevision'] = clientRevision
453
454    return dce.request(request)
455
456def hLsarLookupNames(dce, policyHandle, names, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta):
457    request = LsarLookupNames()
458    request['PolicyHandle'] = policyHandle
459    request['Count'] = len(names)
460    for name in names:
461        itemn = RPC_UNICODE_STRING()
462        itemn['Data'] = name
463        request['Names'].append(itemn)
464    request['TranslatedSids']['Sids'] = NULL
465    request['LookupLevel'] = lookupLevel
466
467    return dce.request(request)
468
469def hLsarLookupSids2(dce, policyHandle, sids, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta, lookupOptions=0x00000000, clientRevision=0x00000001):
470    request = LsarLookupSids2()
471    request['PolicyHandle'] = policyHandle
472    request['SidEnumBuffer']['Entries'] = len(sids)
473    for sid in sids:
474        itemn = LSAPR_SID_INFORMATION()
475        itemn['Sid'].fromCanonical(sid)
476        request['SidEnumBuffer']['SidInfo'].append(itemn)
477
478    request['TranslatedNames']['Names'] = NULL
479    request['LookupLevel'] = lookupLevel
480    request['LookupOptions'] = lookupOptions
481    request['ClientRevision'] = clientRevision
482
483    return dce.request(request)
484
485def hLsarLookupSids(dce, policyHandle, sids, lookupLevel = LSAP_LOOKUP_LEVEL.LsapLookupWksta):
486    request = LsarLookupSids()
487    request['PolicyHandle'] = policyHandle
488    request['SidEnumBuffer']['Entries'] = len(sids)
489    for sid in sids:
490        itemn = LSAPR_SID_INFORMATION()
491        itemn['Sid'].fromCanonical(sid)
492        request['SidEnumBuffer']['SidInfo'].append(itemn)
493
494    request['TranslatedNames']['Names'] = NULL
495    request['LookupLevel'] = lookupLevel
496
497    return dce.request(request)
498
499