Microsoft Defender XDR · Advanced Hunting
Βιβλιοθήκη KQL για ΚΥΑ 1689/2025, NIS2 και ISO 27001
Advanced Hunting queries για το Microsoft Defender XDR, αντιστοιχισμένα στις απαιτήσεις της ΚΥΑ 1689/2025, της Οδηγίας NIS2 και του ISO/IEC 27001. Κάθε query έχει δοκιμαστεί σε πραγματικό tenant.
Κάθε query εδώ απαντά σε μία ερώτηση που θα σου κάνει ο ελεγκτής: «δείξε μου ότι το ελέγχεις». Το αντιγράφεις, το τρέχεις στο Microsoft Defender portal > Hunting > Advanced hunting, και το αποτέλεσμα είναι το τεκμήριό σου για την απαίτηση.
Κανένα query δεν μπαίνει στη βιβλιοθήκη αν δεν έχει τρέξει πρώτα σε πραγματικό tenant. Γι’ αυτό κάθε query έχει ημερομηνία δοκιμής και εικόνα από την εκτέλεση. Η βιβλιοθήκη μεγαλώνει κάθε εβδομάδα.
Τα queries διαβάζουν μόνο δεδομένα, δεν αλλάζουν τίποτα στο tenant. Τρέξε τα με λογαριασμό που έχει το ελάχιστο απαραίτητο δικαίωμα, π.χ. Security Reader.
4 queries · Τελευταία ενημέρωση: 12/10/2026
Identity & Access
2 queries
Sign-ins με legacy authentication
✓
Entra ID
13.ζ19.η21.2.ιA.8.532.1.β
Sign-ins με legacy authentication
Ποιοι λογαριασμοί δέχονται ή κάνουν συνδέσεις με πρωτόκολλα που παρακάμπτουν το MFA (IMAP, POP3, SMTP AUTH, ActiveSync, Other clients), με επιτυχίες, αποτυχίες, IP και χώρες τις τελευταίες 30 ημέρες.
- Δοκιμή
- ✓ Δοκιμασμένο σε πραγματικό tenant, 12/10/2026
- Πίνακας
- EntraIdSignInEvents
- ΚΥΑ 1689/2025
- 13.ζ19.η
- NIS2
- 21.2.ι
- ISO 27001
- A.8.5
- GDPR
- 32.1.β
- Άδεια
- Microsoft Entra ID P2 και Microsoft Defender XDR (για τον πίνακα στο Advanced Hunting)
// Sign-ins με legacy authentication, τελευταίες 30 ημέρες
// ΚΥΑ 1689/2025: 13.ζ, 19.η
let LegacyClients = dynamic(["Exchange ActiveSync", "IMAP4", "POP3", "Authenticated SMTP",
"Exchange Web Services", "MAPI Over HTTP", "Offline Address Book",
"Outlook Anywhere (RPC over HTTP)", "Exchange Online PowerShell",
"Autodiscover", "Other clients"]);
EntraIdSignInEvents
| where Timestamp > ago(30d)
| where ClientAppUsed in (LegacyClients)
| summarize
Successful = countif(ErrorCode == 0),
Failed = countif(ErrorCode != 0),
LastSeen = max(Timestamp),
IPs = make_set(IPAddress, 10),
Countries = make_set(Country, 10)
by AccountUpn, ClientAppUsed, Application
| order by Successful desc, Failed descΠώς το διαβάζεις
Οι επιτυχημένες συνδέσεις είναι το πραγματικό εύρημα, γιατί σημαίνουν ότι κάπου το MFA δεν εφαρμόζεται. Πολλές αποτυχημένες από διαφορετικές χώρες δείχνουν συνήθως password spray. Η διόρθωση είναι πολιτική Conditional Access που μπλοκάρει τα «Other clients» και «Exchange ActiveSync clients».

