Improved malware scan. Added server and user purge

This commit is contained in:
Marcel Baumgartner
2023-08-28 05:08:52 +02:00
parent 95ba81eab4
commit 6972c2bb32
11 changed files with 176 additions and 94 deletions

View File

@@ -9,7 +9,7 @@ public class FakePlayerPluginScan : MalwareScan
public override string Name => "Fake player plugin scan";
public override string Description => "This scan is a simple fake player plugin scan provided by moonlight";
public override async Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider)
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
{
var serverService = serviceProvider.GetRequiredService<ServerService>();
var access = await serverService.CreateFileAccess(server, null!);
@@ -24,19 +24,16 @@ public class FakePlayerPluginScan : MalwareScan
{
if (fileElement.Name.ToLower().Contains("fakeplayer"))
{
return new[]
return new()
{
new MalwareScanResult
{
Title = "Fake player plugin",
Description = $"Suspicious plugin file: {fileElement.Name}",
Author = "Marcel Baumgartner"
}
Title = "Fake player plugin",
Description = $"Suspicious plugin file: {fileElement.Name}",
Author = "Marcel Baumgartner"
};
}
}
}
return Array.Empty<MalwareScanResult>();
return null;
}
}

View File

@@ -9,7 +9,7 @@ public class MinerJarScan : MalwareScan
public override string Name => "Miner jar scan";
public override string Description => "This scan is a simple miner jar scan provided by moonlight";
public override async Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider)
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
{
var serverService = serviceProvider.GetRequiredService<ServerService>();
var access = await serverService.CreateFileAccess(server, null!);
@@ -23,18 +23,15 @@ public class MinerJarScan : MalwareScan
if (fileElements.Any(x => x.Name == "jdk" && !x.IsFile))
{
return new[]
return new()
{
new MalwareScanResult
{
Title = "Found Miner",
Description = "Detected suspicious library directory which may contain a script for miners",
Author = "Marcel Baumgartner"
}
Title = "Found Miner",
Description = "Detected suspicious library directory which may contain a script for miners",
Author = "Marcel Baumgartner"
};
}
}
return Array.Empty<MalwareScanResult>();
return null;
}
}

View File

@@ -0,0 +1,35 @@
using Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
using Moonlight.App.Services;
namespace Moonlight.App.MalwareScans;
public class MinerScan : MalwareScan
{
public override string Name => "Miner (NEZHA)";
public override string Description => "Probably a miner";
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
{
var serverService = serviceProvider.GetRequiredService<ServerService>();
var access = await serverService.CreateFileAccess(server, null!);
var files = await access.Ls();
foreach (var file in files.Where(x => x.IsFile && x.Name.EndsWith(".sh")))
{
var content = await access.Read(file);
if (content.ToLower().Contains("nezha"))
{
return new()
{
Title = "Miner",
Description = "Miner start script (NEZHA)",
Author = "Marcel Baumgartner"
};
}
}
return null;
}
}

View File

@@ -9,7 +9,7 @@ public class SelfBotCodeScan : MalwareScan
public override string Name => "Selfbot code scan";
public override string Description => "This scan is a simple selfbot code scan provided by moonlight";
public override async Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider)
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
{
var serverService = serviceProvider.GetRequiredService<ServerService>();
var access = await serverService.CreateFileAccess(server, null!);
@@ -21,18 +21,15 @@ public class SelfBotCodeScan : MalwareScan
if (rawScript.Contains("https://discord.com/api") && !rawScript.Contains("https://discord.com/api/oauth2") && !rawScript.Contains("https://discord.com/api/webhook") || rawScript.Contains("https://rblxwild.com")) //TODO: Export to plugins, add regex for checking
{
return new[]
return new MalwareScanResult
{
new MalwareScanResult
{
Title = "Potential selfbot",
Description = $"Suspicious script file: {script.Name}",
Author = "Marcel Baumgartner"
}
Title = "Potential selfbot",
Description = $"Suspicious script file: {script.Name}",
Author = "Marcel Baumgartner"
};
}
}
return Array.Empty<MalwareScanResult>();
return null;
}
}

View File

