improve winpeas azure env detection

This commit is contained in:
Carlos Polop 2025-02-23 23:58:41 +01:00
parent 516aafff27
commit b82fc9ac39

View File

@ -1,20 +1,39 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System;
namespace winPEAS.Info.CloudInfo namespace winPEAS.Info.CloudInfo
{ {
internal class AzureInfo : CloudInfoBase internal class AzureInfo : CloudInfoBase
{ {
public override string Name => "Azure VM"; // The Name property now differentiates between an Azure VM and an Azure Container.
public override bool IsCloud => Directory.Exists(WINDOWS_AZURE_FOLDER); 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<string, List<EndpointData>> _endpointData = null; private Dictionary<string, List<EndpointData>> _endpointData = null;
const string WINDOWS_AZURE_FOLDER = "c:\\windowsazure"; const string WINDOWS_AZURE_FOLDER = "c:\\windowsazure";
const string AZURE_BASE_URL = "http://169.254.169.254/metadata/"; const string AZURE_BASE_URL = "http://169.254.169.254/metadata/";
const string API_VERSION = "2021-12-13"; 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<string, List<EndpointData>> EndpointDataList() public override Dictionary<string, List<EndpointData>> EndpointDataList()
{ {
@ -26,27 +45,37 @@ namespace winPEAS.Info.CloudInfo
try try
{ {
string result; string result;
List<Tuple<string, string, bool>> endpoints;
List<Tuple<string, string, bool>> endpoints = new List<Tuple<string, string, bool>>() if (IsContainer())
{ {
new Tuple<string, string, bool>("Instance Details", $"instance?api-version={API_VERSION}", false), // **Running in Azure Container: use the container endpoint and add the "Secret" header if available**
new Tuple<string, string, bool>("Load Balancer details", $"loadbalancer?api-version={API_VERSION}", false), string containerBaseUrl = Environment.GetEnvironmentVariable("MSI_ENDPOINT") ??
new Tuple<string, string, bool>("Management token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://management.azure.com/", true), Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT");
new Tuple<string, string, bool>("Graph token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://graph.microsoft.com/", true), endpoints = new List<Tuple<string, string, bool>>()
new Tuple<string, string, bool>("Vault token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://vault.azure.net/", true), {
new Tuple<string, string, bool>("Storage token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://storage.azure.com/", true) new Tuple<string, string, bool>("Management token", $"identity/oauth2/token?api-version={CONTAINER_API_VERSION}&resource=https://management.azure.com/", true),
}; new Tuple<string, string, bool>("Graph token", $"identity/oauth2/token?api-version={CONTAINER_API_VERSION}&resource=https://graph.microsoft.com/", true),
new Tuple<string, string, bool>("Vault token", $"identity/oauth2/token?api-version={CONTAINER_API_VERSION}&resource=https://vault.azure.net/", true),
if (IsAvailable) new Tuple<string, string, bool>("Storage token", $"identity/oauth2/token?api-version={CONTAINER_API_VERSION}&resource=https://storage.azure.com/", true)
{ };
foreach (var tuple in endpoints) foreach (var tuple in endpoints)
{ {
string url = $"{AZURE_BASE_URL}{tuple.Item2}"; // Ensure proper URL formatting.
string url = $"{containerBaseUrl}{(containerBaseUrl.EndsWith("/") ? "" : "/")}{tuple.Item2}";
result = CreateMetadataAPIRequest(url, "GET", new WebHeaderCollection() { { "Metadata", "true" } }); 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() _endpointDataList.Add(new EndpointData()
{ {
EndpointName = tuple.Item1, EndpointName = tuple.Item1,
@ -54,12 +83,36 @@ namespace winPEAS.Info.CloudInfo
IsAttackVector = tuple.Item3 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<Tuple<string, string, bool>>()
{
new Tuple<string, string, bool>("Instance Details", $"instance?api-version={API_VERSION}", false),
new Tuple<string, string, bool>("Load Balancer details", $"loadbalancer?api-version={API_VERSION}", false),
new Tuple<string, string, bool>("Management token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://management.azure.com/", true),
new Tuple<string, string, bool>("Graph token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://graph.microsoft.com/", true),
new Tuple<string, string, bool>("Vault token", $"identity/oauth2/token?api-version={API_VERSION}&resource=https://vault.azure.net/", true),
new Tuple<string, string, bool>("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 else
{ {
foreach (var endpoint in endpoints) // If neither container nor VM, endpoints remain unset.
foreach (var endpoint in new List<Tuple<string, string, bool>>())
{ {
_endpointDataList.Add(new EndpointData() _endpointDataList.Add(new EndpointData()
{ {
@ -74,6 +127,7 @@ namespace winPEAS.Info.CloudInfo
} }
catch (Exception ex) catch (Exception ex)
{ {
// **Exception handling (e.g., logging) can be added here**
} }
} }
@ -82,7 +136,31 @@ namespace winPEAS.Info.CloudInfo
public override bool TestConnection() 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;
}
} }
} }
} }