1# Copyright (c) 2017 CORE Security Technologies 2# Copyright (c) 2017 @MrAnde7son 3# 4# This software is provided under under a slightly modified version 5# of the Apache Software License. See the accompanying LICENSE file 6# for more information. 7# 8# Author: Itamar (@MrAnde7son) 9# 10# Description: 11# Initial [MS-EVEN6] Interface implementation 12# 13# Best way to learn how to use these calls is to grab the protocol standard 14# so you understand what the call does, and then read the test case located 15# at https://github.com/CoreSecurity/impacket/tree/master/impacket/testcases/SMB_RPC 16# 17# Some calls have helper functions, which makes it even easier to use. 18# They are located at the end of this file. 19# Helper functions start with "h"<name of the call>. 20# There are test cases for them too. 21# 22from impacket import system_errors 23from impacket.dcerpc.v5.dtypes import WSTR, DWORD, LPWSTR, ULONG, LARGE_INTEGER, WORD, BYTE 24from impacket.dcerpc.v5.ndr import NDRCALL, NDRPOINTER, NDRUniConformantArray, NDRUniVaryingArray, NDRSTRUCT 25from impacket.dcerpc.v5.rpcrt import DCERPCException 26from impacket.uuid import uuidtup_to_bin 27 28MSRPC_UUID_EVEN6 = uuidtup_to_bin(('F6BEAFF7-1E19-4FBB-9F8F-B89E2018337C', '1.0')) 29 30class DCERPCSessionError(DCERPCException): 31 def __init__(self, error_string=None, error_code=None, packet=None): 32 DCERPCException.__init__(self, error_string, error_code, packet) 33 34 def __str__(self): 35 key = self.error_code 36 if system_errors.ERROR_MESSAGES.has_key(key): 37 error_msg_short = system_errors.ERROR_MESSAGES[key][0] 38 error_msg_verbose = system_errors.ERROR_MESSAGES[key][1] 39 return 'EVEN6 SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) 40 else: 41 return 'EVEN6 SessionError: unknown error code: 0x%x' % self.error_code 42 43################################################################################ 44# CONSTANTS 45################################################################################ 46 47# Evt Path Flags 48EvtQueryChannelName = 0x00000001 49EvtQueryFilePath = 0x00000002 50EvtReadOldestToNewest = 0x00000100 51EvtReadNewestToOldest = 0x00000200 52 53################################################################################ 54# STRUCTURES 55################################################################################ 56 57class CONTEXT_HANDLE_LOG_HANDLE(NDRSTRUCT): 58 align = 1 59 structure = ( 60 ('Data', '20s=""'), 61 ) 62 63class PCONTEXT_HANDLE_LOG_HANDLE(NDRPOINTER): 64 referent = ( 65 ('Data', CONTEXT_HANDLE_LOG_HANDLE), 66 ) 67 68class CONTEXT_HANDLE_LOG_QUERY(NDRSTRUCT): 69 align = 1 70 structure = ( 71 ('Data', '20s=""'), 72 ) 73 74class PCONTEXT_HANDLE_LOG_QUERY(NDRPOINTER): 75 referent = ( 76 ('Data', CONTEXT_HANDLE_LOG_QUERY), 77 ) 78 79class LPPCONTEXT_HANDLE_LOG_QUERY(NDRPOINTER): 80 referent = ( 81 ('Data', PCONTEXT_HANDLE_LOG_QUERY), 82 ) 83 84class CONTEXT_HANDLE_OPERATION_CONTROL(NDRSTRUCT): 85 align = 1 86 structure = ( 87 ('Data', '20s=""'), 88 ) 89 90class PCONTEXT_HANDLE_OPERATION_CONTROL(NDRPOINTER): 91 referent = ( 92 ('Data', CONTEXT_HANDLE_OPERATION_CONTROL), 93 ) 94 95# 2.2.11 EvtRpcQueryChannelInfo 96class EvtRpcQueryChannelInfo(NDRSTRUCT): 97 structure = ( 98 ('Name', LPWSTR), 99 ('Status', DWORD), 100 ) 101 102class EvtRpcQueryChannelInfoArray(NDRUniVaryingArray): 103 item = EvtRpcQueryChannelInfo 104 105class LPEvtRpcQueryChannelInfoArray(NDRPOINTER): 106 referent = ( 107 ('Data', EvtRpcQueryChannelInfoArray) 108 ) 109 110class RPC_INFO(NDRSTRUCT): 111 structure = ( 112 ('Error', DWORD), 113 ('SubError', DWORD), 114 ('SubErrorParam', DWORD), 115 ) 116 117class PRPC_INFO(NDRPOINTER): 118 referent = ( 119 ('Data', RPC_INFO) 120 ) 121 122class WSTR_ARRAY(NDRUniVaryingArray): 123 item = WSTR 124 125class DWORD_ARRAY(NDRUniVaryingArray): 126 item = DWORD 127 128class LPDWORD_ARRAY(NDRPOINTER): 129 referent = ( 130 ('Data', DWORD_ARRAY) 131 ) 132 133class BYTE_ARRAY(NDRUniVaryingArray): 134 item = 'c' 135 136class CBYTE_ARRAY(NDRUniVaryingArray): 137 item = BYTE 138 139class CDWORD_ARRAY(NDRUniConformantArray): 140 item = DWORD 141 142class LPBYTE_ARRAY(NDRPOINTER): 143 referent = ( 144 ('Data', CBYTE_ARRAY) 145 ) 146 147class ULONG_ARRAY(NDRUniVaryingArray): 148 item = ULONG 149 150# 2.3.1 EVENT_DESCRIPTOR 151class EVENT_DESCRIPTOR(NDRSTRUCT): 152 structure = ( 153 ('Id', WORD), 154 ('Version', BYTE), 155 ('Channel', BYTE), 156 ('LevelSeverity', BYTE), 157 ('Opcode', BYTE), 158 ('Task', WORD), 159 ('Keyword', ULONG), 160 ) 161 162class BOOKMARK(NDRSTRUCT): 163 structure = ( 164 ('BookmarkSize', DWORD), 165 ('HeaderSize', '<L=0x18'), 166 ('ChannelSize', DWORD), 167 ('CurrentChannel', DWORD), 168 ('ReadDirection', DWORD), 169 ('RecordIdsOffset', DWORD), 170 ('LogRecordNumbers', ULONG_ARRAY), 171 ) 172 173 174#2.2.17 RESULT_SET 175class RESULT_SET(NDRSTRUCT): 176 structure = ( 177 ('TotalSize', DWORD), 178 ('HeaderSize', DWORD), 179 ('EventOffset', DWORD), 180 ('BookmarkOffset', DWORD), 181 ('BinXmlSize', DWORD), 182 ('EventData', BYTE_ARRAY), 183 #('NumberOfSubqueryIDs', '<L=0'), 184 #('SubqueryIDs', BYTE_ARRAY), 185 #('BookMarkData', BOOKMARK), 186 ) 187 188################################################################################ 189# RPC CALLS 190################################################################################ 191 192class EvtRpcRegisterLogQuery(NDRCALL): 193 opnum = 5 194 structure = ( 195 ('Path', LPWSTR), 196 ('Query', WSTR), 197 ('Flags', DWORD), 198 ) 199 200class EvtRpcRegisterLogQueryResponse(NDRCALL): 201 structure = ( 202 ('Handle', CONTEXT_HANDLE_LOG_QUERY), 203 ('OpControl', CONTEXT_HANDLE_OPERATION_CONTROL), 204 ('QueryChannelInfoSize', DWORD), 205 ('QueryChannelInfo', EvtRpcQueryChannelInfoArray), 206 ('Error', RPC_INFO), 207 ) 208 209class EvtRpcQueryNext(NDRCALL): 210 opnum = 11 211 structure = ( 212 ('LogQuery', CONTEXT_HANDLE_LOG_QUERY), 213 ('NumRequestedRecords', DWORD), 214 ('TimeOutEnd', DWORD), 215 ('Flags', DWORD), 216 ) 217 218class EvtRpcQueryNextResponse(NDRCALL): 219 structure = ( 220 ('NumActualRecords', DWORD), 221 ('EventDataIndices', DWORD_ARRAY), 222 ('EventDataSizes', DWORD_ARRAY), 223 ('ResultBufferSize', DWORD), 224 ('ResultBuffer', BYTE_ARRAY), 225 ('ErrorCode', ULONG), 226 ) 227 228class EvtRpcQuerySeek(NDRCALL): 229 opnum = 12 230 structure = ( 231 ('LogQuery', CONTEXT_HANDLE_LOG_QUERY), 232 ('Pos', LARGE_INTEGER), 233 ('BookmarkXML', LPWSTR), 234 ('Flags', DWORD), 235 ) 236 237class EvtRpcQuerySeekResponse(NDRCALL): 238 structure = ( 239 ('Error', RPC_INFO), 240 ) 241 242class EvtRpcClose(NDRCALL): 243 opnum = 13 244 structure = ( 245 ("Handle", CONTEXT_HANDLE_LOG_HANDLE), 246 ) 247 248class EvtRpcCloseResponse(NDRCALL): 249 structure = ( 250 ("Handle", PCONTEXT_HANDLE_LOG_HANDLE), 251 ('ErrorCode', ULONG), 252 ) 253 254class EvtRpcOpenLogHandle(NDRCALL): 255 opnum = 17 256 structure = ( 257 ('Channel', WSTR), 258 ('Flags', DWORD), 259 ) 260 261class EvtRpcOpenLogHandleResponse(NDRCALL): 262 structure = ( 263 ('Handle', PCONTEXT_HANDLE_LOG_HANDLE), 264 ('Error', RPC_INFO), 265 ) 266 267class EvtRpcGetChannelList(NDRCALL): 268 opnum = 19 269 structure = ( 270 ('Flags', DWORD), 271 ) 272 273class EvtRpcGetChannelListResponse(NDRCALL): 274 structure = ( 275 ('NumChannelPaths', DWORD), 276 ('ChannelPaths', WSTR_ARRAY), 277 ('ErrorCode', ULONG), 278 ) 279 280################################################################################ 281# OPNUMs and their corresponding structures 282################################################################################ 283 284OPNUMS = { 285 5 : (EvtRpcRegisterLogQuery, EvtRpcRegisterLogQueryResponse), 286 11 : (EvtRpcQueryNext, EvtRpcQueryNextResponse), 287 12 : (EvtRpcQuerySeek, EvtRpcQuerySeekResponse), 288 13 : (EvtRpcClose, EvtRpcCloseResponse), 289 17 : (EvtRpcOpenLogHandle, EvtRpcOpenLogHandle), 290 19 : (EvtRpcGetChannelList, EvtRpcGetChannelListResponse), 291} 292 293################################################################################ 294# HELPER FUNCTIONS 295################################################################################ 296 297def hEvtRpcRegisterLogQuery(dce, path, flags, query='*\x00'): 298 request = EvtRpcRegisterLogQuery() 299 300 request['Path'] = path 301 request['Query'] = query 302 request['Flags'] = flags 303 resp = dce.request(request) 304 return resp 305 306def hEvtRpcQueryNext(dce, handle, numRequestedRecords, timeOutEnd=1000): 307 request = EvtRpcQueryNext() 308 309 request['LogQuery'] = handle 310 request['NumRequestedRecords'] = numRequestedRecords 311 request['TimeOutEnd'] = timeOutEnd 312 request['Flags'] = 0 313 status = system_errors.ERROR_MORE_DATA 314 resp = dce.request(request) 315 while status == system_errors.ERROR_MORE_DATA: 316 try: 317 resp = dce.request(request) 318 except DCERPCException, e: 319 if str(e).find('ERROR_NO_MORE_ITEMS') < 0: 320 raise 321 elif str(e).find('ERROR_TIMEOUT') < 0: 322 raise 323 resp = e.get_packet() 324 return resp 325 326def hEvtRpcClose(dce, handle): 327 request = EvtRpcClose() 328 request['Handle'] = handle 329 resp = dce.request(request) 330 return resp 331 332def hEvtRpcOpenLogHandle(dce, channel, flags): 333 request = EvtRpcOpenLogHandle() 334 335 request['Channel'] = channel 336 request['Flags'] = flags 337 return dce.request(request) 338 339def hEvtRpcGetChannelList(dce): 340 request = EvtRpcGetChannelList() 341 342 request['Flags'] = 0 343 resp = dce.request(request) 344 return resp 345 346