- #_shellntel Blog
- Posts
- Into The Belly Of The Beast
Into The Belly Of The Beast
Browser Session and Cookie Extraction Over WebSocket With Chrome DevTools Protocol

In this post, we introduce a post-exploitation concept and tool designed to dump all cookies, session, and local storage entries to JSON files and it does this through a localhost
WebSocket connection using Chrome/Brave/Edge's remote debug functionality (Chrome DevTools Protocol).
The Belly - Chrome DevTools Protocol (CDP)
CDP was created to allow developers to interact with and control Chromium-based browsers (Edge/Brave/Chrome/Opera, etc.) programmatically and enables things like inspecting web pages in real-time, debugging JavaScript, DOM manipulation, monitoring network activity (extremely useful), and performing nearly anything possible within DevTools. It essentially enables a communication channel between the browser and a client (e.g., a script or some other external application) via a WebSocket through a "debugging port".
When the --remote-debugging-port
switch is enabled (supplied via the command line when launching the browser), external tools or scripts can connect to the browser over the network. It's typically used for tasks such as testing automation with tools like Playwright, Puppeteer, Selenium, etc., or just to debug web applications remotely.
For example, running chrome.exe --remote-debugging-port=9481
starts Chrome with debugging enabled on port 9481
, and is accessible via http://localhost:9481
or via the CDP WebSocket (ws://localhost:9481
)
You can learn more about CDP here.
The Concept
1. Find the users' default browser
This is usually done by querying the HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice
registry path to determine which default program is associated with opening URLs. In this case, the value for ProgId
gives us a hint as to what the default browser is. The ProgId
is typically something like ChromeHTML
, or BraveHTML
, etc, but in the odd case where the default browser hasn't been set, it might look more like FirefoxURL-[RandomString]
. Either way, we can usually determine the default browser by simply retrieving that ProgId
value.
2. Relaunch the browser with the --remote-debugging-port
enabled
If the browser is already open and does not have remote debugging enabled (if it does already, something is unusual), we need to terminate it and relaunch it in order to enable the debug port. Unfortunately, the main caveat to this tool is that the debug port cannot just be enabled on an already running browser (that I know of). This may or may not spark some suspicion or curiosity from the end-user's perspective.
3. Dump all the things
Once the browser is relaunched with the --remote-debugging-port
switch enabled, we can interact with it freely, and have access to a number of things that are useful during engagements, particularly session information (auth tokens, cookies, etc.).
PS C:\> .\TokenTaker.ps1
[+] Targeting default browser: brave at C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe
[+] Default profile directory: C:\Users\user\AppData\Local\BraveSoftware\Brave-Browser\User Data
[+] Starting brave with default profile and debugging on port 9481...
[+] Found 2 tabs.
[+] Connecting to tab: chrome://newtab/ via ws://127.0.0.1:9481/devtools/page/14C19B86195AE6F889CCF53BBFCED2F6
[+] WebSocket connected.
[+] Dumping it all...
[+] WebSocket closed.
[+] Found token for .login.microsoftonline.com
- Total Cookies: 862
- Total Local storage items: 0
- Total Session storage items: 0
[+] Dumped files saved to C:\Users\user\AppData\Local\Temp\901b7af1-32c7-47c8-a5c0-9f875d0855e1
TokenTaker
TokenTaker is a proof-of-concept PowerShell script that automates the above process and dumps all cookies, session and local storage. It can be downloaded from our GitHub page here.
The script will first identify the default browser by querying the Windows registry for the ProgId
of the application handling HTTPS links and uses a lookup table ($browserMap
) to match ProgId
values to known browser paths and user profile directories. Once it’s figured out which browser to use, it first checks if remote debugging is already enabled (it really shouldn’t be by default), but if it is, it will use that. If an existing browser session is detected without remote debugging (the more likely scenario), it is forcibly terminated and a new browser instance is started with --remote-debugging-port=9481
.
Once it has confirmed that remote debugging is enabled, it will retrieve the list of open tabs from the debugging API, and extracts the WebSocket debugging URL from the /json
endpoint. The /json
endpoint returns a list of active tabs, each with a webSocketDebuggerUrl
, which is used to send and receive debugging commands.

Example response from http://127.0.0.1:9481/json
After it’s retrieved list of active tabs, it connects to the first one it finds using the webSocketDebuggerUrl
:

