# Raccoon Stealer 2.0 Malware analysis **any.run/cybersecurity-blog/raccoon-stealer-v2-malware-analysis/** ANY.RUN August 30, 2022 Raccoon Stealer was one of the most mentioned malware in 2019. Cybercriminals sold this simple but versatile info stealer as a MaaS just for $75 per week and $200 per month. And it successfully attacked numerous systems. But in March 2022, threat authors shut down their operations. In July 2022, a new variant of this malware was released. And now Raccoon Stealer 2.0 has gone viral and got a new name in the wild – RecordBreaker. In this article, we will analyze several samples of the info stealer to find out its techniques and what data it collects. ## What is Raccoon Stealer? [Raccoon Stealer is a kind of malware that steals various data from an infected computer. It’s quite a basic malware,](https://any.run/malware-trends/raccoon) but hackers who provide excellent service and simple navigation have made Raccoon popular. Raccoon malwareRaccoon malware **The malware’s owners are interested in the following data:** Login/password pairs from various services saved in browsers Cookies from different browsers Bank data Cryptocurrency wallets Credit card information Arbitrary files, which can be of interest to intruders ## Raccoon – a sample overview In the process of malware analysis, we worked with the following samples: **sha-256** 9ee50e94a731872a74f47780317850ae2b9fae9d6c53a957ed7187173feb4f42 0142baf3e69fe93e0151a1b5719c90df8e2adca4301c3aa255dd19e778d84edf 022432f770bf0e7c5260100fcde2ec7c49f68716751fd7d8b9e113bf06167e03 048c0113233ddc1250c269c74c9c9b8e9ad3e4dae3533ff0412d02b06bdf4059 263c18c86071d085c69f2096460c6b418ae414d3ea92c0c2e75ef7cb47bbe693 27e02b973771d43531c97eb5d3fb662f9247e85c4135fe4c030587a8dea72577 494ab44bb96537fc8a3e832e3cf032b0599501f96a682205bc46d9b7744d52ab f26f5331588cb62a97d44ce55303eb81ef21cf563e2c604fe06b06d97760f544 fcdc29b4d9cb808c178954d08c53c0519970fe585b850204655e44c1a901c4de ----- _Raccoon malware overview in DiE_ MITRE ATT&CK Matrix produced by [ANY.RUN Sandbox:](https://any.run/?utm_source=anyrunblog&utm_medium=article&utm_content=raccoon_stealer) ## Challenges during the malware analysis of Raccoon stealer v2 Raccoon stealer v.2 got extremely famous, and, of course, we decided to look into it closely. And here, we have faced several challenges: When we first started our malware analysis, we immediately got a sample **9ee50e94a731872a74f4778037850ae2b9fae9d6c53a957ed7187173feb4f4, which we were unable to run in our** sandbox. This example was packed and immediately finished execution when we tried to run it in a virtual environment. So, our team decided to investigate the sandbox evasion mechanisms. ----- During the sample s reverse engineering, we encountered another issue: the packer detects the presence of Anti Anti-Debugger and terminates before checking the execution’s environment. In our case, we used TitanHide. When running the program under a debugger, the NtQueryInformationProcess call causes the ProcessInformation variable to be overwritten. The packer compares the random value written to this variable earlier with the value after the call. If they are different, it stops execution. **The challenge was solved with the following script for x64dbg:** ``` bphc run findallmem 0, #e91727f5ff# bph ref.addr(0)+5 run $p = [esp+0x10] $val = [p] log "secret:{0}",$val bphc sti sti mov [$p], $val ret ``` It turned out that [the bug was known but had not been fixed at the moment of our research. After the report, it was](https://github.com/mrexodia/TitanHide/issues/70) [fixed. Therefore, this Anti-debugger detection method no longer works.](https://github.com/mrexodia/TitanHide/commit/6a5a68a2447ad9454adfcbd9390ec05b9dcef2d6) But this script didn’t solve the problem of running in the virtual environment without a debugger. So we continued our malware analysis and came across an interesting piece of code: As it turned out, this piece of code is executed differently in virtual and real environments. An exception occurs after the IF flag is set in the flag register with the popfd command. If we run in a virtual environment, the exception handler pre-installed by the malware considers that the exception occurred on the “call” instruction. However, when running on a real machine, the exception occurs on the “nop” instruction. Thus, by comparing the addresses of the exceptions that occurred, the malware determines the presence of a virtual environment. Bypassing this check is enough to decrease the EIP register value by one when entering the exception handler. After that, the malware is successfully launched. [After making the necessary corrections on our end, this detection method no longer works in ANY.RUN sandbox.](https://any.run/?utm_source=anyrunblog&utm_medium=article&utm_content=raccoon_stealer) ## Execution process of RecordBreaker malware **Loading WinAPI libraries, getting addresses of used functions** First, Raccoon dynamically loads WinAPI libraries using kernel32.dll!LoadLibraryW and gets addresses of WinAPI functions using kernel32.dll!GetProcAddress ----- _Raccoon is dynamically loading needed libraries and getting WinAPI imports addresses_ **Decryption of strings** Depending on the sample, the algorithm for encrypting strings can be: encrypted with RC4 algorithm, then encoded into the Base64 format XOR encrypted with a random key, e.g.: _Raccoon Stealer is using XOR_ _strings encryption_ encryption may not be applied at all **Examples of decrypted strings:** logins.json \autofill.txt \cookies.txt \passwords.txt formhistory.sqlite … **C2 servers decryption** The next malware step is to decrypt C&C servers. There can be several up to five ones. As in the case of strings, the encryption algorithm of C&C servers may vary depending on a sample. From all the samples we have reviewed, at least two methods have been identified: Encryption using the RC4 algorithm with further recoding to Base64: Raccoonstealer is using RC4 -> Base64 encryption chain for C2sRaccoonstealer is using RC4 -> Base64 _encryption chain for C2s_ ----- Encryption with XOR: _XOR C2s encryption_ **Raccoon termination triggers** _Raccoon malware is using_ At this stage the malware has not executed any malicious code yet. There are certain triggers that may cause the program to terminate without executing any other actions. The user’s locale is checked (in some samples, certain locales corresponding to the locales of CIS countries cause Raccoon to terminate) _Raccoon is checking for specific_ _user locale_ A check is made to see if the malware has been rerun, in parallel with another sample running on this machine. RecordBreaker tries to open a particular mutex (the value of the mutex varies in different samples). If it succeeds, it terminates immediately. If not, it creates the mutex itself. _Raccoon v2 is_ _checking for a specific mutex_ [We can see the result in ANY.RUN: the mutex was created.](https://any.run/?utm_source=anyrunblog&utm_medium=article&utm_content=raccoon_stealer) ----- _Mutex operations are captured by ANY.RUN interactive sandbox_ **Privilege Level Check** After creating a mutex, the malware performs a System/LocalSystem level privilege check using Advapi32.dll!GetTokenInformation and Advapi32.dll!ConvertSidToStringSidW comparing StringSid with L “S-1-5-18”: _Raccoonstealer 2.0 is checking for System/LocalSystem privileges_ **Process enumeration** If the check shows that RecordBreaker has the privilege level it needs, it starts enumerating processes using the TlHelp32 API (kernel32.dll!CreateToolhelp32Snapshot to capture processes and kernel32.dll!Process32First / kernel32.dll!Process32Next). In our samples this information isn’t collected or processed in any way. ----- _Raccoon malware is_ _enumerating currently running processes_ **Connecting to C2 servers** The next important step is to attempt to connect to one of the C&C servers. To do this, Raccoon stealer generates a string like: ``` machineId={machineguid}|{username}&configId={c2_key} ``` Then the program tries to send a POST request with the string to every possible server. _Raccoon Stealer is trying to connect to C2s_ [An example of a connection request that was intercepted by the HTTP MITM proxy feature in ANY.RUN sandbox:](https://any.run/?utm_source=anyrunblog&utm_medium=article&utm_content=raccoon_stealer) Raccoon info stealer C2 connection requestRaccoon info stealer C2 connection request It is important to note that if there are multiple C&C servers, the malware will only accept commands from the one it was able to connect to first. In response to the above request, the server will send the malware a configuration. If RecordBreaker fails to connect to any of the C&C servers, it will stop its work. ## Description of the malware configuration structure Configuration lines are divided into prefixes, each tells the malware how to interpret a particular line. Here is a table describing these prefixes and what they do: ----- **Prefix** **Example** **Prefix’s function** libs_ libs_nss3:http://{HOSTADDR}/{RANDOM_STRING}/nss3.dll libs_msvcp140:http://{HOSTADDR}/{RANDOM_STRING}/msvcp140.dll libs_vcruntime140:http://{HOSTADDR}/{RANDOM_STRING}/vcruntime140.dll grbr_ grbr_dekstop:%USERPROFILE%\Desktop\|*.txt, *.doc, *pdf*|-|5|1|0|files grbr_documents:%USERPROFILE%\Documents\|*.txt, *.doc, *pdf*||5|1|0|files grbr_downloads:%USERPROFILE%\Downloads\|*.txt, *.doc, *pdf*|-|5|1|0|files wlts_ wlts_exodus:Exodus;26;exodus;*;*partitio*,*cache*,*dictionar* wlts_atomic:Atomic;26;atomic;*;*cache*,*IndexedDB* wlts_jaxxl:JaxxLiberty;26;com.liberty.jaxx;*;*cache* ews_ ews_meta_e:ejbalbakoplchlghecdalmeeeajnimhm;MetaMask;Local Extension Settings ews_tronl:ibnejdfjmmkpcnlpebklmnkoeoihofec;TronLink;Local Extension Settings ews_bsc:fhbohimaelbohpjbbldcngcnapndodjp;BinanceChain;Local Extension Settings Legitimate libraries necessary for malware work Targeted arbitrary files from custom directories Targeted cryptowallets and the files associated with them Targeted cryptowallet related extensions for Google Chrome ldr_ [missing in the configuration of the sample] Additional commands that should be executed by malware tlgrm_ tlgrm_Telegram:Telegram Desktop\tdata|*|*emoji*,*user_data*,*tdummy*,*dumps* Targeted files related to the Telegram messenger scrnsht_ scrnsht_Screenshot.jpeg:1 The name of the screenshot(s) that the malware takes in the process token 101f4cb19fcd8b9713dcbf6a5816dc74 Part of the URL path for further queries to C2 sstmnfo_ sstmnfo_System Info.txt:System Information: |Installed applications: | The file description with some system data and a list of installed applications that the malware will generate later Once the info stealer receives information concerning what kind of data to collect from C2, it proceeds to do so. ## System data collection The stealer collects various information about the infected system, including the OS bitness, information about RAM, CPU, and user data like the applications installed in the system. **Raccoon’s mechanisms for data collection:** gets the size of the main monitor using user32.dll!GetSystemMetrics Raccoon malware v2 is getting the user’s display resolutionRaccoon malware v2 is getting the user’s display _resolution_ finds a list of GPU devices, using user32.dll!EnumDisplayDevicesW ----- _Raccoon_ _Stealer is iterating through display devices_ determines the architecture (bitness) of the system by calling the x64-specific function kernel32.dll!GetSystemWow64DirectoryW and comparing the last error code with ERROR_CALL_NOT_IMPLEMENTED Raccoon malware v2 is getting the user’s display resolutionRaccoon malware v2 is getting the user’s display _resolution_ collects RAM information via kernel32.dll!GlobalMemoryStatusEx Raccoon malware ver.2 is checking the user’s system RAM informationRaccoon malware ver.2 is checking the _user’s system RAM information_ gets information about the user’s timezone by kernel32!GetTimeZoneInformation: Raccoon malware is collecting the user’s system timezone dataRaccoon malware is collecting the user’s system _timezone data_ grabs the OS version from the registry, using advapi32.dll!RegOpenKeyExW and advapi32.dll!RegQueryValueExW to read the value of the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName _Raccoonstealer gets the user’s OS version_ obtains Information about the vendor of the CPU using asm-instruction __cpuid: ----- _Raccoonstealer 2.0 is_ _getting CPU vendor info_ gets CPU cores number with kernel32.dll!GetSystemInfo Raccoon malware is getting CPU cores countRaccoon malware is getting CPU cores count collects the user’s default locale info requesting kernel32.dll!GetUserDefaultLCID and kernel32.dll!GetLocaleInfoW _Raccoon info stealer is getting the user’s_ _default locale info_ grabs data about installed apps from the registry using advapi32.dll!RegOpenKeyExW, advapi32.dll!RegEnumKeyExW, and advapi32.dll!RegQueryValueExW. The “DisplayName” and “DisplayVersion” values of all \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall key sub-keys: Raccoon malware 2.0 is traversing through the user’s installed applications listRaccoon malware 2.0 is traversing _through the user’s installed applications list_ After obtaining the system information, RecordBreaker gets ready to steal user data. The malware loads the previously downloaded legitimate libraries to reach this goal. Raccoon Stealer is loading previously downloaded legitimate third-party libsRaccoon Stealer is loading previously _downloaded legitimate third-party libs_ This way the program has the functions needed for operations: ----- _Raccoonstealer gets functions addresses from the newly loaded modules_ Once the libraries have been loaded, Raccoon starts to collect user data. ## User data collection **Cookies** First of all, the stealer collects cookies. It creates a copy of the cookies file and tries to open it. If it fails to do so, the current subroutine is terminated. _Raccoon malware v2 is copying the cookies database and trying to open it_ If the sample manages to open the database, it retrieves cookies from it by executing the SQL query ``` SELECT host, path, isSecure, expiry, name, value FROM moz_cookies ``` . ----- _Raccoon_ _stealer v2 is executing a SQL request to retrieve data from the cookies database_ **Autofill data** The next step in Raccoon’s “plan” is to retrieve the autofill data. The program tries to open the database logins.json: ----- _Raccoon Stealer 2.0 is trying to open the logins.json database_ Then the stealer tries to decrypt the data from that database, using the Зnss3.dll!PK11SDR_Decrypt method. _Raccoon malware 2.0 decrypts encrypted_ _logins.json database_ After that, the malware formats collected data like so: ``` “URL:%s\nUSR:%s\nPASS:%s” ``` ----- Using encrypted data, Raccoon malware formats it to a more readable stateUsing encrypted data, Raccoon _malware formats it to a more readable state_ **Autofill form data** After these manipulations, the stealer collects the autofill form data. It attempts to open the formhistory.sqlite database: _Raccoon info stealer tries to open another database_ If the connection to the database is successful, the program retrieves form data values from it with an SQL query like: ``` SELECT name, value FROM autofill ``` ----- _Raccoonstealer is executing another SQL request to retrieve data_ [RecordBreaker concatenates all data together and sends POST requests to C2. ANY.RUN sandbox’s HTTP MITM](https://any.run/?utm_source=anyrunblog&utm_medium=article&utm_content=raccoon_stealer) proxy feature intercepts all the data that the malware has managed to collect. SystemInfo POST request ----- _System info request made by Raccoon aka RecordBreaker_ UserInfo POST request _User info request made by Raccoon malware_ When the C2 server gets each chunk of data, it responds “received”: C2 server responds ## Crypto-wallets, Custom, and Telegram file data collection **Crypto-wallets data** RecordBreaker is looking for users’ crypto-wallets data using filters and templates retrieved from the configuration. ----- _RecordBreaker is looking for the user’s crypto-wallets data_ **Custom files** Then, the wallet.dat file is searched (it contains local information about the bitcoin wallet). After that, the stealer looks for arbitrary files from custom directories specified in the configuration. ----- _Raccoonstealer is looking for any custom files_ **Telegram messenger files** The sample is looking for files related to Telegram messenger using data from the configuration. ----- _RecordBreaker is looking for files related to Telegram messenger_ After the malware has sent all the files, it takes a screenshot(s). _screenshots of the user’s environment_ [An example of a screenshot captured by ANY.RUN:](https://any.run/?utm_source=anyrunblog&utm_medium=article&utm_content=raccoon_stealer) _Raccoon malware v2 is making_ ----- _The screenshot made by the 2d version of Raccoon malware_ If any additional commands are provided in configuration, the sample will execute them before finishing its work. For example, Raccoon executes other commands with the help of WinAPI (shell32.dll!ShellExecuteW) if C2 has sent them in the prefix ldr_: _Raccoonstealer executes extra commands_ Then, the malware releases the remaining allocated resources, unloads the libraries, and finishes its work. ## Raccoon configuration extraction You can use our Python script to extract C2 servers from the unpacked Raccoon sample, or get malware [configuration right in our service, which will unpack the sample from memory dumps and extract C2s for you:](https://app.any.run/tasks/df94e59b-fa59-4f8f-ba81-93781e82046f) ----- _Raccoon malware configuration_ ----- ``` p, y,, g from enum import IntEnum from base64 import b64decode, b64encode from malduck import xor, rc4, base64 # c2 buffer len & invalid c2 placeholder RACCOON_C2_PLACEHOLDER = b" " * 64 RACCOON_C2_BUFF_LEN = len(RACCOON_C2_PLACEHOLDER) # c2s array size & key size RACCOON_C2S_LEN = 5 RACCOON_KEY_LEN = 32 class ERaccoonBuild(IntEnum): UNKNOWN_BUILD = -1, OLD_BUILD = 0, NEW_BUILD = 1 # extracts ascii and unicode strings from binary file class RaccoonStringExtractor: ASCII_BYTE = string.printable.encode() c2_list = [] rc4_key = str() xor_key = str() raccoon_build = ERaccoonBuild.UNKNOWN_BUILD def __init__(self, binary_path) -> None: with open(binary_path, 'rb') as bin: self.buffer = bin.read() self.__process_strings() def __is_base64_encoded(self, data) -> bool: try: data = data.rstrip() return b64encode(b64decode(data)) == data except Exception: return False def __is_valid_key(self, key) -> bool: key_re = re.compile(rb"^[a-z0-9]{%d,}" % RACCOON_KEY_LEN) return re.match(key_re, key) def __process_strings(self) -> None: ascii_re = re.compile(rb"([%s]{%d,})" % (self.ASCII_BYTE, 4)) self.c2_list = [] ascii_strings = [] for i, match in enumerate(ascii_re.finditer(self.buffer)): a_string = match[0] offset = match.start() string_entry = (a_string, offset) ascii_strings.append(string_entry) if len(a_string) == RACCOON_C2_BUFF_LEN and \ a_string != RACCOON_C2_PLACEHOLDER and \ self.__is_base64_encoded(a_string) == True: self.raccoon_build = ERaccoonBuild.OLD_BUILD print(f"[+] found possible encrypted c2 {a_string.rstrip()} at {hex(offset)}") self.c2_list.append(string_entry) if len(self c2 list) == 1: # first c2 found ``` ----- ``` _ y, _ g [ ] # rc4 key should be 32-bytes long and contain only a-z 0-9 chars if self.__is_valid_key(rc4_key): self.rc4_key = rc4_key print(f"[+] found possible rc4 key {self.rc4_key} at {hex(offset)}") else: continue # have we found any c2s yet? if len(self.c2_list) == 0: for a_string, offset in ascii_strings: if len(a_string) == RACCOON_KEY_LEN and self.__is_valid_key(a_string): self.raccoon_build = ERaccoonBuild.NEW_BUILD self.xor_key = a_string print(f"[+] found possible xor key {self.xor_key} at {hex(offset)}") # extract c2s for new builds curr_offset = offset + 36 for _ in range(0, RACCOON_C2S_LEN): enc_c2 = self.buffer[curr_offset : curr_offset + RACCOON_C2_BUFF_LEN] if enc_c2.find(0x20) != 0 and enc_c2 != RACCOON_C2_PLACEHOLDER: # check if c2 is empty print(f"[+] found possible encrypted c2 {enc_c2.rstrip()} at {hex(curr_offset)}") self.c2_list.append((enc_c2, curr_offset)) curr_offset += RACCOON_C2_BUFF_LEN + 8 # each c2 is padded by 8 bytes return # don't process strings any further else: return print(f"[!] C2Cs not found, could be a new build of raccoon sample") class RaccoonC2Decryptor: def __init__(self, sample_path: str) -> None: self.extractor = RaccoonStringExtractor(sample_path) def __is_valid_c2(self, c2): return re.match( rb"((https?):((//)|(\\\\))+([\w\d:#@%/;$()~_?\+-=\\\.&](#!)?)*)", c2 ) def decrypt(self) -> bool: raccoon_build = self.extractor.raccoon_build if raccoon_build == ERaccoonBuild.OLD_BUILD: return self.decrypt_method_1() elif raccoon_build == ERaccoonBuild.NEW_BUILD: return self.decrypt_method_2() else: return False # unknown raccoon build def decrypt_method_1(self) -> None: for enc_c2, _ in self.extractor.c2_list: decrypted_c2 = rc4( self.extractor.rc4_key, base64(enc_c2.rstrip()) ) if self.__is_valid_c2: print(f"[>] decrypted c2: {decrypted_c2}") else: print(f"[!] invalid c2: {decrypted_c2}") def decrypt method 2(self) -> None: ``` ----- ``` _, _ _ decrypted_c2 = xor( self.extractor.xor_key, enc_c2.rstrip() ) if self.__is_valid_c2: print(f"[>] decrypted c2: {decrypted_c2}") else: print(f"[!] invalid c2: {decrypted_c2}") def main(): # parse arguments if len(sys.argv) == 2: sample_path = os.path.abspath(sys.argv[1]) else: print(f"[!] usage: {os.path.basename(__file__)} ") return False try: RaccoonC2Decryptor(sample_path).decrypt() except Exception as ex: print(f"[!] exception: {ex}") if __name__ == '__main__': main() ``` **IOCs:** Filename SHA-256 \AppData\LocalLow\nss3.dll c65b7afb05ee2b2687e6280594019068c3d3829182dfe8604ce4adf2116cc46e \AppData\LocalLow\msvcp140.dll 2db7fd3c9c3c4b67f2d50a5a50e8c69154dc859780dd487c28a4e6ed1af90d01 \AppData\LocalLow\vcruntime140.dll 9d02e952396bdff3abfe5654e07b7a713c84268a225e11ed9a3bf338ed1e424c \AppData\LocalLow\mozglue.dll 4191faf7e5eb105a0f4c5c6ed3e9e9c71014e8aa39bbee313bc92d1411e9e862 \AppData\LocalLow\freebl3.dll b2ae93d30c8beb0b26f03d4a8325ac89b92a299e8f853e5caa51bb32575b06c6 \AppData\LocalLow\softokn3.dll 44be3153c15c2d18f49674a092c135d3482fb89b77a1b2063d01d02985555fe0 \AppData\LocalLow\sqlite3.dll 1b4640e3d5c872f4b8d199f3cff2970319345c766e697a37de65d10a1cffa102 **HTTP/HTTPS Requests:** [http://[C2 address]/](http://10.10.0.46/about:blank) [http://[C2 address] /aN7jD0qO6kT5bK5bQ4eR8fE1xP7hL2vK/nss3.dll](http://10.10.0.46/about:blank) [http://[C2 address]/aN7jD0qO6kT5bK5bQ4eR8fE1xP7hL2vK/msvcp140.dll](http://10.10.0.46/about:blank) [http://[C2 address]/aN7jD0qO6kT5bK5bQ4eR8fE1xP7hL2vK/vcruntime140.dll](http://10.10.0.46/about:blank) [http://[C2 address]/aN7jD0qO6kT5bK5bQ4eR8fE1xP7hL2vK/mozglue.dll](http://10.10.0.46/about:blank) [http://[C2 address]/aN7jD0qO6kT5bK5bQ4eR8fE1xP7hL2vK/freebl3.dll](http://10.10.0.46/about:blank) [http://[C2 address]/aN7jD0qO6kT5bK5bQ4eR8fE1xP7hL2vK/sqlite3.dll](http://10.10.0.46/about:blank) [http://[C2 address]/[config token]](http://10.10.0.46/about:blank) ----- [http://[C2 address]/aN7jD0qO6kT5bK5bQ4eR8fE1xP7hL2vK/softokn3.dll](http://10.10.0.46/about:blank) ## Conclusion [We have done malware analysis of the Raccoon stealer 2.0 performance using a v2 sample in ANY.RUN sandbox.](https://any.run/?utm_source=anyrunblog&utm_medium=article&utm_content=raccoon_stealer) The examined sample has used various techniques to evade detection: legitimate libraries for data collection, dynamic library loading, string encryption, and C&C server encryption. Some examples are additionally protected by packers or being a part of other malware. Copy the script of Raccoon stealer and try to extract C2 servers by yourselves and let us know about your results. And write in the comments below what other malware analysis you are interested in. We will be glad to add it to the series! [malware analysis](https://any.run/cybersecurity-blog/tag/malware-analysis/) -----