Discovery
T1046 — Network Service Discovery
Adversaries may attempt to get a listing of services running on remote hosts and local network infrastructure devices, including those that may be vulnerable to remote software exploitation. Common methods to acquire this information include port, vulnerability, and/or wordlist scans using tools that are brought onto a system. Within cloud environments, adversaries may attempt to discover services running on other cloud hosts...
Investigate Network Service Discovery activity in the context of Discovery: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.
Platforms
Containers, IaaS, Linux, macOS, Network Devices, Windows
Priority / status
medium / complete
Evidence to collect
- Host or resource affected
- Account or identity involved
- Timestamp of the activity
- Related process, file, or network artifact
- Any preceding or follow-on alerts
D3-NTA · detect
Network Traffic Analysis
Monitor for Network Traffic Analysis indicators relevant to this technique.
Tooling: Sentinel, Defender for Endpoint
| ATT&CK Technique | D3FEND Technique | Practical SOC Action | Tooling |
|---|---|---|---|
| T1046 Network Service Discovery | Network Traffic Analysis | Monitor for Network Traffic Analysis indicators relevant to this technique. | Sentinel, Defender for Endpoint |
T1046 Network Service Discovery → D3FEND → SOC action
Investigation steps — Microsoft
- project Timestamp, RemoteIP, RemotePort, InitiatingProcessFileName
Investigation steps — generic
- Confirm whether the observed network service discovery activity matches expected administrative or application behaviour.
- Identify the host, account, or resource where the activity occurred and its business criticality.
- Check for related alerts before and after this activity to reconstruct the broader intrusion timeline.
- Real detection reference: "Internal Network Scanning" -- Flags a host sending connection attempts to more than 30 unique internal IPs within a 60-second window, consistent with automated port scanning or network enumeration.
Response actions
| Action | Risk | Automation safe | Approval required |
|---|---|---|---|
| If scanning from workstation: investigate immediately as com | Low | No | Yes |
| Block the scanning process if malicious | Medium | No | Yes |
| Correlate with lateral movement alerts (GEN-LM-001) | Low | No | Yes |
KQL
GEN-DI-003 — Internal Network Scanning
DeviceNetworkEvents
| where TimeGenerated >= ago(10m)
| where ActionType == "ConnectionAttempted"
| where RemoteIP startswith "10." or RemoteIP startswith "192.168." or RemoteIP startswith "172."
| summarize
StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
UniqueIPs = dcount(RemoteIP),
Ports = make_set(RemotePort, 20)
by DeviceName, InitiatingProcessFileName, bin(TimeGenerated, 60s)
| where UniqueIPs > 30
| extend timestamp = StartTime, HostCustomEntity = DeviceName
| order by UniqueIPs desc d2b6fa0f-6a4c-4c48-8c64-5e2e1ac4e7b9 — AWS Security Hub - Detect EC2 Security groups allowing unrestricted high-risk ports
let HighRiskPorts = dynamic([3389,20,23,110,143,3306,8080,1433,9200,9300,25,445,135,21,1434,4333,5432,5500,5601,22,3000,5000,8088,8888]);
AWSSecurityHubFindings
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/EC2.19"
or tostring(ComplianceSecurityControlId) == "EC2.19"
| mv-expand Resource = Resources
| where tostring(Resource.Type) == "AwsEc2SecurityGroup"
| extend SGDetails = Resource.Details.AwsEc2SecurityGroup
| extend IpPermissions = SGDetails.IpPermissions
| mv-expand Perm = IpPermissions
| where toint(Perm.FromPort) in (HighRiskPorts)
| mv-expand Range = Perm.IpRanges
| where tostring(Range.CidrIp) in ("0.0.0.0/0", "::/0")
| summarize TimeGenerated = max(TimeGenerated), OpenHighRiskPorts = make_set(tostring(Perm.FromPort))
by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
AwsSecurityFindingId, ComplianceSecurityControlId, SecurityGroupId = tostring(SGDetails.GroupId), SecurityGroupARN = tostring(Resource.Id)
| extend OpenHighRiskPorts = strcat_array(OpenHighRiskPorts, ", ") 9b8dd8fd-f192-42eb-84f6-541920400a7a — App Gateway WAF - Scanner Detection
let Threshold = 3;
AGWFirewallLogs
| where Action == "Matched"
| where Message contains "Found User-Agent associated with security scanner"
| project TransactionId, Hostname, RequestUri, TimeGenerated, ClientIp, Message, DetailedMessage, DetailedData
| join kind = inner(
AGWFirewallLogs
| where Action == "Blocked"
) on TransactionId
| extend Uri = strcat(Hostname,RequestUri)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), TransactionID = make_set(TransactionId), Message = make_set(Message), Detail_Message = make_set(DetailedMessage), Detail_Data = make_set(DetailedData), Total_TransactionId = dcount(TransactionId) by ClientIp, Uri, Action
| where Total_TransactionId >= Threshold Escalation criteria
- Network Service Discovery activity observed on a privileged account or critical system.
- Activity follows or precedes other suspicious behaviour in the same investigation.
- Automated triage cannot confidently rule out malicious intent.
False positive considerations
- Authorised vulnerability scanner (Nessus, Qualys) — Add scanner IP to discovery exclusions watchlist
- Network monitoring agents (PRTG, Zabbix, SolarWinds) — Exclude management server IP/hostname
# T1046 - Network Service Discovery
## SOC Recommendation
Investigate Network Service Discovery activity in the context of Discovery: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.
## D3FEND Mappings
| D3FEND Technique | Relationship | Practical SOC Action |
|---|---|---|
| Network Traffic Analysis | Detect | Monitor for Network Traffic Analysis indicators relevant to this technique. |
## Investigation Steps
1. project Timestamp, RemoteIP, RemotePort, InitiatingProcessFileName
## Evidence to Collect
- Host or resource affected
- Account or identity involved
- Timestamp of the activity
- Related process, file, or network artifact
- Any preceding or follow-on alerts
## Response Actions
| Action | Risk | Automation Safe | Approval Required |
|---|---|---|---|
| If scanning from workstation: investigate immediately as com | Low | No | Yes |
| Block the scanning process if malicious | Medium | No | Yes |
| Correlate with lateral movement alerts (GEN-LM-001) | Low | No | Yes |
## KQL
```kql
DeviceNetworkEvents
| where TimeGenerated >= ago(10m)
| where ActionType == "ConnectionAttempted"
| where RemoteIP startswith "10." or RemoteIP startswith "192.168." or RemoteIP startswith "172."
| summarize
StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
UniqueIPs = dcount(RemoteIP),
Ports = make_set(RemotePort, 20)
by DeviceName, InitiatingProcessFileName, bin(TimeGenerated, 60s)
| where UniqueIPs > 30
| extend timestamp = StartTime, HostCustomEntity = DeviceName
| order by UniqueIPs desc
```
```kql
let HighRiskPorts = dynamic([3389,20,23,110,143,3306,8080,1433,9200,9300,25,445,135,21,1434,4333,5432,5500,5601,22,3000,5000,8088,8888]);
AWSSecurityHubFindings
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/EC2.19"
or tostring(ComplianceSecurityControlId) == "EC2.19"
| mv-expand Resource = Resources
| where tostring(Resource.Type) == "AwsEc2SecurityGroup"
| extend SGDetails = Resource.Details.AwsEc2SecurityGroup
| extend IpPermissions = SGDetails.IpPermissions
| mv-expand Perm = IpPermissions
| where toint(Perm.FromPort) in (HighRiskPorts)
| mv-expand Range = Perm.IpRanges
| where tostring(Range.CidrIp) in ("0.0.0.0/0", "::/0")
| summarize TimeGenerated = max(TimeGenerated), OpenHighRiskPorts = make_set(tostring(Perm.FromPort))
by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
AwsSecurityFindingId, ComplianceSecurityControlId, SecurityGroupId = tostring(SGDetails.GroupId), SecurityGroupARN = tostring(Resource.Id)
| extend OpenHighRiskPorts = strcat_array(OpenHighRiskPorts, ", ")
```
```kql
let Threshold = 3;
AGWFirewallLogs
| where Action == "Matched"
| where Message contains "Found User-Agent associated with security scanner"
| project TransactionId, Hostname, RequestUri, TimeGenerated, ClientIp, Message, DetailedMessage, DetailedData
| join kind = inner(
AGWFirewallLogs
| where Action == "Blocked"
) on TransactionId
| extend Uri = strcat(Hostname,RequestUri)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), TransactionID = make_set(TransactionId), Message = make_set(Message), Detail_Message = make_set(DetailedMessage), Detail_Data = make_set(DetailedData), Total_TransactionId = dcount(TransactionId) by ClientIp, Uri, Action
| where Total_TransactionId >= Threshold
```
## Escalation Criteria
- Network Service Discovery activity observed on a privileged account or critical system.
- Activity follows or precedes other suspicious behaviour in the same investigation.
- Automated triage cannot confidently rule out malicious intent.
## False Positive Considerations
- Authorised vulnerability scanner (Nessus, Qualys) — Add scanner IP to discovery exclusions watchlist
- Network monitoring agents (PRTG, Zabbix, SolarWinds) — Exclude management server IP/hostname
Generated by SOC Response Atlas by Basyrix.
Want to push this directly to Confluence? Upgrade to Basyrix Pro.
- /api/techniques/T1046.json
- /api/recommendations/T1046.json
- /api/d3fend/T1046.json
- /api/mappings/T1046.json
- /api/confluence/T1046.md
Example curl:
curl https://atlas.basyrix.com/api/recommendations/T1046.json Response:
{
"technique_id": "T1046",
"name": "Network Service Discovery",
"priority": "medium",
"status": "complete",
"version": "0.1.0",
"last_reviewed": "2026-07-23",
"generated_by": "SOC Response Atlas by Basyrix",
"tactics": [
"Discovery"
],
"platforms": [
"Containers",
"IaaS",
"Linux",
"macOS",
"Network Devices",
"Windows"
],
"summary": "Adversaries may attempt to get a listing of services running on remote hosts and local network infrastructure devices, including those that may be vulnerable to remote software exploitation. Common methods to acquire this information include port, vulnerability, and/or wordlist scans using tools that are brought onto a system. Within cloud environments, adversaries may attempt to discover services running on other cloud hosts...",
"soc_recommendation": "Investigate Network Service Discovery activity in the context of Discovery: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.",
"d3fend_mappings": [
{
"id": "D3-NTA",
"name": "Network Traffic Analysis",
"relationship": "detect",
"practical_action": "Monitor for Network Traffic Analysis indicators relevant to this technique.",
"tooling": [
"Sentinel",
"Defender for Endpoint"
]
}
],
"investigation_steps": {
"microsoft": [
"project Timestamp, RemoteIP, RemotePort, InitiatingProcessFileName"
],
"generic": [
"Confirm whether the observed network service discovery activity matches expected administrative or application behaviour.",
"Identify the host, account, or resource where the activity occurred and its business criticality.",
"Check for related alerts before and after this activity to reconstruct the broader intrusion timeline.",
"Real detection reference: \"Internal Network Scanning\" -- Flags a host sending connection attempts to more than 30 unique internal IPs within a 60-second window, consistent with automated port scanning or network enumeration."
]
},
"evidence_to_collect": [
"Host or resource affected",
"Account or identity involved",
"Timestamp of the activity",
"Related process, file, or network artifact",
"Any preceding or follow-on alerts"
],
"response_actions": [
{
"name": "If scanning from workstation: investigate immediately as com",
"category": "Response",
"risk": "Low",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide",
"notes": "If scanning from workstation: investigate immediately as compromised host"
},
{
"name": "Block the scanning process if malicious",
"category": "Response",
"risk": "Medium",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide"
},
{
"name": "Correlate with lateral movement alerts (GEN-LM-001)",
"category": "Response",
"risk": "Low",
"automation_safe": false,
"approval_required": true,
"tool": "See investigation guide"
}
],
"queries": {
"kql": [
{
"name": "GEN-DI-003 — Internal Network Scanning",
"description": "Flags a host sending connection attempts to more than 30 unique internal IPs within a 60-second window, consistent with automated port scanning or network enumeration. (Source: Bell Integration baseline detection library.)",
"query": "DeviceNetworkEvents\n| where TimeGenerated >= ago(10m)\n| where ActionType == \"ConnectionAttempted\"\n| where RemoteIP startswith \"10.\" or RemoteIP startswith \"192.168.\" or RemoteIP startswith \"172.\"\n| summarize\n StartTime = min(TimeGenerated),\n EndTime = max(TimeGenerated),\n UniqueIPs = dcount(RemoteIP),\n Ports = make_set(RemotePort, 20)\n by DeviceName, InitiatingProcessFileName, bin(TimeGenerated, 60s)\n| where UniqueIPs > 30\n| extend timestamp = StartTime, HostCustomEntity = DeviceName\n| order by UniqueIPs desc"
},
{
"name": "d2b6fa0f-6a4c-4c48-8c64-5e2e1ac4e7b9 — AWS Security Hub - Detect EC2 Security groups allowing unrestricted high-risk ports",
"description": "This query detects EC2 Security Groups that allow unrestricted (0.0.0.0/0 or ::/0) ingress to high-risk ports using AWS Security Hub control EC2.19 findings. Publicly exposed management, database, and service ports (e.g., RDP 3389, SSH 22, SQL 1433/3306) significantly increase the risk of brute-force attacks, exploitation, and lateral movement. (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
"query": "let HighRiskPorts = dynamic([3389,20,23,110,143,3306,8080,1433,9200,9300,25,445,135,21,1434,4333,5432,5500,5601,22,3000,5000,8088,8888]);\nAWSSecurityHubFindings\n| where RecordState == \"ACTIVE\" and ComplianceStatus == \"FAILED\"\n| where tostring(AwsSecurityFindingGeneratorId) == \"security-control/EC2.19\"\n or tostring(ComplianceSecurityControlId) == \"EC2.19\"\n| mv-expand Resource = Resources\n| where tostring(Resource.Type) == \"AwsEc2SecurityGroup\"\n| extend SGDetails = Resource.Details.AwsEc2SecurityGroup\n| extend IpPermissions = SGDetails.IpPermissions\n| mv-expand Perm = IpPermissions\n| where toint(Perm.FromPort) in (HighRiskPorts)\n| mv-expand Range = Perm.IpRanges\n| where tostring(Range.CidrIp) in (\"0.0.0.0/0\", \"::/0\")\n| summarize TimeGenerated = max(TimeGenerated), OpenHighRiskPorts = make_set(tostring(Perm.FromPort))\n by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,\n AwsSecurityFindingId, ComplianceSecurityControlId, SecurityGroupId = tostring(SGDetails.GroupId), SecurityGroupARN = tostring(Resource.Id)\n| extend OpenHighRiskPorts = strcat_array(OpenHighRiskPorts, \", \")"
},
{
"name": "9b8dd8fd-f192-42eb-84f6-541920400a7a — App Gateway WAF - Scanner Detection",
"description": "Identifies a match for a Scanner detection user agent based attack in the App Gateway WAF logs. The threshold value in the query can be changed as per your infrastructure's requirements. References: https://owasp.org/www-community/Vulnerability_Scanning_Tools' (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
"query": "let Threshold = 3;\nAGWFirewallLogs\n| where Action == \"Matched\"\n| where Message contains \"Found User-Agent associated with security scanner\"\n| project TransactionId, Hostname, RequestUri, TimeGenerated, ClientIp, Message, DetailedMessage, DetailedData\n| join kind = inner(\nAGWFirewallLogs\n| where Action == \"Blocked\"\n) on TransactionId\n| extend Uri = strcat(Hostname,RequestUri)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), TransactionID = make_set(TransactionId), Message = make_set(Message), Detail_Message = make_set(DetailedMessage), Detail_Data = make_set(DetailedData), Total_TransactionId = dcount(TransactionId) by ClientIp, Uri, Action\n| where Total_TransactionId >= Threshold"
}
],
"spl": [],
"esql": [
{
"name": "860f2a03-a1cf-48d6-a674-c6d62ae608a1 — Potential Subnet Scanning Activity from Compromised Host",
"description": "(ESQL) This rule detects potential subnet scanning activity from a compromised host. Subnet scanning is a common reconnaissance technique used by attackers to identify live hosts within a network range. A compromised host may exhibit subnet scanning behavior when an attacker is attempting to map out the network topology, identify vulnerable hosts, or prepare for further exploitation... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
"query": "from logs-endpoint.events.network-* metadata _id, _index, _version\n| mv_expand event.action\n| where\n host.os.type == \"linux\" and\n event.type == \"start\" and\n event.action == \"connection_attempted\" and\n not (\n process.executable in (\"/usr/local/bin/prometheus\", \"/app/extra/chrome\", \"/usr/lib/virtualbox/VBoxHeadless\", \"/usr/bin/prometheus\") or\n process.executable like \"/usr/local/prometheus/*/prometheus\" or\n process.executable like \"/usr/share/elastic-agent/*\" or\n process.executable like \"/var/lib/docker/overlay*connectord\" or\n process.executable like \"/opt/rumble/bin/rumble-agent*\" or\n process.executable like \"/opt/gitlab/*\" or\n process.executable like \"/opt/google/chrome/chrome*\" or\n process.executable like \"/snap/firefox/*/firefox\" or\n process.executable like \"/var/lib/docker/overlay2/*/qbittorrent-nox\"\n )\n| keep\n @timestamp,\n _id,\n _index,\n _version,\n host.os.type,\n event.type,\n event.action,\n process.executable,\n destination.ip,\n agent.id,\n host.name,\n data_stream.dataset,\n data_stream.namespace\n\n| stats\n Esql.event_count = count(),\n Esql.destination_ip_count_distinct = count_distinct(destination.ip),\n Esql.agent_id_count_distinct = count_distinct(agent.id),\n Esql.host_name_values = values(host.name),\n Esql.agent_id_values = values(agent.id),\n Esql.data_stream_dataset_values = values(data_stream.dataset),\n Esql.data_stream_namespace_values = values(data_stream.namespace)\n by process.executable\n\n| where\n Esql.agent_id_count_distinct == 1 and\n Esql.destination_ip_count_distinct > 250\n| sort Esql.event_count asc\n\n// Extract unique values to ECS fields for alerts exclusion\n| eval agent.id = mv_min(Esql.agent_id_values),\n host.name = mv_min(Esql.host_name_values)\n\n| keep agent.id, host.name, process.executable, Esql.*"
},
{
"name": "6b341d03-1d63-41ac-841a-2009c86959ca — Potential Port Scanning Activity from Compromised Host",
"description": "(ESQL) This rule detects potential port scanning activity from a compromised host. Port scanning is a common reconnaissance technique used by attackers to identify open ports and services on a target system. A compromised host may exhibit port scanning behavior when an attacker is attempting to map out the network topology, identify vulnerable services, or prepare for further exploitation... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
"query": "from logs-endpoint.events.network-* metadata _id, _index, _version\n| mv_expand event.action\n| where\n host.os.type == \"linux\" and\n event.type == \"start\" and\n event.action == \"connection_attempted\" and\n network.direction == \"egress\" and\n destination.port < 32768 and\n not (\n cidr_match(destination.ip, \"127.0.0.0/8\", \"::1\", \"FE80::/10\", \"FF00::/8\") or\n process.name in (\"java\", \"node\") or\n process.name like \"python*\" or\n process.executable in (\n \"/opt/dbtk/bin/jsvc\", \"/usr/lib/dotnet/dotnet\", \"/usr/sbin/haproxy\", \"/opt/kaspersky/kesl/libexec/kesl\",\n \"/usr/bin/dotnet\", \"/usr/sap/SAPBusinessOne/EDS/bin/EDFBackend\", \"/usr/local/bin/longhorn-instance-manager\"\n ) or\n process.executable like \"/var/opt/kaspersky/kesl/*kesl\" or\n process.executable like \"/opt/google/chrome*\" or\n process.executable like \"/snap/*\" or\n process.executable like \"/home/*/.local/share/JetBrains/*\"\n )\n| keep\n @timestamp,\n _id,\n _index,\n _version,\n host.os.type,\n event.type,\n event.action,\n network.direction,\n destination.port,\n process.executable,\n process.name,\n destination.ip,\n source.ip,\n agent.id,\n host.name,\n data_stream.dataset,\n data_stream.namespace\n\n| stats\n Esql.event_count = count(),\n Esql.destination_port_count_distinct = count_distinct(destination.port),\n Esql.agent_id_count_distinct = count_distinct(agent.id),\n Esql.host_name_values = values(host.name),\n Esql.agent_id_values = values(agent.id),\n Esql.source_ip_values = values(source.ip),\n Esql.data_stream_dataset_values = values(data_stream.dataset),\n Esql.data_stream_namespace_values = values(data_stream.namespace)\n by process.executable, destination.ip\n| where\n Esql.agent_id_count_distinct == 1 and\n Esql.destination_port_count_distinct > 100\n| sort Esql.event_count asc\n\n// Extract unique values to ECS fields for alerts exclusion\n| eval agent.id = mv_min(Esql.agent_id_values),\n host.name = mv_min(Esql.host_name_values)\n\n| keep agent.id, host.name, process.executable, destination.ip, Esql.*"
}
]
},
"automation": {
"safe": [
"Add recommendation as Sentinel incident comment.",
"Run enrichment queries.",
"Create ServiceNow SecOps task."
],
"approval_required": [
"Contain or disable the affected host/account.",
"Any change to production configuration."
]
},
"escalation_criteria": [
"Network Service Discovery activity observed on a privileged account or critical system.",
"Activity follows or precedes other suspicious behaviour in the same investigation.",
"Automated triage cannot confidently rule out malicious intent."
],
"false_positive_considerations": [
"Authorised vulnerability scanner (Nessus, Qualys) — Add scanner IP to discovery exclusions watchlist",
"Network monitoring agents (PRTG, Zabbix, SolarWinds) — Exclude management server IP/hostname"
],
"confluence": {
"title": "T1046 - Network Service Discovery Response Guidance",
"labels": [
"mitre",
"attack",
"d3fend",
"secops",
"basyrix"
],
"sections": [
"summary",
"d3fend_mappings",
"investigation_steps",
"response_actions",
"queries",
"automation",
"escalation_criteria",
"false_positive_considerations"
]
}
}