Using external IP lists in Azure Sentinel for threat intelligence

By Gianni Castaldi

Today’s blog post will be about using external data in Azure Sentinel as threat intelligence. There are two threat intelligence connectors but in this blog post we use the the externaldata operator, to import IP addresses and match these with the SigninLogs and OfficeActivity tables in Azure Sentinel.

For this example, we will query 5 sources, but you can add more or even use your threat intel source. During the building process of this query, I found that if a source is offline the query won’t return any results.

The first step is to query the 5 sources with the externaldata operator.

externaldata(ip:string)
[@"https://rules.emergingthreats.net/blockrules/compromised-ips.txt",
@"https://raw.githubusercontent.com/stamparm/ipsum/master/levels/5.txt",
@"https://cinsscore.com/list/ci-badguys.txt",
@"https://infosec.cert-pa.it/analyze/listip.txt",
@"https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"
]
with(format="csv")

After returning the sources there is some clutter in them, so we we use the matches regex operator to clean the list. And since there could be some overlap we will use the distinct operator for deduplication.

| where ip matches regex "(^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)"
| distinct ip

Now that we have a list of approximately 40k malicious IP addresses we can compare these with the SigninLogs, to view if someone has tried to logon from them. I’ve added the ResultType == 0 to exclude failed sign-ins.

let BlockList = (externaldata(ip:string)
[@"https://rules.emergingthreats.net/blockrules/compromised-ips.txt",
@"https://raw.githubusercontent.com/stamparm/ipsum/master/levels/5.txt",
@"https://cinsscore.com/list/ci-badguys.txt",
@"https://infosec.cert-pa.it/analyze/listip.txt",
@"https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"
]
with(format="csv")
| where ip matches regex "(^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)"
| distinct ip
);
SigninLogs
| where IPAddress in (BlockList)
| where ResultType == "0"

Sign-in logs are important, but so is Office activity. So we modify the query to compare the malicious IP addresses with the Office activity IP addresses.

let BlockList = (externaldata(ip:string)
[@"https://rules.emergingthreats.net/blockrules/compromised-ips.txt",
@"https://raw.githubusercontent.com/stamparm/ipsum/master/levels/5.txt",
@"https://cinsscore.com/list/ci-badguys.txt",
@"https://infosec.cert-pa.it/analyze/listip.txt",
@"https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"
]
with(format="csv")
| where ip matches regex "(^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)"
| distinct ip
);
OfficeActivity
| where ClientIP in (BlockList)

So in this blogpost we created two queries, which can be used as analytics rules in Azure Sentinel. The queries already return the UserPrincipalName/UserId and the IPAddress/ClientIP which can be used in the analytics rule, but we can also ad the following line in the SigninLogs query to show the computer name.

| extend Computer = tostring(DeviceDetail.displayName)

This way we know if the sign in is from a known system.

Thanks for reading and if you have any questions or ideas for a blog post let me know.

Alternative Text

By Gianni Castaldi

MVP | NinjaCat | Researching and Engineering Cyber Security @ KustoWorks

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close