Symlink Attack in Aspnet
How Symlink Attack Manifests in Aspnet
Symlink attacks in Aspnet applications typically exploit the framework's file handling mechanisms to bypass security controls and access unauthorized resources. In Aspnet, these attacks often target the PhysicalFileProvider, PhysicalDirectoryProvider, and file upload/download functionality.
The most common Aspnet-specific symlink attack pattern involves path traversal combined with symbolic links to escape the intended web root directory. Consider an Aspnet Core application using PhysicalFileProvider for serving static files:
public class FileService
{
private readonly IFileProvider _fileProvider;
public FileService()
{
var webRoot = Directory.GetCurrentDirectory();
_fileProvider = new PhysicalFileProvider(webRoot);
}
public async Task<string> ReadFileContent(string relativePath)
{
var fileInfo = _fileProvider.GetFileInfo(relativePath);
if (fileInfo == null || !fileInfo.Exists)
throw new FileNotFoundException();
return await File.ReadAllTextAsync(fileInfo.PhysicalPath);
}
}
An attacker can create a symbolic link within the web root that points to sensitive files outside the intended directory. For example, creating ../../../../etc/passwd as a symlink would allow reading system files when the application validates only the relative path.
Another Aspnet-specific vulnerability occurs in file upload handlers. When users upload files to a directory that's later served statically, an attacker might upload a symlink pointing to system files:
[HttpPost("upload")]
public async Task<IActionResult> UploadFile(IFormFile file)
{
var uploadsPath = Path.Combine(_env.WebRootPath, "uploads");
var filePath = Path.Combine(uploadsPath, file.FileName);
using (var stream = System.IO.File.Create(filePath))
{
await file.CopyToAsync(stream);
}
return Ok();
}
If the uploads directory is served via UseStaticFiles, an attacker could upload a symlink to /etc/passwd and then access it through the web application.
Configuration file injection is another Asplink attack vector specific to Aspnet. When Aspnet applications use ConfigurationBuilder to load settings from file paths, symlinks can redirect the application to load malicious configurations:
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
If appsettings.json is a symlink to a different file, the application might load unexpected configuration values, potentially exposing database credentials or enabling debug modes.
Aspnet-Specific Detection
Detecting symlink attacks in Aspnet applications requires both static analysis and runtime scanning. middleBrick's Aspnet-specific scanning identifies these vulnerabilities through several techniques.
For runtime detection, middleBrick tests file provider endpoints by attempting to access known sensitive files through relative paths. The scanner creates temporary directories and symbolic links to verify if the application properly validates file paths:
# middleBrick scan https://yourapi.com --aspnet-specific
The scanner specifically targets Aspnet's PhysicalFileProvider usage patterns and checks for:
- Path traversal attempts through
..sequences - Symlink resolution bypass in file operations
- Unsafe file upload handling in Aspnet MVC controllers
- Configuration file path manipulation
- Static file serving with insufficient directory restrictions
middleBrick also analyzes OpenAPI specifications for Aspnet APIs to identify endpoints that handle file operations without proper validation. The scanner looks for:
{
"paths": {
"/api/files/{path}": {
"get": {
"operationId": "GetFile",
"parameters": [
{
"name": "path",
"in": "path",
"schema": { "type": "string" }
}
]
}
}
}
}
Endpoints with path parameters that directly map to file system operations are flagged as high-risk for symlink attacks.
For development teams, the middleBrick CLI provides Aspnet-specific checks that can be integrated into CI/CD pipelines:
# GitHub Actions workflow
- name: Scan API Security
run: middlebrick scan https://staging-api.example.com --aspnet --fail-on-severity=high
The scanner reports findings with Aspnet-specific remediation guidance, including code snippets for fixing the identified vulnerabilities.
Aspnet-Specific Remediation
Remediating symlink attacks in Aspnet applications requires implementing proper file path validation and using Aspnet's built-in security features. Here are specific fixes for common Aspnet symlink vulnerabilities.
For PhysicalFileProvider usage, implement strict path validation using Path.GetFullPath and verify the resolved path stays within the intended directory:
public class SecureFileService
{
private readonly IFileProvider _fileProvider;
private readonly string _rootPath;
public SecureFileService(IWebHostEnvironment env)
{
_rootPath = Path.GetFullPath(env.WebRootPath);
_fileProvider = new PhysicalFileProvider(_rootPath);
}
public async Task<string> ReadFileContent(string relativePath)
{
var fullPath = Path.GetFullPath(Path.Combine(_rootPath, relativePath));
if (!fullPath.StartsWith(_rootPath, StringComparison.OrdinalIgnoreCase))
throw new UnauthorizedAccessException("Path traversal detected");
var fileInfo = _fileProvider.GetFileInfo(fullPath.Substring(_rootPath.Length).TrimStart('/'));
if (fileInfo == null || !fileInfo.Exists)
throw new FileNotFoundException();
return await File.ReadAllTextAsync(fileInfo.PhysicalPath);
}
}
For file uploads, validate that uploaded files are not symlinks and use Aspnet's Path.GetRandomFileName for secure storage:
[HttpPost("upload")]
public async Task<IActionResult> UploadFile(IFormFile file)
{
var uploadsPath = Path.Combine(_env.WebRootPath, "uploads");
Directory.CreateDirectory(uploadsPath);
var safeFileName = Path.GetRandomFileName() + Path.GetExtension(file.FileName);
var filePath = Path.Combine(uploadsPath, safeFileName);
using (var stream = System.IO.File.Create(filePath))
{
await file.CopyToAsync(stream);
}
// Verify the file is not a symlink
if (IsSymlink(filePath))
throw new InvalidOperationException("Symlink upload detected");
return Ok(new { Url = $"/uploads/{safeFileName}" });
}
private bool IsSymlink(string path)
{
if (File.Exists(path))
return File.GetAttributes(path).HasFlag(FileAttributes.ReparsePoint);
return false;
}
For configuration file handling, use Aspnet's WebHost.CreateDefaultBuilder which includes security checks, or implement custom validation:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseContentRoot(ValidateContentRoot())
.ConfigureAppConfiguration((context, config) =>
{
config.SetBasePath(ValidateContentRoot());
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false);
})
.UseStartup<Startup>();
private static string ValidateContentRoot()
{
var root = Directory.GetCurrentDirectory();
if (IsSymlink(root))
throw new InvalidOperationException("Application root cannot be a symlink");
return root;
}
For static file serving, configure Aspnet to restrict the served directory and disable directory browsing:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(env.WebRootPath),
ServeUnknownFileTypes = false,
DefaultContentType = "application/octet-stream"
});
// Disable directory browsing
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(env.WebRootPath),
EnableDefaultFiles = false
});
}
Frequently Asked Questions
How does middleBrick detect symlink attacks in Aspnet applications?
PhysicalFileProvider usage, and analyzes OpenAPI specs for high-risk file operation endpoints. It runs 12 security checks in parallel and provides Aspnet-specific findings with severity levels and remediation guidance.