Σχετικά άρθρα
Αναθέσεις ρόλων στο Entra ID
✓
Entra ID
13.γ13.δ24.γ21.2.θA.5.18A.8.232.1.β32.4
Αναθέσεις ρόλων στο Entra ID
Ποιος έδωσε σε ποιον ρόλο του Entra ID και πότε, τις τελευταίες 30 ημέρες, με πρώτους στη λίστα τους προνομιακούς ρόλους όπως Global Administrator και Privileged Role Administrator. Περιλαμβάνει μόνιμες αναθέσεις και eligible αναθέσεις του PIM.
- Δοκιμή
- ✓ Δοκιμασμένο σε πραγματικό tenant, 12/10/2026
- Πίνακας
- CloudAppEvents
- ΚΥΑ 1689/2025
- 13.γ13.δ24.γ
- NIS2
- 21.2.θ
- ISO 27001
- A.5.18A.8.2
- GDPR
- 32.1.β32.4
- Άδεια
- Microsoft Defender for Cloud Apps με ενεργό τον connector του Microsoft 365 (Microsoft 365 E5 ή E5 Security)
// Αναθέσεις ρόλων στο Entra ID, τελευταίες 30 ημέρες
// ΚΥΑ 1689/2025: 13.γ, 13.δ, 24.γ
let PrivilegedRoles = dynamic(["Global Administrator", "Privileged Role Administrator",
"Privileged Authentication Administrator", "Security Administrator",
"Exchange Administrator", "SharePoint Administrator", "User Administrator",
"Application Administrator", "Cloud Application Administrator",
"Conditional Access Administrator", "Intune Administrator",
"Hybrid Identity Administrator"]);
CloudAppEvents
| where Timestamp > ago(30d)
| where ActionType has "member to role"
| extend MP = tostring(RawEventData.ModifiedProperties)
| extend RoleName = extract(@'"Name":"Role\.DisplayName","NewValue":"([^"]*)"', 1, MP)
| extend
Actor = tostring(RawEventData.UserId),
TargetUser = tostring(RawEventData.ObjectId),
Result = tostring(RawEventData.ResultStatus),
IsPrivileged = RoleName in (PrivilegedRoles)
| project Timestamp, ActionType, Actor, TargetUser, RoleName, IsPrivileged, Result, IPAddress
| order by IsPrivileged desc, Timestamp descΠώς το διαβάζεις
Η στήλη IsPrivileged βάζει πάνω-πάνω τους ρόλους υψηλού κινδύνου. Το εύρημα που μετράει είναι μια ανάθεση προνομιακού ρόλου που δεν πέρασε από PIM ή που δεν ξέρεις ποιος την έκανε. Όταν ο Actor είναι Service Principal, η ανάθεση έγινε από εφαρμογή ή αυτοματοποιημένη διαδικασία, οπότε έλεγξε ποια είναι. Αν θεωρείς προνομιακούς και άλλους ρόλους, πρόσθεσέ τους στη λίστα PrivilegedRoles.

Σχετικά άρθρα
Endpoint & Device
1 query
Χρήση αφαιρούμενων μέσων USB
✓
Defender for Endpoint
11.δ24.γ21.2.θA.7.10A.8.12
Χρήση αφαιρούμενων μέσων USB
Κάθε φορά που συνδέθηκε USB storage σε συσκευή τις τελευταίες 30 ημέρες, με τη συσκευή, τον χρήστη που ήταν συνδεδεμένος, τον κατασκευαστή, το μοντέλο και τον σειριακό αριθμό του USB. Οι εικονικές μονάδες CD, DVD και VMware εξαιρούνται, ώστε να μένουν μόνο τα πραγματικά USB sticks και δίσκοι.
- Δοκιμή
- ✓ Δοκιμασμένο σε πραγματικό tenant, 12/10/2026
- Πίνακας
- DeviceEvents, DeviceInfo
- ΚΥΑ 1689/2025
- 11.δ24.γ
- NIS2
- 21.2.θ
- ISO 27001
- A.7.10A.8.12
- Άδεια
- Microsoft Defender for Endpoint Plan 2 για τον πίνακα DeviceEvents στο Advanced Hunting (Microsoft 365 E5 ή Microsoft Defender Suite)
// Χρήση αφαιρούμενων μέσων USB, τελευταίες 30 ημέρες
// ΚΥΑ 1689/2025: 11.δ, 24.γ
let Lookback = 30d;
let Mounts = DeviceEvents
| where Timestamp > ago(Lookback)
| where ActionType == "UsbDriveMounted"
| extend AF = parse_json(AdditionalFields)
| project MountTime = Timestamp, DeviceId, DeviceName,
DriveLetter = tostring(AF.DriveLetter), Manufacturer = tostring(AF.Manufacturer),
Product = tostring(AF.ProductName), SerialNumber = tostring(AF.SerialNumber)
| where not(Product matches regex @"(?i)(CD|DVD|ROM|VIRTUAL|VMWARE)");
Mounts
| join kind=leftouter (
DeviceInfo
| where Timestamp > ago(Lookback + 1d)
| where isnotempty(LoggedOnUsers) and LoggedOnUsers != "[]"
| project InfoTime = Timestamp, DeviceId, LoggedOnUsers
) on DeviceId
| where isnull(InfoTime) or InfoTime <= MountTime
| summarize arg_max(InfoTime, LoggedOnUsers)
by MountTime, DeviceName, DriveLetter, Manufacturer, Product, SerialNumber
| extend LoggedOnUser = tostring(parse_json(LoggedOnUsers)[0].UserName)
| project MountTime, DeviceName, LoggedOnUser, DriveLetter, Manufacturer, Product, SerialNumber
| order by MountTime descΠώς το διαβάζεις
Το εύρημα που μετράει είναι ένα USB σε server ή σε συσκευή όπου η πολιτική σου δεν το επιτρέπει, ή ο ίδιος σειριακός αριθμός σε πολλές συσκευές, που σημαίνει ότι ένα stick κυκλοφορεί από υπολογιστή σε υπολογιστή. Το event της σύνδεσης καταγράφεται από τον λογαριασμό του συστήματος, γι' αυτό ο χρήστης έρχεται από το DeviceInfo, από την τελευταία καταγραφή πριν τη σύνδεση. Αν δεις άλλα εικονικά μέσα στη στήλη Product, πρόσθεσέ τα στο φίλτρο. Για να τα μπλοκάρεις, χρησιμοποίησε το Device control του Defender for Endpoint μέσω Intune.

