Log Injection in Aspnet
How Log Injection Manifests in Aspnet
Log injection in Aspnet applications occurs when untrusted input is written directly to log files without proper sanitization, creating opportunities for attackers to manipulate log contents, inject malicious content, or trigger log forging attacks. Aspnet's extensive logging infrastructure, including ILogger, Serilog, NLog, and built-in Aspnet Core logging, provides multiple attack surfaces.
The most common Aspnet-specific manifestation involves request parameters being logged without validation. Consider an Aspnet Core controller action:
[HttpPost("/api/submit")]
public IActionResult Submit([FromBody] dynamic data) {
_logger.LogInformation($"Received data: {data}");
return Ok();
}An attacker can send a JSON payload containing newline characters and crafted log messages:
{ "message": "Normal data\nERROR: Critical system failure - false alarm\nINFO: User admin logged in from 192.168.1.1" }This injects fake log entries that appear legitimate, potentially triggering false security alerts or masking real attacks.
AspNet Core's structured logging can be exploited through property injection. When using ILogger with dynamic objects:
public async Task ProcessPayment([FromBody] PaymentRequest request) {
_logger.LogInformation("Processing payment", request);
// Payment processing logic
}If PaymentRequest contains properties like "Level" or "Message", structured logging might interpret these as log level indicators rather than data properties, altering how the log entry is recorded.
Middleware logging presents another Aspnet-specific vector. Custom middleware that logs request details without sanitization:
public class RequestLoggingMiddleware {
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public async Task InvokeAsync(HttpContext context) {
_logger.LogInformation($"Request: {context.Request.Path} {context.Request.QueryString}");
await _next(context);
}
}Attackers can craft query strings with embedded newlines or log control characters that break log file structure.
AspNet Identity logging can be compromised when user-supplied data appears in authentication logs. Consider:
public async Task Login(LoginModel model) {
if (await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: true)) {
_logger.LogInformation($"User {model.Email} logged in successfully");
return RedirectToAction("Index", "Home");
}
_logger.LogWarning($"Failed login attempt for {model.Email}");
return View();
} An attacker can use an email like "admin@example.com\nINFO: System rebooted successfully" to inject arbitrary log content.
AspNet-Specific Detection
Detecting log injection in Aspnet applications requires examining both code patterns and runtime behavior. Static code analysis should look for specific Aspnet patterns where user input flows directly to logging calls.
Code review should identify these Aspnet-specific patterns:
LogInformation($"User {username} performed action {action}")
LogWarning($"Error processing {request.Data}")
LogDebug($"Request from {context.Connection.RemoteIpAddress}")Search for string interpolation with variables that originate from HTTP requests, query parameters, or request bodies. Pay special attention to Aspnet Core's minimal APIs:
app.MapPost("/submit", async (HttpContext context) => {
var data = await new StreamReader(context.Request.Body).ReadToEndAsync();
_logger.LogInformation($"Received: {data}");
return Results.Ok();
});middleBrick's Aspnet-specific scanning identifies these patterns automatically. The scanner analyzes your running Aspnet application's endpoints, examining how request data flows through logging calls without requiring source code access.
Runtime detection involves monitoring log files for anomalies. Look for:
- Unexpected log level changes within single entries
- Log entries with inconsistent timestamps or sources
- Repeated patterns suggesting automated injection attempts
- Log entries containing suspicious keywords like "ERROR:", "CRITICAL:", or "WARNING:" that don't match actual application state
middleBrick actively tests for log injection by sending payloads containing newline characters, log level keywords, and structured data that could manipulate Aspnet's logging format. The scanner attempts to inject content into:
- ILogger method parameters
- Middleware request logging
- AspNet Identity authentication logs
- Structured logging properties
Configuration review is critical for Aspnet applications. Examine appsettings.json for logging configurations that might be vulnerable:
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}Ensure logging providers don't have configurations that could be manipulated through injection attacks.
AspNet-Specific Remediation
Remediating log injection in Aspnet applications requires a defense-in-depth approach using Aspnet's built-in features and best practices. The primary defense is input sanitization before logging.
AspNet Core provides several mechanisms for safe logging. Use structured logging instead of string interpolation:
// Vulnerable
_logger.LogInformation($"User {username} logged in from {ip}");
// Secure
_logger.LogInformation("User {Username} logged in from {IP}", username, ip);Structured logging ensures user input is treated as data, not as part of the log format. This prevents log level manipulation and format breaking.
For Aspnet Core applications, implement input sanitization middleware:
public class LogSanitizationMiddleware {
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public async Task InvokeAsync(HttpContext context) {
var originalBody = context.Request.Body;
using (var ms = new MemoryStream()) {
context.Request.Body = ms;
await _next(context);
ms.Position = 0;
var bodyString = await new StreamReader(ms).ReadToEndAsync();
var sanitized = SanitizeForLogging(bodyString);
_logger.LogDebug("Request: {Path} {Query} {Body}",
context.Request.Path, context.Request.QueryString, sanitized);
ms.Position = 0;
await originalBody.CopyToAsync(ms);
}
}
private string SanitizeForLogging(string input) {
return input?.Replace("\n", " ").Replace("\r", " ")
.Replace("ERROR:", "[ERROR]")
.Replace("WARNING:", "[WARNING]")
.Replace("INFO:", "[INFO]");
}
}Register this middleware early in the pipeline to sanitize all request data before logging.
AspNet Identity logging requires special attention. Create custom authorization handlers that sanitize log output:
public class CustomSignInHandler : SignInHandler {
private readonly ILogger _logger;
public async Task<SignInResult> SafeSignInAsync(string email, string password, bool rememberMe) {
try {
var result = await base.SignInAsync(email, password, rememberMe);
var safeEmail = SanitizeEmail(email);
_logger.LogInformation("Login attempt for {Email} - {Result}", safeEmail, result.Succeeded);
return result;
} catch (Exception ex) {
_logger.LogError(ex, "Login error for {Email}", SanitizeEmail(email));
return SignInResult.Failed;
}
}
private string SanitizeEmail(string email) {
return email?.Replace("\n", " ").Replace("\r", " ");
}
}Implement custom logging filters for Aspnet Core that automatically sanitize sensitive data:
public class SanitizingLogFilter : ILogValuesFilter {
public LogValuesFilterContract Filter(string name, object value) {
if (value is string stringValue) {
return new LogValuesFilterContract {
Value = SanitizeForLogging(stringValue),
Matched = true
};
}
return new LogValuesFilterContract { Value = value, Matched = false };
}
}Configure this filter in your logging configuration to automatically sanitize all logged strings.