In my previous blog post (here), I described a technique to extract sensitive data (passwords, cookies) directly from the memory of a Chromium-based browser’s [CBB] process. Google’s response to the responsible disclosure was discouraging, stating “Won’t Fix” since “there is no way for Chrome (or any application) to defend against a malicious user who has managed to log into your device as you” (here).
When I showed this work to some of the experienced security researchers on my team, the general reaction was that it is not very interesting, since there are other known methods to get the same information. Naturally, I was disappointed, but to be completely frank – I was also frustrated! We work in a cybersecurity company, and we all embrace the “assume breach” paradigm. I felt our job was to identify malicious attack vectors and block them before the bad guys do, and a cry was welling up inside me:
Wake up! We are the defense team! GO BLUE!
Hence this blog, in which I try to map the known attack vectors on sensitive data in Chromium-based browsers, propose mitigations for these attack vectors, and demonstrate how some of these mitigations already work in at least one security application (CyberArk Endpoint Privilege Manager).
TL;DR
- Sensitive information (passwords, session-cookies, etc.) is processed and stored by browsers. This information is a prime target of malicious credential stealers.
- Weaknesses in the protection of this information in Chromium-based browsers have been known for many years, and attack tools have been published that demonstrate how the information can be stolen.
- In response to our reported vulnerabilities, Chromium.org indicates that it will not fix the product to protect against attacks carried out by a program running locally on the endpoint.
- The major attack vectors on this sensitive data are identified and mapped.
- A comprehensive Kernel level protection plan is proposed.
- Current implementation of major portions of the protection plan in CyberArk Endpoint Privilege Manager is demonstrated.
Background
Vulnerabilities in web applications have been known for quite a while. A good blog post on this subject was published by Satyam Singh in March 2015. Among other issues, he reports that passwords are stored as clear text in the browser’s memory and suggests a possible mitigation (salted hashing).
This report, like many others, has been mostly neglected. I did not see any web applications that adopted the salted hashing mitigation or anything similar. There are several known attack techniques/tools that bypass many of the popular endpoint protection products (AVs, EDRs). It is important to note that many of these published tools do not need admin privileges.
In this blog post, I propose a plan to protect sensitive data in CBBs (most of it also applicable to other browser types, I believe). The proposed mitigations (blocking actions) are all done in a kernel-mode filter driver[s]. They are meant to block (or make the attack much harder for) both standard and elevated processes (but not kernel-mode code).
Where Are the “Secrets?”
Sensitive data is stored and processed by CBBs in different locations/process routes. To provide comprehensive protection for this data, one needs to address all of the following locations/processes:
- Files on disk
- Browser’s VM
- Keyed-in data (from Keyboard)
- SSL-encrypted messages on their way to the web
- Information delivered by the browser (if you ask nicely)
“Tora! Tora! Tora!” – Main Attack Vectors
There is a multitude of tools and malicious products that “steal” browsers’ “secrets.” In this section, I summarize the underlying techniques (aka “attack vectors”) with a small set of actual samples.
A) Decrypt encoded “secret” values stored in files on disk (MITRE T1555/003)
This is a very common technique that is widely used by credential stealers. Sensitive information is stored by Chromium in disk files using DPAPI encryption. There are published tools that show how to decrypt these values if you run as the original user.
Sample published tool: LaZagne (MITRE S0349) [GitHub here]
Sample Credential Stealer: Redline [Analysis by Cyberint here]
B) Extract “secrets” stored in clear-text format from browser’s Virtual Memory (MITRE T1555/003)
As mentioned above, it has been known for a long time that sensitive information is stored in browsers’ Virtual Memory in clear-text format. We shall consider (in the mitigation section below) three different methods to get the memory data:
a) Access browser from an external process:
hProcess = OpenProcess(PROCESS_VM_READ, FALSE, <browser process pid>) ;
ReadProcessMemory(hProcess , …);
b) Create a browser process:
CreateProcess (0, <browser Activation Command>,…, pStartupInfo, hProcess);
ReadProcessMemory(hProcess , …);
c) Activate a dump utility to dump the memory of the browser process
Sample published tool: mimikittenz [GitHub here]
Sample published tool: my previous blog [here]
C) Ask the browser nicely (use command line arguments) (MITRE T1539)
A hacker known as “Alex” (@mangopdf) published in 2018 a method to activate the browser with a command line parameter (- -remote-debugging-port) that lets you ask the browser “nicely” to give you all its cookies (via a TCP “remote debugging port”).
Sample published tool: cookie_crimes [GitHub here. “Alex”’s Blog here]
A useful implementation: WhiteChocolateMacademiaNut [GitHub here]
D) Code injection into the browser process (MITRE T1185)
Obviously, code injected into the browser process can implement attacks “A” and “B” above. Additional attacks that can be implemented include:
– Logging input characters (to capture passwords)
– Hooking the SSL encryption function (to capture clear-text passwords, cookies and more)
– Hooking other functions to bypass protection mechanisms
Sample exploiter: Cobalt Strike (MITRE S0154)
Sample exploiter: chaes [MITRE S0631]
A Cybereason report [here] on chaes states that “browser hooking is the hallmark feature of most financial malware.”
E) Keylogging (MITRE T1056)
Keylogging can be used to capture “secrets” such as passwords. We shall focus for now only on user-mode standard process attacks.
Sample tool: Basic-Windows-keylogger (GitHub here, blog here)
Sample Credential Stealer: AppleSeed (MITRE S0622) used by Kimsuky (MITRE G0094)
F) Adversary in the middle (MITRE T1539, MITRE T1557)
An AiTM attack on the connection between the browser and the server of a web application can capture clear-text passwords and cookies (with “tokens”) if the communication is not secured (HTTP and not HTTPS). This issue is out of the scope of this blog and is included in this list of attack vectors on browsers for the sake of completeness.
Sample Open source framework: Evilginx 2 (GitHub here, Blog by Kuba Gretzky here)
Sample exploiter: Kimsuky (MITRE G0094) (using a modified version of PHProxy)
Detailed Mitigation Considerations
OK, it’s time to consider the mitigations for the attacks identified above. All mitigations will rely on kernel mode driver callbacks. In the following discussion, we shall refer to the Chrome browser (chrome.exe), but the same logic applies to other Chromium-based browsers (e.g., msedge.exe).
A) Protecting sensitive browser files
Rule: Block unauthorized processes from accessing sensitive browser files.
A) Q: What should be protected?
Consider “Login Data,” which holds encrypted passwords. It is usually found in the folders:
C:\Users\<Windows user>\AppData\Local\Google\Chrome\User Data\<Default | Gmail user>
(where Gmail user is a profile name, not the actual Gmail user name).
However, Chromium started (a short while ago) to create a snapshot of the files in this folder whenever a major upgrade is performed. Therefore, it will also be found in folders such as
\SnapShots\91.0.4472.164\<Default | Gmail user> located in the original “User Data” folder.
So, a good definition of the “Login Data” files that should be protected is:
“?:\Users\*\AppData\Local\Google\Chrome\User Data\*\Login Data”
Q: Which operations should be protected?
– Direct READ access (e.g., copy operation)
– File or path rename operation (which might take the file out of the scope defined above)
– Zipping or archiving by any standard program (for example, tar.exe should not be authorized to access this file)
B) Protecting browser’s VM
Rule: Block unauthorized processes from accessing browser’s memory.
Q: What is the browser process that we are going to protect (and trust)?
Clearly, the Chrome process to be protected (and trusted, e.g.: to access “Login Data”) will be a binary that is signed by Google. Obviously, we do not want to apply our protection to everything signed by Google, as it might create many false positive cases, so we should also verify it is actually the Chrome application.
Intuitively, we might rely on the binary name being chrome.exe or, more strictly, on the full path name “%SYSTEMDRIVE%:\Program Files\Google\Chrome\Application\chrome.exe.” This would be a mistake because a standard attacker can run Chrome from a different folder and under a different name. Try the following cmd.exe batch with a parameter [%1] that defines your attack folder (while Chrome is not already active):
Code Snippet #1: Running Chrome from an unprotected folder and with a different name
cd %1
xcopy /S "c:\Program Files\Google\Chrome" *
cd Application
ren chrome.exe newChrome.exe
newChrome.exe
You will see that a fully functional browser is running, where the binary file name of all the browser’s processes is newChrome.exe.
The solution is to look for a property of the binary file that is included in the signature. A good candidate here is the OriginalFileName property, which is chrome.exe.
So, the processes we want to protect (and trust) are:
processes signed by Google with OriginalFileName = “chrome.exe”
Note that if the attacker modifies OriginalFileName to be newChrome.exe, the binary is no longer signed. Therefore, we will not trust it (e.g., it will not be allowed to access login data or other critical files and will not be a fully functional browser).
Q: How to block access of unauthorized processes to the browser’s memory?
– Remove from OpenProcess the PROCESS_VM_READ access right (if it is requested)
– Prevent unauthorized processes from creating a browser process
– Prevent all potential ways of dumping the memory of the browser process
Explanation: This means that binaries signed by a trusted vendor (e.g., Microsoft) that can perform a memory dump should not be authorized to OpenProcess (PROCESS_VM_READ) the browser. Examples: rundll32, Taskmgr.exe. Might need to examine all LOLbins.
C) Prevent usage of “dangerous” command line arguments
Rule: Block unauthorized processes from creating a browser with “dangerous” command line arguments
This might seem redundant because in the previous section, we listed the requirement to “prevent unauthorized processes from creating a browser process” but note that “unauthorized processes” may be different in these two cases. For example, we may allow cmd.exe to create a new instance of the browser, but not with the “dangerous” command line arguments.
In fact, the default here should be not to authorize any process to create a browser with the “dangerous” command line arguments, and to let the user authorize specific processes (applications) to a minimized set of endpoints.
“- -remote-debugging-port”
As discussed above, creating a browser with this command line argument allows another process to control the operation of the browser via a TCP connection over the specified port. This control includes options to retrieve sensitive data, including all the cookies.
This option is part of Chromium’s DevTools and is usually used for testing web applications. An example of an open-source application using this feature is “ChromeDriver” by Chromium.org. This application is defined here as a “tool for automated testing of web apps across many browsers.” The usage of such an application should be allowed specifically by the user.
If the use of this option is widespread (many endpoints) and continuous, it might be a good idea to implement the following protection scheme (using an NDIS kernel driver):
– Track all browser debugging ports that are currently open.
– Allow only specific applications (e.g.: ChromeDriver.exe) to connect to these ports.
“- -remote-debugging-pipe”
This option is not currently active (as far as I know), but it might be a good idea to be prepared and treat it in the same way “- -remote-debugging-port” is treated.
short format = verbose format
Apparently, in Chrome, short-formatted command line arguments have the same text as the verbose version.
“-remote-debugging-port” has the same effect as “- -remote-debugging-port.”
Make sure the rule[s] you define cover both versions.
“- -headless”
This command line argument is commonly used together with “–remote-debugging-port.” One legitimate use of this mode of working (browser has no user interface) is to perform “web scraping” (web crawlers). I do not know how common this command line argument is in legitimate use, but I do know that malwares use it to achieve “legitimate” communications to their control. So, it might be a good idea to make a separate rule to prohibit usage of this command line argument. If it appears without “–remote-debugging-port” it should be blocked. As usual, the user may authorize specific applications.
D) Prevent code injection into the browser process
This is a very complex protection task, and “holes” in the protection I propose here will probably be discovered (I’ll be grateful if you let me know!), but I shall not cowardly (😃) avoid my duty to protect (and help others protect).
Rule: For unauthorized processes OpenProcess-ing a browser process, remove all “dangerous” access rights
“Dangerous” access rights allow code injection. My list of dangerous access rights includes:
PROCESS_CREATE_THREAD
PROCESS_DUP_HANDLE
PROCESS_SUSPEND_RESUME
PROCESS_VM_OPERATION
PROCESS_VM_READ
PROCESS_VM_WRITE
ACCESS_SYSTEM_SECURITY
WRITE_DAC
WRITE_OWNER
Rule: For unauthorized processes OpenThread-ing a browser process’ thread, remove all “dangerous” access rights
“Dangerous” access rights allow code injection. My list of dangerous access rights includes:
THREAD_IMPERSONATE
THREAD_SET_CONTEXT
THREAD_SET_INFORMATION
THREAD_SET_LIMITED_INFORMATION
THREAD_SET_THREAD_TOKEN
THREAD_SUSPEND_RESUME
ACCESS_SYSTEM_SECURITY
WRITE_DAC
WRITE_OWNER
The list of authorized processes should be very short, but must include the parent of the browser process.
Rule: Prevent browser process from loading unsigned (untrusted) DLL
DLL injection, DLL hijacking, DLL side-loading and Windows hooks are all techniques that can be used to inject a malicious DLL into a process.
Since Chrome.exe can be activated from an unsafe location (as shown above), a standard program can modify any of the DLLs in the current version folder
(e.g.: “C:\Program Files\Google\Chrome\Application\97.0.4692.71\chrome_elf.dll”)
and it will be successfully loaded into the valid browser process.
This rule will block such an attack as well as any other malicious DLL loading (provided, of course, the attacker cannot create a version of a loaded DLL that is signed by an authorized vendor).
E) Keylogging protection
Keylogging is a broad general issue that is not specific to browsers, and there are various commercial anti-keylogging products available.
In my next blog post, I will describe a standard (non-elevated) user-mode keylogging technique and suggest a method to detect if such a keylogging attack is active. Additionally, I will show a method to obstruct this attack during the keying-in of sensitive fields (e.g., password) in the browser.
It is interesting to note that this attack was seen for the first time in the wild (as far as I know) when used recently by the North Korea-based cyberespionage group Kimsuky (MITRE G0094).
Mitigations Summary
- Deny any access of unauthorized processes to sensitive files
(CreateFile, MoveFile) - Deny any access of unauthorized processes to browser’s VM
(OpenProcess, OpenThread) - Prevent unauthorized processes from creating the browser
(CreateProcess) - Block suspicious command line options when browser is created
(CreateProcess-command line) - Prevent browser process from loading unsigned (untrusted) DLL
(LoadLibrary)
Mitigation Demos
The following demos show how some of the mitigations discussed above operate in the CyberArk Endpoint Privilege Manager.
All of the videos work according to the following general plan:
- Turn relevant Endpoint Privilege Manager protection policy OFF
- Successfully execute attack[s]
- Roll back the results of the attack
- Turn the relevant Endpoint Privilege Manager protection policy ON
- Repeat the same attacks and observe that they are blocked
- Show blocking events recorded in the Endpoint Privilege Manager server
Demo#1 – Protecting sensitive files
Demo#2 – Protecting browser memory
Demo#3 – Asking nicely
Demo#4 – Code Injection
Summary
If the proposed protection plan is implemented fully and accurately (mainly in the identification and protection of trusted/authorized processes), I believe that it may:
- Block the vast majority of current credential stealers’ attacks on protected browsers.
- Make it very difficult for a standard user-mode process to steal credentials from protected browsers.
- Make it difficult for elevated user-mode processes to steal credentials from protected browsers (by forcing them to make “noisy,” illegitimate actions that will probably be detected/blocked by other security mechanisms).
- Provide a wide range of protection against other types of attacks on web applications (e.g., by preventing browser hooking, [which] is the hallmark feature of most financial malware).
It will not:
- Protect against kernel-mode (rootkit)
Let us make the attackers sweat.
GO BLUE!
Author note: Thank you to Anatoly Kardash a Senior Director on CyberArk’s R&D team for his support on this research.