HUNT 02 AD ASREP Roastable Accounts Audit 90d
Query
// =========================================================
// HUNT-02 | AD-ASREP-Roastable-Accounts-Audit-90d
// Description : Full audit of all accounts with
// DONT_REQ_PREAUTH (AS-REP Roastable) and
// historical AS-REP request patterns. Surfaces
// accounts that have never required pre-auth,
// and correlates with actual roasting attempts.
// Period : 90 days
// Use Case : Attack surface exposure assessment,
// DONT_REQ_PREAUTH hygiene review
// Tables : SecurityEvent
// =========================================================
let Period = 90d;
// All 4768 events with tostring(column_ifexists("PreAuthType", "")) = 0 (no pre-auth required)
let ASREPRequests = SecurityEvent
| where TimeGenerated > ago(Period)
| where EventID == 4768
| where tostring(column_ifexists("PreAuthType", "")) == "0"
| where TargetUserName !endswith "$"
| extend
IsOffHours = hourofday(TimeGenerated) < 8 or hourofday(TimeGenerated) >= 19
| summarize
TotalASREP = count(),
UniqueRequesters = dcount(IpAddress),
RequestingIPs = make_set(IpAddress, 20),
OffHoursRequests = countif(IsOffHours),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
RecentRequests = countif(TimeGenerated > ago(7d))
by RoastableAccount = TargetUserName,
AccountDomain = TargetDomainName;
// Normal 4768 events (with pre-auth, for baseline comparison)
let NormalTGTs = SecurityEvent
| where TimeGenerated > ago(Period)
| where EventID == 4768
| where tostring(column_ifexists("PreAuthType", "")) != "0"
| where TargetUserName !endswith "$"
| summarize NormalTGTCount = count()
by TargetUserName, TargetDomainName;
ASREPRequests
| join kind=leftouter (NormalTGTs) on
$left.RoastableAccount == $right.TargetUserName,
$left.AccountDomain == $right.TargetDomainName
| extend
OffHoursRatio = round(todouble(OffHoursRequests) / todouble(TotalASREP), 2),
// If this account ONLY appears with tostring(column_ifexists("PreAuthType", ""))=0 it's permanently set DONT_REQ_PREAUTH
OnlySeenASREP = isnull(NormalTGTCount) or NormalTGTCount == 0,
RiskScore = (TotalASREP * 3)
+ (UniqueRequesters * 5)
+ iff(OffHoursRequests > 0, 10, 0)
+ iff(RecentRequests > 0, 20, 0)
| extend
RiskLevel = case(
RiskScore >= 60, "Critical",
RiskScore >= 25, "High",
"Medium"
),
Recommendation = case(
OnlySeenASREP, "Set PreAuthentication required, rotate password immediately",
TotalASREP > 5, "Review why account lacks pre-authentication requirement",
"Monitor for further requests"
)
| project
RoastableAccount,
AccountDomain,
RiskLevel,
RiskScore,
TotalASREP,
UniqueRequesters,
OffHoursRatio,
OnlySeenASREP,
RecentRequests,
FirstSeen,
LastSeen,
Recommendation,
RequestingIPs
| order by RiskScore descExplanation
This query is designed to identify and assess the risk of accounts in an Active Directory environment that are vulnerable to AS-REP roasting attacks. Here's a simplified breakdown of what the query does:
-
Time Period: The query examines data from the past 90 days.
-
AS-REP Roastable Accounts: It focuses on accounts that do not require pre-authentication (indicated by EventID 4768 with
PreAuthTypeset to "0"). These accounts are potentially vulnerable to AS-REP roasting attacks. -
Data Collection: The query collects various statistics about these accounts, such as:
- Total number of AS-REP requests.
- Number of unique IP addresses making requests.
- Requests made during off-hours (before 8 AM or after 7 PM).
- First and last time the account was seen in the logs.
- Number of requests in the last 7 days.
-
Comparison with Normal Accounts: It compares these potentially vulnerable accounts with normal accounts that do require pre-authentication to establish a baseline.
-
Risk Assessment: For each account, it calculates a risk score based on:
- Total AS-REP requests.
- Number of unique requesters.
- Presence of off-hours requests.
- Recent request activity.
-
Risk Level and Recommendations: Based on the risk score, it assigns a risk level (Critical, High, or Medium) and provides recommendations, such as:
- Setting pre-authentication requirements.
- Rotating passwords.
- Monitoring the account for further activity.
-
Output: The query outputs a list of accounts with their associated risk levels, scores, and recommendations, sorted by risk score in descending order.
Overall, this query helps identify accounts that might be at risk of being exploited due to their lack of pre-authentication requirements and provides actionable insights to mitigate these risks.
Details

David Alonso
Released: March 24, 2026
Tables
Keywords
Operators