diff --git a/SQLCheck/SQLCheck/Collectors.cs b/SQLCheck/SQLCheck/Collectors.cs index e5a52b1..f2c5703 100644 --- a/SQLCheck/SQLCheck/Collectors.cs +++ b/SQLCheck/SQLCheck/Collectors.cs @@ -15,6 +15,10 @@ using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography; using System.Linq; +using System.ComponentModel; +using System.Runtime.Remoting.Messaging; +using System.Security.Principal; +using System.Runtime.ConstrainedExecution; namespace SQLCheck { @@ -47,10 +51,12 @@ public static void Collect(DataSet ds) CollectSQLAlias(ds); CollectClientSNI(ds); CollectCertificate(ds); + CollectCertificatePerm(ds); CollectService(ds); CollectSPNAccount(ds); CollectSQLInstance(ds); // dropped SQL 2000 and RS 2000 CollectSQLServer(ds); + // Collect SSRS // Collect OLAP @@ -3423,5 +3429,54 @@ public static bool CompareAccounts(string account1, string account2) // no match return false; } + + private static void CollectCertificatePerm(DataSet ds) + { + DataTable dtCertificatePerm = ds.Tables["CertificatePermissions"]; + DataRow Certificate = null; + try + { + + X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); //set store to Local Machine/My + store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); + string keyPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"/Microsoft/Crypto/RSA/MachineKeys/"; + foreach (X509Certificate2 mCert in store.Certificates) //loop through all private keys in store directory + { + if (mCert.HasPrivateKey)//check to see if the certificate has a private key + { + try + { + RSACryptoServiceProvider pkey = (RSACryptoServiceProvider)mCert.PrivateKey; //save private key to a veriable + + if (pkey != null) + { + //get private key file name + string Container = pkey.CspKeyContainerInfo.KeyContainerName.ToString(); //get private key file name + string[] pKeyName = Container.Split('}'); + string PrivateKey = pKeyName[pKeyName.Length - 1]; + //add private key file name to the folder path + if (File.Exists(keyPath + PrivateKey)) + { + FileSecurity fSecurity = File.GetAccessControl(keyPath + PrivateKey); + //loop through all ACL on the file and add it to the data collector + foreach (FileSystemAccessRule rule in fSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount))) + { + Certificate = dtCertificatePerm.NewRow(); + Certificate["FriendlyName"] = mCert.FriendlyName; + Certificate["Thumbprint"] = mCert.Thumbprint; + Certificate["UserID"] = $"{rule.IdentityReference.Value}"; + Certificate["Permissions"] = $"{rule.FileSystemRights}"; + dtCertificatePerm.Rows.Add(Certificate); + } + } + } + } + catch { }; + } + } + store.Close(); + } + catch (Exception ex) { Console.WriteLine(ex); }; + } } } diff --git a/SQLCheck/SQLCheck/Storage.cs b/SQLCheck/SQLCheck/Storage.cs index 48eb6d0..a7020f2 100644 --- a/SQLCheck/SQLCheck/Storage.cs +++ b/SQLCheck/SQLCheck/Storage.cs @@ -586,6 +586,19 @@ public static DataSet CreateDataSet(String ComputerName) dt.AddColumn("Message", "String"); ds.Tables.Add(dt); + // + //Certificate User and Permissions + // + + dt = new DataTable("CertificatePermissions"); + dt.AddColumn("ID", "Integer"); + dt.Columns["ID"].AutoIncrement=true; + dt.AddColumn("FriendlyName", "String"); + dt.AddColumn("Thumbprint", "String"); + dt.AddColumn("UserID", "String"); + dt.AddColumn("Permissions", "String"); + ds.Tables.Add(dt); + return ds; } diff --git a/SQLCheck/SQLCheck/TextReport.cs b/SQLCheck/SQLCheck/TextReport.cs index 23e6070..ea87251 100644 --- a/SQLCheck/SQLCheck/TextReport.cs +++ b/SQLCheck/SQLCheck/TextReport.cs @@ -43,6 +43,7 @@ public static void Report(DataSet ds, TextWriter s) s.WriteLine(SmartString.CenterText("SQL Server Information", fieldWidth)); s.WriteLine(); ReportCertificate(ds, s); + ReportCertificatePermissions(ds, s); ReportService(ds, s); ReportSQLServer(ds, s); ReportFooter(s); @@ -1041,6 +1042,26 @@ static void ReportSQLServer(DataSet ds, TextWriter s) // outputs computer and d } } + static void ReportCertificatePermissions(DataSet ds, TextWriter s) // outputs Certificate friendly name, thumbprint, UserID's and permissions + { + DataTable dtCertificatePerm = ds.Tables["CertificatePermissions"]; + s.WriteLine("Certificate Permissions:"); + s.WriteLine(); + ReportFormatter rf = new ReportFormatter(); + rf.SetColumnNames("Friendly Name:L", "Thumbprint:L", "UserID:L", "Permissions:L"); + foreach (DataRow drCertPerm in dtCertificatePerm.Rows) + { + rf.SetcolumnData(drCertPerm.GetString("FriendlyName"), + drCertPerm.GetString("Thumbprint"), + drCertPerm.GetString("UserID"), + drCertPerm.GetString("Permissions")); + } + s.WriteLine(rf.GetHeaderText()); + s.WriteLine(rf.GetSeparatorText()); + for (int i = 0; i < rf.GetRowCount(); i++) s.WriteLine(rf.GetDataText(i)); + s.WriteLine(); + ReportMessages(ds, s, "Certificate Permissions", -1); // returns a blank line at the end ... -1 = messages for all rows + } static void ReportMessages(DataSet ds, TextWriter s, string tableName, int tableRow, bool blankLineAlways = false, bool WarningsAndAbove = false) {