Daily "Network Port Sweep detected on port x" but no Source IP

Copper Contributor

For a couple of months we have been getting "Network Port Sweep was detection by multiple IPs" with ports 135 and 445 mostly. The KQL attached lists a load of Destination IPs but no Source IP (see example below)  All these are inside our network, and so not coming from outside the network where the firewall would block such scans. We suspect it is one of our network tools such as Solarwinds but without the Source IP it is difficult to prove anything. 

 

MarcusBoyce_0-1719217193965.png

 

 

// The query_now parameter represents the time (in UTC) at which the scheduled analytics rule ran to produce this alert.
set query_now = datetime(2024-06-24T03:01:10.2587643Z);
let lookback = 1h;
let threshold = 20;
_Im_NetworkSession(starttime=ago(lookback), endtime=now())
| where NetworkDirection == "Inbound"
| summarize make_set(DstIpAddr, 100) by DstPortNumber
| where array_length(set_DstIpAddr) > threshold

 

Tried to modify the query, this is the KQL I have tried. 

 

set query_now = datetime(2024-01-26T07:47:48.3756000Z); let lookback = 1h; let threshold = 20; _Im_NetworkSession(starttime=ago(lookback), endtime=now()) | where NetworkDirection == "Inbound" | summarize make_set(DstIpAddr, 100), make_set(SrcIpAddr, 100) by DstPortNumber | where array_length(set_DstIpAddr) > threshold

 

Anyone got any suggestions on how we can track down what is causing this alert in Sentinel? 

 

 

6 Replies
Hello, are you saying there is no SOURCE IP column/or its blank or just that your query isnt displaying it? Currently as you are summarising the data you are only seeing the columns you name.
There are some ideas in this query, to get you started


let lookback = 1h;
let threshold = 20;
_Im_NetworkSession(starttime=ago(lookback), endtime=now())
| where NetworkDirection =~ "Inbound"
| where ipv4_is_private(SrcIpAddr)==false
| distinct SrcIpAddr, DstIpAddr, DvcHostname, DstPortNumber
| extend country_=geo_info_from_ip_address(SrcIpAddr)


https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/make-set-aggregation-function

as you are using make-set with 100 you get 100 random values, lets say you have 200 results you maybe missing something in the 100 you are dropping

@Clive_Watson Hi, there’s no source IP. The query running is one built into Sentinel. 

I shall try running your query. Thanks for the feedback. 

@Clive_Watson Hi Clive,

 

With the line for not being a private IP we get what is expected, and only see hits against our external DNS. 

 

let lookback = 8h;
let threshold = 20;
_Im_NetworkSession(starttime=ago(lookback), endtime=now())
| where NetworkDirection =~ "Inbound"
// | where ipv4_is_private(SrcIpAddr)==false
| distinct SrcIpAddr, DstIpAddr, DvcHostname, DstPortNumber
// | extend country_=geo_info_from_ip_address(SrcIpAddr)

 

Commenting that out we get a load of scans. The two specific ports (135 and 445) are listed, and the query that Sentinel is flagging is only against the ones with ::ffff at the front. 

 

Rule: Network Port Sweep from External Network (ASIM Network Session schema)

Description: This detection rule detects scenarios when a particular port is being scanned by multiple external sources. The rule utilize [ASIM](https://aka.ms/AboutASIM) normalization, and is applied to any source which supports the ASIM Network Session schema.

 

 

MarcusBoyce_0-1719818457047.png

 

Theory, Sentinel is thinking these IPs are external because of the ::ffff in front of them. It only flags those. SO my question is why are the logged IPs having that in front of them? 

https://blog.ip2location.com/knowledge-base/ipv4-mapped-ipv6-address/ I agree Sentinel does seem to think they are something else, if you split it out to remove the prefix that may work?

let sourceIP ="::ffff.10.10.10.10";
print sourceIP = iif(sourceIP has "ffff",split(sourceIP,"f.")[1],sourceIP)
We also have issues with this stupid rule when Sentinel thinks ffff:pri.vate.add.ress is external. Is there any easy fix can be implemented for this?
You can use the idea above and filter out any entries with ffff: as part of a custom rule - this isnt a fully developed Rule, so adjust to suit

let lookback = 8d;
let threshold = 20;
_Im_NetworkSession(starttime=ago(lookback), endtime=now())
| where NetworkDirection =~ "Inbound"
| extend originalSrcIpAddr = SrcIpAddr
| extend SrcIpAddr = iif(SrcIpAddr has "::ffff",split(SrcIpAddr,"f:")[1],SrcIpAddr)
| where ipv4_is_private(SrcIpAddr)==false
| where SrcIpAddr !='127.0.0.1' and SrcIpAddr !='0.0.0.0'
| distinct SrcIpAddr, DstIpAddr, DvcHostname, DstPortNumber, originalSrcIpAddr