はじめに
In July, Google announced a new protection mechanism for cookies stored within Chrome on Windows, known as Application-Bound Encryption. There is no doubt this security implementation has raised the bar and directly impacted the malware ecosystem. After months with this new feature, many infostealers have written new code to bypass this protection (as the Chrome Security Team predicted) in order to stay competitive in the market and deliver capabilities that reliably retrieve cookie data from Chrome browsers.
Elastic Security Labs has been tracking a subset of this activity, identifying multiple techniques used by different malware families to circumvent App-Bound Encryption. While the ecosystem is still evolving in light of this pressure, our goal is to share technical details that help organizations understand and defend against these techniques. In this article, we will cover the different methods used by the following infostealer families:
- STEALC/VIDAR
- METASTEALER
- PHEMEDRONE
- XENOSTEALER
- LUMMA
重要なポイント
- Latest versions of infostealers implement bypasses around Google’s recent cookie protection feature using Application-Bound Encryption
- Techniques include integrating offensive security tool ChromeKatz, leveraging COM to interact with Chrome services and decrypt the app-bound encryption key, and using the remote debugging feature within Chrome
- Defenders should actively monitor for different cookie bypass techniques against Chrome on Windows in anticipation of future mitigations and bypasses likely to emerge in the near- to mid-term
- Elastic Security provides mitigations through memory signatures, behavioral rules, and hunting opportunities to enable faster identification and response to infostealer activity
背景
Generically speaking, cookies are used by web applications to store visitor information in the browser the visitor uses to access that web app. This information helps the web app track that user, their preferences, and other information from location to location– even across devices.
The authentication token is one use of the client-side data storage structures that enables much of how modern web interactivity works. These tokens are stored by the browser after the user has successfully authenticated with a web application. After username and password, after multifactor authentication (MFA) via one-time passcodes or biometrics, the web application “remembers” your browser is you via the exchange of this token with each subsequent web request.
A malicious actor who gets access to a valid authentication token can reuse it to impersonate the user to that web service with the ability to take over accounts, steal personal or financial information, or perform other actions as that user such as transfer financial assets.
Cybercriminals use infostealers to steal and commoditize this type of information for their financial gain.
Google Chrome Cookie Security
Legacy versions of Google Chrome on Windows used the Windows native Data Protection API (DPAPI) to encrypt cookies and protect them from other user contexts. This provided adequate protection against several attack scenarios, but any malicious software running in the targeted user’s context could decrypt these cookies using the DPAPI methods directly. Unfortunately, this context is exactly the niche that infostealers often find themselves in after social engineering for initial access. The DPAPI scheme is now well known to attackers with several attack vectors; from local decryption using the API, to stealing the masterkey and decrypting remotely, to abusing the domain-wide backup DPAPI key in an enterprise environment.
With the release of Chrome 127 in July 2024, Google implemented Application-Bound Encryption of browser data. This mechanism directly addressed many common DPAPI attacks against Windows Chrome browser data–including cookies. It does this by storing the data in encrypted datafiles, and using a service running as SYSTEM to verify any decryption attempts are coming from the Chrome process before returning the key to that process for decryption of the stored data.
While it is our view that this encryption scheme is not a panacea to protect all browser data (as the Chrome Security Team acknowledges in their release) we do feel it has been successful in driving malware authors to TTPs that are more overtly malicious, and easier for defenders to identify and respond to.
Stealer Bypass Techniques, Summarized
The following sections will describe specific infostealer techniques used to bypass Google’s App-Bound Encryption feature as observed by Elastic. Although this isn’t an exhaustive compilation of bypasses, and development of these families is ongoing, they represent an interesting dynamic within the infostealer space showing how malware developers responded to Google’s recently updated security control. The techniques observed by our team include:
- Remote debugging via Chrome’s DevTools Protocol
- Reading process memory of Chrome network service process (ChromeKatz and
ReadProcessMemory
(RPM)) - Elevating to
SYSTEM
then decryptingapp_bound_encryption_key
with theDecryptData
method ofGoogleChromeElevationService
through COM
STEALC/VIDAR
Our team observed new code introduced to STEALC/VIDAR related to the cookie bypass technique around September 20th. These were atypical samples that stood out from previous versions and were implemented as embedded 64-bit PE files along with conditional checks. Encrypted values in the SQLite databases where Chrome stores its data are now prefixed with v20, indicating that the values are now encrypted using application-bound encryption.
STEALC was introduced in 2023 and was developed with “heavy inspiration” from other more established stealers such as RACOON and VIDAR. STEALC and VIDAR have continued concurrent development, and in the case of App-Bound Encryption bypasses have settled on the same implementation.
During the extraction of encrypted data from the databases the malware checks for this prefix. If it begins with v20
, a child process is spawned using the embedded PE file in the .data
section of the binary. This program is responsible for extracting unencrypted cookie values residing in one of Chrome's child processes.
This embedded binary creates a hidden desktop via OpenDesktopA
/ CreateDesktopA
then uses CreateToolhelp32Snapshot
to scan and terminate all chrome.exe
processes. A new chrome.exe
process is then started with the new desktop object. Based on the installed version of Chrome, the malware selects a signature pattern for the Chromium feature CookieMonster, an internal component used to manage cookies.
We used the signature patterns to pivot to existing code developed for an offensive security tool called ChromeKatz. At this time, the patterns have been removed from the ChromeKatz repository and replaced with a new technique. Based on our analysis, the malware author appears to have reimplemented ChromeKatz within STEALC in order to bypass the app-bound encryption protection feature.
Once the malware identifies a matching signature, it enumerates Chrome’s child processes to check for the presence of the --utility-sub-type=network.mojom.NetworkService
command-line flag. This flag indicates that the process is the network service responsible for handling all internet communication. It becomes a prime target as it holds the sensitive data the attacker seeks, as described in MDSec’s post. It then returns a handle for that specific child process.
Next, it enumerates each module in the network service child process to find and retrieve the base address and size of chrome.dll
loaded into memory. STEALC uses CredentialKatz::FindDllPattern
and CookieKatz::FindPattern
to locate the CookieMonster instances. There are 2 calls to CredentialKatz::FindDllPattern
.
In the first call to CredentialKatz::FindDllPattern
, it tries to locate one of the signature patterns (depending on the victim’s Chrome version) in chrome.dll
. Once found, STEALC now has a reference pointer to that memory location where the byte sequence begins which is the function net::CookieMonster::~CookieMonster
, destructor of the CookieMonster
class.
The second call to CredentialKatz::FindDllPattern
passes in the function address for net::CookieMonster::~CookieMonster(void)
as an argument for the byte sequence search, resulting in STEALC having a pointer to CookieMonster
’s Virtual Function Pointer struct.
The following method used by STEALC is again, identical to ChromeKatz, where it locates CookieMonster
instances by scanning memory chunks in the chrome.dll
module for pointers referencing the CookieMonster
vtable. Since the vtable is a constant across all objects of a given class, any CookieMonster
object will have the same vtable pointer. When a match is identified, STEALC treats the memory location as a CookieMonster
instance and stores its address in an array.
For each identified CookieMonster
instance, STEALC accesses the internal CookieMap
structure located at an offset of +0x30
, and which is a binary tree. Each node within this tree contains pointers to CanonicalCookieChrome
structures. CanonicalCookieChrome
structures hold unencrypted cookie data, making it accessible for extraction. STEALC then initiates a tree traversal by passing the first node into a dedicated traversal function.
For each node, it calls ReadProcessMemory
to access the CanonicalCookieChrome
structure from the target process’s memory, then further processing it in jy::GenerateExfilString
.
STEALC formats the extracted cookie data by converting the expiration date to UNIX format and verifying the presence of the HttpOnly
and Secure
flags. It then appends details such as the cookie's name, value, domain, path, and the HttpOnly
and Secure
into a final string for exfiltration. OptimizedString
structs are used in place of strings, so string values can either be the string itself, or if the string length is greater than 23, it will point to the address storing the string.
METASTEALER
METASTEALER, first observed in 2022, recently upgraded its ability to steal Chrome data, bypassing Google’s latest mitigation efforts. On September 30th, the malware authors announced this update via their Telegram channel, highlighting its enhanced capability to extract sensitive information, including cookies, despite the security changes in Chrome's version 129+
.
The first sample observed in the wild by our team was discovered on September 30th, the same day the authors promoted the update. Despite claims that the malware operates without needing Administrator
privileges, our testing revealed it does require elevated access, as it attempts to impersonate the SYSTEM
token during execution.
As shown in the screenshots above, the get_decryption
method now includes a new Boolean parameter. This value is set to TRUE
if the encrypted data (cookie) begins with the v20
prefix, indicating that the cookie is encrypted using Chrome's latest encryption method. The updated function retains backward compatibility, still supporting the decryption of cookies from older Chrome versions if present on the infected machine.
The malware then attempts to access the Local State
or LocalPrefs.json
files located in the Chrome profile directory. Both files are JSON formatted and store encryption keys (encrypted_key
) for older Chrome versions and app_bound_encrypted_key
for newer ones. If the flag is set to TRUE
, the malware specifically uses the app_bound_encrypted_key
to decrypt cookies in line with the updated Chrome encryption method.
In this case, the malware first impersonates the SYSTEM
token using a newly introduced class called ContextSwitcher
.
It then decrypts the key by creating an instance via the COM of the Chrome service responsible for decryption, named GoogleChromeElevationService
, using the CLSID 708860E0-F641-4611-8895-7D867DD3675B
. Once initialized, it invokes the DecryptData
method to decrypt the app_bound_encrypted_key
key which will be used to decrypt the encrypted cookies.
METASTEALER employs a technique similar to the one demonstrated in a gist shared on X on September 27th, which may have served as inspiration for the malware authors. Both approaches leverage similar methods to bypass Chrome's encryption mechanisms and extract sensitive data.
PHEMEDRONE
This open-source stealer caught the world’s attention earlier in the year through its usage of a Windows SmartScreen vulnerability (CVE-2023-36025). While its development is still occurring on Telegram, our team found a recent release (2.3.2) submitted at the end of September including new cookie grabber functionality for Chrome.
The malware first enumerates the different profiles within Chrome, then performs a browser check using function (BrowserHelpers.NewEncryption
) checking for the Chrome browser with a version greater than or equal to 127
.
If the condition matches, PHEMEDRONE uses a combination of helper functions to extract the cookies.
By viewing the ChromeDevToolsWrapper
class and its different functions, we can see that PHEMEDRONE sets up a remote debugging session within Chrome to access the cookies. The default port (9222
) is used along with window-position set to -2400
,-2400
which is set off-screen preventing any visible window from alerting the victim.
Next, the malware establishes a WebSocket connection to Chrome’s debugging interface making a request using deprecated Chrome DevTools Protocol method (Network.getAllCookies
).
The cookies are then returned from the previous request in plaintext, below is a network capture showing this behavior:
XENOSTEALER
XENOSTEALER is an open-source infostealer hosted on GitHub. It appeared in July 2024 and is under active development at the time of this publication. Notably, the Chrome bypass feature was committed on September 26, 2024.
The approach taken by XENOSTEALER is similar to that of METASTEALER. It first parses the JSON file under a given Chrome profile to extract the app_bound_encrypted_key
. However, the decryption process occurs within a Chrome process. To achieve this, XENOSTEALER launches an instance of Chrome.exe
, then injects code using a helper class called SharpInjector
, passing the encrypted key as a parameter.
The injected code subsequently calls the DecryptData
method from the GoogleChromeElevationService
to obtain the decrypted key.
LUMMA
In mid-October, the latest version of LUMMA implemented a new method to bypass Chrome cookie protection, as reported by @g0njxa.
We analyzed a recent version of LUMMA, confirming that it managed to successfully recover the cookie data from the latest version of Google Chrome (130.0.6723.70
). LUMMA first creates a visible Chrome process via Kernel32!CreateProcessW
.
This activity was followed up in the debugger with multiple calls to NtReadVirtualMemory
where we identified LUMMA searching within the Chrome process for chrome.dll
.
Once found, the malware copies the chrome.dll
image to its own process memory using NtReadVirtualMemory
. In a similar fashion to the ChromeKatz technique, Lumma leverages pattern scanning to target Chrome’s CookieMonster
component.
Lumma uses an obfuscated signature pattern to pinpoint the CookieMonster
functionality:
3Rf5Zn7oFA2a????k4fAsdxx????l8xX5vJnm47AUJ8uXUv2bA0s34S6AfFA????kdamAY3?PdE????6G????L8v6D8MJ4uq????k70a?oAj7a3????????K3smA????maSd?3l4
Below is the YARA rule after de-obfuscation:
rule lumma_stealer
{
meta:
author = "Elastic Security Labs"
strings:
$lumma_pattern = { 56 57 48 83 EC 28 89 D7 48 89 CE E8 ?? ?? ?? ?? 85 FF 74 08 48 89 F1 E8 ?? ?? ?? ?? 48 89 F0 48 83 C4 28 5F 5E C3 CC CC CC CC CC CC CC CC CC CC 56 57 48 83 EC 38 48 89 CE 48 8B 05 ?? ?? ?? ?? 48 31 E0 48 89 44 24 ?? 48 8D 79 ?? ?? ?? ?? 28 E8 ?? ?? ?? ?? 48 8B 46 20 48 8B 4E 28 48 8B 96 ?? ?? ?? ?? 4C 8D 44 24 ?? 49 89 10 48 C7 86 ?? ?? ?? ?? ?? ?? ?? ?? 48 89 FA FF 15 ?? ?? ?? ?? 48 8B 4C 24 ?? 48 31 E1}
condition:
all of them
}
After decoding and searching for the pattern in chrome.dll
, this leads to the CookieMonster
destructor (net::CookieMonster::~CookieMonster
).
The cookies are then identified in memory and dumped out in clear text from the Chrome process.
Once completed, LUMMA sends out the cookies along with the other requested data as multiple zip files (xor encrypted and base64 encoded) to the C2 server.
検知
Below are the following behavioral detections that can be used to identify techniques used by information stealers:
- Web Browser Credential Access via Unusual Process
- Web Browser Credential Access via Unsigned Process
- Access to Browser Credentials from Suspicious Memory
- Failed Access Attempt to Web Browser Files
- Browser Debugging from Unusual Parent
- Potential Browser Information Discovery
Additionally, the following queries can be used for hunting diverse related abnormal behaviors:
Cookies access by an unusual process
This query uses file open events and aggregate accesses by process, then looks for ones that are observed in unique hosts and with a low total access count:
FROM logs-endpoint.events.file-default*
| where event.category == "file" and event.action == "open" and file.name == "Cookies" and file.path like "*Chrome*"
| keep file.path, process.executable, agent.id
| eval process_path = replace(to_lower(process.executable), """c:\\users\\[a-zA-Z0-9\.\-\_\$]+\\""", "c:\\\\users\\\\user\\\\")
| stats agents_count = COUNT_DISTINCT(agent.id), access_count= count(*) by process_path
| where agents_count <= 2 and access_count <=2
Below example of matches from diverse information stealers including the updated ones with new Chrome cookies stealing capabilities:
METASTEALER behavior tends to first terminate all running chrome instances then calls CoCreateInstance
to instantiate the Google Chrome elevation service, this series of events can be expressed with the following EQL query:
sequence by host.id with maxspan=1s
[process where event.action == "end" and process.name == "chrome.exe"] with runs=5
[process where event.action == "start" and process.name == "elevation_service.exe"]
The previous hunt indicates suspicious agents but doesn't identify the source process. By enabling registry object access auditing through event 4663 on the Chrome Elevation service CLSID registry key {708860E0-F641-4611-8895-7D867DD3675B}
, we can detect unusual processes attempting to access that key:
FROM logs-system.security-default* | where event.code == "4663" and winlog.event_data.ObjectName == "\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\CLSID\\{708860E0-F641-4611-8895-7D867DD3675B}" and not winlog.event_data.ProcessName in ("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe") and not winlog.event_data.ProcessName like "C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\*\\\\elevation_service.exe" | stats agents_count = COUNT_DISTINCT(agent.id), access_count= count(*) by winlog.event_data.ProcessName | where agents_count <= 2 and access_count <=2
Below is an example of matches on the METASTEALER malware while calling CoCreateInstance (CLSID_Elevator)
:
The PHEMEDRONE stealer uses the known browser debugging method to collect cookies via Chromium API, this can be observed in the following screenshot where we can see an instance of NodeJs communicating with a browser instance with debugging enabled over port 9222
:
The following EQL query can be used to look for unusual processes performing similar behavior:
sequence by host.id, destination.port with maxspan=5s
[network where event.action == "disconnect_received" and
network.direction == "ingress" and
process.executable in~ ("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe") and
source.address like "127.*" and destination.address like "127.*"]
[network where event.action == "disconnect_received" and network.direction == "egress" and not
process.executable in~ ("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe") and source.address like "127.*" and destination.address like "127.*"]
Chrome Browser Spawned from an Unusual Parent
The STEALC sample that uses ChromeKatz implementation spawns an instance of Google Chrome to load the user default profile, while looking for normal parent executables, it turns out it’s limited to Chrome signed parents and Explorer.exe, the following ES|QL query can be used to find unusual parents:
FROM logs-endpoint.events.process-*
| where event.category == "process" and event.type == "start" and to_lower(process.name) == "chrome.exe" and process.command_line like "*--profile-directory=Default*"
| eval process_parent_path = replace(to_lower(process.parent.executable), """c:\\users\\[a-zA-Z0-9\.\-\_\$]+\\""", "c:\\\\users\\\\user\\\\")
| stats agents_count = COUNT_DISTINCT(agent.id), total_executions = count(*) by process_parent_path
| where agents_count == 1 and total_executions <= 10
Untrusted Binaries from Chrome Application folder
Since the Chrome elevation service trusts binaries running from the Chrome program files
folder, the following queries can be used to hunt for unsigned or untrusted binaries executed or loaded from there:
Unsigned DLLs loaded from google chrome application folder
FROM logs-endpoint.events.library*
| where event.category == "library" and event.action == "load" and to_lower(dll.path) like "c:\\\\program files\\\\google\\\\chrome\\\\application\\\\*" and not (dll.code_signature.trusted == true)
| keep process.executable, dll.path, dll.hash.sha256, agent.id
| stats agents_count = COUNT_DISTINCT(agent.id), total_executions = count(*) by process.executable, dll.path, dll.hash.sha256
| where agents_count == 1 and total_executions <= 10
Unsigned executable launched from google chrome application folder
FROM logs-endpoint.events.process*
| where event.category == "library" and event.type == "start" and (to_lower(process.executable) like "c:\\\\program files\\\\google\\\\chrome\\\\application\\\\*" or to_lower(process.executable) like "c:\\\\scoped_dir\\\\program files\\\\google\\\\chrome\\\\application\\\\*")
and not (process.code_signature.trusted == true and process.code_signature.subject_name == "Goole LLC")
| keep process.executable,process.hash.sha256, agent.id
| stats agents_count = COUNT_DISTINCT(agent.id), total_executions = count(*) by process.executable, process.hash.sha256
| where agents_count == 1 and total_executions <= 10
まとめ
Google has raised the bar implementing new security controls to protect cookie data within Chrome. As expected, this has caused malware developers to develop or integrate their own bypasses. We hope Google will continue to innovate to provide stronger protection for user data.
Organizations and defenders should consistently monitor for unusual endpoint activity. While these new techniques may be successful, they are also noisy and detectable with the right security instrumentation, processes, and personnel.
Stealer Bypasses and MITRE ATT&CK
Elasticは、 MITRE ATT&CK フレームワークを使用して、脅威がエンタープライズネットワークに対して使用する一般的な戦術、手法、手順を文書化します。
戦術(Tactics)
戦術は、テクニックまたはサブテクニックの理由を表します。 それは敵の戦術的な目標であり、行動を実行する理由です。
手法
手法は、敵対者がアクションを実行することによって戦術的な目標を達成する方法を表します。
- Steal Web Session Cookie
- プロセスインジェクション
- Credentials from Password Stores
- システム情報の検出
- プロセスディスカバリー
- Inter-Process Communication: Component Object Model
ヤラ
Elasticセキュリティは、このアクティビティを識別するためのYARAルールを作成しました。
- Windows.Trojan.Stealc
- Windows.Infostealer.PhemedroneStealer
- Windows.Trojan.MetaStealer
- Windows.Trojan.Xeno
- Windows.Trojan.Lumma
- Windows.Infostealer.Generic
観測
すべてのオブザーバブルは、ECS形式とSTIX形式の両方で ダウンロード することもできます。
この研究では、次の観測量について議論しました。
Observable | タイプ | 名前 | 参考 |
---|---|---|---|
27e4a3627d7df2b22189dd4bebc559ae1986d49a8f4e35980b428fadb66cf23d | SHA-256の | num.exe | STEALC |
08d9d4e6489dc5b05a6caa434fc36ad6c1bd8c8eb08888f61cbed094eac6cb37 | SHA-256の | HardCoreCrack.exe | PHEMEDRONE |
43cb70d31daa43d24e5b063f4309281753176698ad2aba9c557d80cf710f9b1d | SHA-256の | Ranginess.exe | METASTEALER |
84033def9ffa70c7b77ce9a7f6008600c0145c28fe5ea0e56dfafd8474fb8176 | SHA-256の | LUMMA | |
b74733d68e95220ab0630a68ddf973b0c959fd421628e639c1b91e465ba9299b | SHA-256の | XenoStealer.exe | XENOSTEALER |
参照資料
上記の研究を通じて、以下のことが参照されました。