generated from Dicken/dickendock
round58: Router-IP vom vollstaendigen Portscan im Sammel-Scan ausnehmen (FritzOS-Angriffserkennung reagierte auf vollen masscan-Scan gegen sich selbst)
This commit is contained in:
@@ -50,6 +50,28 @@ function formatToolsUsed(toolsUsed: {
|
|||||||
return `${masscanPart}, ${httpxPart}`;
|
return `${masscanPart}, ${httpxPart}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Löst FRITZBOX_HOST (Umgebungsvariable, siehe /api/scan/fritzbox weiter
|
||||||
|
* unten) zur IP-Adresse des Routers selbst auf - wird genutzt, um genau
|
||||||
|
* dieses eine Gerät vom vollständigen masscan-Portscan im Sammel-Scan
|
||||||
|
* auszunehmen (siehe Kommentar dort). Ist FRITZBOX_HOST bereits eine
|
||||||
|
* IP-Adresse, wird sie direkt übernommen, sonst per DNS aufgelöst. Liefert
|
||||||
|
* null, wenn nicht konfiguriert oder nicht auflösbar - dann greift einfach
|
||||||
|
* keine Ausnahme, wie vor round58.
|
||||||
|
*/
|
||||||
|
async function resolveRouterIp(): Promise<string | null> {
|
||||||
|
const host = process.env.FRITZBOX_HOST;
|
||||||
|
if (!host) return null;
|
||||||
|
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(host)) return host;
|
||||||
|
try {
|
||||||
|
const { lookup } = await import("node:dns/promises");
|
||||||
|
const { address } = await lookup(host);
|
||||||
|
return address;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scannt EIN Gerät (Ports, Titel/Favicon, Softwareerkennung) und schreibt die
|
* Scannt EIN Gerät (Ports, Titel/Favicon, Softwareerkennung) und schreibt die
|
||||||
* Ergebnisse in die Datenbank. Ausgelagert aus der Route, damit sowohl der
|
* Ergebnisse in die Datenbank. Ausgelagert aus der Route, damit sowohl der
|
||||||
@@ -249,7 +271,35 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
|||||||
// keine masscan-/httpx-Aufrufe mehr, nur noch die (leichtgewichtigen,
|
// keine masscan-/httpx-Aufrufe mehr, nur noch die (leichtgewichtigen,
|
||||||
// reinen HTTP-)Detailabfragen pro Port (Titel, Favicon,
|
// reinen HTTP-)Detailabfragen pro Port (Titel, Favicon,
|
||||||
// Softwareerkennung).
|
// Softwareerkennung).
|
||||||
const deviceIps = devices.map((d) => d.ip);
|
// NEU (round58): Die FritzBox (der Router selbst, NICHT ein Repeater
|
||||||
|
// o. ä.) hat eine eingebaute Angriffs-/Portscan-Erkennung
|
||||||
|
// (Sicherheitseinstellungen -> Angriffserkennung). Ein voller
|
||||||
|
// masscan-Lauf über 1-65535 Ports gegen die eigene Router-IP sieht
|
||||||
|
// dafür genau wie ein klassischer Portscan-Angriff aus - die
|
||||||
|
// FritzBox blockt/ignoriert die Scan-Quelle daraufhin offenbar
|
||||||
|
// kurzzeitig, sodass selbst der direkt danach laufende normale
|
||||||
|
// 80/443-Retry (siehe scanDeviceServices) noch nichts findet (siehe
|
||||||
|
// Bugreport: "0 Dienst(e) gefunden (Ports: keine)" bei der FritzBox
|
||||||
|
// selbst, während ein FRITZ!Repeater im selben Lauf ganz normal alle
|
||||||
|
// Dienste liefert - Repeater haben typischerweise nicht dieselbe
|
||||||
|
// Absicherung wie der Router, der ja die Sicherheits-Gateway-Rolle
|
||||||
|
// fürs ganze Netz hat). Die Router-IP wird daher gezielt aus dem
|
||||||
|
// masscan-Batch ausgenommen - für sie greift stattdessen weiter
|
||||||
|
// unten ganz normal die schonende "übliche Portliste"-Prüfung
|
||||||
|
// (kein vollständiger Portscan, kein masscan), ihre echten Dienste
|
||||||
|
// kennen wir ohnehin schon zuverlässig über den eigenen
|
||||||
|
// TR-064-Scanner (siehe scanner/fritzbox.ts).
|
||||||
|
const routerIp = await resolveRouterIp();
|
||||||
|
|
||||||
|
const deviceIps = devices.map((d) => d.ip).filter((ip) => ip !== routerIp);
|
||||||
|
if (routerIp && devices.some((d) => d.ip === routerIp)) {
|
||||||
|
logRepo.logScan({
|
||||||
|
type: "device",
|
||||||
|
targetId: null,
|
||||||
|
level: "info",
|
||||||
|
message: `Sammel-Scan: Router-IP ${routerIp} vom vollständigen Portscan ausgenommen (FritzOS-Angriffserkennung reagiert empfindlich auf volle Portscans gegen sich selbst) - wird stattdessen mit der üblichen Portliste geprüft.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Sichtbarer Fortschritt VOR dem eigentlichen Geräte-Scan: ohne das
|
// Sichtbarer Fortschritt VOR dem eigentlichen Geräte-Scan: ohne das
|
||||||
// stand die Anzeige die ganze Vorabscan-Zeit über bei "1 von 120" und
|
// stand die Anzeige die ganze Vorabscan-Zeit über bei "1 von 120" und
|
||||||
@@ -391,20 +441,22 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// WICHTIG (Bugfix round56): masscanBatch.get(device.ip) liefert
|
// Router-IP: siehe Kommentar oben bei resolveRouterIp() -
|
||||||
// "undefined" in ZWEI völlig unterschiedlichen Fällen: (a) der
|
// bewusst NICHT preFetched/fullScan nutzen, sondern die
|
||||||
// gesamte masscan-Batch ist fehlgeschlagen (masscanBatch ===
|
// schonende Standard-Portliste (kein voller 1-65535-Scan
|
||||||
// null), ODER (b) der Batch war erfolgreich, aber DIESES
|
// gegen den Router selbst, keine Angriffserkennung
|
||||||
// Gerät hat schlicht KEINE offenen Ports - ein bei Handys/
|
// getriggert).
|
||||||
// Smart-Geräten völlig normales, gültiges Ergebnis. Der
|
const isRouter = routerIp !== null && device.ip === routerIp;
|
||||||
// bisherige Code hat beide Fälle identisch behandelt und
|
if (isRouter) {
|
||||||
// damit für JEDES Gerät mit null gefundenen Ports fälschlich
|
const result = await performDeviceScan(device, false);
|
||||||
// einen kompletten, langsamen 65535-Port-TCP-Fallback-Scan
|
created += result.created;
|
||||||
// ausgelöst - genau das, was masscan eigentlich vermeiden
|
updated += result.updated;
|
||||||
// sollte. Ein leeres Array ist in JS truthy (nur undefined/
|
allStale.push(...result.staleServices);
|
||||||
// null/0/""/NaN/false sind falsy), daher reicht es, hier statt
|
allNameChanges.push(...result.nameChanges);
|
||||||
// "undefined" bewusst ein leeres Array zu liefern, wenn der
|
allNew.push(...result.newServices);
|
||||||
// Batch als Ganzes erfolgreich war.
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const masscanPorts = masscanBatch ? masscanBatch.get(device.ip) ?? [] : undefined;
|
const masscanPorts = masscanBatch ? masscanBatch.get(device.ip) ?? [] : undefined;
|
||||||
const preFetched: PreFetchedScanData = {
|
const preFetched: PreFetchedScanData = {
|
||||||
masscanAttempted: true,
|
masscanAttempted: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user