HIGH aspnetcsharpssrf cloud metadata

Ssrf Cloud Metadata in Aspnet (Csharp)

Ssrf Cloud Metadata in Aspnet with Csharp

Server-Side Request Forgery (SSRF) against cloud metadata endpoints is a high-impact pattern when an ASP.NET application written in C# makes outbound HTTP requests to instance metadata services. In cloud environments (e.g., Azure IMDS, AWS EC2 Instance Metadata Service, GCP metadata), these endpoints are typically bound to a local link-scope address such as 169.254.169.254. An SSRF vulnerability occurs when an ASP.NET controller or service accepts a user-supplied URL and uses it to form a request without strict validation, allowing an attacker to redirect traffic from the metadata service to a malicious endpoint, or to probe internal services that are otherwise not exposed.

In C# ASP.NET applications, common vulnerable patterns include using HttpClient with a user-controlled uriString, or using WebClient and HttpWebRequest with a URL built from request parameters. Because these APIs do not inherently prevent redirection to non-public endpoints, an attacker can supply a URL like http://169.254.169.254/metadata/instance (Azure) or http://169.254.169.254/latest/meta-data/ (AWS), causing the server to disclose sensitive cloud metadata such as instance identity, security tokens, and network configuration. An attacker may also pivot from the metadata service to other internal services that the cloud host can reach, leading to further compromise.

An example of a vulnerable ASP.NET Core controller in C#:

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace SsrfDemo.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class ProxyController : ControllerBase
    {
        private readonly HttpClient _httpClient;

        public ProxyController(IHttpClientFactory httpClientFactory)
        {
            _httpClient = httpClientFactory.CreateClient();
        }

        [HttpGet("fetch")]
        public async Task<IActionResult> Fetch([FromQuery] string url)
        {
            if (string.IsNullOrWhiteSpace(url))
                return BadRequest("url is required");

            // Vulnerable: user-controlled URL used directly
            var response = await _httpClient.GetAsync(url);
            var content = await response.Content.ReadAsStringAsync();
            return Content(content, "text/plain");
        }
    }
}

In this example, an attacker can supply ?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ to leak IAM roles. To mitigate this, the application must validate and restrict the target host, disallow private and reserved IP ranges (including 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, and the cloud metadata link-local range 169.254.0.0/16), and enforce an allowlist of permitted domains. Additionally, disabling automatic redirection and using a tightly scoped HttpClient with a short timeout and no credentials helps reduce exposure.

OWASP API Top 10 categorizes this as an API1:2023 Broken Object Level Authorization issue when the endpoint is used to access unauthorized resources, but SSRF specifically maps to API2:2023 Broken Authentication and Session Management when credentials are exposed. Input validation and host allowlisting are essential controls, and frameworks such as ASP.NET should not be relied upon to provide these protections automatically.

Csharp-Specific Remediation in Aspnet

Remediation of SSRF in C# ASP.NET requires explicit validation of the destination host and URL construction, rather than relying on runtime defaults. You should avoid passing user input directly into HttpClient.GetAsync or similar methods. Instead, use a strict allowlist of permitted hostnames or IP ranges and parse the user input to validate the host before constructing the request.

Below is a secure C# example for ASP.NET Core that demonstrates host allowlisting, blocking of private and cloud metadata ranges, and safe request execution:

using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;

namespace SecureApi.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class SafeProxyController : ControllerBase
    {
        private readonly HttpClient _httpClient;
        private readonly string[] _allowedHosts;

        public SafeProxyController(IHttpClientFactory httpClientFactory, IConfiguration configuration)
        {
            _httpClient = httpClientFactory.CreateClient();
            // Configure allowed hosts via appsettings.json or environment variables
            _allowedHosts = configuration.GetSection("AllowedHosts").Get<string[]>() ?? Array.Empty<string>();
        }

        [HttpGet("fetch")]
        public async Task<IActionResult> Fetch([FromQuery] string url)
        {
            if (string.IsNullOrWhiteSpace(url))
                return BadRequest("url is required");

            if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
                return BadRequest("Invalid URI");

            // Block private and cloud metadata ranges
            if (IsPrivateOrMetadataAddress(uri.Host, uri.AddressFamily))
                return Forbid("Request to restricted address is not allowed");

            // Host allowlist check
            if (Array.IndexOf(_allowedHosts, uri.Host) == -1)
                return Forbid("Host not permitted");

            // Optional: enforce HTTPS for allowed hosts
            if (uri.Scheme != Uri.UriSchemeHttps)
                return BadRequest("Only HTTPS requests are allowed");

            // Configure request to not follow redirects automatically
            var handler = new HttpClientHandler
            {
                AllowAutoRedirect = false
            };
            using var scopedClient = new HttpClient(handler);
            var response = await scopedClient.GetAsync(uri);
            var content = await response.Content.ReadAsStringAsync();
            return Content(content, "text/plain");
        }

        private bool IsPrivateOrMetadataAddress(string host, AddressFamily addressFamily)
        {
            // Try parsing IP address; if not an IP, skip IP checks
            if (System.Net.IPAddress.TryParse(host, out var ip))
            {
                // IPv4 checks
                if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                    var bytes = ip.GetAddressBytes();
                    // 127.0.0.0/8
                    if (bytes[0] == 127) return true;
                    // 10.0.0.0/8
                    if (bytes[0] == 10) return true;
                    // 172.16.0.0/12
                    if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31) return true;
                    // 192.168.0.0/16
                    if (bytes[0] == 192 && bytes[1] == 168) return true;
                    // 169.254.0.0/16 (cloud metadata link-local)
                    if (bytes[0] == 169 && bytes[1] == 254) return true;
                }
                // Add IPv6 checks if needed
            }

            // Optionally block known cloud metadata hostnames
            var lowerHost = host.ToLowerInvariant();
            if (lowerHost == "169.254.169.254" || lowerHost.EndsWith(".compute.internal", StringComparison.OrdinalIgnoreCase) ||
                lowerHost.EndWith(".amazonaws.com", StringComparison.OrdinalIgnoreCase))
                return true;

            return false;
        }
    }
}

Additional measures include disabling automatic redirects (as shown), setting short timeouts, and ensuring that the HttpClient does not flow default credentials. For ASP.NET applications consuming internal cloud service APIs, prefer using managed identities or configured credentials rather than constructing URLs from user input. The middleBrick CLI can be used in CI/CD to validate that your endpoints do not inadvertently expose metadata paths by scanning your API surface with the middlebrick scan <url> command, helping to catch misconfigurations before deployment.

Frequently Asked Questions

What is an example of a cloud metadata SSRF payload targeting AWS?
An attacker can supply http://169.254.169.254/latest/meta-data/iam/security-credentials/ to enumerate IAM roles. A C# ASP.NET vulnerable proxy that forwards user-supplied URLs without validation will disclose this information.
How does middleBrick relate to SSRF findings in ASP.NET APIs?
middleBrick scans unauthenticated attack surfaces and reports findings such as SSRF with remediation guidance. You can run middlebrick scan from the CLI to test endpoints and integrate the GitHub Action to fail builds if risky behavior is detected.