From b82fc9ac397b2e12513ca148740f0b81390bc6dc Mon Sep 17 00:00:00 2001 From: Carlos Polop Date: Sun, 23 Feb 2025 23:58:41 +0100 Subject: [PATCH] improve winpeas azure env detection --- .../winPEAS/Info/CloudInfo/AzureInfo.cs | 132 ++++++++++++++---- 1 file changed, 105 insertions(+), 27 deletions(-) diff --git a/winPEAS/winPEASexe/winPEAS/Info/CloudInfo/AzureInfo.cs b/winPEAS/winPEASexe/winPEAS/Info/CloudInfo/AzureInfo.cs index e37f19f..6c4386b 100644 --- a/winPEAS/winPEASexe/winPEAS/Info/CloudInfo/AzureInfo.cs +++ b/winPEAS/winPEASexe/winPEAS/Info/CloudInfo/AzureInfo.cs @@ -1,20 +1,39 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Net; -using System; namespace winPEAS.Info.CloudInfo { internal class AzureInfo : CloudInfoBase { - public override string Name => "Azure VM"; - public override bool IsCloud => Directory.Exists(WINDOWS_AZURE_FOLDER); - + // The Name property now differentiates between an Azure VM and an Azure Container. + public override string Name + { + get + { + if (IsContainer()) + return "Azure Container"; // **Container environment detected** + return "Azure VM"; // **VM environment detected** + } + } + + // IsCloud now returns true if either the Azure VM folder exists or container env vars are set. + public override bool IsCloud => Directory.Exists(WINDOWS_AZURE_FOLDER) || IsContainer(); + private Dictionary> _endpointData = null; const string WINDOWS_AZURE_FOLDER = "c:\\windowsazure"; const string AZURE_BASE_URL = "http://169.254.169.254/metadata/"; const string API_VERSION = "2021-12-13"; + const string CONTAINER_API_VERSION = "2019-08-01"; + + // **New helper method to detect if running inside an Azure container** + private bool IsContainer() + { + return !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT")) || + !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSI_ENDPOINT")); + } public override Dictionary> EndpointDataList() { @@ -25,28 +44,38 @@ namespace winPEAS.Info.CloudInfo try { - string result; + string result; + List> endpoints; - List> endpoints = new List>() + if (IsContainer()) { - new Tuple("Instance Details", $"instance?api-version={API_VERSION}", false), - new Tuple("Load Balancer details", $"loadbalancer?api-version={API_VERSION}", false), - new Tuple("Management token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://management.azure.com/", true), - new Tuple("Graph token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://graph.microsoft.com/", true), - new Tuple("Vault token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://vault.azure.net/", true), - new Tuple("Storage token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://storage.azure.com/", true) - }; - - if (IsAvailable) - { - - + // **Running in Azure Container: use the container endpoint and add the "Secret" header if available** + string containerBaseUrl = Environment.GetEnvironmentVariable("MSI_ENDPOINT") ?? + Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT"); + endpoints = new List>() + { + new Tuple("Management token", $"identity/oauth2/token?api-version={CONTAINER_API_VERSION}&resource=https://management.azure.com/", true), + new Tuple("Graph token", $"identity/oauth2/token?api-version={CONTAINER_API_VERSION}&resource=https://graph.microsoft.com/", true), + new Tuple("Vault token", $"identity/oauth2/token?api-version={CONTAINER_API_VERSION}&resource=https://vault.azure.net/", true), + new Tuple("Storage token", $"identity/oauth2/token?api-version={CONTAINER_API_VERSION}&resource=https://storage.azure.com/", true) + }; + foreach (var tuple in endpoints) { - string url = $"{AZURE_BASE_URL}{tuple.Item2}"; - - result = CreateMetadataAPIRequest(url, "GET", new WebHeaderCollection() { { "Metadata", "true" } }); - + // Ensure proper URL formatting. + string url = $"{containerBaseUrl}{(containerBaseUrl.EndsWith("/") ? "" : "/")}{tuple.Item2}"; + var headers = new WebHeaderCollection(); + string msiSecret = Environment.GetEnvironmentVariable("MSI_SECRET"); + if (!string.IsNullOrEmpty(msiSecret)) + { + headers.Add("Secret", msiSecret); + } + string identitySecret = Environment.GetEnvironmentVariable("IDENTITY_HEADER"); + if (!string.IsNullOrEmpty(identitySecret)) + { + headers.Add("X-IDENTITY-HEADER", identitySecret); + } + result = CreateMetadataAPIRequest(url, "GET", headers); _endpointDataList.Add(new EndpointData() { EndpointName = tuple.Item1, @@ -54,12 +83,36 @@ namespace winPEAS.Info.CloudInfo IsAttackVector = tuple.Item3 }); } + } + else if (Directory.Exists(WINDOWS_AZURE_FOLDER)) + { + // **Running in Azure VM: use the standard metadata endpoint with "Metadata: true" header** + endpoints = new List>() + { + new Tuple("Instance Details", $"instance?api-version={API_VERSION}", false), + new Tuple("Load Balancer details", $"loadbalancer?api-version={API_VERSION}", false), + new Tuple("Management token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://management.azure.com/", true), + new Tuple("Graph token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://graph.microsoft.com/", true), + new Tuple("Vault token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://vault.azure.net/", true), + new Tuple("Storage token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://storage.azure.com/", true) + }; - + foreach (var tuple in endpoints) + { + string url = $"{AZURE_BASE_URL}{tuple.Item2}"; + result = CreateMetadataAPIRequest(url, "GET", new WebHeaderCollection() { { "Metadata", "true" } }); + _endpointDataList.Add(new EndpointData() + { + EndpointName = tuple.Item1, + Data = result, + IsAttackVector = tuple.Item3 + }); + } } else { - foreach (var endpoint in endpoints) + // If neither container nor VM, endpoints remain unset. + foreach (var endpoint in new List>()) { _endpointDataList.Add(new EndpointData() { @@ -74,6 +127,7 @@ namespace winPEAS.Info.CloudInfo } catch (Exception ex) { + // **Exception handling (e.g., logging) can be added here** } } @@ -82,7 +136,31 @@ namespace winPEAS.Info.CloudInfo public override bool TestConnection() { - return CreateMetadataAPIRequest(AZURE_BASE_URL, "GET") != null; - } + if (IsContainer()) + { + // **Test connection for Azure Container** + string containerBaseUrl = Environment.GetEnvironmentVariable("MSI_ENDPOINT") ?? + Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT"); + if (string.IsNullOrEmpty(containerBaseUrl)) + return false; + var headers = new WebHeaderCollection(); + string msiSecret = Environment.GetEnvironmentVariable("MSI_SECRET"); + if (!string.IsNullOrEmpty(msiSecret)) + { + headers.Add("Secret", msiSecret); + } + string identitySecret = Environment.GetEnvironmentVariable("IDENTITY_HEADER"); + if (!string.IsNullOrEmpty(identitySecret)) + { + headers.Add("X-IDENTITY-HEADER", identitySecret); + } + return CreateMetadataAPIRequest(containerBaseUrl, "GET", headers) != null; + } + else + { + // **Test connection for Azure VM** + return CreateMetadataAPIRequest(AZURE_BASE_URL, "GET", new WebHeaderCollection() { { "Metadata", "true" } }) != null; + } + } } }