1# Copyright (c) 2003-2018 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-BKRP] 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#
21# ToDo:
22# [ ] 2.2.2 Client-Side-Wrapped Secret
23
24from impacket.dcerpc.v5.ndr import NDRCALL, NDRPOINTER, NDRUniConformantArray
25from impacket.dcerpc.v5.dtypes import DWORD, NTSTATUS, GUID, RPC_SID, NULL
26from impacket.dcerpc.v5.rpcrt import DCERPCException
27from impacket import system_errors
28from impacket.uuid import uuidtup_to_bin, string_to_bin
29from impacket.structure import Structure
30
31MSRPC_UUID_BKRP = uuidtup_to_bin(('3dde7c30-165d-11d1-ab8f-00805f14db40', '1.0'))
32
33class DCERPCSessionError(DCERPCException):
34    def __init__(self, error_string=None, error_code=None, packet=None):
35        DCERPCException.__init__(self, error_string, error_code, packet)
36
37    def __str__( self ):
38        key = self.error_code
39        if system_errors.ERROR_MESSAGES.has_key(key):
40            error_msg_short = system_errors.ERROR_MESSAGES[key][0]
41            error_msg_verbose = system_errors.ERROR_MESSAGES[key][1]
42            return 'BKRP SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose)
43        else:
44            return 'BKRP SessionError: unknown error code: 0x%x' % self.error_code
45
46################################################################################
47# CONSTANTS
48################################################################################
49
50BACKUPKEY_BACKUP_GUID = string_to_bin("7F752B10-178E-11D1-AB8F-00805F14DB40")
51BACKUPKEY_RESTORE_GUID_WIN2K = string_to_bin("7FE94D50-178E-11D1-AB8F-00805F14DB40")
52BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID = string_to_bin("018FF48A-EABA-40C6-8F6D-72370240E967")
53BACKUPKEY_RESTORE_GUID =  string_to_bin("47270C64-2FC7-499B-AC5B-0E37CDCE899A")
54
55################################################################################
56# STRUCTURES
57################################################################################
58class BYTE_ARRAY(NDRUniConformantArray):
59    item = 'c'
60
61class PBYTE_ARRAY(NDRPOINTER):
62    referent = (
63        ('Data', BYTE_ARRAY),
64    )
65
66# 2.2.4.1 Rc4EncryptedPayload Structure
67class Rc4EncryptedPayload(Structure):
68    structure = (
69        ('R3', '32s=""'),
70        ('MAC', '20s=""'),
71        ('SID', ':', RPC_SID),
72        ('Secret', ':'),
73    )
74
75# 2.2.4 Secret Wrapped with Symmetric Key
76class WRAPPED_SECRET(Structure):
77    structure = (
78        ('SIGNATURE', '<L=1'),
79        ('Payload_Length', '<L=0'),
80        ('Ciphertext_Length', '<L=0'),
81        ('GUID_of_Wrapping_Key', '16s=""'),
82        ('R2', '68s=""'),
83        ('_Rc4EncryptedPayload', '_-Rc4EncryptedPayload', 'self["Payload_Length"]'),
84        ('Rc4EncryptedPayload', ':'),
85    )
86
87################################################################################
88# RPC CALLS
89################################################################################
90# 3.1.4.1 BackuprKey(Opnum 0)
91class BackuprKey(NDRCALL):
92    opnum = 0
93    structure = (
94       ('pguidActionAgent', GUID),
95       ('pDataIn', BYTE_ARRAY),
96       ('cbDataIn', DWORD),
97       ('dwParam', DWORD),
98    )
99
100class BackuprKeyResponse(NDRCALL):
101    structure = (
102       ('ppDataOut', PBYTE_ARRAY),
103       ('pcbDataOut', DWORD),
104       ('ErrorCode', NTSTATUS),
105    )
106
107################################################################################
108# OPNUMs and their corresponding structures
109################################################################################
110OPNUMS = {
111 0 : (BackuprKey, BackuprKeyResponse),
112}
113
114################################################################################
115# HELPER FUNCTIONS
116################################################################################
117def hBackuprKey(dce, pguidActionAgent, pDataIn, dwParam=0):
118    request = BackuprKey()
119    request['pguidActionAgent'] = pguidActionAgent
120    request['pDataIn'] = pDataIn
121    if pDataIn == NULL:
122        request['cbDataIn'] = 0
123    else:
124        request['cbDataIn'] = len(pDataIn)
125    request['dwParam'] = dwParam
126    return dce.request(request)
127
128