public static Dictionary <string, ulong> YaraScanFile(string fileName) { Dictionary <string, ulong> beaconScanMatches = new Dictionary <string, ulong>(); using (var ctx = new YaraContext()) { Rules rules = null; try { using (Compiler compiler = new Compiler()) { // Retrieve YARA rules from YaraRules static class and compile them for scanning foreach (string rule in YaraRules.meterpreterRules) { compiler.AddRuleString(rule); } compiler.AddRuleString(YaraRules.cobaltStrikeRule); rules = compiler.GetRules(); } // Scanner and ScanResults do not need to be disposed. var scanner = new Scanner(); var results = scanner.ScanFile(fileName, rules); foreach (ScanResult result in results) { if (result.MatchingRule.Identifier.Contains("CobaltStrike")) { // Get Version 3 match - find the first occurrence of the config string if (result.Matches.ContainsKey(v3)) { beaconScanMatches.Add(v3, result.Matches[v3][0].Offset); } // Get Version 4 match if (result.Matches.ContainsKey(v4)) { beaconScanMatches.Add(v4, result.Matches[v4][0].Offset); } } } } finally { // Rules and Compiler objects must be disposed. if (rules != null) { rules.Dispose(); } } return(beaconScanMatches); } }
/// <summary> /// Perform YARA scan on process memory to detect meterpreter or Cobalt Strike payloads. /// </summary> /// <param name="processBytes">Byte array of target process to be scanned</param> public static Dictionary <string, ulong> YaraScanBytes(byte[] processBytes) { Dictionary <string, ulong> beaconScanMatches = new Dictionary <string, ulong>(); using (var ctx = new YaraContext()) { Rules rules = null; try { using (Compiler compiler = new Compiler()) { // Retrieve YARA rules from YaraRules static class and compile them for scanning foreach (string rule in YaraRules.meterpreterRules) { compiler.AddRuleString(rule); } compiler.AddRuleString(YaraRules.cobaltStrikeRule); rules = compiler.GetRules(); } // Perform scan on process memory byte[] Scanner scanner = new Scanner(); var results = scanner.ScanMemory(processBytes, rules); // Check for rule matches in process bytes foreach (ScanResult result in results) { if (result.MatchingRule.Identifier.Contains("CobaltStrike")) { // Get Version 3 match - find the first occurrence of the config string if (result.Matches.ContainsKey(v3)) { beaconScanMatches.Add(v3, result.Matches[v3][0].Offset); } // Get Version 4 match if (result.Matches.ContainsKey(v4)) { beaconScanMatches.Add(v4, result.Matches[v4][0].Offset); } } } } finally { if (rules != null) { rules.Dispose(); } } return(beaconScanMatches); } }
public void CheckMemoryNotMatchTest() { // Initialize yara context using (YaraContext ctx = new YaraContext()) { // Compile yara rules CompiledRules rules = null; using (var compiler = new Compiler()) { compiler.AddRuleString("rule foo: bar {strings: $a = \"nml\" condition: $a}"); rules = compiler.Compile(); } if (rules != null) { // Initialize the scanner var scanner = new Scanner(); Encoding encoding = Encoding.ASCII; byte[] buffer = encoding.GetBytes("abcdefgjiklmnoprstuvwxyz"); List <ScanResult> scanResult = scanner.ScanMemory(ref buffer, rules); Assert.True(scanResult.Count == 0); } } }
public void CheckStringNotMatchTest() { // Initialize yara context using (YaraContext ctx = new YaraContext()) { // Compile yara rules CompiledRules rules = null; using (var compiler = new Compiler()) { compiler.AddRuleString("rule foo: bar {strings: $a = \"nml\" condition: $a}"); rules = compiler.Compile(); } if (rules != null) { // Initialize the scanner var scanner = new Scanner(); List <ScanResult> scanResult = scanner.ScanString("abcdefgjiklmnoprstuvwxyz", rules); Assert.True(scanResult.Count == 0); } } }
public void CheckExternalVariableRuleTest() { // Initialize yara context using (YaraContext ctx = new YaraContext()) { using (var compiler = new Compiler()) { //must declare this or the compiler will complain it doesn't exist when a rule references it compiler.DeclareExternalStringVariable("filename"); //declare rule with an external variable available compiler.AddRuleString("rule foo: bar {strings: $a = \"lmn\" condition: $a and filename matches /\\.txt$/is}"); CompiledRules compiledRules = compiler.Compile(); Assert.True(compiledRules.RuleCount == 1); Encoding encoding = Encoding.ASCII; byte[] buffer = encoding.GetBytes("abcdefgjiklmnoprstuvwxyz"); // Initialize a customscanner we can add variables to var scanner = new CustomScanner(compiledRules); ExternalVariables externalVariables = new ExternalVariables(); externalVariables.StringVariables.Add("filename", "Alphabet.txt"); List <ScanResult> compiledScanResults = scanner.ScanMemory(ref buffer, externalVariables); Assert.True(compiledScanResults.Count == 1); Assert.Equal("foo", compiledScanResults[0].MatchingRule.Identifier); //release before falling out of the yara context scanner.Release(); } } }
/// <summary> /// Perform YARA scan on process memory to detect meterpreter or Cobalt Strike payloads. /// </summary> /// <param name="processBytes">Byte array of target process to be scanned</param> public static List <BeaconMatch> YaraScanBytes(byte[] processBytes) { List <BeaconMatch> beaconScanMatches = new List <BeaconMatch>(); using (var ctx = new YaraContext()) { Rules rules = null; try { using (Compiler compiler = new Compiler()) { // Retrieve YARA rules from YaraRules static class and compile them for scanning /* * foreach (string rule in YaraRules.meterpreterRules) * { * compiler.AddRuleString(rule); * } */ compiler.AddRuleString(YaraRules.cobaltStrikeRule); rules = compiler.GetRules(); } // Perform scan on process memory byte[] Scanner scanner = new Scanner(); var results = scanner.ScanMemory(processBytes, rules); beaconScanMatches = ParseScanResults(results); } finally { if (rules != null) { rules.Dispose(); } } return(beaconScanMatches); } }
public void CheckSaveLoadRuleTest() { // Initialize yara context using (YaraContext ctx = new YaraContext()) { using (var compiler = new Compiler()) { compiler.AddRuleString("rule foo: bar {strings: $a = \"lmn\" condition: $a}"); CompiledRules compiledRules = compiler.Compile(); Assert.True(compiledRules.RuleCount == 1); Encoding encoding = Encoding.ASCII; byte[] buffer = encoding.GetBytes("abcdefgjiklmnoprstuvwxyz"); // Initialize the scanner var scanner = new Scanner(); List <ScanResult> compiledScanResults = scanner.ScanMemory(ref buffer, compiledRules); Assert.True(compiledScanResults.Count == 1); Assert.Equal("foo", compiledScanResults[0].MatchingRule.Identifier); //save the rule to disk string tempfile = System.IO.Path.GetTempFileName(); bool saved = compiledRules.Save(tempfile); Assert.True(saved); //load the saved rule to a new ruleset CompiledRules loadedRules = new CompiledRules(tempfile); List <ScanResult> loadedScanResults = scanner.ScanMemory(ref buffer, loadedRules); Assert.True(loadedScanResults.Count == 1); Assert.Equal("foo", loadedScanResults[0].MatchingRule.Identifier); System.IO.File.Delete(tempfile); } } }
public void CheckIterateRulesTest() { string ruleText = @"rule foo: bar { meta: bool_meta = true int_meta = 10 string_meta = ""what a long, drawn-out thing this is!"" strings: $a = ""nml"" condition: $a }"; // Initialize yara context using (YaraContext ctx = new YaraContext()) { // Compile yara rules CompiledRules rules = null; using (var compiler = new Compiler()) { compiler.AddRuleString(ruleText); rules = compiler.Compile(); } if (rules != null) { var rule = rules.Rules.ToList()[0]; Assert.NotEmpty(rules.Rules); Assert.Equal("foo", rule.Identifier); Assert.Equal("bar", rule.Tags[0]); Assert.Equal(true, rule.Metas["bool_meta"]); Assert.Equal((long)10, rule.Metas["int_meta"]); Assert.Equal("what a long, drawn-out thing this is!", rule.Metas["string_meta"]); } } }
/// <summary> /// Compile all yara rules in the directory to memory and disk signature blobs, containing the respective rules enabled in the settings /// </summary> /// <param name="rulesDir">Directory containing directories full of yara rules</param> /// <returns>Paths to the sucessfully created rules files</returns> private string[] RecompileRules(string rulesDir) { List <string> savedrules = new List <string>(); EnumerationOptions opts = new EnumerationOptions() { MatchCasing = MatchCasing.CaseInsensitive, IgnoreInaccessible = true, RecurseSubdirectories = true }; List <string> ruleFiles = Directory.GetFiles(rulesDir, "*.yar*", opts).ToList(); ruleFiles.AddRange(Directory.GetFiles(rulesDir, "*.txt", opts).ToList()); // Compile list of yara rules var AllRulesCompiler = new Compiler(); while (true) { bool failed = false; foreach (string rulespath in ruleFiles) { string contents = File.ReadAllText(rulespath); if (contents.Contains("rule", StringComparison.OrdinalIgnoreCase) && contents.Contains("condition", StringComparison.OrdinalIgnoreCase)) { try { //if (GlobalConfig.SignatureScanLimits.TryGetValue()) AllRulesCompiler.AddRuleString(contents); } catch (Exception e) { //a bad rule causes an exeption in compilation and cant be removed, so we have to remove the whole file and recompile all from scratch failed = true; Logging.RecordException($"Failed to compile Yara rule in file {rulespath}: {e.Message}", e); ruleFiles.Remove(rulespath); if (!ruleFiles.Any()) { Logging.RecordLogEvent($"No valid YARA rules found in directory {rulesDir}", Logging.LogFilterType.Error); return(savedrules.ToArray()); } AllRulesCompiler.Dispose(); AllRulesCompiler = new Compiler(); break; } } } if (!failed) { break; } } //compilation will fail if the variable used by a rule isn't declared at compile time AllRulesCompiler.DeclareExternalStringVariable("filename"); AllRulesCompiler.DeclareExternalStringVariable("extension"); AllRulesCompiler.DeclareExternalStringVariable("filepath"); AllRulesCompiler.DeclareExternalStringVariable("filetype"); loadedRules = AllRulesCompiler.Compile(); AllRulesCompiler.Dispose(); //memoryScanRules = compiler.Compile(); // fileScanRules = compiler.Compile(); //compiler.Dispose(); if (loadedRules.RuleCount > 0) { string diskpath = Path.Combine(rulesDir, "precompiled_rules.yarac"); if (File.Exists(diskpath)) { File.Delete(diskpath); } if (loadedRules.Save(diskpath)) { savedrules.Add(diskpath); } } return(savedrules.ToArray()); }
public static List <BeaconMatch> YaraScanFile(string fileName, bool verbose) { List <BeaconMatch> beaconScanMatches = new List <BeaconMatch>(); using (var ctx = new YaraContext()) { Rules rules = null; try { using (Compiler compiler = new Compiler()) { // Retrieve YARA rules from YaraRules static class and compile them for scanning foreach (string rule in YaraRules.meterpreterRules) { compiler.AddRuleString(rule); } compiler.AddRuleString(YaraRules.cobaltStrikeRule); rules = compiler.GetRules(); } // Scanner and ScanResults do not need to be disposed. var scanner = new Scanner(); List <ScanResult> results = new List <ScanResult>(); // If file size > 2GB, stream the file and use ScanMemory() on file chunks rather than reading the whole file via if (new FileInfo(fileName).Length < Int32.MaxValue) { results.AddRange(scanner.ScanFile(fileName, rules)); } else { using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { // Parse the file in 200MB chunks int chunkSize = 1024 * 1024 * 200; byte[] chunk = new byte[chunkSize]; int bytesRead = 0; long bytesToRead = fileStream.Length; while (bytesToRead != 0) { int n = fileStream.Read(chunk, 0, chunkSize); if (n == 0) { break; } // Yara scan the file chunk and add any results to the list var scanResults = scanner.ScanMemory(chunk, rules); // Because the file is being scanned in chunks, match offsets are based on the start of the chunk. Need to add // previous bytes read to the current match offsets if (scanResults.Count > 0) { foreach (ScanResult result in scanResults) { if (result.MatchingRule.Identifier.Contains("CobaltStrike")) { foreach (string key in result.Matches.Keys) { result.Matches[key][0].Offset += (ulong)bytesRead; } results.Add(result); } } } bytesRead += n; bytesToRead -= n; // Shitty progress update if (verbose && bytesRead > 0 && bytesRead <= fileStream.Length) { Console.Write($"\r\tScanned {bytesRead} bytes of {fileStream.Length} byte file..."); } } } if (verbose) { Console.WriteLine($"\r\tFinished scanning file: {fileName}\t\t\t"); } } beaconScanMatches = ParseScanResults(results); } finally { // Rules and Compiler objects must be disposed. if (rules != null) { rules.Dispose(); } } return(beaconScanMatches); } }