Splunk Enterprise Security

Splunk port scan detection

christianubeda
Path Finder

Hi team!

It's my very first time and I need help.

I want to detect a port scan. I did that but I dont know how to continue.

I want to detect the scans of ports made from some internal zone to another internal zone

index=xxx_paloalto sourcetype="pan:traffic"  type=TRAFFIC (src_zone!="Inet-WAN1" OR src_zone!="Inet-WAN2")(dest_zone!="Inet-WAN1" OR dest_zone!="Inet-WAN2") `Users_Subnets` `Not_Common_Ports_xxx` |stats count, values(src_ip), values(dest_ip), values(src_zone),values(dest_zone),values(user) by generated_time | rename values(src_ip) as Source_IP, values(dest_ip) as Destination_IP, count as Count, user as User, values(src_zone) as Source_Zone, values(dest_zone) as Dest_Zone, values(user) as User

Any advice? I have no idea how to do it

Thank you!


marked code as code - dmj

0 Karma
1 Solution

DalJeanis
SplunkTrust
SplunkTrust

First, you need to decide exactly what you mean by port-scan. When you aggregate your records, you need to do so in a meaningful way, so that each record that comes out of the stats command means something specific. So, before you code your search, define exactly what you are searching for.

Example: "When I say 'port scan', I mean that, during the period of the search, a single source zone and source ip is talking to a large number (8 or more) of ports on a specific destination IP (which will always be in a single zone), and where the two IPs are in different zones."

If that was your definition, then you would want by src_zone src_ip dest_ip to be part of your stats command, and you'd want to keep the values of the dest_ports that were accessed. It might look like this...

 index=xxx_paloalto sourcetype="pan:traffic"  type=TRAFFIC 
    (src_zone!="Inet-WAN1" OR src_zone!="Inet-WAN2")
    (dest_zone!="Inet-WAN1" OR dest_zone!="Inet-WAN2") 
    `Users_Subnets` `Not_Common_Ports_xxx` 
| stats count, values(dest_zone) as dest_zone, values(dest_port) as dest_port,
    values(user) as User by src_zone src_ip dest_ip
