Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills

Complete skill folder anatomy across all cybersecurity skills:
- scripts/agent.py: 80-150 line Python agents using real libraries (impacket,
  boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.)
- references/api-reference.md: real API documentation with method signatures
- LICENSE: MIT license for all skill folders
This commit is contained in:
mukul975
2026-03-10 21:02:12 +01:00
parent c74d52fa30
commit 27c6414ca5
1390 changed files with 106806 additions and 0 deletions
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Anthropic Agent Skills Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,62 @@
# API Reference: Browser History Extraction Agent
## Dependencies
| Library | Version | Purpose |
|---------|---------|---------|
| sqlite3 | stdlib | Query Chrome/Firefox SQLite databases |
| csv | stdlib | Export results to CSV format |
## CLI Usage
```bash
python scripts/agent.py \
--chrome-dir "/mnt/evidence/Users/suspect/AppData/Local/Google/Chrome/User Data/Default" \
--firefox-dir "/mnt/evidence/Users/suspect/AppData/Roaming/Mozilla/Firefox/Profiles/abc.default" \
--output-dir /cases/analysis/ \
--output browser_report.json
```
## Functions
### `chrome_time_to_utc(chrome_ts) -> str`
Converts Chrome/WebKit timestamp (microseconds since 1601-01-01) to ISO-8601 UTC string.
### `firefox_time_to_utc(ff_ts) -> str`
Converts Firefox timestamp (microseconds since Unix epoch) to ISO-8601 UTC string.
### `extract_chrome_history(db_path, limit) -> list`
Queries the `urls` table from Chrome's `History` SQLite DB. Returns URL, title, last_visit, visit_count.
### `extract_chrome_downloads(db_path, limit) -> list`
Queries the `downloads` table for file path, source URL, size, timestamps, and danger type.
### `extract_chrome_cookies(db_path, limit) -> list`
Queries the `cookies` table. Note: cookie values are DPAPI-encrypted on Windows.
### `extract_firefox_history(db_path, limit) -> list`
Queries `moz_places` JOIN `moz_historyvisits` from Firefox `places.sqlite`.
### `extract_firefox_cookies(db_path, limit) -> list`
Queries `moz_cookies` from Firefox `cookies.sqlite`.
### `export_to_csv(data, output_path)`
Writes list of dicts to CSV with headers.
### `generate_report(chrome_dir, firefox_dir, output_dir) -> dict`
Orchestrates extraction from both browsers and exports CSVs.
## Browser Database Locations (Windows)
| Browser | Path |
|---------|------|
| Chrome | `%LOCALAPPDATA%\Google\Chrome\User Data\Default\History` |
| Edge | `%LOCALAPPDATA%\Microsoft\Edge\User Data\Default\History` |
| Firefox | `%APPDATA%\Mozilla\Firefox\Profiles\*.default\places.sqlite` |
## Timestamp Formats
| Browser | Epoch | Unit |
|---------|-------|------|
| Chrome/Edge | 1601-01-01 | Microseconds |
| Firefox | 1970-01-01 | Microseconds |
@@ -0,0 +1,202 @@
#!/usr/bin/env python3
"""Browser history artifact extraction agent using sqlite3 for Chrome/Firefox/Edge forensics."""
import argparse
import csv
import json
import logging
import os
import sqlite3
import sys
from datetime import datetime, timedelta
from typing import List, Optional
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
CHROME_EPOCH = datetime(1601, 1, 1)
UNIX_EPOCH = datetime(1970, 1, 1)
def chrome_time_to_utc(chrome_ts: int) -> str:
"""Convert Chrome/WebKit timestamp (microseconds since 1601-01-01) to ISO UTC."""
if not chrome_ts or chrome_ts < 0:
return ""
try:
dt = CHROME_EPOCH + timedelta(microseconds=chrome_ts)
return dt.isoformat() + "Z"
except (OverflowError, ValueError):
return ""
def firefox_time_to_utc(ff_ts: int) -> str:
"""Convert Firefox timestamp (microseconds since Unix epoch) to ISO UTC."""
if not ff_ts or ff_ts < 0:
return ""
try:
dt = UNIX_EPOCH + timedelta(microseconds=ff_ts)
return dt.isoformat() + "Z"
except (OverflowError, ValueError):
return ""
def extract_chrome_history(db_path: str, limit: int = 5000) -> List[dict]:
"""Extract browsing history from Chrome/Edge History database."""
if not os.path.exists(db_path):
logger.warning("Chrome History DB not found: %s", db_path)
return []
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
cursor = conn.cursor()
cursor.execute("""
SELECT urls.url, urls.title, urls.last_visit_time, urls.visit_count, urls.typed_count
FROM urls ORDER BY urls.last_visit_time DESC LIMIT ?
""", (limit,))
rows = cursor.fetchall()
conn.close()
results = []
for url, title, last_visit, visit_count, typed_count in rows:
results.append({
"url": url, "title": title or "",
"last_visit": chrome_time_to_utc(last_visit),
"visit_count": visit_count, "typed_count": typed_count,
})
logger.info("Extracted %d Chrome history entries from %s", len(results), db_path)
return results
def extract_chrome_downloads(db_path: str, limit: int = 1000) -> List[dict]:
"""Extract downloads from Chrome/Edge History database."""
if not os.path.exists(db_path):
return []
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
cursor = conn.cursor()
cursor.execute("""
SELECT current_path, tab_url, total_bytes, start_time, end_time, mime_type, danger_type
FROM downloads ORDER BY start_time DESC LIMIT ?
""", (limit,))
rows = cursor.fetchall()
conn.close()
return [{
"path": r[0], "source_url": r[1], "size_bytes": r[2],
"start_time": chrome_time_to_utc(r[3]), "end_time": chrome_time_to_utc(r[4]),
"mime_type": r[5], "danger_type": r[6],
} for r in rows]
def extract_chrome_cookies(db_path: str, limit: int = 5000) -> List[dict]:
"""Extract cookies from Chrome Cookies database."""
if not os.path.exists(db_path):
return []
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
cursor = conn.cursor()
cursor.execute("""
SELECT host_key, name, path, creation_utc, last_access_utc, is_secure, is_httponly
FROM cookies ORDER BY last_access_utc DESC LIMIT ?
""", (limit,))
rows = cursor.fetchall()
conn.close()
return [{
"host": r[0], "name": r[1], "path": r[2],
"created": chrome_time_to_utc(r[3]), "last_access": chrome_time_to_utc(r[4]),
"secure": bool(r[5]), "httponly": bool(r[6]),
} for r in rows]
def extract_firefox_history(db_path: str, limit: int = 5000) -> List[dict]:
"""Extract browsing history from Firefox places.sqlite."""
if not os.path.exists(db_path):
logger.warning("Firefox places.sqlite not found: %s", db_path)
return []
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
cursor = conn.cursor()
cursor.execute("""
SELECT moz_places.url, moz_places.title, moz_historyvisits.visit_date,
moz_places.visit_count, moz_historyvisits.visit_type
FROM moz_places
JOIN moz_historyvisits ON moz_places.id = moz_historyvisits.place_id
ORDER BY moz_historyvisits.visit_date DESC LIMIT ?
""", (limit,))
rows = cursor.fetchall()
conn.close()
return [{
"url": r[0], "title": r[1] or "",
"visit_date": firefox_time_to_utc(r[2]),
"visit_count": r[3], "visit_type": r[4],
} for r in rows]
def extract_firefox_cookies(db_path: str, limit: int = 5000) -> List[dict]:
"""Extract cookies from Firefox cookies.sqlite."""
if not os.path.exists(db_path):
return []
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
cursor = conn.cursor()
cursor.execute("""
SELECT host, name, path, creationTime, lastAccessed, isSecure, isHttpOnly
FROM moz_cookies ORDER BY lastAccessed DESC LIMIT ?
""", (limit,))
rows = cursor.fetchall()
conn.close()
return [{
"host": r[0], "name": r[1], "path": r[2],
"created": firefox_time_to_utc(r[3]), "last_access": firefox_time_to_utc(r[4]),
"secure": bool(r[5]), "httponly": bool(r[6]),
} for r in rows]
def export_to_csv(data: List[dict], output_path: str) -> None:
"""Export extracted data to CSV."""
if not data:
return
with open(output_path, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
logger.info("Exported %d rows to %s", len(data), output_path)
def generate_report(chrome_dir: str = "", firefox_dir: str = "",
output_dir: str = ".") -> dict:
"""Generate comprehensive browser forensics report."""
report = {"analysis_date": datetime.utcnow().isoformat(), "browsers": {}}
if chrome_dir and os.path.isdir(chrome_dir):
history = extract_chrome_history(os.path.join(chrome_dir, "History"))
downloads = extract_chrome_downloads(os.path.join(chrome_dir, "History"))
cookies = extract_chrome_cookies(os.path.join(chrome_dir, "Cookies"))
report["browsers"]["chrome"] = {
"history_count": len(history), "download_count": len(downloads),
"cookie_count": len(cookies),
}
export_to_csv(history, os.path.join(output_dir, "chrome_history.csv"))
export_to_csv(downloads, os.path.join(output_dir, "chrome_downloads.csv"))
if firefox_dir and os.path.isdir(firefox_dir):
history = extract_firefox_history(os.path.join(firefox_dir, "places.sqlite"))
cookies = extract_firefox_cookies(os.path.join(firefox_dir, "cookies.sqlite"))
report["browsers"]["firefox"] = {
"history_count": len(history), "cookie_count": len(cookies),
}
export_to_csv(history, os.path.join(output_dir, "firefox_history.csv"))
return report
def main():
parser = argparse.ArgumentParser(description="Browser History Extraction Agent")
parser.add_argument("--chrome-dir", default="", help="Path to Chrome/Edge User Data/Default")
parser.add_argument("--firefox-dir", default="", help="Path to Firefox profile directory")
parser.add_argument("--output-dir", default=".", help="Output directory for CSVs and report")
parser.add_argument("--output", default="browser_report.json")
args = parser.parse_args()
os.makedirs(args.output_dir, exist_ok=True)
report = generate_report(args.chrome_dir, args.firefox_dir, args.output_dir)
with open(os.path.join(args.output_dir, args.output), "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved")
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()