Σχετικά άρθρα
Email & Collaboration
1 query
Phishing που παραδόθηκε και αφαιρέθηκε εκ των υστέρων (ZAP)
✓
Defender for Office 365
20.γ24.ε21.2.βA.8.7A.5.25
Phishing που παραδόθηκε και αφαιρέθηκε εκ των υστέρων (ZAP)
Κάθε μήνυμα phishing ή malware που έφτασε σε mailbox και το Zero-hour auto purge (ZAP) το αφαίρεσε αργότερα, τις τελευταίες 30 ημέρες. Για το καθένα βλέπεις σε ποιον χρήστη πήγε, από ποιον αποστολέα και πόσα λεπτά έμεινε στο mailbox.
- Δοκιμή
- ✓ Δοκιμασμένο σε πραγματικό tenant, 12/10/2026
- Πίνακας
- EmailPostDeliveryEvents, EmailEvents
- ΚΥΑ 1689/2025
- 20.γ24.ε
- NIS2
- 21.2.β
- ISO 27001
- A.8.7A.5.25
- Άδεια
- Microsoft Defender for Office 365 Plan 2 για τους πίνακες email στο Advanced Hunting (Microsoft 365 E5 ή Microsoft Defender Suite). Το ίδιο το ZAP λειτουργεί και χωρίς αυτό
// Phishing και malware που παραδόθηκαν και αφαιρέθηκαν εκ των υστέρων από το ZAP, τελευταίες 30 ημέρες
// ΚΥΑ 1689/2025: 20.γ, 24.ε
let Lookback = 30d;
EmailPostDeliveryEvents
| where Timestamp > ago(Lookback)
| where ActionType in ("Phish ZAP", "Malware ZAP")
| project ZapTime = Timestamp, NetworkMessageId, RecipientEmailAddress,
ActionType, Action, ActionResult
| join kind=inner (
EmailEvents
| where Timestamp > ago(Lookback)
| where DeliveryAction == "Delivered"
| project DeliveredTime = Timestamp, NetworkMessageId, RecipientEmailAddress,
SenderFromAddress, Subject, DeliveryLocation
) on NetworkMessageId, RecipientEmailAddress
| extend MinutesInMailbox = datetime_diff('minute', ZapTime, DeliveredTime)
| project DeliveredTime, ZapTime, MinutesInMailbox, RecipientEmailAddress,
SenderFromAddress, Subject, DeliveryLocation, ActionType, Action, ActionResult
| order by MinutesInMailbox descΠώς το διαβάζεις
Η στήλη MinutesInMailbox είναι το πραγματικό εύρημα. Όσο περισσότερο έμεινε ένα μήνυμα στο mailbox, τόσο πιθανότερο είναι να το άνοιξε ή να έκανε κλικ ο χρήστης, οπότε ξεκίνα από την κορυφή της λίστας και έλεγξε αυτούς τους χρήστες. Αν η στήλη ActionResult δεν δείχνει επιτυχία, το ZAP δεν κατάφερε να αφαιρέσει το μήνυμα και χρειάζεται άμεση ενέργεια.

Σχετικά άρθρα
Κανένα query δεν ταιριάζει με τα φίλτρα.
Πριν τα χρησιμοποιήσεις
Τα queries δίνονται ως παράδειγμα, χωρίς εγγύηση. Ένα query που φέρνει αποτελέσματα υποστηρίζει μια απαίτηση, δεν αποδεικνύει από μόνο του συμμόρφωση. Η Microsoft αλλάζει κατά καιρούς ονόματα πινάκων και στηλών: αν πάρεις σφάλμα, έλεγξε το Schema reference του Advanced Hunting. Η αντιστοίχιση στις απαιτήσεις ακολουθεί τους οδηγούς για την ΚΥΑ 1689/2025, την Οδηγία NIS2, το ISO/IEC 27001 και τον GDPR.