SOLVED

KQL to extract IP addresses from SecurityAlerts

%3CLINGO-SUB%20id%3D%22lingo-sub-2179551%22%20slang%3D%22en-US%22%3EKQL%20to%20extract%20IP%20addresses%20from%20SecurityAlerts%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2179551%22%20slang%3D%22en-US%22%3E%3CP%3EI'm%20not%20sure%20if%20there%20is%20a%20simpler%20way%20to%20do%20this%2C%20but%20I%20wanted%20to%20get%20a%20list%20of%20all%20the%20IP%20addresses%20in%20both%20Entities%20and%20ExtendedProperties%20of%20SecurityAlerts.%20This%20is%20helpful%20to%20join%20on%20DeviceNetworkEvents%20or%20other%20tables%20that%20contain%20IP%20addresses%20to%20see%20if%20any%20IP%20from%20a%20SecurityAlert%20had%20other%20activity%20in%20your%20environment.%3C%2FP%3E%3CP%3EHere%20is%20the%20KQL%20query%20that%20I%20came%20up%20with%20and%20saved%20as%20a%20custom%20function.%20Suggestions%20for%20improvement%20are%20welcome!%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-sql%22%3E%3CCODE%3ESecurityAlert%20%0A%2F%2F%20First%20get%20lists%20of%20IP%20addresses%20from%20ExtendedProperties%0A%7C%20extend%20properties%20%3D%20parse_json(ExtendedProperties)%0A%7C%20extend%20IP_list%20%3D%20split(tostring(properties%5B%22IP%20Addresses%22%5D)%2C%20%22%2C%22)%0A%7C%20project%20IP_list%0A%7C%20where%20isnotempty(IP_list)%20%0A%7C%20summarize%20make_set(IP_list)%0A%7C%20mv-expand%20set_IP_list%20%2F%2F%20get%20each%20IP%20on%20its%20own%20row%0A%7C%20where%20isnotempty(set_IP_list)%0A%7C%20project%20IP%20%3D%20tostring(set_IP_list)%0A%2F%2F%20Now%20get%20every%20IP%20address%20from%20Entities%20that%20are%20type%20%22ip%22%0A%7C%20union%20(SecurityAlert%20%0A%7C%20extend%20Entities%20%3D%20parse_json(Entities)%0A%7C%20project%20Entities%0A%7C%20mv-expand%20Entities%0A%7C%20extend%20EType%20%3D%20tostring(Entities.Type)%0A%7C%20where%20EType%20%3D%3D%20%22ip%22%0A%7C%20extend%20IP%20%3D%20tostring(Entities.Address)%0A%7C%20project%20IP)%0A%7C%20order%20by%20IP%3C%2FCODE%3E%3C%2FPRE%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2188692%22%20slang%3D%22en-US%22%3ERe%3A%20KQL%20to%20extract%20IP%20addresses%20from%20SecurityAlerts%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2188692%22%20slang%3D%22en-US%22%3E%3CP%3EGood%20stuff%20!%20I%20modified%20the%20query%20a%20bit.%20I%20think%20it%20gets%20the%20same%20results.%20Also%20I%20use%20distinct%20just%20to%20grab%20unique%20IPs.%20I%20think%20that%20what%20you%20were%20trying%20to%20achieve%20with%20the%20summarize%20make%20set.%3C%2FP%3E%3CP%3EIf%20you%20run%20a%20%22%7C%20count%22%20you%20can%20see%20the%20difference.%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ESecurityAlert%3CBR%20%2F%3E%2F%2F%20First%20get%20lists%20of%20unique%20IP%20addresses%20from%20the%20Extended%20Properties%3CBR%20%2F%3E%7C%20project%20IPs%20%3D%20tostring(parse_json(ExtendedProperties)%5B%22IP%20Addresses%22%5D)%3CBR%20%2F%3E%7C%20extend%20IPs%20%3D%20split(IPs%2C%22%2C%22)%20%7C%20mv-expand%20IPs%3CBR%20%2F%3E%7C%20where%20isnotempty(IPs)%20%7C%20distinct%20tostring(IPs)%20%2F%2F%20get%20only%20unique%20IPs%3CBR%20%2F%3E%7C%20union%20(SecurityAlert%20%2F%2F%20join%20to%20Entities%20IP%20pool%3CBR%20%2F%3E%7C%20mv-expand%20parse_json(Entities)%3CBR%20%2F%3E%7C%20project%20IPs%20%3D%20Entities%5B%22Address%22%5D%3CBR%20%2F%3E%7C%20where%20isnotempty(IPs)%20%7C%20distinct%20tostring(IPs))%20%2F%2F%20get%20only%20unique%20IPs%3CBR%20%2F%3E%7C%20order%20by%20IPs%3CBR%20%2F%3E%7C%20count%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2188858%22%20slang%3D%22en-US%22%3ERe%3A%20KQL%20to%20extract%20IP%20addresses%20from%20SecurityAlerts%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2188858%22%20slang%3D%22en-US%22%3EThank%20you!%20That's%20a%20nice%20improvement!%3C%2FLINGO-BODY%3E
Occasional Contributor

I'm not sure if there is a simpler way to do this, but I wanted to get a list of all the IP addresses in both Entities and ExtendedProperties of SecurityAlerts. This is helpful to join on DeviceNetworkEvents or other tables that contain IP addresses to see if any IP from a SecurityAlert had other activity in your environment.

Here is the KQL query that I came up with and saved as a custom function. Suggestions for improvement are welcome!

SecurityAlert 
// First get lists of IP addresses from ExtendedProperties
| extend properties = parse_json(ExtendedProperties)
| extend IP_list = split(tostring(properties["IP Addresses"]), ",")
| project IP_list
| where isnotempty(IP_list) 
| summarize make_set(IP_list)
| mv-expand set_IP_list // get each IP on its own row
| where isnotempty(set_IP_list)
| project IP = tostring(set_IP_list)
// Now get every IP address from Entities that are type "ip"
| union (SecurityAlert 
| extend Entities = parse_json(Entities)
| project Entities
| mv-expand Entities
| extend EType = tostring(Entities.Type)
| where EType == "ip"
| extend IP = tostring(Entities.Address)
| project IP)
| order by IP
2 Replies
best response confirmed by rpargman (Occasional Contributor)
Solution

Good stuff ! I modified the query a bit. I think it gets the same results. Also I use distinct just to grab unique IPs. I think that what you were trying to achieve with the summarize make set.

If you run a "| count" you can see the difference. 

 

SecurityAlert
// First get lists of unique IP addresses from the Extended Properties
| project IPs = tostring(parse_json(ExtendedProperties)["IP Addresses"])
| extend IPs = split(IPs,",") | mv-expand IPs
| where isnotempty(IPs) | distinct tostring(IPs) // get only unique IPs
| union (SecurityAlert // join to Entities IP pool
| mv-expand parse_json(Entities)
| project IPs = Entities["Address"]
| where isnotempty(IPs) | distinct tostring(IPs)) // get only unique IPs
| order by IPs
| count

Thank you! That's a nice improvement!