Retrieving list of active tabs and initial WebSocket Connection
The first command sent over the WebSocket is:
$cookieCommand = @{
"id" = 1;
"method" = "Network.getAllCookies"
} | ConvertTo-Json
The above command tells the browser to use the Network.getAllCookies
method, which fetches all cookies accessible to the browser, along with assigning a request ID to track responses, and converted to JSON format.
The script then sends this JSON-encoded message over the WebSocket with the Send-WsMsg
function:
Send-WsMsg -WebSocket $ws -Message $cookieCommand -OutputFile $cookieFile | Out-Null
Inside Send-WsMsg
, the command is converted to UTF-8 bytes and sent to the browser WebSocket, and the WebSocket returns a JSON object with all of the stored cookies:

Example cookie output
Unlike cookies, Local Storage and Session Storage are not accessible via Network
methods, and instead, JavaScript execution is required via the Runtime.evaluate
method. To retrieve Local Storage, the script sends:
$localStorageCommand = @{
"id" = 2;
"method" = "Runtime.evaluate";
"params" = @{ "expression" = "JSON.stringify(localStorage)" }
} | ConvertTo-Json
The Runtime.evaluate
method runs JavaScript inside the active browser tab, and "params": { "expression": "JSON.stringify(localStorage)" }
is used to convert the Local Storage into a JSON string. The $localStorageCommand
is then sent to the WebSocket, and it returns something like the following:

Example Local Storage Output
Session Storage works the same way as Local Storage but is tab-specific and cleared when the browser is closed.
After retrieving cookies, local storage, and session storage, TokenTaker gracefully terminates the WebSocket connection. This sends a Close
frame over the WebSocket, ensuring a clean disconnection.
$ws.CloseAsync(
[System.Net.WebSockets.WebSocketCloseStatus]::NormalClosure,
"Done",
[System.Threading.CancellationToken]::None
).Wait()
Write-Output "[+] WebSocket closed."
All files are saved to a random GUID-named folder in $env:TEMP
.
For Defenders
Disabling the --remote-debugging-port
functionality can be accomplished in several ways, including GPOs, registry modifications, and system-level mitigations.
Since Chrome, Brave and Microsoft Edge are built on Chromium, the following similar methods can be used.
Completely Disable Developer Tools via Group Policy
You can disable Developer Tools entirely, which will also block remote debugging:
Download the Chrome/Edge ADMX templates from:
Chrome: Google Enterprise Policy
Import the ADMX files into Group Policy Editor.
Navigate to:
Computer Configuration -> Administrative Templates -> Google Chrome / Microsoft Edge
Enable:
"Disable Developer Tools" (
DeveloperToolsAvailability
set to2
)
Block Just Remote Debugging Ports via Group Policy
In Group Policy Editor, go to:
Computer Configuration -> Administrative Templates -> Google Chrome / Microsoft Edge -> Security Settings
Enable the
Command-line argument overrides are not allowed
policy:(RestrictCommandLineFlags
).Add the following blocked arguments:
--remote-debugging-port
Modify The Windows Registry (an alternative)
If GPO is not an option, use the Windows Registry:
Open Registry Editor (
regedit
).Navigate to (or create):
For Chrome
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome
Or for Edge:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\MicrosoftEdge
Create a
DWORD (32-bit) Value
:Name:
DeveloperToolsAvailability
Value:
2
(Disabled)
Create another key (if it doesn’t exist):
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\CommandLineFlagSecurity
Add a String Value:
RestrictCommandLineFlags
Set value to:
--remote-debugging-port
Network-Based Restrictions
If remote debugging is being misused over the network, consider blocking relevant TCP ports.
Remote debugging typically runs on port
9222
(the default) or any other arbitrary port.Use a firewall rule (Windows Defender Firewall, Group Policy, or network firewall) to block outbound/inbound traffic on
TCP 9222
, etc.
Application Whitelisting
Use Windows AppLocker or Microsoft Defender Application Control to restrict the use of Chrome/Edge with non-approved command-line arguments.
Disabling Debugging Features via Browser Extensions
Some security tools offer browser extensions that block debugging. Consider deploying a security extension that prevents script injection or debugging.
Disclaimer
This tool is provided purely for educational purposes and authorized security testing only. It is intended to help users understand web browser security concepts, vulnerabilities, and to help find ways to defend against these sorts of things. Unauthorized use, including but not limited to attacking systems without explicit permission, is strictly prohibited and may violate applicable laws. The developers are not responsible for any misuse, damage, or legal consequences resulting from the use of this tool. Use responsibly and ethically, and always obtain proper consent before testing any system.