| tstats summariesonly=true count FROM datamodel=Web WHERE earliest=-7d BY Web.src Web.uri_path Web.status _time span=1m | rename Web.* AS * | search NOT src IN ("REPLACE_WITH_AUTHORISED_SCANNER_IP") | eval path=lower(uri_path) | eval door=case(match(path, "^/(arcgis/(admin|manager|rest/admin)|geoserver/(web|rest))"), "GIS server", match(path, "^/(v1/(models|chat/completions|completions|embeddings)|api/(tags|generate|ps)|rest/workflows|console/api)"), "AI endpoint", match(path, "^/(remote/login|\+cscoe\+/|vpn/index\.html|logon/logonpoint|tmui/|mgmt/tm/)"), "Edge-device login", match(path, "^/(console/login|wls-wsat|_async|bea_wls_internal)"), "WebLogic", match(path, "(^/\.env|/\.git/|/web\.config|/wp-config\.php|\.(bak|old|sql|tar|tgz|zip|7z)$|^/backup)"), "Config or backup file", match(path, "^/(admin|administrator|manager|phpmyadmin|actuator|server-status)(/|$)"), "Admin panel") | where isnotnull(door) | stats sum(count) AS per_minute values(door) AS doors values(path) AS path_list values(status) AS statuses BY src _time | eval hour=floor(_time/3600) | stats sum(per_minute) AS requests max(per_minute) AS peak_per_minute dc(hour) AS active_hours dc(doors) AS door_count values(doors) AS doors dc(path_list) AS paths values(statuses) AS statuses min(_time) AS first_seen max(_time) AS last_seen BY src | where door_count >= 2 AND paths >= 5 | eval throttled=if(peak_per_minute <= 30 AND active_hours >= 3, "yes", "no"), got_a_200=if(isnotnull(mvfind(statuses, "^200$")), "yes", "no") | convert ctime(first_seen) ctime(last_seen) | sort 0 -door_count -paths