@@ -9,7 +9,7 @@ public class SelfBotScan : MalwareScan
public override string Name => "Selfbot Scan";
public override string Description => "This scan is a simple selfbot scan provided by moonlight";
public override async Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider)
public override async Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider)
{
var serverService = serviceProvider.GetRequiredService<ServerService>();
var access = await serverService.CreateFileAccess(server, null!);
@@ -17,17 +17,14 @@ public class SelfBotScan : MalwareScan
if (fileElements.Any(x => x.Name == "tokens.txt"))
{
return new[]
return new MalwareScanResult
{
new MalwareScanResult
{
Title = "Found SelfBot",
Description = "Detected suspicious 'tokens.txt' file which may contain tokens for a selfbot",
Author = "Marcel Baumgartner"
}
Title = "Found SelfBot",
Description = "Detected suspicious 'tokens.txt' file which may contain tokens for a selfbot",
Author = "Marcel Baumgartner"
};
}
return Array.Empty<MalwareScanResult>();
return null;
}
}

View File

@@ -6,5 +6,5 @@ public abstract class MalwareScan
{
public abstract string Name { get; }
public abstract string Description { get; }
public abstract Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider);
public abstract Task<MalwareScanResult?> Scan(Server server, IServiceProvider serviceProvider);
}

View File

@@ -15,7 +15,7 @@ public class MalwareBackgroundScanService
public bool IsRunning => !ScanTask?.IsCompleted ?? false;
public bool ScanAllServers { get; set; }
public readonly Dictionary<Server, MalwareScanResult[]> ScanResults;
public readonly Dictionary<Server, MalwareScanResult> ScanResults;
public string Status { get; private set; } = "N/A";
private Task? ScanTask;
@@ -70,16 +70,16 @@ public class MalwareBackgroundScanService
Status = $"[{i} / {servers.Length}] Scanning server {server.Name}";
await Event.Emit("malwareScan.status", IsRunning);
var results = await malwareScanService.Perform(server);
var result = await malwareScanService.Perform(server);
if (results.Any())
if (result != null)
{
lock (ScanResults)
{
ScanResults.Add(server, results);
ScanResults.Add(server, result);
}
await Event.Emit("malwareScan.result");
await Event.Emit("malwareScan.result", server);
}
i++;

View File

@@ -5,7 +5,7 @@ using Moonlight.App.Services.Plugins;
namespace Moonlight.App.Services;
public class MalwareScanService //TODO: Make this moddable using plugins
public class MalwareScanService
{
private readonly PluginService PluginService;
private readonly IServiceScopeFactory ServiceScopeFactory;
@@ -16,34 +16,29 @@ public class MalwareScanService //TODO: Make this moddable using plugins
ServiceScopeFactory = serviceScopeFactory;
}
public async Task<MalwareScanResult[]> Perform(Server server)
public async Task<MalwareScanResult?> Perform(Server server)
{
var defaultScans = new List<MalwareScan>
{
new SelfBotScan(),
new MinerJarScan(),
new SelfBotCodeScan(),
new FakePlayerPluginScan()
new FakePlayerPluginScan(),
new MinerScan()
};
var scans = await PluginService.BuildMalwareScans(defaultScans.ToArray());
var results = new List<MalwareScanResult>();
using var scope = ServiceScopeFactory.CreateScope();
foreach (var scan in scans)
{
var result = await scan.Scan(server, scope.ServiceProvider);
if (result.Any())
{
foreach (var scanResult in result)
{
results.Add(scanResult);
}
}
if (result != null)
return result;
}
return results.ToArray();
return null;
}
}

View File

@@ -113,19 +113,17 @@ public class ServerService
if (ConfigService.Get().Moonlight.Security.MalwareCheckOnStart && signal == PowerSignal.Start ||
signal == PowerSignal.Restart)
{
var results = await new MalwareScanService(
var result = await new MalwareScanService(
PluginService,
ServiceScopeFactory
).Perform(server);
if (results.Any())
if (result != null)
{
var resultText = string.Join(" ", results.Select(x => x.Title));
Logger.Warn($"Found malware on server {server.Uuid}. Results: " + resultText);
Logger.Warn($"Found malware on server {server.Uuid}. Result: " + result.Title);
throw new DisplayException(
$"Unable to start server. Found following malware on this server: {resultText}. Please contact the support if you think this detection is a false positive",
$"Unable to start server. Found following malware on this server: {result.Title}. Please contact the support if you think this detection is a false positive",
true);
}
}