| where (mvcount(dest_port) >= 😎 AND (src_zone != dest_zone)

By the way, never rename your fields to human-readable "pretty" form until the very end, when you are sure that everything is working and ready to be presented to the audience. Otherwise, you cause unnecessary hunting for errors in capitalization and spelling.

Now, if you had defined it a different way, you might have a completely different search.

Example: "When I say 'port scan', I mean that, during any five minute period of the day, a single source zone and source ip is talking to a large number (5 or more) of ports on a specific destination IP (which will always be in a single zone), and where the two IPs are in different zones.... OR if during the entire day, the same source zone and source IP is talking to more than 25 ports on a single specific destination IP."

 index=xxx_paloalto sourcetype="pan:traffic"  type=TRAFFIC 
    (src_zone!="Inet-WAN1" OR src_zone!="Inet-WAN2")
    (dest_zone!="Inet-WAN1" OR dest_zone!="Inet-WAN2") 
    `Users_Subnets` `Not_Common_Ports_xxx` 
| bin _time span=5m
| stats count, values(dest_zone) as dest_zone, values(dest_port) as dest_port,
    values(user) as User by _time src_zone src_ip dest_ip  
| where (src_zone != dest_zone)
| bin _time as Day span=1d 
| eventstats values(dest_port) as all_dest_ports by Day src_ip dest_ip
| where (mvcount(dest_port) >= 5)  OR (mvcount(all_dest_ports) >= 25)

View solution in original post

DalJeanis
SplunkTrust
SplunkTrust

First, you need to decide exactly what you mean by port-scan. When you aggregate your records, you need to do so in a meaningful way, so that each record that comes out of the stats command means something specific. So, before you code your search, define exactly what you are searching for.

Example: "When I say 'port scan', I mean that, during the period of the search, a single source zone and source ip is talking to a large number (8 or more) of ports on a specific destination IP (which will always be in a single zone), and where the two IPs are in different zones."

If that was your definition, then you would want by src_zone src_ip dest_ip to be part of your stats command, and you'd want to keep the values of the dest_ports that were accessed. It might look like this...

 index=xxx_paloalto sourcetype="pan:traffic"  type=TRAFFIC 
    (src_zone!="Inet-WAN1" OR src_zone!="Inet-WAN2")
    (dest_zone!="Inet-WAN1" OR dest_zone!="Inet-WAN2") 
    `Users_Subnets` `Not_Common_Ports_xxx` 
| stats count, values(dest_zone) as dest_zone, values(dest_port) as dest_port,
    values(user) as User by src_zone src_ip dest_ip
| where (mvcount(dest_port) >= 😎 AND (src_zone != dest_zone)

By the way, never rename your fields to human-readable "pretty" form until the very end, when you are sure that everything is working and ready to be presented to the audience. Otherwise, you cause unnecessary hunting for errors in capitalization and spelling.

Now, if you had defined it a different way, you might have a completely different search.

Example: "When I say 'port scan', I mean that, during any five minute period of the day, a single source zone and source ip is talking to a large number (5 or more) of ports on a specific destination IP (which will always be in a single zone), and where the two IPs are in different zones.... OR if during the entire day, the same source zone and source IP is talking to more than 25 ports on a single specific destination IP."

 index=xxx_paloalto sourcetype="pan:traffic"  type=TRAFFIC 
    (src_zone!="Inet-WAN1" OR src_zone!="Inet-WAN2")
    (dest_zone!="Inet-WAN1" OR dest_zone!="Inet-WAN2") 
    `Users_Subnets` `Not_Common_Ports_xxx` 
| bin _time span=5m
| stats count, values(dest_zone) as dest_zone, values(dest_port) as dest_port,
    values(user) as User by _time src_zone src_ip dest_ip  
| where (src_zone != dest_zone)
| bin _time as Day span=1d 
| eventstats values(dest_port) as all_dest_ports by Day src_ip dest_ip
| where (mvcount(dest_port) >= 5)  OR (mvcount(all_dest_ports) >= 25)

View solution in original post

christianubeda
Path Finder

You have already helped me a lot and I think I have a slight idea of ​​how to continue.

I have to create a search that is capable of detecting a massive port scan within my environment. The conditions are that it is from an internal zone to another internal zone and that there are 100 events in less than 2 seconds.

I need the data of threat_name, timestamp, source ip, dest ip, vendor action, user

With this search I have to make two tables, one for the TCP port scan and another one for the UDP port scan

Thanks a lot!

0 Karma

DalJeanis
SplunkTrust
SplunkTrust

@christianubeda - you're welcome.

Here's some other items to think about: "within 2 seconds" is not as simple as you think. You can't just chunk time up into 2 second blocks, because you might divide a port-scan into two pieces and miss it.

We weren't that worried about a 5m number, but when you go that granular, other considerations can take precedence. I'd probably tweak the requirements to a rolling 3-second window as the easiest and clearest way to definitely find your port scans. For that, we use streamstats.

  index=xxx_paloalto sourcetype="pan:traffic"  type=TRAFFIC 
     (src_zone!="Inet-WAN1" OR src_zone!="Inet-WAN2")
     (dest_zone!="Inet-WAN1" OR dest_zone!="Inet-WAN2") 
     `Users_Subnets` `Not_Common_Ports_xxx` 
 | bin _time span=1s
 | stats count as secCount, values(dest_zone) as dest_zone, values(dest_port) as dest_port,
     values(user) as User by _time src_zone src_ip dest_ip  
 | where (src_zone != dest_zone)

 | streamstats time_window=3s sum(secCount) as sumCount,
        values(dest_zone) as all_dest_ports by  src_zone src_ip dest_ip 
 | where (mvcount(all_dest_ports) >= 100)

DalJeanis
SplunkTrust
SplunkTrust

By the way, if your current problem is solved, please accept the answer.

0 Karma
Register for .conf21 Now! Go Vegas or Go Virtual!

How will you .conf21? You decide! Go in-person in Las Vegas, 10/18-10/21, or go online with .conf21 Virtual, 10/19-10/20.