Public Azure Virtual Machines are one of the most exploited resources in the Azure cloud. As we mentioned in our recent white paper (here) it only takes a few seconds on average for someone to test your Virtual Machine for weaknesses, if they are available on the internet.
As we also state, it is very simple to misconfigure cloud resources in such a way that they do end up being publicly available.
One very fresh vulnerability that has been found on many Azure Virtual Machines falls into this category, and that’s the OMIGOD! vulnerability as disclosed by Wiz on their blog.
“Public” is quite a simple word, but there need to be a few different things in place in the cloud for something to actually be public. On Azure, that is at least the following:
Only if all of these are configured “the wrong way” will a VM be publicly available. Yes, there are other mitigation tactics like Azure Firewall, Gateways, OS firewalls, but for the majority of cases, above list is what causes a VM to be publicly available.
Unfortunately, as simple as it is to make a VM accessible from the internet it is not as simple to identify which VMs in one’s environment are accessible from the internet.
Of course, we can browse to the Azure Portal and view all the Virtual Machines in our Azure Subscriptions and we will be able to see for example if the VMs have public IP addresses, which is one critical part of the recipe for “being public”. What we cannot see, and what requires a lot of clicks and deeper understanding of the cloud infrastructure, is the networking configuration.
Who has time for that?
However, we can make use of some automation here. Azure Resource Graph Explorer allows us to execute queries against the Azure infrastructure in a SQL-like language called KQL (Kusto Query Language).
With that we can get close to finding all our exposed VMs. Here is an example query that can find all Network Security Groups (NSG) that allow Port 22 from the internet and where the NSG is attached to a NIC or a Subnet.
|where type == 'microsoft.network/networksecuritygroups'
| mvexpand properties.securityRules
| extend destinationPortRange = properties_securityRules.properties.destinationPortRange,
destinationPortRanges = properties_securityRules.properties.destinationPortRanges
| extend hasPortRange = iif(destinationPortRange contains '-', true, false)
| extend exploitable = iif(isnotempty(properties.subnets) or isnotempty(properties.networkInterfaces), true, false)
| extend destinationPortRangesArray = iif(hasPortRange, split(destinationPortRange, '-'), dynamic(null))
| extend destinationPortRangeStart = tolong(destinationPortRangesArray), destinationPortRangeEnd = tolong(destinationPortRangesArray)
| where exploitable and properties_securityRules.properties.direction == 'Inbound' and properties_securityRules.properties.access == 'Allow' and (properties_securityRules.properties.protocol == '*' or toupper(properties_securityRules.properties.protocol) == 'TCP' or toupper(properties_securityRules.properties.protocol) == 'UDP') and ((destinationPortRange == '*' or destinationPortRange == '22' or tostring(destinationPortRanges) has '\'22\'') or (destinationPortRangeStart <= 22 and 22 <= destinationPortRangeEnd)) and ((properties_securityRules.properties.sourceAddressPrefix == 'Internet' or properties_securityRules.properties.sourceAddressPrefix == '*' or properties_securityRules.properties.sourceAddressPrefix == '0.0.0.0/0' or properties_securityRules.properties.sourceAddressPrefix == '::/0') or (properties_securityRules.properties.sourceAddressPrefixes contains '0.0.0.0/0' or properties_securityRules.properties.sourceAddressPrefixes contains '0.0.0.0' or properties_securityRules.properties.sourceAddressPrefixes contains '::/0'))
This already narrows down the resources to investigate. As a next step we would need to match this to route tables and VMs in order to get the full picture.
Instead of doing this manually, why not use a service like ARGOS that does this automatically for you?
Identification and optional remediation of this issue is already covered by ARGOS.
If you have not signed up to ARGOS yet then why not spend a few minutes (seriously, minutes!) and sign up to our free trial and see if you have any publicly available Azure Virtual Machines in your environment.
Sign up at https://argos-security.io