mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-13 19:05:17 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
---
|
||||
name: performing-cloud-storage-forensic-acquisition
|
||||
description: Perform forensic acquisition and analysis of cloud storage services including Google Drive, OneDrive, Dropbox, and Box by collecting both API-based remote data and local sync client artifacts from endpoint devices.
|
||||
domain: cybersecurity
|
||||
subdomain: digital-forensics
|
||||
tags: [cloud-forensics, google-drive, onedrive, dropbox, box, cloud-acquisition, api-forensics, sync-client, endpoint-artifacts, magnet-axiom]
|
||||
version: "1.0"
|
||||
author: mahipal
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Performing Cloud Storage Forensic Acquisition
|
||||
|
||||
## Overview
|
||||
|
||||
Cloud storage forensic acquisition involves collecting digital evidence from services like Google Drive, OneDrive, Dropbox, and Box through both API-based remote acquisition and local endpoint artifact analysis. Modern investigations must address the challenge that cloud-synced files may exist in multiple states: locally synchronized, cloud-only (on-demand), cached, and deleted. Endpoint devices that have synchronized with cloud storage contain a wealth of metadata about locally synced files, files present only in the cloud, and even deleted items recoverable from cache folders. API-based acquisition using service-specific APIs provides direct access to remote data with valid credentials and proper legal authorization.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Legal authorization (warrant, consent, or corporate policy) for cloud data access
|
||||
- Valid user credentials or administrative access tokens
|
||||
- Magnet AXIOM Cloud, Cellebrite Cloud Analyzer, or equivalent tool
|
||||
- KAPE with cloud storage target files
|
||||
- Python 3.8+ with google-api-python-client, msal, dropbox SDK
|
||||
- Network connectivity for API-based acquisition
|
||||
|
||||
## Acquisition Methods
|
||||
|
||||
### Method 1: API-Based Remote Acquisition
|
||||
|
||||
#### Google Drive API Acquisition
|
||||
|
||||
```python
|
||||
from google.oauth2.credentials import Credentials
|
||||
from googleapiclient.discovery import build
|
||||
from googleapiclient.http import MediaIoBaseDownload
|
||||
import io
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class GoogleDriveForensicAcquisition:
|
||||
"""Forensically acquire files and metadata from Google Drive via API."""
|
||||
|
||||
def __init__(self, credentials_path: str, output_dir: str):
|
||||
self.creds = Credentials.from_authorized_user_file(credentials_path)
|
||||
self.service = build("drive", "v3", credentials=self.creds)
|
||||
self.output_dir = output_dir
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
self.acquisition_log = []
|
||||
|
||||
def list_all_files(self, include_trashed: bool = True) -> list:
|
||||
"""List all files including trashed items."""
|
||||
files = []
|
||||
page_token = None
|
||||
query = "" if include_trashed else "trashed = false"
|
||||
|
||||
while True:
|
||||
results = self.service.files().list(
|
||||
q=query,
|
||||
pageSize=1000,
|
||||
fields="nextPageToken, files(id, name, mimeType, size, "
|
||||
"createdTime, modifiedTime, trashed, trashedTime, "
|
||||
"owners, sharingUser, permissions, md5Checksum, "
|
||||
"parents, webViewLink, driveId)",
|
||||
pageToken=page_token
|
||||
).execute()
|
||||
|
||||
files.extend(results.get("files", []))
|
||||
page_token = results.get("nextPageToken")
|
||||
if not page_token:
|
||||
break
|
||||
|
||||
return files
|
||||
|
||||
def download_file(self, file_id: str, file_name: str, mime_type: str) -> str:
|
||||
"""Download a file from Google Drive preserving forensic integrity."""
|
||||
output_path = os.path.join(self.output_dir, file_name)
|
||||
|
||||
if mime_type.startswith("application/vnd.google-apps"):
|
||||
export_formats = {
|
||||
"application/vnd.google-apps.document": "application/pdf",
|
||||
"application/vnd.google-apps.spreadsheet": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.google-apps.presentation": "application/pdf",
|
||||
}
|
||||
export_mime = export_formats.get(mime_type, "application/pdf")
|
||||
request = self.service.files().export_media(fileId=file_id, mimeType=export_mime)
|
||||
else:
|
||||
request = self.service.files().get_media(fileId=file_id)
|
||||
|
||||
with io.FileIO(output_path, "wb") as fh:
|
||||
downloader = MediaIoBaseDownload(fh, request)
|
||||
done = False
|
||||
while not done:
|
||||
_, done = downloader.next_chunk()
|
||||
|
||||
self.acquisition_log.append({
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"file_id": file_id,
|
||||
"file_name": file_name,
|
||||
"output_path": output_path,
|
||||
"action": "downloaded"
|
||||
})
|
||||
return output_path
|
||||
|
||||
def get_activity_log(self, file_id: str) -> list:
|
||||
"""Retrieve activity/revision history for a specific file."""
|
||||
revisions = self.service.revisions().list(
|
||||
fileId=file_id,
|
||||
fields="revisions(id, modifiedTime, lastModifyingUser, size, md5Checksum)"
|
||||
).execute()
|
||||
return revisions.get("revisions", [])
|
||||
|
||||
def export_acquisition_report(self) -> str:
|
||||
"""Export acquisition log for chain of custody documentation."""
|
||||
report_path = os.path.join(self.output_dir, "acquisition_log.json")
|
||||
with open(report_path, "w") as f:
|
||||
json.dump({
|
||||
"acquisition_start": self.acquisition_log[0]["timestamp"] if self.acquisition_log else None,
|
||||
"acquisition_end": datetime.utcnow().isoformat(),
|
||||
"total_files": len(self.acquisition_log),
|
||||
"entries": self.acquisition_log
|
||||
}, f, indent=2)
|
||||
return report_path
|
||||
```
|
||||
|
||||
#### OneDrive / Microsoft 365 API Acquisition
|
||||
|
||||
```python
|
||||
import msal
|
||||
import requests
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class OneDriveForensicAcquisition:
|
||||
"""Forensically acquire files and metadata from OneDrive via Microsoft Graph API."""
|
||||
|
||||
def __init__(self, client_id: str, tenant_id: str, client_secret: str, output_dir: str):
|
||||
self.output_dir = output_dir
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
authority = f"https://login.microsoftonline.com/{tenant_id}"
|
||||
self.app = msal.ConfidentialClientApplication(
|
||||
client_id, authority=authority, client_credential=client_secret
|
||||
)
|
||||
token_result = self.app.acquire_token_for_client(
|
||||
scopes=["https://graph.microsoft.com/.default"]
|
||||
)
|
||||
self.access_token = token_result.get("access_token")
|
||||
self.headers = {"Authorization": f"Bearer {self.access_token}"}
|
||||
self.base_url = "https://graph.microsoft.com/v1.0"
|
||||
|
||||
def list_user_files(self, user_id: str) -> list:
|
||||
"""List all files in user's OneDrive."""
|
||||
url = f"{self.base_url}/users/{user_id}/drive/root/children"
|
||||
files = []
|
||||
while url:
|
||||
response = requests.get(url, headers=self.headers)
|
||||
data = response.json()
|
||||
files.extend(data.get("value", []))
|
||||
url = data.get("@odata.nextLink")
|
||||
return files
|
||||
|
||||
def download_file(self, user_id: str, item_id: str, filename: str) -> str:
|
||||
"""Download a file from OneDrive."""
|
||||
url = f"{self.base_url}/users/{user_id}/drive/items/{item_id}/content"
|
||||
response = requests.get(url, headers=self.headers, stream=True)
|
||||
output_path = os.path.join(self.output_dir, filename)
|
||||
with open(output_path, "wb") as f:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
f.write(chunk)
|
||||
return output_path
|
||||
|
||||
def get_deleted_items(self, user_id: str) -> list:
|
||||
"""Retrieve items from OneDrive recycle bin."""
|
||||
url = f"{self.base_url}/users/{user_id}/drive/special/recyclebin/children"
|
||||
response = requests.get(url, headers=self.headers)
|
||||
return response.json().get("value", [])
|
||||
```
|
||||
|
||||
### Method 2: Local Endpoint Artifact Collection
|
||||
|
||||
#### KAPE Targets for Cloud Storage
|
||||
|
||||
```powershell
|
||||
# Collect all cloud storage artifacts using KAPE
|
||||
kape.exe --tsource C: --tdest C:\Output\CloudArtifacts --target GoogleDrive,OneDrive,Dropbox,Box
|
||||
|
||||
# OneDrive artifacts
|
||||
# %USERPROFILE%\AppData\Local\Microsoft\OneDrive\logs\
|
||||
# %USERPROFILE%\AppData\Local\Microsoft\OneDrive\settings\
|
||||
# %USERPROFILE%\OneDrive\
|
||||
|
||||
# Google Drive artifacts
|
||||
# %USERPROFILE%\AppData\Local\Google\DriveFS\
|
||||
# Contains metadata SQLite databases and cached files
|
||||
|
||||
# Dropbox artifacts
|
||||
# %USERPROFILE%\AppData\Local\Dropbox\
|
||||
# %USERPROFILE%\Dropbox\.dropbox.cache\
|
||||
# Contains filecache.dbx (encrypted SQLite), host.dbx, config.dbx
|
||||
```
|
||||
|
||||
#### OneDrive Local Database Analysis
|
||||
|
||||
```python
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
def analyze_onedrive_sync_engine(db_path: str) -> list:
|
||||
"""Analyze OneDrive SyncEngineDatabase for file metadata."""
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Query for all tracked files including cloud-only items
|
||||
cursor.execute("""
|
||||
SELECT fileName, fileSize, lastChange,
|
||||
resourceID, parentResourceID, eTag
|
||||
FROM od_ClientFile_Records
|
||||
ORDER BY lastChange DESC
|
||||
""")
|
||||
|
||||
files = []
|
||||
for row in cursor.fetchall():
|
||||
files.append({
|
||||
"filename": row[0],
|
||||
"size": row[1],
|
||||
"last_change": row[2],
|
||||
"resource_id": row[3],
|
||||
"parent_id": row[4],
|
||||
"etag": row[5]
|
||||
})
|
||||
|
||||
conn.close()
|
||||
return files
|
||||
```
|
||||
|
||||
## Cloud Storage Artifacts Summary
|
||||
|
||||
| Service | Local Database | Cache Location | Log Files |
|
||||
|---------|---------------|----------------|-----------|
|
||||
| OneDrive | SyncEngineDatabase.db | %LOCALAPPDATA%\Microsoft\OneDrive\cache\ | %LOCALAPPDATA%\Microsoft\OneDrive\logs\ |
|
||||
| Google Drive | metadata_sqlite_db | %LOCALAPPDATA%\Google\DriveFS\{account}\content_cache\ | %LOCALAPPDATA%\Google\DriveFS\Logs\ |
|
||||
| Dropbox | filecache.dbx (encrypted) | %APPDATA%\Dropbox\.dropbox.cache\ | %APPDATA%\Dropbox\logs\ |
|
||||
| Box | sync_db | %LOCALAPPDATA%\Box\Box\cache\ | %LOCALAPPDATA%\Box\Box\logs\ |
|
||||
|
||||
## References
|
||||
|
||||
- SANS Cloud Storage Acquisition: https://www.sans.org/blog/cloud-storage-acquisition-from-endpoint-devices
|
||||
- Magnet AXIOM Cloud: https://www.magnetforensics.com/blog/how-to-acquire-and-analyze-cloud-data-with-magnet-axiom/
|
||||
- AWS Cloud Forensics Framework: https://docs.aws.amazon.com/prescriptive-guidance/latest/security-reference-architecture/cyber-forensics.html
|
||||
- API-Based Forensic Acquisition of Cloud Drives: https://arxiv.org/abs/1603.06542
|
||||
@@ -0,0 +1,22 @@
|
||||
# Cloud Storage Forensic Acquisition Report
|
||||
|
||||
## Case Information
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Case Number | |
|
||||
| Examiner | |
|
||||
| Legal Authorization | |
|
||||
|
||||
## Cloud Services Identified
|
||||
| Service | Account | Files Acquired | Deleted Items | Shared Items |
|
||||
|---------|---------|---------------|--------------|-------------|
|
||||
| | | | | |
|
||||
|
||||
## Acquisition Summary
|
||||
| Method | Files | Size | Hash Verified |
|
||||
|--------|-------|------|-------------- |
|
||||
| API-Based | | | |
|
||||
| Endpoint Artifacts | | | |
|
||||
|
||||
## Findings
|
||||
_(Summary of cloud storage forensic analysis)_
|
||||
@@ -0,0 +1,18 @@
|
||||
# Standards - Cloud Storage Forensic Acquisition
|
||||
|
||||
## Standards
|
||||
- NIST SP 800-86: Guide to Integrating Forensic Techniques
|
||||
- ISO/IEC 27037: Digital Evidence Collection
|
||||
- NIST Cloud Computing Forensic Science Challenges (NISTIR 8006)
|
||||
- CSA Cloud Forensics Capability Implementation Guide
|
||||
|
||||
## Tools
|
||||
- Magnet AXIOM Cloud: Commercial multi-cloud acquisition
|
||||
- Cellebrite Cloud Analyzer: SaaS evidence collection
|
||||
- kumodd: Open-source proof-of-concept cloud acquisition tool
|
||||
- KAPE: Endpoint-based cloud artifact collection
|
||||
|
||||
## API References
|
||||
- Google Drive API v3: https://developers.google.com/drive/api/v3/reference
|
||||
- Microsoft Graph API: https://docs.microsoft.com/en-us/graph/api/resources/onedrive
|
||||
- Dropbox API v2: https://www.dropbox.com/developers/documentation/http/documentation
|
||||
@@ -0,0 +1,33 @@
|
||||
# Workflows - Cloud Storage Forensic Acquisition
|
||||
|
||||
## Workflow 1: API-Based Remote Acquisition
|
||||
```
|
||||
Obtain legal authorization and credentials
|
||||
|
|
||||
Authenticate via service API (OAuth2 / app credentials)
|
||||
|
|
||||
Enumerate all files including shared and trashed items
|
||||
|
|
||||
Download file contents preserving metadata
|
||||
|
|
||||
Collect revision history and activity logs
|
||||
|
|
||||
Hash all acquired files (SHA-256)
|
||||
|
|
||||
Generate acquisition log with timestamps
|
||||
```
|
||||
|
||||
## Workflow 2: Endpoint Artifact Collection
|
||||
```
|
||||
Identify cloud sync client installations
|
||||
|
|
||||
Collect local sync databases (KAPE cloud targets)
|
||||
|
|
||||
Parse sync engine databases (OneDrive, GDrive, Dropbox)
|
||||
|
|
||||
Identify cloud-only files from metadata
|
||||
|
|
||||
Recover cached and deleted files from local storage
|
||||
|
|
||||
Correlate local artifacts with API-acquired data
|
||||
```
|
||||
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Cloud Storage Forensic Acquisition Processor
|
||||
|
||||
Collects and analyzes local cloud storage sync client artifacts
|
||||
from endpoint devices for OneDrive, Google Drive, and Dropbox.
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class CloudStorageArtifactCollector:
|
||||
"""Collect and analyze local cloud storage sync artifacts."""
|
||||
|
||||
def __init__(self, evidence_root: str, output_dir: str):
|
||||
self.evidence_root = Path(evidence_root)
|
||||
self.output_dir = Path(output_dir)
|
||||
self.output_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.findings = {}
|
||||
|
||||
def find_onedrive_artifacts(self) -> dict:
|
||||
"""Locate and parse OneDrive sync artifacts."""
|
||||
onedrive_paths = [
|
||||
"AppData/Local/Microsoft/OneDrive/settings",
|
||||
"AppData/Local/Microsoft/OneDrive/logs",
|
||||
]
|
||||
artifacts = {"databases": [], "logs": [], "config_files": []}
|
||||
|
||||
for user_dir in self.evidence_root.glob("Users/*"):
|
||||
for rel_path in onedrive_paths:
|
||||
full_path = user_dir / rel_path
|
||||
if full_path.exists():
|
||||
for f in full_path.rglob("*"):
|
||||
if f.is_file():
|
||||
category = "databases" if f.suffix in (".db", ".dat") else "logs"
|
||||
artifacts[category].append(str(f))
|
||||
|
||||
# Try to parse SyncEngineDatabase
|
||||
for db_path in artifacts["databases"]:
|
||||
if "SyncEngineDatabase" in db_path:
|
||||
try:
|
||||
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
|
||||
artifacts["sync_tables"] = [r[0] for r in cursor.fetchall()]
|
||||
conn.close()
|
||||
except Exception as e:
|
||||
artifacts["sync_error"] = str(e)
|
||||
|
||||
return artifacts
|
||||
|
||||
def find_google_drive_artifacts(self) -> dict:
|
||||
"""Locate and parse Google Drive FS artifacts."""
|
||||
artifacts = {"databases": [], "cache_files": [], "logs": []}
|
||||
|
||||
for user_dir in self.evidence_root.glob("Users/*"):
|
||||
gdrive_path = user_dir / "AppData/Local/Google/DriveFS"
|
||||
if gdrive_path.exists():
|
||||
for f in gdrive_path.rglob("*"):
|
||||
if f.is_file():
|
||||
if "metadata_sqlite_db" in f.name:
|
||||
artifacts["databases"].append(str(f))
|
||||
elif "content_cache" in str(f):
|
||||
artifacts["cache_files"].append(str(f))
|
||||
elif f.suffix == ".log":
|
||||
artifacts["logs"].append(str(f))
|
||||
|
||||
return artifacts
|
||||
|
||||
def find_dropbox_artifacts(self) -> dict:
|
||||
"""Locate and parse Dropbox artifacts."""
|
||||
artifacts = {"databases": [], "cache_files": [], "config": []}
|
||||
|
||||
for user_dir in self.evidence_root.glob("Users/*"):
|
||||
dropbox_path = user_dir / "AppData/Local/Dropbox"
|
||||
if dropbox_path.exists():
|
||||
for f in dropbox_path.rglob("*"):
|
||||
if f.is_file():
|
||||
if f.suffix in (".dbx", ".db"):
|
||||
artifacts["databases"].append(str(f))
|
||||
elif "cache" in str(f).lower():
|
||||
artifacts["cache_files"].append(str(f))
|
||||
|
||||
dropbox_cache = user_dir / "Dropbox/.dropbox.cache"
|
||||
if dropbox_cache.exists():
|
||||
for f in dropbox_cache.rglob("*"):
|
||||
if f.is_file():
|
||||
artifacts["cache_files"].append(str(f))
|
||||
|
||||
return artifacts
|
||||
|
||||
def generate_report(self) -> str:
|
||||
"""Generate comprehensive cloud storage artifact report."""
|
||||
self.findings = {
|
||||
"analysis_timestamp": datetime.now().isoformat(),
|
||||
"evidence_root": str(self.evidence_root),
|
||||
"onedrive": self.find_onedrive_artifacts(),
|
||||
"google_drive": self.find_google_drive_artifacts(),
|
||||
"dropbox": self.find_dropbox_artifacts(),
|
||||
}
|
||||
|
||||
report_path = self.output_dir / "cloud_storage_artifacts.json"
|
||||
with open(report_path, "w") as f:
|
||||
json.dump(self.findings, f, indent=2)
|
||||
|
||||
for service in ["onedrive", "google_drive", "dropbox"]:
|
||||
data = self.findings[service]
|
||||
db_count = len(data.get("databases", []))
|
||||
print(f"[*] {service}: {db_count} databases found")
|
||||
|
||||
print(f"[*] Report: {report_path}")
|
||||
return str(report_path)
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: python process.py <evidence_root> <output_dir>")
|
||||
sys.exit(1)
|
||||
collector = CloudStorageArtifactCollector(sys.argv[1], sys.argv[2])
|
||||
collector.generate_report()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user