- AddLog() neuer Parameter 'persist' (default true) - 4 Routine-Poll-Logs nur noch im In-Memory-Log: - '0 PushEvents empfangen' - 'X Events, 0 neue PushEvents' - 'X Events, X neue PushEvents → X scannen' - 'X Diffs gescannt, 0 neue Keys' - 'X Diffs gescannt, X neue Keys' wird bei Keys > 0 weiterhin persistiert
188 lines
6.7 KiB
Markdown
188 lines
6.7 KiB
Markdown
# Umsetzungsplan: Pastebin Scraping Scanner
|
||
|
||
## Zusammenfassung
|
||
Kontinuierliches Scraping neuer öffentlicher Pastebin-Pastes über die Scraping API.
|
||
Pastebin ist eine der häufigsten Quellen für geleakte API-Keys, Credentials und Secrets.
|
||
|
||
## Warum Pastebin?
|
||
- **Klassische Dump-Plattform** für Secrets, Credentials, Config-Dateien
|
||
- User posten Keys zum Teilen, Debuggen oder versehentlich
|
||
- Automated Dumps von Credential-Stealern landen häufig auf Pastebin
|
||
- Kein Suchindex → man muss den Firehose-Stream der neuen Pastes scannen
|
||
- Ergänzt alle anderen Scanner die nur per Suchquery arbeiten
|
||
|
||
## Voraussetzung: Pastebin PRO Account
|
||
- **Pastebin PRO** ($29 Lifetime) ist **zwingend erforderlich**
|
||
- IP-Adresse muss auf https://pastebin.com/doc_scraping_api gewhitelisted werden
|
||
- Nur 1 IP pro Account, kann aber beliebig oft geändert werden (Änderungen greifen innerhalb 1 Minute)
|
||
- Ohne Whitelist → API-Zugriff wird blockiert
|
||
|
||
## API-Analyse
|
||
|
||
### Scraping API – 3 Endpoints
|
||
|
||
#### 1. Recent Pastes (Firehose)
|
||
```
|
||
GET https://scrape.pastebin.com/api_scraping.php?limit=250
|
||
```
|
||
- Liefert die **neuesten öffentlichen** Pastes (max 250 pro Request)
|
||
- Response: JSON-Array mit `scrape_url`, `full_url`, `date`, `key`, `size`, `expire`, `title`, `syntax`, `user`
|
||
- Caching: ~2 Minuten Verzögerung
|
||
- **Kein Suchfilter** – man bekommt ALLE neuen Pastes und muss lokal filtern
|
||
|
||
#### 2. Paste Content
|
||
```
|
||
GET https://scrape.pastebin.com/api_scrape_item.php?i={paste_key}
|
||
```
|
||
- Liefert den Rohtext eines Pastes
|
||
- Nur über die Scraping-API abrufbar (nicht /raw/)
|
||
|
||
#### 3. Paste Metadata
|
||
```
|
||
GET https://scrape.pastebin.com/api_scrape_item_meta.php?i={paste_key}
|
||
```
|
||
- Liefert erweiterte Metadaten (Hits, Syntax, etc.)
|
||
- Für unseren Use Case nicht zwingend nötig
|
||
|
||
### Rate Limits
|
||
- Kein hartes Rate Limit dokumentiert
|
||
- Empfehlung: Max 1 Request/Sekunde
|
||
- IP-basiert – nur gewhitelistete IP hat Zugriff
|
||
- Bei Missbrauch → IP-Block
|
||
|
||
## Implementierungsplan
|
||
|
||
### Phase 1: Config – Server Settings
|
||
|
||
Neues Setting in `ServerSettingsService.cs`:
|
||
```csharp
|
||
("PastebinScrapeEnabled", "toggle", "false", "Scanner", "Pastebin Scraping", "Pastebin Scraping API aktivieren (erfordert PRO Account + IP Whitelist)"),
|
||
```
|
||
|
||
Kein API-Key nötig – die Authentifizierung läuft über IP-Whitelist.
|
||
|
||
### Phase 2: Neue Scan-Methode `ScanPastebin`
|
||
|
||
```csharp
|
||
private async Task<List<(string Key, string Url)>> ScanPastebin(CancellationToken ct)
|
||
```
|
||
|
||
**Ablauf:**
|
||
1. Neueste Pastes abrufen: `GET api_scraping.php?limit=250`
|
||
2. Für jeden Paste:
|
||
- Prüfen ob `paste_key` bereits gescannt (lokales HashSet + DB-Check)
|
||
- Paste-Content abrufen: `GET api_scrape_item.php?i={key}`
|
||
- Content mit `KeyPatterns.Compiled` Regex scannen
|
||
- Bei Treffer: Key + `full_url` sammeln
|
||
3. Gescannte Paste-Keys merken (um Re-Scans zu vermeiden)
|
||
4. Zwischen Content-Requests: 1s Pause
|
||
|
||
### Phase 3: Paste-Key Tracking (Deduplication)
|
||
|
||
Da die Firehose dieselben Pastes mehrfach liefern kann, brauchen wir ein Tracking:
|
||
|
||
**Option A: In-Memory HashSet** (einfach, geht bei Neustart verloren)
|
||
```csharp
|
||
private readonly HashSet<string> _scannedPasteKeys = new();
|
||
```
|
||
|
||
**Option B: DB-Tabelle** (persistent, verhindert Re-Scans nach Neustart)
|
||
```sql
|
||
CREATE TABLE IF NOT EXISTS pastebin_scanned (
|
||
paste_key TEXT PRIMARY KEY,
|
||
scanned_at TEXT NOT NULL
|
||
);
|
||
```
|
||
|
||
**Empfehlung:** Option A (In-Memory) mit TTL – die Pastes laufen sowieso ab.
|
||
Das HashSet wird beim Scan-Start befüllt und nach 24h geleert.
|
||
|
||
### Phase 4: Integration in RunScan
|
||
|
||
```csharp
|
||
// In RunScan(), nach HuggingFace:
|
||
if (mode != "quick")
|
||
{
|
||
var pastebinEnabled = _settings.GetBool("PastebinScrapeEnabled", false);
|
||
if (pastebinEnabled)
|
||
{
|
||
SetProgress("Pastebin Scraping", "Starte…");
|
||
var pbKeys = await ScanPastebin(ct);
|
||
allFoundKeys.AddRange(pbKeys.Select(k => (k.Key, k.Url, "pastebin")));
|
||
AddLog("scan", "Pastebin-Scan: " + pbKeys.Count + " Key(s) gefunden");
|
||
}
|
||
}
|
||
```
|
||
|
||
- **Mode `quick`:** Kein Pastebin-Scan (zu viele Requests)
|
||
- **Mode `web`:** Pastebin-Scan aktiv (Web-Quelle)
|
||
- **Mode `full`:** Pastebin-Scan aktiv
|
||
|
||
### Phase 5: Intelligentes Filtern
|
||
|
||
Nicht jeder Paste muss heruntergeladen werden. Vor-Filterung über Metadaten:
|
||
|
||
```csharp
|
||
// Relevante Syntax-Typen (höhere Wahrscheinlichkeit für Keys)
|
||
private static readonly HashSet<string> RelevantSyntax = new(StringComparer.OrdinalIgnoreCase)
|
||
{
|
||
"", "text", "python", "javascript", "bash", "json", "yaml", "ini",
|
||
"php", "ruby", "java", "csharp", "go", "rust", "typescript",
|
||
"powershell", "shell", "markdown", "xml", "toml", "properties"
|
||
};
|
||
|
||
// Relevante Titel-Keywords
|
||
private static readonly string[] TitleKeywords =
|
||
{
|
||
"key", "api", "token", "secret", "credential", "config", "env",
|
||
"anthropic", "openai", "aws", "claude", "password", "leak"
|
||
};
|
||
```
|
||
|
||
**Strategie:**
|
||
1. **Titel-Match:** Wenn Titel ein Keyword enthält → immer scannen
|
||
2. **Syntax-Match:** Wenn Syntax relevant (Code/Text) → scannen
|
||
3. **Größen-Filter:** Nur Pastes < 500 KB (keine riesigen Dumps)
|
||
4. **Syntax-Ausschluss:** Binär-Formate, Bilder, etc. → überspringen
|
||
|
||
### Phase 6: Scan-Frequenz
|
||
|
||
Da der tägliche Full-Scan nur einmal läuft, würden wir zwischen zwei Scans viele Pastes verpassen (Pastebin hat ~10.000+ neue Pastes/Tag).
|
||
|
||
**Zwei Optionen:**
|
||
|
||
**A. Einmaliger Snapshot pro Full-Scan (einfach)**
|
||
- Beim Full-Scan einmal 250 neueste Pastes abrufen + scannen
|
||
- Verpfasst die meisten Pastes, aber fängt zumindest aktuelle ab
|
||
- Empfohlen für den Anfang
|
||
|
||
**B. Kontinuierlicher Hintergrund-Scanner (komplex)**
|
||
- Eigener BackgroundService der alle 2-3 Minuten pollt
|
||
- Fängt nahezu alle neuen Pastes ab
|
||
- Deutlich mehr Requests (~720/Tag × 250 = 180.000 Pastes/Tag)
|
||
- Kann später hinzugefügt werden
|
||
|
||
**Empfehlung:** Option A für Phase 1, Option B als optionales Follow-up.
|
||
|
||
## Scan-Volumina (geschätzt)
|
||
|
||
| Szenario | Pastes gescannt | API Requests | Dauer |
|
||
|---|---|---|---|
|
||
| Einmal 250 Pastes | 250 | ~251 (1 Liste + 250 Content) | ~5 Min |
|
||
| Einmal 250, nur gefiltert | ~100 | ~101 | ~2 Min |
|
||
| Kontinuierlich (alle 3 Min) | ~180.000/Tag | ~720 Listen + ~180.000 Content | Dauerhaft |
|
||
|
||
## Aufwandsschätzung
|
||
- **Implementierung:** ~200 Zeilen Code
|
||
- **Komplexität:** Niedrig-Mittel (einfache API, aber Dedup + Filterung)
|
||
- **Erwarteter Ertrag:** 🔥 Hoch (Pastebin = klassische Secret-Dump-Plattform)
|
||
- **Kosten:** $29 einmalig für Pastebin PRO
|
||
|
||
## Risiken
|
||
- IP-Whitelist → funktioniert nur von einer festen IP (Server)
|
||
- Nur **öffentliche** Pastes sind sichtbar (unlisted/private nicht)
|
||
- Pastes können schnell gelöscht werden → zeitnahes Scraping wichtig
|
||
- Hohe Paste-Menge → viele Keys sind False Positives (Test-Keys, bereits revoked)
|
||
- Bei zu aggressivem Polling → IP-Block möglich
|
||
- Pastebin kann API-Bedingungen jederzeit ändern
|