{
	"id": "e9dc9a36-7a3c-4524-8eca-f997f1c01723",
	"created_at": "2026-04-06T00:20:17.789688Z",
	"updated_at": "2026-04-10T03:22:57.003944Z",
	"deleted_at": null,
	"sha1_hash": "e3134e97ec5e12490901ccda2827357cca652bba",
	"title": "Detecting COR_PROFILER manipulation for persistence | Red Canary",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 108495,
	"plain_text": "Detecting COR_PROFILER manipulation for persistence | Red\r\nCanary\r\nBy susannah.matt@redcanary.com\r\nArchived: 2026-04-05 12:58:33 UTC\r\nEditor’s note: We originally published this article on May 7 as part of our Blue Mockingbird research. MITRE\r\nhas since added the COR_PROFILER technique detailed in this blog to the ATT\u0026CK® Framework. As such, we\r\nwanted to present this work to our readers again—and add references to its new ATT\u0026CK page:\r\nCOR_PROFILER (T1574.012). \r\nWe believe that security teams should prioritize their detection efforts according to the threats that are most likely\r\nto affect them. In fact, that’s one reason we produce our annual Threat Detection Report, which analyzes the top\r\nMITRE ATT\u0026CK techniques observed across our customer base and by industry.\r\nWhen it comes to persistence, Scheduled Task (T1053) ranked second overall and even topped the list for a couple\r\nof industry verticals in 2019. Today, we’d like to talk about a novel form of persistence that the Red Canary Cyber\r\nIncident Response Team (CIRT) has observed an adversary leveraging in multiple incident response (IR)\r\nengagements. My colleague Tony Lambert has broken down the adversary behaviors and TTPs in this blog post.\r\nComponent Object Model (COM) hijacking (T1122) did not come anywhere close to the top of our 2020 report (it\r\nbarely cracked the top 100). This doesn’t mean it isn’t leveraged by adversaries—rather, it’s usually the same\r\n“tried and true” methods of persistence (scheduled tasks, autorun registry keys, services, etc.) that we see used\r\nover and over again that dominate our Threat Detection Report. This is why we urge new security teams to focus\r\non detecting the most likely forms of persistence.\r\nAn adversary we’ve dubbed “Blue Mockingbird” leveraged multiple forms of persistence when deploying their\r\nprimary payload consisting of XMRIG packaged as a dynamic link library (DLL), including:\r\nScheduled Tasks (T1053)\r\nModify Existing Service (T1031)\r\nNew Service (T1050)\r\nCOM Hijack using COR_PROFILER (T1574.012)\r\nWe have detection logic for catching each of the techniques listed above, but the COR_PROFILER technique is\r\npretty unusual. So let’s take a closer look.\r\nCOR_PROFILER for managed code development\r\nThe .NET framework supports the loading of an unmanaged (something outside the .NET framework like C++,\r\nwhich interacts directly with hardware) profiler DLL as a code profiler to monitor a managed application. This\r\nfeature is intended to allow the unmanaged profiler DLL to load into any .NET process and interact directly with\r\nhttps://redcanary.com/blog/cor_profiler-for-persistence/\r\nPage 1 of 7\n\ncallback interfaces through a profiling API to receive information about the state of the profiled application.\r\nEssentially, this means .NET developers can measure their managed code performance with an unmanaged DLL,\r\nwhich aids in troubleshooting and debugging their managed application.\r\nFor our purposes, we will be looking at startup-load profilers, which are attached to the unmanaged profiler when\r\na managed application starts. A startup-load profiler can be registered by adding a few environment variables. Per\r\nMicrosoft:\r\nCOR_ENABLE_PROFILING=1\r\nA value of 1 will enable the COR_PROFILER , while 0 will disable it.\r\nCOR_PROFILER={CLSID of profiler}\r\nPrior to .NET Framework 4, this CLSID must be specified and map to a COM object specifying the\r\nlocation of the profiling DLL on disk. This can be any CLSID of the attackers choosing.\r\nCOR_PROFILER_PATH=full path of the profiler DLL\r\nThis environment variable was added with .NET Framework 4 and will skip searching the Registry for the\r\ncorresponding COM object specified in the COR_PROFILER environment variable for the path to the\r\nprofiling DLL on disk. If COR_PROFILER_PATH is set, any arbitrary CLSID can be used for the\r\nCOR_PROFILER environment variable.\r\nIn Windows, environment variables can have three scopes. The location of the COR_PROFILER environment\r\nvariable definition dictates which types of processes will be profiled. Knowledge of these scopes can help inform\r\na detection strategy when environment variables are abused.\r\nMachine (or system) scope\r\nMachine environment variables are inherited by all downstream users and processes. Modifying machine\r\nenvironment variables requires administrative permissions. These environment variables are stored in the\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment registry hive.\r\nBlue Mockingbird leveraged this type of environment variable, resulting in a more reliable persistence\r\nmechanism as all .NET processes loaded the malicious profiling DLL regardless of whether or not a user\r\nwas logged on.)\r\nUser scope\r\nUser scope environment variables are only available to individual users and include all machine\r\nenvironment variables. These are stored in the current user registry hive at\r\nHKEY_CURRENT_USER\\Environment and in each respective user hive. For example, here is where the system\r\naccount environment variables are stored: HKEY_USERS\\S-1-5-18\\Environment\r\nhttps://redcanary.com/blog/cor_profiler-for-persistence/\r\nPage 2 of 7\n\nProcess scope\r\nProcess environment variables are constructed from the machine and user scope environment variables.\r\nChild processes inherit any process scope environment variables from their parent process. Process scope\r\nenvironment variables are only available to the current process and any of its children. These variables are\r\ngenerally set using something like the SET command in Command Prompt, the $Env PowerShell variable,\r\nor by the Environment.SetEnvironmentVariable .NET method. This is generally where a conservative .NET\r\ndeveloper would place their COR_PROFILER environment variables.\r\nCOR_PROFILER and COM\r\nEarly versions of .NET Framework required the COR_PROFILER to be attached to a COM object in the registry.\r\nBeginning with .NET Framework 4, a registry-free COR_PROFILER can be configured by specifying the\r\nCOR_PROFILER_PATH to the unmanaged profiling DLL on disk and any arbitrary CLSID. The CLSID does not\r\nneed to actually exist in the registry as the CLR will load the specified DLL in COR_PROFILER_PATH without\r\ninitializing COM.\r\nCOR_PROFILER and red teams\r\nIn May 2017, Casey Smith wrote a blog post outlining the potential for this feature to be abused by an adversary\r\nto hijack legitimate .NET processes and load a malicious unmanaged DLL. Since then a few researchers and red\r\nteam bloggers have expanded on this technique as a method of persistence, bypassing User Account Control\r\n(UAC) (T1088) and Applocker restrictions when DLL enforcement is not turned on. There is also Invisi-Shell,\r\nwhich leverages a DLL profiler to hook .NET assemblies responsible for PowerShell’s logging and the\r\nAntimalware Scanning Interface (AMSI).\r\nRegistry-free process scope COR_PROFILER\r\nhttps://redcanary.com/blog/cor_profiler-for-persistence/\r\nPage 3 of 7\n\nCOR_PROFILER in the wild\r\nThere are multiple methods of modifying the environment variables required to configure the COR_PROFILER . For\r\nexample, Reg.exe, Setx, and the Registry Editor ( regedit.exe ) are good candidates. Blue Mockingbird\r\nemployed the Windows Management Instrumentation (WMI) command-line utility, Wmic.exe , to add the\r\nCOR_PROFILER as machine (system) environment variables. You can see a complete list of the commands Blue\r\nMockingbird leveraged in my colleague Tony’s blog post.\r\nWe have observed adversaries registering the CLSID COM interface specified in the COR_PROFILER environment\r\nvariable in the Windows Registry to ensure backwards compatibility on machines with versions of .NET\r\nFramework lower than version 4. This makes sense, as an adversary will want to ensure their persistence\r\nmechanisms are resilient and work regardless of the environment. If the machine they land on is running .NET\r\nFramework 4, the malicious DLL specified in the COR_PROFILER_PATH will be loaded and the COM interface will\r\nnot be used.\r\nIf the machine is running versions of .NET Framework lower than 4 and the COR_PROFILER_PATH environment\r\nvariable is supplied, the technique will still work as the malicious DLL in the registered COM interface will be\r\nloaded.\r\nIn our experience with the COR_PROFILER technique, what results is a stealthy persistence mechanism that\r\nexecutes each time any process loads the .NET CLR. Native Windows processes like PowerShell and the\r\nMicrosoft Management Console ( mmc.exe ) load the .NET CLR, and any installed application written in .NET\r\nwill load the CLR. This results in the malicious profiling DLL loading into the memory space of each of those\r\nprocesses and deploying more traditional forms of persistence like services and scheduled tasks that seemingly\r\nappear out of thin air.\r\nIt’s worth noting the malicious profiling DLLs we’ve observed in IR engagements were not detected by antivirus\r\nscanners on VirusTotal. It’s also worth noting that Microsoft’s Autoruns does not check for the COR_PROFILER\r\nleveraged for persistence.\r\nDetection Analytics\r\nTo aid defenders in detecting malicious COM Hijacking and UAC bypass leveraging the COR_PROFILER , we’ve\r\nreleased three Atomic Red Team tests. The first test uses user scope environment variables and registers a COM\r\nobject in the Registry. This test leverages PowerShell to modify COR_PROFILER user scope environment variables\r\nin the Windows Registry and deploys an unmanaged payload DLL written in C++.\r\nHere is an example of what the user scope environment variable modifications look like in endpoint detection and\r\nresponse (EDR) telemetry:\r\nhttps://redcanary.com/blog/cor_profiler-for-persistence/\r\nPage 4 of 7\n\nThe second Atomic Red Team test leverages machine (system) scope COR_PROFILER environment variables\r\nsimilarly to how we have observed adversaries abuse this technique, with a slight twist. This test does not add a\r\nCOM object associated with the CLSID GUID we set in the COR_PROFILER environment variable. This technique\r\nrequires .NET Framework 4 or higher, which ships with all modern versions of Windows. This technique also\r\nrequires the machine to reboot for the system environment variables to take effect.\r\nHere is an example of what the system scope environment variable modifications look like:\r\nThe third test leverages Registry-free user scope COR_PROFILER environment variables. Again, .NET\r\nFramework 4 is required. This technique will not bypass UAC.\r\nHere is an example of the unmanaged profiling DLL loading into PowerShell shortly after the CLR is loaded:\r\nDetection strategies should focus on suspicious modifications to the environment variables associated with the\r\nCOR_PROFILER in the System and User registry hives. This will ensure you can detect COR_PROFILER\r\nmodifications regardless of the method employed to set environment variables.\r\nUser scope:\r\nHKEY_USERS\\\u003cuser_sid\u003e\\environment\\cor_enable_profiling\r\nHKEY_USERS\\\u003cuser_sid\u003e\\environment\\cor_profiler\r\nHKEY_USERS\\\u003cuser_sid\u003e\\environment\\cor_profiler_path\r\nMachine (system) scope environment variables can be detected by looking for the same registry modification in\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\\ :\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\\cor_enable_profiling\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\\cor_profiler\r\nhttps://redcanary.com/blog/cor_profiler-for-persistence/\r\nPage 5 of 7\n\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\\cor_profiler_path\r\nNote: process scope environment variables are stored in memory. Higher integrity child processes do not inherit\r\nthese environment variables if their parent process is of a lower integrity, therefore, UAC is not bypassed.\r\nInvestigation should focus on the malicious profiler DLL written to disk and loading shortly after the CLR\r\n( clr.dll ) is loaded in the victim processes. The telemetry presented below shows our Atomic Red Team T1122\r\ntests loading the unmanaged DLL payload into mmc.exe and executing the legitimate notepad.exe as a child\r\nprocess. If system or user scope COR_PROFILER are leveraged and run with an administrative account, this\r\ntechnique will also bypass UAC.\r\nAgain, any arbitrary CLSID COM interface (GUID) can be specified. With .NET Framework 4, the COM\r\ninterface does not need to exist as long as the COR_PROFILER_PATH environment variable points to the location of\r\nthe profiling DLL on disk.\r\nIn our research, leveraging wmic.exe to modify the COR_PROFILER environment variables has been directly\r\nassociated with adversary activity. Some legitimate developer debugging tools, like Ncover or AppDynamics, may\r\nread or delete the COR_PROFILER registry keys, but it’s less likely you’ll see these tools repeatedly writing data\r\ninto these registry keys.\r\nMitigations\r\nThe COR_PROFILER is a legitimate method developed by Microsoft for profiling managed applications. There\r\ndoesn’t appear to be a method for disabling the feature to prevent adversaries from using for persistence. As with\r\nother techniques that abuse system features, it’s best to have a solid detection strategy.\r\nIt is possible to mitigate the UAC bypass by ensuring proper segmentation of administrative accounts. We\r\nrecommend ensuring administrative accounts are not used for day-to-day operations by implementing Least-Privilege Administrative Models.\r\nClosing thoughts\r\nWhen leveraged maliciously, the COR_PROFILER can be a highly effective form of persistence that has the added\r\nbenefit of bypassing UAC. This technique can also bypass AppLocker as DLL enforcement is not typically\r\nenabled by default. Defenders can audit the Registry keys associated with the COR_PROFILER and create high\r\nsignal-to-noise methods for detection.\r\nhttps://redcanary.com/blog/cor_profiler-for-persistence/\r\nPage 6 of 7\n\nIf you’ve seen the COR_PROFILER leveraged for persistence, bypassing UAC, or in other ways, please reach out—\r\nwe would love to hear from you. You can also join the Atomic Red Team Slack and share your thoughts,\r\nimprovements, and questions about the COR_PROFILER tests.\r\nSource: https://redcanary.com/blog/cor_profiler-for-persistence/\r\nhttps://redcanary.com/blog/cor_profiler-for-persistence/\r\nPage 7 of 7",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://redcanary.com/blog/cor_profiler-for-persistence/"
	],
	"report_names": [
		"cor_profiler-for-persistence"
	],
	"threat_actors": [
		{
			"id": "e568e9d7-ae94-4ce5-9039-4fd17c731c1d",
			"created_at": "2022-10-25T15:50:23.491763Z",
			"updated_at": "2026-04-10T02:00:05.342897Z",
			"deleted_at": null,
			"main_name": "Blue Mockingbird",
			"aliases": [
				"Blue Mockingbird"
			],
			"source_name": "MITRE:Blue Mockingbird",
			"tools": [
				"FRP",
				"Mimikatz"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434817,
	"ts_updated_at": 1775791377,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/e3134e97ec5e12490901ccda2827357cca652bba.pdf",
		"text": "https://archive.orkl.eu/e3134e97ec5e12490901ccda2827357cca652bba.txt",
		"img": "https://archive.orkl.eu/e3134e97ec5e12490901ccda2827357cca652bba.jpg"
	}
}