/// <summary> /// On linux we check the central trusted root store (a folder), which has symlinks to actual cert locations scattered across the db /// We list all the certificates and then create a new X509Certificate2 object for each by filename. /// </summary> public void ExecuteLinux() { try { if (ExternalCommandRunner.RunExternalCommand("ls", "/etc/ssl/certs -A", out string result, out string _) == 0) { foreach (var _line in result.Split('\n')) { Log.Debug("{0}", _line); try { using X509Certificate2 certificate = new X509Certificate2("/etc/ssl/certs/" + _line); var obj = new CertificateObject( StoreLocation: StoreLocation.LocalMachine.ToString(), StoreName: StoreName.Root.ToString(), Certificate: new SerializableCertificate(certificate)) { Pkcs7 = Convert.ToBase64String(certificate.Export(X509ContentType.Cert)) }; Results.Enqueue(obj); } catch (Exception e) { Log.Debug("{0} {1} Issue creating certificate based on /etc/ssl/certs/{2}", e.GetType().ToString(), e.Message, _line); Log.Debug("{0}", e.StackTrace); } } } } catch (Exception e) { Log.Error(e, "Failed to dump certificates from 'ls /etc/ssl/certs -A'."); } }
/// <summary> /// On linux we check the central trusted root store (a folder), which has symlinks to actual cert locations scattered across the db /// We list all the certificates and then create a new X509Certificate2 object for each by filename. /// </summary> public void ExecuteLinux() { try { var result = ExternalCommandRunner.RunExternalCommand("ls", new string[] { "/etc/ssl/certs", "-A" }); foreach (var _line in result.Split('\n')) { Log.Debug("{0}", _line); try { using X509Certificate2 certificate = new X509Certificate2("/etc/ssl/certs/" + _line); var obj = new CertificateObject( StoreLocation: StoreLocation.LocalMachine.ToString(), StoreName: StoreName.Root.ToString(), Certificate: new SerializableCertificate(certificate), Pkcs7: certificate.Export(X509ContentType.Cert).ToString()); DatabaseManager.Write(obj, RunId); } catch (Exception e) { Log.Debug("{0} {1} Issue creating certificate based on /etc/ssl/certs/{2}", e.GetType().ToString(), e.Message, _line); Log.Debug("{0}", e.StackTrace); } } } catch (Exception e) { Log.Error(e, "Failed to dump certificates from 'ls /etc/ssl/certs -A'."); } }
public void TestServiceCollectorWindows() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var FirstRunId = "TestServiceCollector-1"; var SecondRunId = "TestServiceCollector-2"; var fwc = new ServiceCollector(FirstRunId); fwc.Execute(); // Create a service - This won't throw an exception, but it won't work if you are not an Admin. var serviceName = "AsaDemoService"; var exeName = "AsaDemoService.exe"; var cmd = string.Format("create {0} binPath=\"{1}\"", serviceName, exeName); ExternalCommandRunner.RunExternalCommand("sc.exe", cmd); fwc = new ServiceCollector(SecondRunId); fwc.Execute(); // Clean up cmd = string.Format("delete {0}", serviceName); ExternalCommandRunner.RunExternalCommand("sc.exe", cmd); BaseCompare bc = new BaseCompare(); if (!bc.TryCompare(FirstRunId, SecondRunId)) { Assert.Fail(); } var results = bc.Results; Assert.IsTrue(results.ContainsKey("SERVICE_CREATED")); Assert.IsTrue(results["SERVICE_CREATED"].Where(x => x.Identity.Contains("AsaDemoService")).Count() > 0); } }
public void TestUserCollectorWindows() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Assert.IsTrue(AsaHelpers.IsAdmin()); var FirstRunId = "TestUserCollector-1"; var SecondRunId = "TestUserCollector-2"; var fwc = new UserAccountCollector(FirstRunId); fwc.Execute(); var user = System.Guid.NewGuid().ToString().Substring(0, 10); var password = System.Guid.NewGuid().ToString().Substring(0, 10); var cmd = string.Format("user /add {0} {1}", user, password); ExternalCommandRunner.RunExternalCommand("net", cmd); var serviceName = System.Guid.NewGuid(); fwc = new UserAccountCollector(SecondRunId); fwc.Execute(); cmd = string.Format("user /delete {0}", user); ExternalCommandRunner.RunExternalCommand("net", cmd); BaseCompare bc = new BaseCompare(); if (!bc.TryCompare(FirstRunId, SecondRunId)) { Assert.Fail(); } var results = bc.Results; Assert.IsTrue(results.ContainsKey("USER_CREATED")); Assert.IsTrue(results["USER_CREATED"].Where(x => x.Identity.Contains(user)).Count() > 0); } }
public void TestFirewallCollectorLinux() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { Setup(); var FirstRunId = "TestFirewallCollector-1"; var SecondRunId = "TestFirewallCollector-2"; var fwc = new FirewallCollector(FirstRunId); fwc.Execute(); var result = ExternalCommandRunner.RunExternalCommand("iptables", "-A INPUT -p tcp --dport 19999 -j DROP"); fwc = new FirewallCollector(SecondRunId); fwc.Execute(); result = ExternalCommandRunner.RunExternalCommand("iptables", "-D INPUT -p tcp --dport 19999 -j DROP"); BaseCompare bc = new BaseCompare(); if (!bc.TryCompare(FirstRunId, SecondRunId)) { Assert.Fail(); } var results = bc.Results; Assert.IsTrue(results.ContainsKey("FIREWALL_CREATED")); Assert.IsTrue(results["FIREWALL_CREATED"].Where(x => x.Identity.Contains("9999")).Count() > 0); TearDown(); } }
/// <summary> /// Executes the OpenPortCollector on OS X. Calls out to the `lsof` /// command and parses the output, sending the output to the database. /// </summary> private void ExecuteOsX() { try { string result = ExternalCommandRunner.RunExternalCommand("lsof", "-Pn -i4 -i6"); foreach (var _line in result.Split('\n')) { var line = _line.ToUpperInvariant(); if (!line.Contains("LISTEN")) { continue; // Skip any lines which aren't open listeners } var parts = Regex.Split(line, @"\s+"); if (parts.Length <= 9) { continue; // Not long enough } var addressMatches = Regex.Match(parts[8], @"^(.*):(\d+)$"); if (addressMatches.Success) { var address = addressMatches.Groups[1].ToString(); var port = addressMatches.Groups[2].ToString(); if (int.TryParse(port, out int portInt)) { var transport = parts[7].ToUpperInvariant().Equals("TCP") ? TRANSPORT.TCP : parts[7].ToUpperInvariant().Equals("TCP") ? TRANSPORT.UDP : TRANSPORT.UNKNOWN; var family = ADDRESS_FAMILY.Unknown; switch (parts[4]) { case "IPv4": family = ADDRESS_FAMILY.InterNetwork; break; case "IPv6": family = ADDRESS_FAMILY.InterNetworkV6; break; default: family = ADDRESS_FAMILY.Unknown; break; } var obj = new OpenPortObject(portInt, transport, family) { Address = address, ProcessName = parts[0] }; Results.Push(obj); } } } } catch (Exception e) { Log.Error(e, Strings.Get("Err_Lsof")); } }
public void TestUserCollectorWindows() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Assert.IsTrue(AsaHelpers.IsAdmin()); var user = System.Guid.NewGuid().ToString().Substring(0, 10); var password = "******" + CryptoHelpers.GetRandomString(13); var cmd = string.Format("user /add {0} {1}", user, password); ExternalCommandRunner.RunExternalCommand("net", cmd); var uac = new UserAccountCollector(); uac.TryExecute(); Assert.IsTrue(uac.Results.Any(x => x is UserAccountObject y && y.Name.Equals(user))); ConcurrentStack <CollectObject> results = new ConcurrentStack <CollectObject>(); uac = new UserAccountCollector(changeHandler: x => results.Push(x)); uac.TryExecute(); Assert.IsTrue(results.Any(x => x is UserAccountObject y && y.Name.Equals(user))); cmd = string.Format("user /delete {0}", user); ExternalCommandRunner.RunExternalCommand("net", cmd); } }
public void TestServiceCollectorWindows() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // Create a service - This won't throw an exception, but it won't work if you are not an Admin. var serviceName = "AsaDemoService"; var exeName = "AsaDemoService.exe"; var cmd = string.Format("create {0} binPath=\"{1}\"", serviceName, exeName); ExternalCommandRunner.RunExternalCommand("sc.exe", cmd); var sc = new ServiceCollector(new CollectCommandOptions()); sc.TryExecute(); Assert.IsTrue(sc.Results.Any(x => x is ServiceObject RO && RO.Name.Equals(serviceName))); ConcurrentStack <CollectObject> results = new ConcurrentStack <CollectObject>(); sc = new ServiceCollector(changeHandler: x => results.Push(x)); sc.TryExecute(); Assert.IsTrue(results.Any(x => x is ServiceObject RO && RO.Name.Equals(serviceName))); // Clean up cmd = string.Format("delete {0}", serviceName); ExternalCommandRunner.RunExternalCommand("sc.exe", cmd); } }
public void TestFirewallCollectorOSX() { if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { Setup(); var FirstRunId = "TestFirewallCollector-1"; var SecondRunId = "TestFirewallCollector-2"; var fwc = new FirewallCollector(FirstRunId); fwc.Execute(); _ = ExternalCommandRunner.RunExternalCommand("/usr/libexec/ApplicationFirewall/socketfilterfw", "--add", "/bin/bash"); fwc = new FirewallCollector(SecondRunId); fwc.Execute(); _ = ExternalCommandRunner.RunExternalCommand("/usr/libexec/ApplicationFirewall/socketfilterfw", "--remove", "/bin/bash"); BaseCompare bc = new BaseCompare(); if (!bc.TryCompare(FirstRunId, SecondRunId)) { Assert.Fail(); } var results = bc.Results; Assert.IsTrue(results.ContainsKey("FIREWALL_CREATED")); Assert.IsTrue(results["FIREWALL_CREATED"].Where(x => x.Identity.Contains("/bin/bash")).Count() > 0); TearDown(); } }
/// <summary> /// Collect event logs on macOS using the 'log' utility /// </summary> public void ExecuteMacOs() { _ = DatabaseManager.Transaction; var outputPath = Path.Combine(Directory.GetCurrentDirectory(), "events"); var file = (GatherVerboseLogs)? ExternalCommandRunner.RunExternalCommand("log", "show") : ExternalCommandRunner.RunExternalCommand("log", "show --predicate \"messageType == 16 || messageType == 17\""); // New log entries start with a timestamp like so: // 2019-09-25 20:38:53.784594-0700 0xdbf47 Error 0x0 0 0 kernel: (Sandbox) Sandbox: mdworker(15726) deny(1) mach-lookup com.apple.security.syspolicy Regex LogHeader = new Regex("^([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]).*?0x[0-9a-f]*[\\s]*([A-Za-z]*)[\\s]*0x[0-9a-f][\\s]*[0-9]*[\\s]*([0-9]*)[\\s]*(.*?):(.*)"); List <string> data = null; string previousLine = null; foreach (var line in file.Split('\n')) { if (LogHeader.IsMatch(line)) { if (previousLine != null) { var obj = new EventLogObject() { Data = (data.Count > 0) ? data : null, Event = previousLine, Level = LogHeader.Matches(previousLine).Single().Groups[2].Value, Summary = string.Format("{0}:{1}", LogHeader.Matches(previousLine).Single().Groups[4].Captures[0].Value, LogHeader.Matches(previousLine).Single().Groups[5].Captures[0].Value), Timestamp = LogHeader.Matches(previousLine).Single().Groups[1].Captures[0].Value, Source = LogHeader.Matches(previousLine).Single().Groups[4].Captures[0].Value }; DatabaseManager.Write(obj, runId); } previousLine = line; data = new List <string>(); } else { if (previousLine != null) { data.Add(line); } } } if (previousLine != null) { var obj = new EventLogObject() { Data = (data.Count > 0) ? data:null, Event = previousLine, Level = LogHeader.Matches(previousLine).Single().Groups[2].Value, Summary = string.Format("{0}:{1}", LogHeader.Matches(previousLine).Single().Groups[4].Captures[0].Value, LogHeader.Matches(previousLine).Single().Groups[5].Captures[0].Value), Timestamp = LogHeader.Matches(previousLine).Single().Groups[1].Captures[0].Value, Source = LogHeader.Matches(previousLine).Single().Groups[4].Captures[0].Value }; DatabaseManager.Write(obj, runId); } DatabaseManager.Commit(); }
public override void Stop() { // restore the old auditpolicy ExternalCommandRunner.RunExternalCommand("auditpol", String.Format("/restore /file:{0}", tmpFileName)); //delete temporary file ExternalCommandRunner.RunExternalCommand("del", tmpFileName); log.EnableRaisingEvents = false; }
public void TestFirewallCollectorOSX() { if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { _ = ExternalCommandRunner.RunExternalCommand("/usr/libexec/ApplicationFirewall/socketfilterfw", "--add /bin/bash"); var fwc = new FirewallCollector(); fwc.TryExecute(); _ = ExternalCommandRunner.RunExternalCommand("/usr/libexec/ApplicationFirewall/socketfilterfw", "--remove /bin/bash"); Assert.IsTrue(fwc.Results.Any(x => x is FirewallObject FWO && FWO.ApplicationName == "/bin/bash")); } }
/// <summary> /// Executes the OpenPortCollector on OS X. Calls out to the `lsof` /// command and parses the output, sending the output to the database. /// The 'ss' command used on Linux isn't available on OS X. /// </summary> private void ExecuteOsX() { try { var result = ExternalCommandRunner.RunExternalCommand("sudo", "lsof -Pn -i4 -i6"); foreach (var _line in result.Split('\n')) { var line = _line.ToLower(); if (!line.Contains("listen")) { continue; // Skip any lines which aren't open listeners } var parts = Regex.Split(line, @"\s+"); if (parts.Length <= 9) { continue; // Not long enough } string address = null; string port = null; var addressMatches = Regex.Match(parts[8], @"^(.*):(\d+)$"); if (addressMatches.Success) { address = addressMatches.Groups[1].ToString(); port = addressMatches.Groups[2].ToString(); var obj = new OpenPortObject() { // Assuming family means IPv6 vs IPv4 family = parts[4], address = address, port = port, type = parts[7], processName = parts[0] }; try { DatabaseManager.Write(obj, this.runId); } catch (Exception e) { Logger.DebugException(e); } } } } catch (Exception e) { Log.Error(Strings.Get("Err_Lsof")); Logger.DebugException(e); } }
public override void StartRun() { // backup the current auditpolicy ExternalCommandRunner.RunExternalCommand("auditpol", $"/backup /file:{tmpFileName}"); // start listening to the event log log.EntryWritten += new EntryWrittenEventHandler(MyOnEntryWritten); log.EnableRaisingEvents = true; // Enable auditing for registry events GUID for Registry subcategory of audit policy https://msdn.microsoft.com/en-us/library/dd973928.aspx ExternalCommandRunner.RunExternalCommand("auditpol", "/set /subcategory:{0CCE921E-69AE-11D9-BED3-505054503030} /success:enable /failure:enable"); }
public void TestFirewallCollectorLinux() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { var result = ExternalCommandRunner.RunExternalCommand("iptables", "-A INPUT -p tcp --dport 19999 -j DROP"); var fwc = new FirewallCollector(); fwc.TryExecute(); Assert.IsTrue(fwc.Results.Any(x => x is FirewallObject FWO && FWO.LocalPorts.Contains("19999"))); result = ExternalCommandRunner.RunExternalCommand("iptables", "-D INPUT -p tcp --dport 19999 -j DROP"); } }
/// <summary> /// Executes the OpenPortCollector on Linux. Calls out to the `ss` /// command and parses the output, sending the output to the database. /// </summary> internal void ExecuteLinux(CancellationToken cancellationToken) { try { var result = ExternalCommandRunner.RunExternalCommand("ss", "-ln"); foreach (var _line in result.Split('\n')) { if (cancellationToken.IsCancellationRequested) { return; } var line = _line; line = line.ToUpperInvariant(); if (!line.Contains("LISTEN")) { continue; } var parts = Regex.Split(line, @"\s+"); if (parts.Length < 5) { continue; // Not long enough, must be an error } var addressMatches = Regex.Match(parts[4], @"^(.*):(\d+)$"); if (addressMatches.Success) { var address = addressMatches.Groups[1].ToString(); var port = addressMatches.Groups[2].ToString(); if (int.TryParse(port, out int portInt)) { var transport = parts[0].ToUpperInvariant().Equals("TCP") ? TRANSPORT.TCP : TRANSPORT.UDP; var family = address.Contains('.') ? ADDRESS_FAMILY.InterNetwork : address.Contains(':') ? ADDRESS_FAMILY.InterNetworkV6 : ADDRESS_FAMILY.Unknown; var obj = new OpenPortObject(portInt, transport, family) { Address = address }; HandleChange(obj); } } } } catch (Exception e) { Log.Warning(Strings.Get("Err_Iproute2")); Log.Debug(e, ""); } }
private long SizeOnDisk(FileInfo path) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { try { uint clusterSize = 0; var root = path.Directory.Root.FullName; if (!ClusterSizes.ContainsKey(root)) { ClusterSizes[root] = 0; NativeMethods.GetDiskFreeSpace(root, out uint lpSectorsPerCluster, out uint lpBytesPerSector, out _, out _); ClusterSizes[root] = lpSectorsPerCluster * lpBytesPerSector; } clusterSize = ClusterSizes[root]; if (clusterSize > 0) { uint lowSize = NativeMethods.GetCompressedFileSizeW(path.FullName, out uint highSize); long size = (long)highSize << 32 | lowSize; return(((size + clusterSize - 1) / clusterSize) * clusterSize); } } catch (Exception e) { Log.Debug("Failed to GetDiskFreeSpace for {0} ({1}:{2})", path.FullName, e.GetType(), e.Message); } return(-1); } else { if (sizesOnDisk.ContainsKey(path.FullName)) { return(sizesOnDisk[path.FullName]); } var exitCode = ExternalCommandRunner.RunExternalCommand("du", path.FullName, out string StdOut, out string StdErr); if (exitCode == 0 && long.TryParse(StdOut.Split('\t')[0], out long result)) { return(result); } else { return(-1); } } }
/// <summary> /// Executes the OpenPortCollector on OS X. Calls out to the `lsof` /// command and parses the output, sending the output to the database. /// The 'ss' command used on Linux isn't available on OS X. /// </summary> private void ExecuteOsX() { try { string result = ExternalCommandRunner.RunExternalCommand("lsof", "-Pn -i4 -i6"); foreach (var _line in result.Split('\n')) { var line = _line.ToUpperInvariant(); if (!line.Contains("LISTEN")) { continue; // Skip any lines which aren't open listeners } var parts = Regex.Split(line, @"\s+"); if (parts.Length <= 9) { continue; // Not long enough } var addressMatches = Regex.Match(parts[8], @"^(.*):(\d+)$"); if (addressMatches.Success) { var address = addressMatches.Groups[1].ToString(); var port = addressMatches.Groups[2].ToString(); if (int.TryParse(port, out int portInt)) { var obj = new OpenPortObject(portInt) { // Assuming family means IPv6 vs IPv4 Family = parts[4], Address = address, Type = parts[7], ProcessName = parts[0] }; DatabaseManager.Write(obj, RunId); } } } } catch (Exception e) { Log.Error(e, Strings.Get("Err_Lsof")); } }
/// <summary> /// Executes the OpenPortCollector on Linux. Calls out to the `ss` /// command and parses the output, sending the output to the database. /// </summary> private void ExecuteLinux() { try { var result = ExternalCommandRunner.RunExternalCommand("ss", "-ln"); foreach (var _line in result.Split('\n')) { var line = _line; line = line.ToUpperInvariant(); if (!line.Contains("LISTEN")) { continue; } var parts = Regex.Split(line, @"\s+"); if (parts.Length < 5) { continue; // Not long enough, must be an error } string address = null; string port = null; var addressMatches = Regex.Match(parts[4], @"^(.*):(\d+)$"); if (addressMatches.Success) { address = addressMatches.Groups[1].ToString(); port = addressMatches.Groups[2].ToString(); var obj = new OpenPortObject() { Family = parts[0],//@TODO: Determine IPV4 vs IPv6 via looking at the address Address = address, Port = port, Type = parts[0] }; DatabaseManager.Write(obj, this.RunId); } } } catch (Exception e) { Log.Warning(Strings.Get("Err_Iproute2")); Log.Debug(e, ""); } }
/// <summary> /// Uses launchctl /// </summary> internal void ExecuteMacOs(CancellationToken cancellationToken) { // Get the user processes run "launchtl dumpstate" for the super detailed view However, dumpstate // is difficult to parse Dictionary <string, ServiceObject> outDict = new Dictionary <string, ServiceObject>(); try { var result = ExternalCommandRunner.RunExternalCommand("launchctl", "list"); foreach (var _line in result.Split('\n')) { if (cancellationToken.IsCancellationRequested) { return; } // Lines are formatted like this: // PID Exit Name //1015 0 com.apple.appstoreagent var _fields = _line.Split('\t'); if (_fields.Length < 3 || _fields[0].Contains("PID")) { continue; } var obj = new ServiceObject(_fields[2]) { DisplayName = _fields[2], // If we have a current PID then it is running. State = (_fields[0].Equals("-")) ? "Stopped" : "Running" }; if (!outDict.ContainsKey(obj.Identity)) { HandleChange(obj); outDict.Add(obj.Identity, obj); } } } catch (ExternalException) { Log.Error("Error executing {0}", "launchctl list"); } }
/// <summary> /// On macos we use the keychain and export the certificates as .pem. However, on macos /// Certificate2 doesn't support loading from a pem. So first we need pkcs12s instead, we /// convert using openssl, which requires we set a password we import the pkcs12 with all /// our certs, delete the temp files and then iterate over it the certs /// </summary> internal void ExecuteMacOs(CancellationToken cancellationToken) { try { if (ExternalCommandRunner.RunExternalCommand("security", "find-certificate -ap /System/Library/Keychains/SystemRootCertificates.keychain", out string result, out string _) == 0) { string tmpPath = Path.Combine(Directory.GetCurrentDirectory(), "tmpcert.pem"); string pkPath = Path.Combine(Directory.GetCurrentDirectory(), "tmpcert.pk12"); File.WriteAllText(tmpPath, result); if (ExternalCommandRunner.RunExternalCommand("openssl", $"pkcs12 -export -nokeys -out {pkPath} -passout pass:pass -in {tmpPath}", out string _, out string _) == 0) { X509Certificate2Collection xcert = new X509Certificate2Collection(); xcert.Import(pkPath, "pass", X509KeyStorageFlags.DefaultKeySet); //lgtm [cs/hardcoded-credentials] File.Delete(tmpPath); File.Delete(pkPath); var X509Certificate2Enumerator = xcert.GetEnumerator(); while (X509Certificate2Enumerator.MoveNext()) { if (cancellationToken.IsCancellationRequested) { return; } var certificate = X509Certificate2Enumerator.Current; var obj = new CertificateObject( StoreLocation: StoreLocation.LocalMachine.ToString(), StoreName: StoreName.Root.ToString(), Certificate: new SerializableCertificate(certificate)); HandleChange(obj); } } else { Log.Debug("Failed to export certificate with OpenSSL."); //DevSkim: ignore DS440000 } }
public static void Main(string[] args) { Logger.Setup(true, true); try { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (!Elevation.IsAdministrator()) { Log.Fatal("Must run as administrator."); Log.CloseAndFlush(); Environment.Exit(-1); } var user = System.Guid.NewGuid().ToString().Substring(0, 10); var password = System.Guid.NewGuid().ToString().Substring(0, 10); var cmd = string.Format("user /add {0} {1}", user, password); ExternalCommandRunner.RunExternalCommand("net", cmd); Log.Information("Created user {0} with password {1}", user, password); var serviceName = System.Guid.NewGuid(); var exeName = "AsaDemoService.exe"; cmd = string.Format("create {0} binPath=\"{1}\"", serviceName, exeName); ExternalCommandRunner.RunExternalCommand("sc.exe", cmd); Log.Information("Created service {0} for not-present exe {1}", serviceName, exeName); } else { Log.Fatal("Only supported on Windows."); } } catch (Exception ex) { Console.WriteLine(ex.Message); Console.ReadLine(); } }
/// <summary> /// On macos we use the keychain and export the certificates as .pem. /// However, on macos Certificate2 doesn't support loading from a pem. /// So first we need pkcs12s instead, we convert using openssl, which requires we set a password /// we import the pkcs12 with all our certs, delete the temp files and then iterate over it the certs /// </summary> public void ExecuteMacOs() { try { if (ExternalCommandRunner.RunExternalCommand("security", "find-certificate -ap /System/Library/Keychains/SystemRootCertificates.keychain", out string result, out string _) == 0) { string tmpPath = Path.Combine(Directory.GetCurrentDirectory(), "tmpcert.pem"); string pkPath = Path.Combine(Directory.GetCurrentDirectory(), "tmpcert.pk12"); File.WriteAllText(tmpPath, result); if (ExternalCommandRunner.RunExternalCommand("openssl", $"pkcs12 -export -nokeys -out {pkPath} -passout pass:pass -in {tmpPath}", out string _, out string _) == 0) { X509Certificate2Collection xcert = new X509Certificate2Collection(); xcert.Import(pkPath, "pass", X509KeyStorageFlags.DefaultKeySet); //lgtm [cs/hardcoded-credentials] File.Delete(tmpPath); File.Delete(pkPath); var X509Certificate2Enumerator = xcert.GetEnumerator(); while (X509Certificate2Enumerator.MoveNext()) { var certificate = X509Certificate2Enumerator.Current; var obj = new CertificateObject( StoreLocation: StoreLocation.LocalMachine.ToString(), StoreName: StoreName.Root.ToString(), Certificate: new SerializableCertificate(certificate)) { Pkcs7 = Convert.ToBase64String(certificate.Export(X509ContentType.Cert)) }; DatabaseManager.Write(obj, RunId); } } else { Log.Debug("Failed to export certificate with OpenSSL."); } }
/// <summary> /// Executes the OpenPortCollector on Linux. Calls out to the `ss` /// command and parses the output, sending the output to the database. /// </summary> private void ExecuteLinux() { Log.Debug("ExecuteLinux()"); var result = ExternalCommandRunner.RunExternalCommand("ss", "-ln"); foreach (var _line in result.Split('\n')) { var line = _line; line = line.ToLower(); if (!line.Contains("listen")) { continue; } var parts = Regex.Split(line, @"\s+"); if (parts.Length < 5) { continue; // Not long enough, must be an error } string address = null; string port = null; var addressMatches = Regex.Match(parts[4], @"^(.*):(\d+)$"); if (addressMatches.Success) { address = addressMatches.Groups[1].ToString(); port = addressMatches.Groups[2].ToString(); var obj = new OpenPortObject() { family = parts[0],//@TODO: Determine IPV4 vs IPv6 via looking at the address address = address, port = port, type = parts[0] }; DatabaseManager.Write(obj, this.runId); } } }
/// <summary> /// On macos we use the keychain and export the certificates as .pem. /// However, on macos Certificate2 doesn't support loading from a pem. /// So first we need pkcs12s instead, we convert using openssl, which requires we set a password /// we import the pkcs12 with all our certs, delete the temp files and then iterate over it the certs /// </summary> public void ExecuteMacOs() { try { var result = ExternalCommandRunner.RunExternalCommand("security", new string[] { "find-certificate", "-ap", "/System/Library/Keychains/SystemRootCertificates.keychain" }); string tmpPath = Path.Combine(Directory.GetCurrentDirectory(), "tmpcert.pem"); string pkPath = Path.Combine(Directory.GetCurrentDirectory(), "tmpcert.pk12"); File.WriteAllText(tmpPath, result); _ = ExternalCommandRunner.RunExternalCommand("openssl", new string[] { "pkcs12", "-export", "-nokeys", "-out", pkPath, "-passout pass:pass", "-in", tmpPath }); X509Certificate2Collection xcert = new X509Certificate2Collection(); xcert.Import(pkPath, "pass", X509KeyStorageFlags.DefaultKeySet); File.Delete(tmpPath); File.Delete(pkPath); var X509Certificate2Enumerator = xcert.GetEnumerator(); while (X509Certificate2Enumerator.MoveNext()) { var obj = new CertificateObject() { StoreLocation = StoreLocation.LocalMachine.ToString(), StoreName = StoreName.Root.ToString(), CertificateHashString = X509Certificate2Enumerator.Current.GetCertHashString(), Subject = X509Certificate2Enumerator.Current.Subject, Pkcs12 = X509Certificate2Enumerator.Current.GetRawCertDataString() }; DatabaseManager.Write(obj, this.runId); } } catch (Exception e) { Log.Error("Failed to dump certificates from 'security' or 'openssl'."); Logger.DebugException(e); } }
private static long SizeOnDisk(string path) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { FileInfo info = new FileInfo(path); uint clusterSize = ClusterSizes[info.Directory.Root.FullName]; uint lowSize = GetCompressedFileSizeW(path, out uint highSize); long size = (long)highSize << 32 | lowSize; return(((size + clusterSize - 1) / clusterSize) * clusterSize); } else { var exitCode = ExternalCommandRunner.RunExternalCommand("du", path, out string StdOut, out string StdErr); if (exitCode == 0 && long.TryParse(StdOut.Split('\t')[0], out long result)) { return(result); } else { return(0); } } }
/// <summary> /// On linux we check the central trusted root store (a folder), which has symlinks to /// actual cert locations scattered across the db We list all the certificates and then /// create a new X509Certificate2 object for each by filename. /// </summary> internal void ExecuteLinux(CancellationToken cancellationToken) { try { if (ExternalCommandRunner.RunExternalCommand("ls", "/etc/ssl/certs -A", out string result, out string _) == 0) { foreach (var _line in result.Split('\n')) { if (cancellationToken.IsCancellationRequested) { return; } Log.Debug("{0}", _line); try { using X509Certificate2 certificate = new X509Certificate2("/etc/ssl/certs/" + _line); var obj = new CertificateObject( StoreLocation: StoreLocation.LocalMachine.ToString(), StoreName: StoreName.Root.ToString(), Certificate: new SerializableCertificate(certificate)); HandleChange(obj); } catch (Exception e) { Log.Debug("{0} {1} Issue creating certificate based on /etc/ssl/certs/{2}", e.GetType().ToString(), e.Message, _line); Log.Debug("{0}", e.StackTrace); } } } } catch (Exception e) { Log.Error(e, "Failed to dump certificates from 'ls /etc/ssl/certs -A'."); } }
/// <summary> /// On linux we check the central trusted root store (a folder), which has symlinks to actual cert locations scattered across the db /// We list all the certificates and then create a new X509Certificate2 object for each by filename. /// </summary> public void ExecuteLinux() { try { var result = ExternalCommandRunner.RunExternalCommand("ls", new string[] { "/etc/ssl/certs", "-A" }); foreach (var _line in result.Split('\n')) { Log.Debug("{0}", _line); try { X509Certificate2 certificate = new X509Certificate2("/etc/ssl/certs/" + _line); var obj = new CertificateObject() { StoreLocation = StoreLocation.LocalMachine.ToString(), StoreName = StoreName.Root.ToString(), CertificateHashString = certificate.GetCertHashString(), Subject = certificate.Subject, Pkcs12 = certificate.HasPrivateKey ? "redacted" : certificate.Export(X509ContentType.Pkcs12).ToString() }; DatabaseManager.Write(obj, this.runId); } catch (Exception e) { Log.Debug("{0} {1} Issue creating certificate based on /etc/ssl/certs/{2}", e.GetType().ToString(), e.Message, _line); Log.Debug("{0}", e.StackTrace); } } } catch (Exception e) { Log.Error("Failed to dump certificates from 'ls /etc/ssl/certs -A'."); Logger.DebugException(e); } }
/// <summary> /// Uses systemctl (relies on systemd) and also checks /etc/init.d /// </summary> internal void ExecuteLinux(CancellationToken cancellationToken) { try { var result = ExternalCommandRunner.RunExternalCommand("systemctl", "list-units --type service"); //Split lines and remove header var lines = result.Split('\n').Skip(1); foreach (var _line in lines) { if (cancellationToken.IsCancellationRequested) { return; } var _fields = _line.Split('\t'); if (_fields.Length == 5) { var obj = new ServiceObject(_fields[0]) { DisplayName = _fields[4], State = _fields[3], }; HandleChange(obj); } } } catch (ExternalException) { Log.Error("Error executing {0}", "systemctl list-units --type service"); } try { var result = ExternalCommandRunner.RunExternalCommand("ls", "/etc/init.d/ -l"); var lines = result.Split('\n').Skip(1); String pattern = @".*\s(.*)"; foreach (var _line in lines) { Match match = Regex.Match(_line, pattern); GroupCollection groups = match.Groups; var serviceName = groups[1].ToString(); var obj = new ServiceObject(serviceName) { DisplayName = serviceName, }; HandleChange(obj); } } catch (ExternalException) { Log.Error("Error executing {0}", "ls /etc/init.d/ -l"); } // CentOS chkconfig --list // BSD service -l this provides very minor amount of info }
/// <summary> /// Executes the ServiceCollector (main entrypoint). /// </summary> public override void Execute() { Start(); if (!this.CanRunOnPlatform()) { Log.Information("ServiceCollector cannot run on this platform."); return; } Truncate(runId); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // This gathers official "services" on Windows, but perhaps neglects other startup items foreach (ServiceController service in ServiceController.GetServices()) { if (this.filter != null && !this.filter(service)) { Log.Information("Service [{0}] did not pass filter, ignoring.", service.ToString()); continue; } var obj = new ServiceObject() { DisplayName = service.DisplayName, ServiceName = service.ServiceName, StartType = service.StartType.ToString(), CurrentState = service.Status.ToString() }; this.Write(obj); } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { var runner = new ExternalCommandRunner(); // Get the user processes // run "launchtl dumpstate" for the super detailed view // However, dumpstate is difficult to parse var result = runner.RunExternalCommand("launchctl", "list"); Dictionary <string, ServiceObject> outDict = new Dictionary <string, ServiceObject>(); foreach (var _line in result.Split('\n')) { // Lines are formatted like this: // PID Exit Name //1015 0 com.apple.appstoreagent var _fields = _line.Split('\t'); if (_fields.Length < 3 || _fields[0].Contains("PID")) { continue; } var obj = new ServiceObject() { DisplayName = _fields[2], ServiceName = _fields[2], StartType = "Unknown", // If we have a current PID then it is running. CurrentState = (_fields[0].Equals("-"))?"Stopped":"Running" }; if (!outDict.ContainsKey(obj.GetUniqueHash())) { this.Write(obj); outDict.Add(obj.GetUniqueHash(), obj); } } // Then get the system processes result = runner.RunExternalCommand("sudo", "launchctl list"); foreach (var _line in result.Split('\n')) { // Lines are formatted like this, with single tab separation: // PID Exit Name // 1015 0 com.apple.appstoreagent var _fields = _line.Split('\t'); if (_fields.Length < 3 || _fields[0].Contains("PID")) { continue; } var obj = new ServiceObject() { DisplayName = _fields[2], ServiceName = _fields[2], StartType = "Unknown", // If we have a current PID then it is running. CurrentState = (_fields[0].Equals("-")) ? "Stopped" : "Running" }; if (!outDict.ContainsKey(obj.GetUniqueHash())) { this.Write(obj); outDict.Add(obj.GetUniqueHash(), obj); } } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { var runner = new ExternalCommandRunner(); var result = runner.RunExternalCommand("systemctl", "list-units --type service"); //Split lines and remove header var lines = result.Split('\n'); lines.ToList().RemoveAt(0); foreach (var _line in lines) { var _fields = _line.Split('\t'); if (_fields.Count() == 5) { var obj = new ServiceObject() { DisplayName = _fields[4], ServiceName = _fields[0], StartType = "Unknown", CurrentState = _fields[3], }; Write(obj); } } result = runner.RunExternalCommand("ls", "/etc/init.d/ -l"); lines = result.Split('\n'); String pattern = @".*\s(.*)"; foreach (var _line in lines) { Match match = Regex.Match(_line, pattern); GroupCollection groups = match.Groups; var serviceName = groups[1].ToString(); var obj = new ServiceObject() { DisplayName = serviceName, ServiceName = serviceName, StartType = "Unknown", CurrentState = "Unknown" }; Write(obj); } // without systemd (maybe just CentOS) // chkconfig --list // BSD // service -l // this provides very minor amount of info } Stop(); }