HIGH aspnetssrf blind

Ssrf Blind in Aspnet

How Blind SSRF Manifests in ASP.NET

Blind Server-Side Request Forgery (SSRF) occurs when an attacker can induce an ASP.NET application to make HTTP requests to arbitrary URLs but cannot directly view the response. Instead, attackers rely on side channels like response timing, error messages, or out-of-band (OAST) indicators to extract information. In ASP.NET, this commonly arises when user-supplied URLs are passed to HttpClient or IHttpClientFactory without validation, particularly in scenarios where the response is not returned to the user.

A typical vulnerable pattern in ASP.NET Core controllers looks like this:

[HttpPost("api/webhook")]
public async Task RegisterWebhook([FromBody] WebhookRequest request)
{
    // Vulnerable: user-controlled URL used without validation
    var httpClient = _httpClientFactory.CreateClient();
    var response = await httpClient.PostAsync(request.Url, 
        new StringContent("test"));
    // Only a generic status is returned; response body is hidden
    return Ok(new { status = "registered" });
}

Here, an attacker can supply request.Url pointing to internal infrastructure (e.g., http://169.254.169.254/latest/meta-data/ on AWS) or other cloud provider metadata endpoints. Because the response isn't exposed, the attack is "blind," but timing differences or error messages (e.g., 403 vs 200) can reveal information about internal services. Another common vector is URL parameters in GET endpoints that trigger server-side fetches:

[HttpGet("api/fetch")]
public async Task FetchData([FromQuery] string target)
{
    // Blind SSRF: response not returned, but request is made
    var client = _httpClientFactory.CreateClient("ExternalService");
    await client.GetAsync(target); // No response read
    return Ok(new { message = "Request processed" });
}

ASP.NET applications often use HttpClient with default credentials or proxy settings inherited from the host environment. If an attacker can reach the metadata service (e.g., http://169.254.169.254 on AWS, http://169.254.169.254/metadata/instance on Azure), they may steal IAM credentials. Blind SSRF can also probe internal network topology by observing latency changes when requesting http://internal-host:port.

ASP.NET-Specific Detection

Detecting blind SSRF in ASP.NET requires out-of-band techniques since the response isn't visible in the HTTP response. middleBrick automates this by injecting unique, attacker-controlled URLs into every parameter that might be used for server-side requests (identified via OpenAPI spec analysis or heuristic scanning). When the ASP.NET application makes a request to one of these URLs, middleBrick's monitoring infrastructure logs the inbound connection, confirming SSRF vulnerability.

For ASP.NET APIs, middleBrick specifically tests:

  • All string parameters in GET/POST bodies that resemble URLs (e.g., url, endpoint, callback, redirect_uri).
  • OpenAPI/Swagger definitions with format: uri or format: url.
  • Common ASP.NET patterns like webhook registration endpoints, proxy controllers, and OAuth redirect_uri implementations.

Example scan command using middleBrick's CLI:

middlebrick scan https://api.example.com/swagger/v1/swagger.json

middleBrick will submit payloads like http://.oastify.com to vulnerable parameters. If the ASP.NET app initiates a request to that domain, middleBrick detects it via DNS/HTTP logs. The scanner also checks for cloud metadata endpoint access attempts (e.g., http://169.254.169.254/latest/meta-data/) and reports them as high-severity findings. Because middleBrick resolves all $ref in OpenAPI specs, it accurately identifies every URL-accepting parameter, even in complex ASP.NET Core API projects with nested definitions.

ASP.NET-Specific Remediation

Remediating blind SSRF in ASP.NET requires strict validation of any user-supplied URL before it is used with HttpClient. The primary defenses are:

  1. Allowlist permitted schemes and domains: Only allow http and https, and restrict to known external domains.
  2. Block private IP ranges and cloud metadata endpoints: Prevent requests to 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, and 169.254.169.254.
  3. Use a dedicated HttpMessageHandler to enforce validation at the HTTP client level.

Here is a robust validation helper for ASP.NET Core:

public static class SsrfValidator
{
    private static readonly HashSet AllowedSchemes = new() { "http", "https" };
    private static readonly byte[][] PrivateRanges = 
    {
        new byte[] { 10, 0, 0, 0 }, new byte[] { 10, 255, 255, 255 }, // 10.0.0.0/8
        new byte[] { 172, 16, 0, 0 }, new byte[] { 172, 31, 255, 255 }, // 172.16.0.0/12
        new byte[] { 192, 168, 0, 0 }, new byte[] { 192, 168, 255, 255 }, // 192.168.0.0/16
        new byte[] { 127, 0, 0, 0 }, new byte[] { 127, 255, 255, 255 } // 127.0.0.0/8
    };

    public static bool IsSafeUrl(string url, out string error)
    {
        error = string.Empty;
        if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
        {
            error = "Invalid URL format";
            return false;
        }
        if (!AllowedSchemes.Contains(uri.Scheme.ToLowerInvariant()))
        {
            error = "Only HTTP/HTTPS schemes allowed";
            return false;
        }
        // Block cloud metadata endpoints explicitly
        if (uri.Host.Equals("169.254.169.254", StringComparison.OrdinalIgnoreCase))
        {
            error = "Access to metadata endpoint blocked";
            return false;
        }
        try
        {
            var addresses = Dns.GetHostAddresses(uri.Host);
            foreach (var ip in addresses)
            {
                if (ip.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
                    continue;
                var bytes = ip.GetAddressBytes();
                if (IsPrivateIp(bytes))
                {
                    error = "Private IP ranges are not allowed";
                    return false;
                }
            }
        }
        catch
        {
            error = "DNS resolution failed";
            return false; // Fail-safe on DNS errors
        }
        return true;
    }

    private static bool IsPrivateIp(byte[] bytes)
    {
        // Simple range check for IPv4
        if (bytes[0] == 10) return true;
        if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31) return true;
        if (bytes[0] == 192 && bytes[1] == 168) return true;
        if (bytes[0] == 127) return true;
        return false;
    }
}

Use this validator in your controller before making any HttpClient call:

[HttpPost("api/webhook")]
public async Task RegisterWebhook([FromBody] WebhookRequest request)
{
    if (!SsrfValidator.IsSafeUrl(request.Url, out var error))
    {
        return BadRequest(new { error = $"Invalid URL: {error}" });
    }
    var client = _httpClientFactory.CreateClient();
    await client.PostAsync(request.Url, new StringContent("test"));
    return Ok(new { status = "registered" });
}

For higher assurance, create a custom DelegatingHandler that validates every outgoing request URI:

public class SsrfProtectionHandler : DelegatingHandler
{
    protected override async Task SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (!SsrfValidator.IsSafeUrl(request.RequestUri.ToString(), out var error))
        {
            throw new InvalidOperationException($"Blocked SSRF attempt: {error}");
        }
        return await base.SendAsync(request, cancellationToken);
    }
}

// In Program.cs:
services.AddHttpClient("SecureClient")
    .AddHttpMessageHandler();

This ensures all outgoing requests from that client are validated, even if called from deeper layers. Note that DNS rebinding attacks can bypass host-based checks; consider using a library like Microsoft.AspNetCore.Http.Features to further restrict connections, but the core principle is to never trust user-supplied URLs.

Frequently Asked Questions

What is blind SSRF and how does it differ from regular SSRF?
Blind SSRF occurs when an attacker can trigger a server to make an HTTP request to an arbitrary URL but cannot see the response content. Attackers rely on side channels like timing differences, error messages, or out-of-band data exfiltration (e.g., DNS or HTTP callbacks) to infer information. Regular SSRF typically exposes the response directly in the HTTP reply, making exploitation easier. Blind SSRF is harder to detect but can still disclose sensitive data or probe internal networks.
Why are ASP.NET applications particularly vulnerable to SSRF?
ASP.NET applications frequently use HttpClient to integrate with external services, and it's common to accept URLs from user input (e.g., webhook endpoints, proxy features, OAuth callbacks). Developers may assume that because the response isn't returned to the user, the risk is low. However, blind SSRF can still access cloud metadata endpoints (like AWS's 169.254.169.254) or scan internal infrastructure via timing. The widespread use of IHttpClientFactory doesn't inherently prevent SSRF—validation must be explicit.