Was macht Analyse von Outlook PST für E-Mail-Forensik?
Überblick
Microsoft Outlook PST (Personal Storage Table) und OST (Offline Storage Table) Dateien sind wichtige Beweisquellen in der digitalen Forensik. PST-Dateien speichern E-Mail-Nachrichten, Kalendereinträge, Kontakte, Aufgaben und Notizen in einem proprietären Binärformat, das auf dem MAPI (Messaging Application Programming Interface) Eigenschaftssystem basiert. Die forensische Analyse dieser Dateien ermöglicht die Wiederherstellung gelöschter E-Mails (aus dem Ordner „Wiederherstellbare Elemente“), die Extraktion von E-Mail-Headern zur Nachverfolgung von Nachrichtenwegen, die Analyse von Anhängen auf Malware oder exfiltrierte Daten sowie die Rekonstruktion von Kommunikationsmustern. Moderne PST-Dateien verwenden das Unicode-Format mit 4KB-Seiten und können bis zu 50 GB groß werden, während das ältere ANSI-Format auf 2 GB begrenzt ist.
Verwendungszwecke
- Bei der Untersuchung von Sicherheitsvorfällen, die die Analyse von Outlook PST für E-Mail-Forensik erfordert
- Bei der Erstellung von Erkennungsregeln oder Bedrohungssuchabfragen für diesen Bereich
- Wenn SOC-Analysten strukturierte Verfahren für diesen Analysetyp benötigen
- Bei der Validierung der Sicherheitsüberwachung für verwandte Angriffstechniken
Voraussetzungen
- libpff/pffexport (Open-Source PST-Parser)
- Python 3.8+ mit pypff- oder libratom-Bibliotheken
- MailXaminer, Forensic Email Collector oder SysTools PST Forensics (kommerziell)
- Microsoft Outlook (optional, für nativen PST-Zugriff)
- Ausreichend Speicherplatz für extrahierte Inhalte
PST-Datei-Speicherorte
| Quelle | Pfad |
|---|---|
| Outlook 2016+ Standard | %USERPROFILE%\Dokumente\Outlook-Dateien*.pst |
| Outlook Legacy | %LOCALAPPDATA%\Microsoft\Outlook*.pst |
| OST-Cache | %LOCALAPPDATA%\Microsoft\Outlook*.ost |
| Archiv | %USERPROFILE%\Dokumente\Outlook-Dateien\archive.pst |
Analyse mit Open-Source-Tools
libpff / pffexport
# Alle Elemente aus der PST-Datei exportieren
pffexport -m all evidence.pst -t exported_pst
# Nur E-Mail-Nachrichten exportieren
pffexport -m items evidence.pst -t exported_emails
# Wiederhergestellte/gelöschte Elemente exportieren
pffexport -m recovered evidence.pst -t recovered_items
# PST-Dateiinformationen abrufen
pffinfo evidence.pst
Python PST-Analyse
import pypff
import os
import json
import hashlib
import email
import sys
from datetime import datetime
from collections import defaultdict
class PSTForensicAnalyzer:
"""Forensische Analyse von Outlook PST/OST-Dateien."""
def __init__(self, pst_path: str, output_dir: str):
self.pst_path = pst_path
self.output_dir = output_dir
os.makedirs(output_dir, exist_ok=True)
self.pst = pypff.file()
self.pst.open(pst_path)
self.messages = []
self.attachments = []
self.stats = defaultdict(int)
def process_folder(self, folder, folder_path: str = ""):
"""PST-Ordner rekursiv verarbeiten und Nachrichten extrahieren."""
folder_name = folder.name or "Root"
current_path = f"{folder_path}/{folder_name}" if folder_path else folder_name
for i in range(folder.number_of_sub_messages):
try:
message = folder.get_sub_message(i)
msg_data = self.extract_message(message, current_path)
if msg_data:
self.messages.append(msg_data)
self.stats["total_messages"] += 1
except Exception as e:
self.stats["parse_errors"] += 1
for i in range(folder.number_of_sub_folders):
try:
subfolder = folder.get_sub_folder(i)
self.process_folder(subfolder, current_path)
except Exception:
continue
def extract_message(self, message, folder_path: str) -> dict:
"""Forensische Metadaten aus einer einzelnen E-Mail-Nachricht extrahieren."""
msg_data = {
"folder": folder_path,
"subject": message.subject or "",
"sender": message.sender_name or "",
"sender_email": "",
"creation_time": str(message.creation_time) if message.creation_time else None,
"delivery_time": str(message.delivery_time) if message.delivery_time else None,
"modification_time": str(message.modification_time) if message.modification_time else None,
"has_attachments": message.number_of_attachments > 0,
"attachment_count": message.number_of_attachments,
"body_size": len(message.plain_text_body or b""),
"html_size": len(message.html_body or b""),
}
# Transport-Header für die Routing-Analyse extrahieren
headers = message.transport_headers
if headers:
msg_data["headers_present"] = True
msg_data["headers_size"] = len(headers)
# Wichtige Header parsen
parsed = email.message_from_string(headers)
msg_data["from_header"] = parsed.get("From", "")
msg_data["to_header"] = parsed.get("To", "")
msg_data["date_header"] = parsed.get("Date", "")
msg_data["message_id"] = parsed.get("Message-ID", "")
msg_data["x_originating_ip"] = parsed.get("X-Originating-IP", "")
msg_data["received_headers"] = parsed.get_all("Received", [])
# Anhänge verarbeiten
for j in range(message.number_of_attachments):
try:
attachment = message.get_attachment(j)
att_data = {
"message_subject": msg_data["subject"],
"name": attachment.name or f"attachment_{j}",
"size": attachment.size,
"content_type": "",
}
self.attachments.append(att_data)
self.stats["total_attachments"] += 1
except Exception:
continue
return msg_data
def save_attachments(self, max_size_mb: int = 100):
"""Anhänge zur Analyse auf die Festplatte exportieren."""
att_dir = os.path.join(self.output_dir, "attachments")
os.makedirs(att_dir, exist_ok=True)
root = self.pst.get_root_folder()
self._save_attachments_recursive(root, att_dir, max_size_mb)
def _save_attachments_recursive(self, folder, att_dir, max_size_mb):
for i in range(folder.number_of_sub_messages):
try:
message = folder.get_sub_message(i)
for j in range(message.number_of_attachments):
att = message.get_attachment(j)
if att.size and att.size < max_size_mb * 1024 * 1024:
name = att.name or f"unknown_{i}_{j}"
safe_name = "".join(c if c.isalnum() or c in ".-_" else "_" for c in name)
path = os.path.join(att_dir, safe_name)
try:
data = att.read_buffer(att.size)
with open(path, "wb") as f:
f.write(data)
except Exception:
continue
except Exception:
continue
for i in range(folder.number_of_sub_folders):
try:
self._save_attachments_recursive(folder.get_sub_folder(i), att_dir, max_size_mb)
except Exception:
continue
def generate_report(self) -> str:
"""Umfassenden PST-Forensik-Analysebericht generieren."""
root = self.pst.get_root_folder()
self.process_folder(root)
report = {
"analysis_timestamp": datetime.now().isoformat(),
"pst_file": self.pst_path,
"pst_size_bytes": os.path.getsize(self.pst_path),
"statistics": dict(self.stats),
"messages": self.messages[:500],
"attachments": self.attachments[:200],
}
report_path = os.path.join(self.output_dir, "pst_forensic_report.json")
with open(report_path, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[*] Nachrichten insgesamt: {self.stats['total_messages']}")
print(f"[*] Anhänge insgesamt: {self.stats['total_attachments']}")
print(f"[*] Parse-Fehler: {self.stats['parse_errors']}")
return report_path
def close(self):
self.pst.close()
def main():
if len(sys.argv) < 3:
print("Verwendung: python process.py <pst_file> <output_dir>")
sys.exit(1)
analyzer = PSTForensicAnalyzer(sys.argv[1], sys.argv[2])
analyzer.generate_report()
analyzer.close()
if __name__ == "__main__":
main()
E-Mail-Header-Analyse
Wichtige Header für forensische Untersuchungen:
| Header | Forensischer Wert |
|---|---|
| Received | Nachrichten-Routing-Kette (von unten nach oben lesen) |
| X-Originating-IP | Tatsächliche IP-Adresse des Absenders |
| Message-ID | Eindeutige Kennung für Korrelation |
| Date | Sendezeitstempel |
| Return-Path | Bounce-Adresse (kann von From abweichen) |
| DKIM-Signature | Domänenauthentifizierungssignatur |
| Authentication-Results | SPF-, DKIM-, DMARC-Überprüfungsergebnisse |
| X-Mailer | Verwendeter E-Mail-Client |
Referenzen
- MailXaminer PST Forensics: https://www.mailxaminer.com/blog/outlook-pst-file-forensics/
- libpff Dokumentation: https://github.com/libyal/libpff
- PST-Dateiformatspezifikation: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-pst/
- SANS E-Mail-Forensik: https://www.sans.org/blog/email-forensics/
Beispielausgabe
$ pffexport /beweise/jsmith_archive.pst -t /analyse/pst_ausgabe
pffexport 20231205 - libpff PST/OST Export-Tool
=================================================
Eingabe: /beweise/jsmith_archive.pst (2,3 GB)
PST-Inhalte werden exportiert...
Ordner: 45
Nachrichten: 12.456
Anhänge: 3.234
Kontakte: 567
Kalender: 234
Aufgaben: 89
Export abgeschlossen in 3 Min 42 Sek.
$ python3 pst_analyzer.py /analyse/pst_ausgabe /analyse/email_bericht
PST-Forensik-Analysebericht
==============================
Quelle: jsmith_archive.pst ([email protected])
Datumsbereich: 2023-06-01 bis 2024-01-18
--- Postfachstatistiken ---
E-Mails insgesamt: 12.456
Gesendet: 4.567
Empfangen: 7.889
Mit Anhängen: 3.234
Gelöscht (wiederhergestellt): 234
--- Phishing / Verdächtige E-Mails ---
E-Mail #8923
Datum: 2024-01-15 14:30:22 UTC
Von: "IT-Support" <[email protected]>
An: [email protected]
Betreff: Dringend: Passwort zurücksetzen erforderlich
Header:
Return-Path: [email protected]
X-Originating-IP: 203.0.113.55
Received: von mail-relay.c0rporate-help.com (203.0.113.55)
SPF: FEHLGESCHLAGEN (Domain c0rporate-help.com)
DKIM: KEINE
DMARC: FEHLGESCHLAGEN
Anhänge:
- Password_Reset_Form.xlsm (245 KB) SHA-256: 7a3b8c9d...e1f2a3b4
Textvorschau: "Sehr geehrte Mitarbeiterin, sehr geehrter Mitarbeiter,
Ihr Passwort läuft in 24 Stunden ab.
Bitte öffnen Sie das beigefügte Formular, um Ihre Zugangsdaten zurückzusetzen..."
--- Hinweise auf Datenexfiltration ---
E-Mail #9102
Datum: 2024-01-16 03:15:45 UTC
Von: [email protected]
An: [email protected]
Betreff: (kein Betreff)
Anhänge:
- archive_part1.7z (24,5 MB) - verschlüsselt
- archive_part2.7z (24,5 MB) - verschlüsselt
E-Mail #9103
Datum: 2024-01-16 03:18:22 UTC
Von: [email protected]
An: [email protected]
Betreff: Re:
Anhänge:
- archive_part3.7z (18,2 MB) - verschlüsselt
--- Schlüsselworttreffer ---
"vertraulich": 45 E-Mails
"passwort": 23 E-Mails
"übertragung": 12 E-Mails
"kündigung": 3 E-Mails
"beweise löschen": 1 E-Mail (E-Mail #9200, 2024-01-17 22:30:00 UTC)
Zusammenfassung:
Phishing-E-Mails erkannt: 1 (initialer Kompromittierungsvektor)
Verdächtige gesendete E-Mails: 5 (an persönliche Konten mit Anhängen)
Verschlüsselte Anhänge: 3 (insgesamt 67,2 MB - mögliche Exfiltration)
Bericht: /analyse/email_bericht/pst_forensic_report.json