Disabled accounts that were previously disabled in Active Directory but are still being used with Squid proxy in the current environment may indicate persistent adversary access, as attackers could be leveraging dormant accounts to maintain long-term persistence and exfiltrate data undetected. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential covert channels and unauthorized access that evade traditional detection mechanisms.
KQL Query
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = starttime - 14d;
let disabledAccounts = (){
SigninLogs
| where TimeGenerated between(lookback..starttime)
| where ResultType == 50057
| where ResultDescription =~ "User account is disabled. The account has been disabled by an administrator."
};
let proxyEvents = (){
Syslog
| where TimeGenerated between(starttime..endtime)
| where ProcessName contains "squid"
| extend URL = extract("(([A-Z]+ [a-z]{4,5}:\\/\\/)|[A-Z]+ )([^ :]*)",3,SyslogMessage),
SourceIP = extract("([0-9]+ )(([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3}))",2,SyslogMessage),
Status = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))",1,SyslogMessage),
HTTP_Status_Code = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})",8,SyslogMessage),
User = extract("(CONNECT |GET )([^ ]* )([^ ]+)",3,SyslogMessage),
RemotePort = extract("(CONNECT |GET )([^ ]*)(:)([0-9]*)",4,SyslogMessage),
Domain = extract("(([A-Z]+ [a-z]{4,5}:\\/\\/)|[A-Z]+ )([^ :\\/]*)",3,SyslogMessage),
Bytes = toint(extract("([A-Z]+\\/[0-9]{3} )([0-9]+)",2,SyslogMessage)),
contentType = extract("([a-z/]+$)",1,SyslogMessage)
| extend TLD = extract("\\.[a-z]*$",0,Domain)
};
proxyEvents
| where Status !contains 'DENIED'
| join kind=inner disabledAccounts on $left.User == $right.UserPrincipalName
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, URLCustomEntity = URL
id: 959fe0f0-7ac0-467c-944f-5b8c6fdc9e72
name: Disabled accounts using Squid proxy
description: |
'Query finds accounts recorded as disabled by AD in previous time period but still using proxy in current time period. Presumes default squid log format is used. http://www.squid-cache.org/Doc/config/access_log/'
description_detailed: |
'Look for accounts that have a been recorded as disabled by AD in the previous time period but are still using the proxy during
the current time period. This query presumes the default squid log format is being used. http://www.squid-cache.org/Doc/config/access_log/'
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
tactics:
- CredentialAccess
relevantTechniques:
- T1110
query: |
let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let lookback = starttime - 14d;
let disabledAccounts = (){
SigninLogs
| where TimeGenerated between(lookback..starttime)
| where ResultType == 50057
| where ResultDescription =~ "User account is disabled. The account has been disabled by an administrator."
};
let proxyEvents = (){
Syslog
| where TimeGenerated between(starttime..endtime)
| where ProcessName contains "squid"
| extend URL = extract("(([A-Z]+ [a-z]{4,5}:\\/\\/)|[A-Z]+ )([^ :]*)",3,SyslogMessage),
SourceIP = extract("([0-9]+ )(([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3}))",2,SyslogMessage),
Status = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))",1,SyslogMessage),
HTTP_Status_Code = extract("(TCP_(([A-Z]+)(_[A-Z]+)*)|UDP_(([A-Z]+)(_[A-Z]+)*))/([0-9]{3})",8,SyslogMessage),
User = extract("(CONNECT |GET )([^ ]* )([^ ]+)",3,SyslogMessage),
RemotePort = extract("(CONNECT |GET )([^ ]*)(:)([0-9]*)",4,SyslogMessage),
Domain = extract("(([A-Z]+ [a-z]{4,5}:\\/\\/)|[A-Z]+ )([^ :\\/]*)",3,SyslogMessage),
Bytes = toint(extract("([A-Z]+\\/[0-9]{3} )([0-9]+)",2,SyslogMessage)),
contentType = extract("([a-z/]+$)",1,SyslogMessage)
| extend TLD = extract("\\.[a-z]*$",0,Domain)
};
proxyEvents
| where Status !contains 'DENIED'
| join kind=inner disabledAccounts on $left.User == $right.UserPrincipalName
| extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, URLCustomEntity = URL
version: 1.0.1
metadata:
source:
kind: Community
author:
name: Shain
support:
tier: Community
categories:
domains: [ "Security - Network" ]
| Sentinel Table | Notes |
|---|---|
SigninLogs | Ensure this data connector is enabled |
Syslog | Ensure this data connector is enabled |
Scenario: Scheduled System Maintenance Job Using Squid Proxy
Description: A scheduled job (e.g., Windows Task Scheduler or cron job) runs maintenance tasks that temporarily use Squid proxy for internal resource access.
Filter/Exclusion: Exclude traffic from known maintenance scripts or processes (e.g., systemd-tmpfiles, logrotate, or rsync jobs) using a source IP or process name filter.
Scenario: Admin Task Using Squid Proxy for Internal Monitoring
Description: An administrator uses Squid proxy to monitor internal network traffic (e.g., using tcpdump or Wireshark) for diagnostic purposes.
Filter/Exclusion: Exclude traffic originating from admin workstations or specific admin user accounts (e.g., admin, root, or svc_account) using a source IP or user filter.
Scenario: Legacy Application Using Squid Proxy for Authentication
Description: A legacy application (e.g., Apache HTTP Server or IIS) configured to use Squid proxy for authentication purposes, even though the account is disabled in AD.
Filter/Exclusion: Exclude traffic from known legacy applications using a destination port or application-specific signature (e.g., HTTP/1.1 with Proxy-Authorization header).
Scenario: Proxy Server Configuration Testing by DevOps Team
Description: A DevOps team tests Squid proxy configurations (e.g., using curl or Postman) and inadvertently logs activity under a disabled account.
Filter/Exclusion: Exclude traffic from DevOps tools or test environments using a source IP range or user-agent filter.
Scenario: Proxy Server Logs Being Analyzed by SIEM Tool
Description: A SIEM tool (e.g., Splunk, ELK Stack, or `