Raccoon is a malware written in C++. It came to my attention while looking at my twitter feed and spotting a tweet from @tkanalyst. I was not aware of it, and as a malware analyst working at a sandbox company(tria.ge), I wanted immediately to analyze it and develop signatures. Also, I have not any background in Threat Intel or attribution, so the name was chosen due to @tkanalyst tweet.
The sample that was analyzed has the following information:
- MD5 HASH (Packed) : 126ed436b3531dd857b25b9da2c80462
- MD5 HASH (Unpacked): 3367E9FC3CDBE03D65460E5BF86EE16B
- Raccoon Version: 1.2
Generally, the sample is a typical infostealer malware. It checks for the existence of various types of applications such as browsers, email clients, coin wallets and attempts to steal their data by reading their configuration files or databases. The execution of the malware is closely related with the configuration that the CnC server will send, thus there is an obstacle during the dynamic analysis if the CnC domain is down. In our case this was solved by writing a module in Fakenet-NG and emulating the responses of the CnC(Figure 1).
While I am not that fond of malware written in C++ for obvious reasons, Raccoon was not that complicated - it does not have any ANTI - methods, and its execution is straight forward. With the help of FLIRT signatures if correctly applied, the static analysis can become a lot easier. While spending some time doing static analysis, I noticed some patterns for string decryption. The majority of the strings are encrypted with a combination of bitwise NOT/XOR (depending on the sample)(Figure 2,3). To make my life easier and to practice my IDApython skills, I created a script in order to search and decrypt these strings: . Some main points from the script:
- It has two major functions responsible for reading ASM instructions and gathering the data and decrypting it.
- It is based on pre-defined regex for deciding whether there is potential encrypted data. There is often overlap between the addresses which is solved by checking the decrypted strings and deciding which one is valid.
- It's really easy to fix a decrypted string that it is wrong or was overwritten by another pattern - you just call one of the two available functions having as a parameter the address of the instruction that one believes to move data needed for the decryption of the string.
Starting to analyze the malware dynamically, the malware first checks for a mutex, in order to determine if an instance of it is already running. Specifically, the mutex's name is a result of a string decryption and concatenation with the current user's name. If the mutex does not exist, it is created and the function returns 1, else it returns 0. (Figure 4)
Immediately after that, the malware check the privilege that is executed with. Specifically, with the help of the token is determined whether the process is run from Local System group. If that's the case, then a snapshot of running processes is acquired, and it will try to duplicate a token(with higher privileges) from another one in order to call CreateProcessWithTokenW API, restarting with higher privileges.(Figure 5)
As it was mentioned in Cybereason's post, the malware checks the locale of the system against various other values such as: Russian, Ukrainian, Belarussian, Kazakh, Kyrgyz, Armenian, Tajik, and Uzbek.
In order to continue the execution, the malware needs to get its JSON config. The CnC server serving the config does not exist inside the sample - instead, the sample dynamically acquires its CnC via another request. The samples firstly proceeds into decrypting a RC4 key (1@zFg08*@45) which is further used to decrypt a URL and sample's Config ID. (Figure 6)
There are 2 hardcoded strings, encrypted with RC4 and encoded with base64 encoding .They also have multiple newline and space characters (probably to break static tool?). These strings are the URL of the first domain and the Config ID of the current sample. (Figure 7)
In the current sample, a request is performed towards a drive.google.com url followed, by a lookup in the response headers in order to locate two substrings: '.txt";filename*=UTF-8' and 'attachment;filename='(Figure 8,10). Their values are the RC4 encrypted CnC that is ought to respond later with a valid JSON configuration. (Figure 9). It should be noted that, the key RC4 key for decrypting the CnC domain is different than the one used before, but it is hardcoded in the sample (7effd829b15db71f1e5431670f17da25).
After that, it's time for the UUID of the infected workstation to be built. This is done by getting the machine GUID, user's name and the previously encrypted config in the sample all together concentrated. The parameter is encoded with base64 encoding and a POST request is performed to the previously decrypted CnC domain. (Figure 11, 12)
The malware ensures that a response is valid by either checking for the existence of the string 'Wrong config id' or by the string 'url'. Also, if the response does not contain the 'Wrong config id' but somehow contains the string 'url', will later fail during the parsing of the configuration. (C++ exceptions). (Figure 13)
If the JSON config is valid, then the the value of 'url' json property is acquired. Also, a folder is created in TEMP with named 'TrashCan' which was not used during execution. (Figure 14). It should be also noted that, all the file operations are performed via transactions, something that Fumiko, another malware researcher has described in one of his blog posts.
Another check of properties in the confiq occurs, for 'config' and 'mask'. If succesfull located the sample continues to create a string 'C:\\Users\\user\\AppData\\Local\\Temp\\Log.zip' for future usage. Another property check happens, for 'attachment_url'. If it exists, its value will be acquired, which in our case is a .dll. The malware will start preparing the ground to download and load the particular library.As it is common with Raccoon, a string is decrypted in memory and in this case it is 'sqlite3.dll'. Later, a full TEMP path will be built in order to be used by UrlDownloadToFileA to download and save the file.( Figure 15)
Then it proceeds into checking the value of the 'history_is_enabled' property and begins its first stealing operation - loading the dropped sqlite3.dll library getting the data from Chrome-like browsers by searching in specific folders. This is done by iterating an array of structures with size 18h, containing 4 offsets to various paths like Login Data, Cookies, Web Data and User Data for various browsers descendant of Chrome. The index is saved in ESI register while accessing the various members of the structures holding the information about the browsers. (Figure 16, 17)
Next, the sample attempts to steal all the data associated with Internet Explorer. This is done by calling three different functions, each aimed at stealing different data such as auto complete information, http basic authentication passwords stored in credentials store and finally data from Vault. The methods used here are known to the public and were detailed explained here. (Figure 18)
Lastly, another string is decrypted in memory 'libraries' and again its existence is checked against the response. If the property exists then the its value will be acquired resulting in a URL containing additional libraries. The sample will attempt to perform its next stealing operation targeting Firefox - like browsers by downloading the additional libraries, loading them and resolving the needed APIs in order to steal the data. It should be noted that, the path that the additional libraries were extracted is added as a value in the enviromental variable 'PATH'. (Figure 19)
Firstly the malware checks if the "C:\\Users\\user\\AppData\\Local\\Temp\\AdLibs\\nss3.dll" (Figure 20 ) exists in disk and if not, it then proceeds into downloading the set of libraries to the path "C:\\Users\\user\\AppData\\Local\\Temp\\AdLibs\\ff-funcs.zip" and unzip the libraries at "C:\\Users\\user\\AppData\\Local\\Temp\\AdLibs\\". Finally, the 'nss3.dll' library will be loaded and the associated APIs will be resolved in order to be used in the next function (Figure 21). The malware attempts to steal History, Signons, cookies, places.sqlite by looping again against an array of structures holding information for Firefox-like browsers.
Finishing with the browsers, the sample proceeds into stealing email data associated with Outlook browser. This was covered by Cybereason's blogspot so we will proceed into the next stealing operation - taking data from FoxMail client. It is thourogly checks for the existence of( Figure 22):
- D:\\Program Files\\Foxmail 7.2\\Storage
- D:\\Program Files (x86)\\Foxmail 7.2\\Storage
- D:\\Foxmail 7.2\\Storage
- C:\\Program Files\\Foxmail 7.2\\Storage
- C:\\Program Files (x86)\\Foxmail 7.2\\Storage
- C:\\Foxmail 7.2\\Storage
and collects all the relative data.
Finishing from stealing data from Email clients, next thing is to collect information from the infected workstation. The value of the 'IP' property is being parsed from the JSON response and then a function is responsible for gathering and writing to a file named 'machineinfo.txt' information. The installed programs are being determined by looping through the entries of 'SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall'(Table 1) . The information that is collected and written is the following (Figure 23, 24):
- PropertyValueRaccoon's versionHardcodedBuild Time:HardcodedBot IDConcatenation of strings (SOFTWARE\Microsoft\Cryptography\ MachineGuid + '_' + GetComputerNameA()System LanguageGetLocaleInfoA()UsernameGetUserNameA()External IP(Returned by the configuration)Windows versionSOFTWARE\Microsoft\Windows NT\CurrentVersion\ ProductNameSystem archGetSystemWow64DirectoryW()CPUCPUIDRAM (MB Used etc etc)GlobalMemoryStatusEx()Display DevicesEnumDisplayDevicesA()Screen ResolutionGetSystemMetrics()Installed APPsSOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersi on\Uninstall(Table 1)
The malware also has the capability of taking a screenshot. If the 'is_screen_enabled' property exists in the JSON config and its value is 1, then the malware will take a screenshot and saved it as screen.png in TEMP. (Figure 25)
Last but not least the sample looks for various crypto coin wallets and attempt to steal their data. There is a general search in the APPDATA for files named as 'wallet.dat' and after that, famous wallets are targeted such as (Figures 26,27):
- Ethereum Wallet
Finally, the sample is preparing for the exfiltration phase. That means collecting all the information that was written to Temp and zipping them up to a zip file named 'Log.zip'. The following files are searched up to be included in the zip and are products of the previous attempts to steal data:
- machineinfo.txt but included in the zip as System Info.txt
The additional libraries that were dropped in disk are deleted, and so all the files that were included in the zip file. Before the sample deletes itself and terminate its execution it does something interesting: it checks for the existence of property 'loader_urls' in the JSON config. If it exists, then the sample will generate a random 10 letter name, part of an executable path.(Picture). This will be the location that the executable will be downloaded from the URL, which is the value of the 'loader_urls'. The executable then will be executed. The file will be executed with the ShellExecuteW Windows API. (Figure 28)
Lastly, the malware deletes itself from the infected workstation by executing 'cmd.exe /C ping 126.96.36.199 -n 1 -w 3000 > Nul & Del /f /q "%s"' as it was stated in Cybereason's blogspot. One thing that comes in mind immediately after finishing the analysis is - did we miss to locate the way that the malware is acquiring persistence in the system, or it does not have any persistence method at all? In the next blogspot, we will discuss and analyze the PE file which was downloaded earlier and the way it is enforcing a persistence across the system. (Figure 29)
As it is normal for that kind of malware, there was a new version while this article was written. Another malware researcher Fumiko, was kind enough to point me to another Raccoon sample found in his tracker ( MD5:121f7cba18bcb38e68bd4fc4f2e71815 ). During a quick static analysis by running our IDAPython script, it was revealed that there was indeed a new version, specifically called '[Raccoon Stealer] - v1.3.2 UC-International Release'(Figure 30)
While a responsible analyst would take a closer look, diff the functions in order to discover new changes etc etc, we are of the lazy type. So instead of all that, all the strings from a sample with version 1.2 were dumped to a .txt file and diffed against all the strings from the new version. This resulted in the following :
- Some new targets were added and specifically FileZilla (Figure 31)
- There was some new SQLITE queries added (maybe to support newer browser versions?) (Figure 32)
In order to confirm our findings, we would have to execute the malware and monitor specific API calls to verify the above. What's the point of working in a sandboxing company if not using the sandbox for that kind of things (Well, apart from malware classification)? Executing the malware and inspecting the logs revealed that indeed the samples is checking for that kind of paths. (Figure 33) Also, a new directory called (TempDir-Extended) is created and the two files are potentially stored there. The new directory also exists in our diffing thus further verifying the validity of our results. (Figure 34)
From a quick look of the static code and based on the execution logs taken from the sandbox execution we concluded that:
- The content of the wallets that were stolen is stored in new files based on the type of the coin ( trevor, ledge ) also in a new path but will be added to the Log.zip file with the same name.
- There seems to be a change in the way that the dumped passwords are stored in the associate .txt files based on static code compare to the older versions. (Couldn't verify that as I have a VM without pre-configured data)
- Seems that in the System Info.txt was added the information of the computer's name. This was later verified by inspecting the dropped .txt file before being deleted by the sample. (Figure 35)
Raccoon is a infostealer capable of performing a variety of actions, justifying its price and its heavy usage from a variety of criminals. From the above analysis, one must remember that:
- The CnC domain is acquired dynamically - there is an HTTP request beforehand to get the CnC encrypted with RC4 ( It is not hardcoded in the sample)
- The credentials that were grabbed are saved in TEMP folder with specific names - easy to keep in mind during a IR assessment.
- In version 1.2/1.3.2 there is not a persistence method - in this particular case thought, the response did have an EXE to be executed which would create a scheduled task but in general, there isn't one.
- Some numeric constants did not change - if we carefully examine the code, most of the tags used during the completion of the machineinfo.txt file are 128bit constants hardcoded in the sample. Apart from the constant used to define the new version of the malware, the other ones are the same. ( With the addition of one used to decrypt 'ComputerName' string ). (Figure 36)
Lastly, there are some more things to figure out and improve during the analysis of this family such as:
- There is not a clear explanation for the width property in the JSON - the same applies for the mask property too. It could be a placeholder for a future capability maybe?
- By inspecting strings, it was revealed that the author is using a famous open source JSON library for C++, and specifically the version 3.4.0. There was an attempt to produce a .lib file in order to use IDA's way of producing FLIRT signatures and make the analysis easier but was not successful. ( There were problems compiling a .hpp header with template definitions and no useful information was generated. )
- There was not further exploration of the properties of the JSON thus there is no guarantee that this analysis covered all the potential capabilities of the malware.
- xorsthingsv2 for taking the time to review the analysis and the doc.
- Fumiko, for showing me the new sample
- @tkanalyst, for posting the raccoon samples
Configurations (Table 2):