internal bool IsShareReadable(string share) { if (share.EndsWith("IPC$", StringComparison.OrdinalIgnoreCase) || share.EndsWith("print$", StringComparison.OrdinalIgnoreCase)) { return(false); } BlockingMq Mq = BlockingMq.GetMq(); try { string[] files = Directory.GetFiles(share); return(true); } catch (UnauthorizedAccessException) { return(false); } catch (DirectoryNotFoundException) { return(false); } catch (IOException) { return(false); } catch (Exception e) { Mq.Trace("Unhandled exception in IsShareReadable() for share path: " + share + " Full Exception:" + e.ToString()); } return(false); }
internal bool IsShareReadable(string share) { BlockingMq Mq = BlockingMq.GetMq(); try { string[] files = Directory.GetFiles(share); return(true); } catch (UnauthorizedAccessException) { return(false); } catch (Exception e) { Mq.Trace(e.ToString()); } return(false); }
public bool ClassifyFile(FileInfo fileInfo) { BlockingMq Mq = BlockingMq.GetMq(); // figure out what part we gonna look at string stringToMatch = null; switch (ClassifierRule.MatchLocation) { case MatchLoc.FileExtension: stringToMatch = fileInfo.Extension; // special handling to treat files named like 'thing.kdbx.bak' if (stringToMatch == ".bak") { // strip off .bak string subName = fileInfo.Name.Replace(".bak", ""); stringToMatch = Path.GetExtension(subName); // if this results in no file extension, put it back. if (stringToMatch == "") { stringToMatch = ".bak"; } } // this is insane that i have to do this but apparently files with no extension return // this bullshit if (stringToMatch == "") { return(false); } break; case MatchLoc.FileName: stringToMatch = fileInfo.Name; break; case MatchLoc.FilePath: stringToMatch = fileInfo.FullName; break; case MatchLoc.FileLength: if (!SizeMatch(fileInfo)) { return(false); } else { break; } default: Mq.Error("You've got a misconfigured file classifier rule named " + ClassifierRule.RuleName + "."); return(false); } TextResult textResult = null; if (!String.IsNullOrEmpty(stringToMatch)) { TextClassifier textClassifier = new TextClassifier(ClassifierRule); // check if it matches textResult = textClassifier.TextMatch(stringToMatch); if (textResult == null) { // if it doesn't we just bail now. return(false); } } FileResult fileResult; // if it matches, see what we're gonna do with it switch (ClassifierRule.MatchAction) { case MatchAction.Discard: // chuck it. return(true); case MatchAction.Snaffle: // snaffle that bad boy fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule, TextResult = textResult }; // if the file was list-only, don't bother sending a result back to the user. if (!fileResult.RwStatus.CanRead && !fileResult.RwStatus.CanModify && !fileResult.RwStatus.CanWrite) { return(false); } ; Mq.FileResult(fileResult); return(false); case MatchAction.CheckForKeys: // do a special x509 dance List <string> x509MatchReason = x509Match(fileInfo); if (x509MatchReason.Count >= 0) { // if there were any matchreasons, cat them together... string matchContext = String.Join(",", x509MatchReason); // and sling the results on the queue fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule, TextResult = new TextResult() { MatchContext = matchContext, MatchedStrings = new List <string>() { "" } } }; if (!fileResult.RwStatus.CanRead && !fileResult.RwStatus.CanModify && !fileResult.RwStatus.CanWrite) { return(false); } ; Mq.FileResult(fileResult); } return(false); case MatchAction.Relay: // bounce it on to the next ClassifierRule try { bool fLoggedContentSizeWarning = false; foreach (string relayTarget in ClassifierRule.RelayTargets) { ClassifierRule nextRule = MyOptions.ClassifierRules.First(thing => thing.RuleName == relayTarget); if (nextRule.EnumerationScope == EnumerationScope.ContentsEnumeration) { if (fileInfo.Length > MyOptions.MaxSizeToGrep) { if (!fLoggedContentSizeWarning) { // Just log once per relay rule, no need to fill up the log with one for each relay target Mq.Trace("The following file was bigger than the MaxSizeToGrep config parameter:" + fileInfo.FullName); fLoggedContentSizeWarning = true; } continue; } ContentClassifier nextContentClassifier = new ContentClassifier(nextRule); nextContentClassifier.ClassifyContent(fileInfo); } else if (nextRule.EnumerationScope == EnumerationScope.FileEnumeration) { FileClassifier nextFileClassifier = new FileClassifier(nextRule); nextFileClassifier.ClassifyFile(fileInfo); } else { Mq.Error("You've got a misconfigured file ClassifierRule named " + ClassifierRule.RuleName + "."); } } return(false); } catch (IOException e) { Mq.Trace(e.ToString()); } catch (Exception e) { Mq.Error("You've got a misconfigured file ClassifierRule named " + ClassifierRule.RuleName + "."); Mq.Trace(e.ToString()); } return(false); case MatchAction.EnterArchive: // do a special looking inside archive files dance using // https://github.com/adamhathcock/sharpcompress // TODO FUUUUUCK throw new NotImplementedException("Haven't implemented walking dir structures inside archives."); default: Mq.Error("You've got a misconfigured file ClassifierRule named " + ClassifierRule.RuleName + "."); return(false); } }
public List <string> x509Match(FileInfo fileInfo) { BlockingMq Mq = BlockingMq.GetMq(); string certPath = fileInfo.FullName; List <string> matchReasons = new List <string>(); X509Certificate2 parsedCert = null; bool nopwrequired = false; // TODO - handle if there is no private key, strip out unnecessary stuff from Certificate.cs, make work with pfx style stuff below try { // try to parse it, it'll throw if it needs a password parsedCert = parseCert(certPath); // if it parses we know we didn't need a password nopwrequired = true; } catch (CryptographicException e) { // if it doesn't parse that almost certainly means we need a password Mq.Trace(e.ToString()); // build the list of passwords to try including the filename List <string> passwords = MyOptions.CertPasswords; passwords.Add(Path.GetFileNameWithoutExtension(fileInfo.Name)); // try each of our very obvious passwords foreach (string password in MyOptions.CertPasswords) { try { parsedCert = parseCert(certPath, password); if (password == "") { matchReasons.Add("PasswordBlank"); } else { matchReasons.Add("PasswordCracked: " + password); } } catch (CryptographicException ee) { Mq.Trace("Password " + password + " invalid for cert file " + fileInfo.FullName + " " + ee.ToString()); } } if (matchReasons.Count == 0) { matchReasons.Add("HasPassword"); matchReasons.Add("LookNearbyFor.txtFiles"); } } catch (Exception e) { Mq.Error("Unhandled exception parsing cert: " + fileInfo.FullName + " " + e.ToString()); } if (parsedCert != null) { // check if it includes a private key, if not, who cares? if (parsedCert.HasPrivateKey) { matchReasons.Add("HasPrivateKey"); if (nopwrequired) { matchReasons.Add("NoPasswordRequired"); } matchReasons.Add("Subject:" + parsedCert.Subject); // take a look at the extensions X509ExtensionCollection extensions = parsedCert.Extensions; // this feels dumb but whatever foreach (X509Extension extension in extensions) { AsnEncodedData asndata = new AsnEncodedData(extension.Oid, extension.RawData); string asndataString = asndata.Format(false); if (extension.Oid.FriendlyName == "Basic Constraints") { if (asndataString.Contains("Subject Type=CA")) { matchReasons.Add("IsCACert"); } } if (extension.GetType() == typeof(X509KeyUsageExtension)) { matchReasons.Add((extension as X509KeyUsageExtension).KeyUsages.ToString()); } if (extension.GetType() == typeof(X509EnhancedKeyUsageExtension)) { List <string> ekus = new List <string>(); X509EnhancedKeyUsageExtension ekuExtension = (X509EnhancedKeyUsageExtension)extension; foreach (Oid eku in ekuExtension.EnhancedKeyUsages) { ekus.Add(eku.FriendlyName); } // include the EKUs in the info we're passing to the user string ekustring = String.Join("|", ekus); matchReasons.Add(ekustring); } ; if (extension.Oid.FriendlyName == "Subject Alternative Name") { byte[] sanbytes = extension.RawData; string san = Encoding.UTF8.GetString(sanbytes, 0, sanbytes.Length); matchReasons.Add(asndataString); } } matchReasons.Add("Expiry:" + parsedCert.GetExpirationDateString()); matchReasons.Add("Issuer:" + parsedCert.Issuer); } } return(matchReasons); }
public bool ClassifyFile(FileInfo fileInfo) { BlockingMq Mq = BlockingMq.GetMq(); // figure out what part we gonna look at string stringToMatch = null; switch (ClassifierRule.MatchLocation) { case MatchLoc.FileExtension: stringToMatch = fileInfo.Extension; // special handling to treat files named like 'thing.kdbx.bak' if (stringToMatch == ".bak") { // strip off .bak string subName = fileInfo.Name.Replace(".bak", ""); stringToMatch = Path.GetExtension(subName); // if this results in no file extension, put it back. if (stringToMatch == "") { stringToMatch = ".bak"; } } // this is insane that i have to do this but apparently files with no extension return // this bullshit if (stringToMatch == "") { return(false); } break; case MatchLoc.FileName: stringToMatch = fileInfo.Name; break; case MatchLoc.FilePath: stringToMatch = fileInfo.FullName; break; case MatchLoc.FileLength: if (!SizeMatch(fileInfo)) { return(false); } else { break; } default: Mq.Error("You've got a misconfigured file classifier rule named " + ClassifierRule.RuleName + "."); return(false); } TextResult textResult = null; if (!String.IsNullOrEmpty(stringToMatch)) { TextClassifier textClassifier = new TextClassifier(ClassifierRule); // check if it matches textResult = textClassifier.TextMatch(stringToMatch); if (textResult == null) { // if it doesn't we just bail now. return(false); } } FileResult fileResult; // if it matches, see what we're gonna do with it switch (ClassifierRule.MatchAction) { case MatchAction.Discard: // chuck it. return(true); case MatchAction.Snaffle: // snaffle that bad boy fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule, TextResult = textResult }; Mq.FileResult(fileResult); return(true); case MatchAction.CheckForKeys: // do a special x509 dance if (x509PrivKeyMatch(fileInfo)) { fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule }; Mq.FileResult(fileResult); } return(true); case MatchAction.Relay: // bounce it on to the next ClassifierRule // TODO concurrency uplift make this a new task on the poolq try { ClassifierRule nextRule = MyOptions.ClassifierRules.First(thing => thing.RuleName == ClassifierRule.RelayTarget); if (nextRule.EnumerationScope == EnumerationScope.ContentsEnumeration) { ContentClassifier nextContentClassifier = new ContentClassifier(nextRule); nextContentClassifier.ClassifyContent(fileInfo); return(true); } else if (nextRule.EnumerationScope == EnumerationScope.FileEnumeration) { FileClassifier nextFileClassifier = new FileClassifier(nextRule); nextFileClassifier.ClassifyFile(fileInfo); return(true); } else { Mq.Error("You've got a misconfigured file ClassifierRule named " + ClassifierRule.RuleName + "."); return(false); } } catch (IOException e) { Mq.Trace(e.ToString()); } catch (Exception e) { Mq.Error("You've got a misconfigured file ClassifierRule named " + ClassifierRule.RuleName + "."); Mq.Trace(e.ToString()); } return(false); case MatchAction.EnterArchive: // do a special looking inside archive files dance using // https://github.com/adamhathcock/sharpcompress // TODO FUUUUUCK throw new NotImplementedException("Haven't implemented walking dir structures inside archives. Prob needs pool queue."); default: Mq.Error("You've got a misconfigured file ClassifierRule named " + ClassifierRule.RuleName + "."); return(false); } }
public void ClassifyContent(FileInfo fileInfo) { BlockingMq Mq = BlockingMq.GetMq(); FileResult fileResult; try { if (MyOptions.MaxSizeToGrep >= fileInfo.Length) { // figure out if we need to look at the content as bytes or as string. switch (ClassifierRule.MatchLocation) { case MatchLoc.FileContentAsBytes: byte[] fileBytes = File.ReadAllBytes(fileInfo.FullName); if (ByteMatch(fileBytes)) { fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule }; Mq.FileResult(fileResult); } return; case MatchLoc.FileContentAsString: string fileString = File.ReadAllText(fileInfo.FullName); TextClassifier textClassifier = new TextClassifier(ClassifierRule); TextResult textResult = textClassifier.TextMatch(fileString); if (textResult != null) { fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule, TextResult = textResult }; Mq.FileResult(fileResult); } return; case MatchLoc.FileLength: bool lengthResult = SizeMatch(fileInfo); if (lengthResult) { fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule }; Mq.FileResult(fileResult); } return; case MatchLoc.FileMD5: bool Md5Result = MD5Match(fileInfo); if (Md5Result) { fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule }; Mq.FileResult(fileResult); } return; default: Mq.Error("You've got a misconfigured file ClassifierRule named " + ClassifierRule.RuleName + "."); return; } } else { Mq.Trace("The following file was bigger than the MaxSizeToGrep config parameter:" + fileInfo.FullName); } } catch (UnauthorizedAccessException) { Mq.Error($"Not authorized to access file: {fileInfo.FullName}"); return; } catch (IOException e) { Mq.Error($"IO Exception on file: {fileInfo.FullName}. {e.Message}"); return; } catch (Exception e) { Mq.Error(e.ToString()); return; } }
public void ClassifyContent(FileInfo fileInfo) { BlockingMq Mq = BlockingMq.GetMq(); FileResult fileResult; try { if (MyOptions.MaxSizeToGrep >= fileInfo.Length) { // figure out if we need to look at the content as bytes or as string. switch (ClassifierRule.MatchLocation) { case MatchLoc.FileContentAsBytes: byte[] fileBytes = File.ReadAllBytes(fileInfo.FullName); if (ByteMatch(fileBytes)) { fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule }; // if the file was list-only, don't bother sending a result back to the user. if (!fileResult.RwStatus.CanRead && !fileResult.RwStatus.CanModify && !fileResult.RwStatus.CanWrite) { return; } ; Mq.FileResult(fileResult); } return; case MatchLoc.FileContentAsString: try { string fileString; #if ULTRASNAFFLER // if it's an office doc or a PDF or something, parse it to a string first i guess? List <string> parsedExtensions = new List <string>() { ".doc", ".docx", ".xls", ".xlsx", ".eml", ".msg", ".pdf", ".ppt", ".pptx", ".rtf", ".docm", ".xlsm", ".pptm", ".dot", ".dotx", ".dotm", ".xlt", ".xlsm", ".xltm" }; if (parsedExtensions.Contains(fileInfo.Extension)) { fileString = ParseFileToString(fileInfo); } else { fileString = File.ReadAllText(fileInfo.FullName); } #else fileString = File.ReadAllText(fileInfo.FullName); #endif TextClassifier textClassifier = new TextClassifier(ClassifierRule); TextResult textResult = textClassifier.TextMatch(fileString); if (textResult != null) { fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule, TextResult = textResult }; // if the file was list-only, don't bother sending a result back to the user. if (!fileResult.RwStatus.CanRead && !fileResult.RwStatus.CanModify && !fileResult.RwStatus.CanWrite) { return; } ; Mq.FileResult(fileResult); } } catch (UnauthorizedAccessException) { return; } catch (IOException) { return; } return; case MatchLoc.FileLength: bool lengthResult = SizeMatch(fileInfo); if (lengthResult) { fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule }; // if the file was list-only, don't bother sending a result back to the user. if (!fileResult.RwStatus.CanRead && !fileResult.RwStatus.CanModify && !fileResult.RwStatus.CanWrite) { return; } ; Mq.FileResult(fileResult); } return; case MatchLoc.FileMD5: bool Md5Result = MD5Match(fileInfo); if (Md5Result) { fileResult = new FileResult(fileInfo) { MatchedRule = ClassifierRule }; // if the file was list-only, don't bother sending a result back to the user. if (!fileResult.RwStatus.CanRead && !fileResult.RwStatus.CanModify && !fileResult.RwStatus.CanWrite) { return; } ; Mq.FileResult(fileResult); } return; default: Mq.Error("You've got a misconfigured file ClassifierRule named " + ClassifierRule.RuleName + "."); return; } } else { Mq.Trace("The following file was bigger than the MaxSizeToGrep config parameter:" + fileInfo.FullName); } } catch (UnauthorizedAccessException) { Mq.Error($"Not authorized to access file: {fileInfo.FullName}"); return; } catch (IOException e) { Mq.Error($"IO Exception on file: {fileInfo.FullName}. {e.Message}"); return; } catch (Exception e) { Mq.Error(e.ToString()); return; } }