Overview
Browser-Data-Exfiltrator is a post-exploitation proof-of-concept demonstrating browser history theft from Windows targets.
It consists of a PowerShell client that runs on the victim machine and a Python Flask server on the attacker side. The client queries Chrome and Firefox SQLite history databases directly, collects metadata (username, hostname, timestamps), and POSTs the results as JSON to the server — which stores, exposes, and provides analytics on the collected data.
Features
Multi-Browser Support
- Extracts history from Chrome/Chromium and Firefox
- Dynamically discovers all browser profiles on the system
- Queries native SQLite databases (
History,places.sqlite) directly
Client-Side Exfiltration (PowerShell)
- Downloads and loads
System.Data.SQLite.dllat runtime from the attacker server - Creates temporary copies of locked database files before querying
- Cleans up all temporary files post-execution
- Captures last 50 URLs per profile along with visit timestamps
- Collects machine metadata: username, hostname, browser type
Server-Side Collection (Python/Flask)
- Receives and stores exfiltrated data as persistent JSON
- Serves the base64-encoded SQLite DLL to victim clients
- Provides REST API endpoints for data access and management
- Built-in analytics: client count, entry count, browsers, users, hostnames
REST API Endpoints
GET /— HTML dashboard listing all endpointsPOST /upload— Receive exfiltrated history data from victimGET /data— View all collected data (JSON)GET /stats— Analytics summaryPOST /clear— Reset all stored dataGET /sqldllBase64.txt— Serve base64-encoded SQLite DLL to victim
Architecture
Browser-Data-Exfiltrator/
├── Attacker/
│ ├── server.py # Flask server – receives, stores, and serves data
│ └── sqldllBase64.txt # Base64-encoded System.Data.SQLite.dll
├── Victim/
│ └── exfil.ps1 # PowerShell exfiltration client
├── ReadMe.md
└── .gitignore
Data flow:
Victim runs exfil.ps1
↓
Download + decode SQLite DLL from attacker server
↓
Discover Chrome/Firefox profiles on victim machine
↓
Copy locked DB files → Query via SQLite → Extract last 50 URLs
↓
Bundle with metadata (user, host, browser, timestamp)
↓
POST JSON payload → http://<attacker>:5000/upload
↓
Server stores data → browser_history_data.json
Implementation Details
Copying locked database files — Both Chrome and Firefox hold an exclusive lock on their SQLite history databases while the browser is running. Rather than failing on a locked file, the script copies each database to a temp path with a random GUID filename before querying, which sidesteps the lock entirely.
Base64 DLL delivery — Shipping the System.Data.SQLite.dll as a base64-encoded text file serves two purposes: it allows the Flask server to deliver a binary dependency over a plain HTTP GET without encoding issues, and it makes the transfer look like a text response rather than a raw binary, which is less likely to trigger network-level inspection.
Artifact cleanup — All temporary files (copied databases, decoded DLL) are deleted after execution using random GUID names, reducing forensic footprint on the victim machine.
Sample Output
Server /stats endpoint:
{
"total_clients": 1,
"total_entries": 97,
"browsers_found": ["Chrome", "Firefox"],
"users": ["john"],
"hostnames": ["DESKTOP-ABC123"],
"last_received": "2026-05-22T14:33:10"
}
Server /data endpoint (excerpt):
[
{
"user": "john",
"hostname": "DESKTOP-ABC123",
"browser": "Chrome",
"url": "https://example.com",
"title": "Example Domain",
"visit_time": "2026-05-22 13:45:00",
"timestamp": "2026-05-22T14:33:10"
}
]