Malware is constantly evolving. As the different types do so, they find new ways to bypass security solutions and try to slip under the radar of security companies to become more persistent and hide their identity. During the last year, Avira researchers have been monitoring and investigating a loader family. The loader caught our attention because of the anti-analysis methods it implemented throughout its infection cycle.
Once the loader is activated, the payload can trigger a chain of events that eventually result in the installation of adware, bots , pay-per-install campaigns, and even other Trojan Downloaders.
We were seeing DLLs with the name msimg32.dll being loaded by an executable named setup.exe. Even though the former is not an original Windows DLL, both of them were part of the archive, with the archive typically containing one further resource DLL. The msimg32.dll libraries—each always containing setup.exe – with the remaining two files changing daily.
In general the Portable Executable attributes of the DLL were constantly changing, except one: The export name “AlphaBlend”. The DLL came packed using one of many popular packers like UPX, MPress, VMProtect, or using custom packers.
Figure 1: Exporting of msimg32.dll
The msimg32.dll library was executed in the analysis environment, but it failed to execute. So before we began our static analysis of the file, we assumed that it may have failed to execute because the DLL expects to be loaded by the setup.exe file along with the resource DLL. Consequently, we decided to find the archive—which we achieved with the help of Avira Threat Intelligence. The archive was always called something like “setup.zip” or “setup_<4-digit random number>.zip”.
The file setup.exe is a digitally signed clean file, and is a component of the software.
Unfortunately this time, even with the complete archive, the sample failed to execute in the analysis environment which included both virtual and physical environments. When we executed the sample, an error message was thrown:
As our attempt to run the sample failed, it made us even more curious to investigate it further. So we started digging into the code of msimg32.dll to find out exactly why the sample didn’t execute.
After initial unpacking, the sample starts to calculate the base address of the kernel32.dll from the TEB (Thread Environment Block)—a typical method used by malware to retrieve the API addresses required for it to execute.
Figure 4: Base address calculation of kernel32.dll
Figure 5: Relevant APIs retrieved in the first stage
After resolving the APIs, the DLL collects certain information listed below:
- It uses RegOpenKeyExW to check if HKCU\Software has the Avira or ESET key name in it, and then stores the result.
- It loads the resource DLL (second DLL in the archive), then loads a string from the resource DLL and internally compares it to the string present in msimg32.dll
- It retrieves the DNS cache of the machine for which the malware uses the DnsGetCacheDataTable API function to do. The malware checks the result of the DNS cache entries for three strings (see below for the list of domains).
- The sample checks if it has admin privileges by checking if it has access to SeRestorePrivilege using LookupPrivilegeValueA. It then launches itself with the command line “a70a003acda2a13c1bad50d2ba0139ac” to become an administrator user. A normal Windows UAC prompts appears—but this is only natural as since the process name “setup.exe” is a special process name.
Windows UAC window will be prompted anyhow.
Figure 6: Strings that are searched for in the DNS cache entry
Based on an evaluation of the information collected in the first stage, the DLL decides to continue or not. See below for the conditions that must be satisfied:
- If the Avira or ESET key is present in the registry under HKCU\Software, it stops execution and exits.
- If the string from the resource DLL doesn’t match the string in the loader DLL, the loader stops execution and exits. Here, the loader confirms it executes from the whole archive by checking the integrity of the resource DLL.
- If “.avira” or “.eset” is present in the DNS cache, it stops execution and exits.
- It retrieves the command line of the running process and checks if it contains “a70a003acda2a13c1bad50d2ba0139ac”.
- If “dms.images.consumer” isn’t present in the DNS cache, it stops execution and exits.
a) Checks for the AVIRA key in the registry
b) Compares local decrypted string with string loaded from accompanying DLL inside the archive
c) Calls to DnsGetCacheDataTable
d) Searches for the “.eset” string in the retrieved DNS cache list
e) Looks for the specific string in the DNS cache
Figure 7: Sequence of checks
Of all the checks, the one which stands out the most was the one for the specific string “dms.images.consumer“. This string was searched for within each entry inside the DNS cache—meaning that if it is found, victims will have visited this page previously. The string looks like part of a domain name and not a complete one. None of our telemetry sensors concluded that this was targeted, so all victims had this in their DNS cache. Consequently, we assumed that this was part of an infection chain to make the user visit the website containing the string “dms.images.consumer”. Still, questions persisted such as how come so many users ended up getting infected. To find out why, we needed to identify how these setup.zip archives were getting onto each victim’s machine.
Why is “dms.images.consumer” important?
Before finding out how the setup.zip files ended up on the machine, we needed to determine why the domain with the string “dms.images.consumer” is important for execution of the sample. So to find that out, we just patched the result in a debugger to make the malware believe our analysis machines had the domain containing the required string. While allowing the code to continue, we found that the malware is interested in the last eleven characters of the domain name contain the string “dms.images.consumer”. Consequently, it was expecting something like this in the cache: “dms.images.consumerXXXXXXXXXXX”, whereby it appends the last eleven characters with the string “13d32” as perhaps some sort of marker. So the value that it stores is
“XXXXXXXXXXX13d32”, but we don’t yet know what will appear in place of X.
The next stage involves the code resolving the next set of APIs. See below for the key ones:
Figure 8: Relevant APIs involved in the second stage
After resolving the relevant APIs, the malware loads the accompanying DLL present in the same directory. It loads the DLL with the LOAD_LIBRARY_AS_DATAFILE flag using the LoadLibraryExW API, then loads the resource named RCDATA. After this, it tries to set up the decryption platform using Bcrypt.dll. Here are the steps:
- It calls BCryptOpenAlgorithmProvider and sets the provider to AES.
- It calls BCryptGetProperty for the pszProperties ObjectLength & BlockLength.
- It calls BCryptSetProperty for the pszProperties ChainingMode & ChainingModeCBC.
- It calls BCryptGenerateSymmetricKey.
- The fifth argument, pbSecret points to the last eleven characters of “dms.images.consumer” + “13d32”, so now it is “XXXXXXXXXXX13d32”. Consequently, we know we will not generate the required key object and fail.
- It calls BCryptDecrypt
- The second argument, pbInput, is a pointer to the resource data loaded earlier, which is in an accompanying DLL present in the same directory.
Right now we can’t execute decryption since we don’t have a proper secret key.
Initial infection vector
Now we know why “dms.images.consumer” is important, so now we have to find the domain name which contains “dms.images.consumer”. A simple pattern match in a URL database should have been enough, but that won’t exactly answer the question as to how did the DNS cache of so many users machines end up containing this domain name. So we need to find out what the initial infection vector was. The first thing we checked was where these setup.zip files are hosted. Most of the time the setup.zip files are hosted on clean websites, which attackers hack and use as host platforms. Most of the clean websites were running outdated web servers, making it easy for attackers to run file upload vulnerability exploits.
Irrespective of this, the domain name of each clean website didn’t contain the string “dms.images.consumer”. So at this stage it is clear that users may have been victims of a drive-by download attack or social engineering scam. So we started looking back into our telemetry and began noticing that in many cases the sample was executed inside the installation directory of popular software and games. Why would a user run the sample “setup.exe” from these directories? The answer is that these victims were trying to install fake cracks believing them to be genuine.
Spreading malware through cracks, or keygens, isn’t new, but actors behind this campaign are always very successful in getting malware into many machines. Every day, new victims from all over the world fall prey—so there must be something driving these users to fake crack websites. If we are able to find these fake crack websites and trigger a download to get setup.zip, we should be able to find the domain which contained the string “dms.images.consumer”.
The search engine connection
We started the same way as any normal user would when searching for cracks. See below for our list of what we would expect an average-Joe user would do to download a crack and execute it—which of course is an assumption on our part:
- Visit any popular search engine like Google or Yahoo!
- Search using keywords like “any popular software name” + “crack or serial number or full version”
- Most probably visit the top 10 pages
- Download the crack, copy it to the target software install directory, and execute it
So if the attackers are successful at getting into the top 10 search results, there is a high probability that the user may visit the website and fall victim. Search engines uses various algorithms and methods to rank the websites based on search keywords. It’s something we won’t address here, but for a detailed guide see here
So assuming the above, we performed a search using google.com as our search engine. And our assumption proved correct, as we were able to obtain a setup.zip file by these means. Immediately, we checked our analysis machines to verify if we had the domain name containing the string “dms.images.consumer” in DNS Cache.
When we went through the returned search results, we noticed multiple websites being hosted on Weebly.com. Weebly is a free web hosting service that offers many SEO
features too. We were interested only in those pages hosted on Weebly because we were able find multiple pages all with some sort of the same pattern in their code when performing a search using the same keyword. So we fine-tuned our search and added one more keyword: “weebly”.
Figure 9: Search results from keyword: Double Cad,serial number,weebly
Figure 9.1: Search results from keywords: Autodesk,serial number, weebly
We decoded the script and identified that there are two layers before the actual check is completed and a fake download page pops up.
In the second layer, the script checks if “document.referrer” contains any of the entries listed in Figure 12. If not, the script will skip popping up the fake download page and additionally check if the user agent doesn’t match any of the entries listed in Figure 13. This comprehensive check of both aspects is done to avoid serving content to crawlers that visit the URL directly without referrers.
Figure 12: List of accepted referrers
Figure 13: List of blocked user agents
Figure 14: Script that avoids crawlers and pops-up a fake download page
After passing the above checks, a fake download page pops up that tricks the user into clicking the download button. Then, a few redirects happen before the setup.zip file drops onto the machine. While analyzing the traffic, we were able to find the response which provides the download link to setup.zip. It also contained an iframe that loads an image from https://crdms.images.consumerreports.org/t_pcard_sm,dpr_2.0,w_200,c_scale/prod/products/cr/product-groups/28984 measuring 1px X 1px , which in turn updates the DNS cache with the domain name crdms.images.consumerreports.org. Now it is clear how the domain name containing the string “dms.images.consumer” is present in the DNS cache of each victim’s machine. Additionally the response had an IP fingerprinting function.
Figure 16: Response with download link and DNS cache entry for decryption
While tracking this threat, we noticed that most of the time attackers, are hacking clean websites and hosting the malware. We also spotted that the hacked clean websites are poorly configured using outdated web server versions, making life easier for the attacker to hunt for and exploit these kinds of websites.
Figure 17: Hosted malware example 1, Open Directory
Figure 18: Hosted malware example 2, Open Directory
Armed with the Decryption key
Now armed with knowledge about how the pre-execution check works, it is easy to reproduce this in the analysis environment. That said, we did a bit more static analysis just to confirm if any more checks were still happening before the loader proceeds. This time we edited the value of the argument “pbSecret” to “reports.org13d32” which is passed to the BCryptGenerateSymmetricKey API. The decrypted resource was a shell code which resolves a set APIs. It then enumerates the whole process using K32EnumProcesses. As a next step it uses Process IDs to retrieve the handle to process using the OpenProcess function, and from the retrieved handles it loops to find the file path of all loaded processes using GetModuleFileName. From the list of file paths of the loaded process, it searches for the Avira process names listed below. If found, it won’t execute further and exits the programs.
Figure 19: Avira Antivirus process
The loader’s next step is to decrypt the server URL and request an update. Based on the response, the loader decides how to continue processing.
Figure 20: Connecting to the update server
From our analysis we noticed that the server URL changes quite often, but the domain registration pattern and page to which the request is directed doesn’t:
domain name pattern—<alphabet, length 6~8>-cloud.icu. “-cloud.icu” has been present in the domains for a long time.
page—”update.php” was the page name in all the samples we’ve analyzed so far.
In the next stage of execution, the loader drops further components into the directory under “%windir%\System32\microsoft\protect\S-<random>\ or “%windir%\Syswow64\microsoft\protect\S-<random>\ and marks ownership of the folder and files to NT AUTHORITY\SYSTEM and attributes to Hidden and System.
Figure 21: List of further components dropped by the loader
RB_22.214.171.124.exe—Clean Apple Push executable, which imports AppleVersions.dll. Naming of the file is random, but the prefix is always RB_.
msvcp100.dll & msvcr100.dll—Microsoft® C Runtime Library.
AppleVersions.dll & data.dll—Second stage component of the loader, which decides whether a further payload is dropped to the machine
RB_126.96.36.199.exe loads AppleVersions.dll due to DLL search Order Hijacking
Final Stage components are dropped by Second Stage Components of the Loader
TiWorker.exe – Clean Sysinternals tool NotMyfault
Riched32.dll – Final Stage component of the loader
Final stage components are usually dropped under “%windir%\System32\<random>\S-<random>\” or “%windir%\Syswow64\<random>\S-<random>\” .
TiWorker.exe loads Riched32.dll due to DLL search Order Hijacking , not directly imported by NotMyfault tool but internally loads it using LoadLibrary API
The loader tries to disable Windows Defender features by altering the corresponding Windows Defender registry settings.
Figure 22: Altering Windows Defender settings
The loader alters the machine’s power scheme using the Windows utility powercfg.exe. The commands listed below are typically used by coin miners and keep the machine running even though the user isn’t actually using it. In this case, the loader seeks to actively install further payloads like pay-per-install campaigns.
Figure 23: Altering the power scheme
The loader schedules the Apple Push (RB_188.8.131.52) executable to run every 15 minutes indefinitely, with the loader leveraging taskschd.dll to achieve this.
Figure 24: Loader persistence
The payload varied each time the loader was activated. Of course, the loader may behave differently based on the particular system and victim’s geographical location. One thing we noticed during multiple runs of the loader was that in most cases the download assistant was dropped to the %Temp% directory with the filename run_<6-digit random number>.exe or just <6-digit random number>.exe. See below for a list of each malware family that got into the machine directly or indirectly while the loader was activated. The payloads never stayed the same and always varied.
Figure 25: Malware dropped by the loader during one of the successful execution attempts
CoinLoader is a highly sophisticated campaign that has been running for at least a year. It updates its components on a daily basis, ranging from files to hosting URLs. It also tries to evade security solutions through various means, from initial infection vectors to the final payloads.
Figure 26: Execution flow of CoinLoader
CoinLoader abuses free web hosting services, exploits poorly configured clean websites to host its payloads, and further abuses clean software using DLL search order hijacking. Ultimately, the main reason for its success is due to users still falling victim to social engineering scams. CoinLoader once again proves that social engineering still plays a major role in spreading malware.
All components associated with the CoinLoader family are detected by Avira as TR/CoinLoader.Gen & TR/AD.CoinLoader.B
T1027– Obfuscated Files or Information
T1038– DLL Search Order Hijacking
T1043– Commonly Used Port
T1053– Scheduled Task
T1059– Command-Line Interface
T1089– Disabling Security Tools
T1129– Execution through Module Load
T1158– Hidden Files and Directories
IOC: CoinLoader Full IOC List available here