///////////////////////////////////////////////////// // // // GetMitigateItems() // // // ///////////////////////////////////////////////////// //Description: Crawls the GUI listview controls that // hold the registry, file and memory // signature matches. It builds an XML // structure from these values in preparation // for sending them to the agent for mitigation. // //Returns: void ///////////////////////////////////////////////////// private CwXML.CodewordAgentSignatureMatches GetCollectMitigateItems(ref string outputMessage, string mitigateOrCollectMsg) { int numRegMitigate = 0,numFileMitigate=0,numMemMitigate=0; int count = 0; bool mitigateAll = false; CwXML.CodewordAgentSignatureMatches matches = new CwXML.CodewordAgentSignatureMatches(); outputMessage = ""; //------------------------------------- // CALCULATE COUNTS //------------------------------------- foreach (ListViewItem lvi in AgentResults_RegistryListview.Items) if (lvi.Checked) numRegMitigate++; foreach (ListViewItem lvi in AgentResults_FileListview.Items) if (lvi.Checked) numFileMitigate++; foreach (ListViewItem lvi in AgentResults_MemoryListview.Items) if (lvi.Checked) numMemMitigate++; //if there were no items selected, prompt to mitigate all findings if ((numRegMitigate + numFileMitigate + numMemMitigate) == 0) { if (MessageBox.Show("No findings were selected. Would you like to "+mitigateOrCollectMsg+" all findings?", mitigateOrCollectMsg+" all findings?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) != DialogResult.Yes) return null; numRegMitigate = AgentResults_RegistryListview.Items.Count; numFileMitigate = AgentResults_FileListview.Items.Count; numMemMitigate = AgentResults_MemoryListview.Items.Count; mitigateAll = true; } CwXML.RegistrySignatureMatch[] regMatchesToMitigate = new CwXML.RegistrySignatureMatch[numRegMitigate]; CwXML.FileSignatureMatch[] fileMatchesToMitigate = new CwXML.FileSignatureMatch[numFileMitigate]; CwXML.MemorySignatureMatch[] memMatchesToMitigate = new CwXML.MemorySignatureMatch[numMemMitigate]; //------------------------------------- // REGISTRY //------------------------------------- if (numRegMitigate > 0) { outputMessage += "Registry findings (" + numRegMitigate + "):\n"; //build list of registry signature matches to mitigate foreach (ListViewItem lvi in AgentResults_RegistryListview.Items) { if (!lvi.Checked && !mitigateAll) continue; //add to display based on action selected for this finding outputMessage += " " + lvi.SubItems[0].Text + "\\" + lvi.SubItems[1] + " : " + lvi.SubItems[5].Text + "\n"; regMatchesToMitigate[count] = new CwXML.RegistrySignatureMatch(); regMatchesToMitigate[count].RegistryKeyName = lvi.SubItems[0].Text; regMatchesToMitigate[count].RegistryValueName = lvi.SubItems[1].Text; regMatchesToMitigate[count].RegistryValueData = lvi.SubItems[2].Text; regMatchesToMitigate[count].RegistryChangeValueData = lvi.SubItems[3].Text; try { regMatchesToMitigate[count].IsFileOnDisk = bool.Parse(lvi.SubItems[4].Text); } catch (Exception) { regMatchesToMitigate[count].IsFileOnDisk = false; } regMatchesToMitigate[count].Action = lvi.SubItems[5].Text; try { regMatchesToMitigate[count].ActionSuccessful = bool.Parse(lvi.SubItems[6].Text); } catch (Exception) { regMatchesToMitigate[count].ActionSuccessful = false; } count++; } count = 0; } //------------------------------------- // FILE //------------------------------------- if (numFileMitigate > 0) { outputMessage += "File findings (" + numFileMitigate + "):\n"; //build list of registry signature matches to mitigate foreach (ListViewItem lvi in AgentResults_FileListview.Items) { if (!lvi.Checked && !mitigateAll) continue; //add to display based on action selected for this finding if (lvi.SubItems[0].Text != "") //filename outputMessage += " " + lvi.SubItems[1].Text + " : " + lvi.SubItems[8].Text + "\n"; else if (lvi.SubItems[3].Text != "") //hash outputMessage += " [Hash=" + lvi.SubItems[3].Text + "] : " + lvi.SubItems[8].Text + "\n"; else if (lvi.SubItems[2].Text != "") //filesize outputMessage += " [FileSize=" + lvi.SubItems[2].Text + "] : " + lvi.SubItems[8].Text + "\n"; fileMatchesToMitigate[count] = new CwXML.FileSignatureMatch(); fileMatchesToMitigate[count].FileName = lvi.SubItems[0].Text; fileMatchesToMitigate[count].FullPath = lvi.SubItems[1].Text; long.TryParse(lvi.SubItems[2].Text, out fileMatchesToMitigate[count].FileSize); fileMatchesToMitigate[count].FileHash = lvi.SubItems[3].Text; fileMatchesToMitigate[count].FilePEHeaderSignature = lvi.SubItems[4].Text; fileMatchesToMitigate[count].FileCreationDate = lvi.SubItems[5].Text; fileMatchesToMitigate[count].FileLastAccessDate = lvi.SubItems[6].Text; fileMatchesToMitigate[count].FileLastModifiedDate = lvi.SubItems[7].Text; fileMatchesToMitigate[count].Action = lvi.SubItems[8].Text; try { fileMatchesToMitigate[count].ActionSuccessful = bool.Parse(lvi.SubItems[9].Text); } catch (Exception) { fileMatchesToMitigate[count].ActionSuccessful = false; } count++; } count = 0; } //------------------------------------- // MEMORY //------------------------------------- if (numMemMitigate > 0) { outputMessage += "Memory findings (" + numMemMitigate + "):\n"; //build list of registry signature matches to mitigate foreach (ListViewItem lvi in AgentResults_MemoryListview.Items) { if (!lvi.Checked && !mitigateAll) continue; outputMessage += " " + lvi.SubItems[2].Text + " (" + lvi.SubItems[0].Text + ") : " + lvi.SubItems[7].Text; //we cant populate all the fields of the memorysignaturematch structure, //because we didn't populate the GUI listview with all these fields (there are too many) //however, memory mitigation consists of killing the process by name/pid or suspending the thread. //so we dont need all that crap anyway. memMatchesToMitigate[count] = new CwXML.MemorySignatureMatch(); uint.TryParse(lvi.SubItems[0].Text, out memMatchesToMitigate[count].ProcessId); uint.TryParse(lvi.SubItems[1].Text, out memMatchesToMitigate[count].ParentProcessId); memMatchesToMitigate[count].ProcessName = lvi.SubItems[2].Text; memMatchesToMitigate[count].ChildThreadIds = lvi.SubItems[6].Text; memMatchesToMitigate[count].Action = lvi.SubItems[7].Text; try { memMatchesToMitigate[count].ActionSuccessful = bool.Parse(lvi.SubItems[8].Text); } catch (Exception) { memMatchesToMitigate[count].ActionSuccessful = false; } count++; } } matches.RegistrySignatureMatches = regMatchesToMitigate; matches.FileSignatureMatches = fileMatchesToMitigate; matches.MemorySignatureMatches = memMatchesToMitigate; return matches; }
///////////////////////////////////////////////////// // // // ScanForRegistrySignatures() // // // ///////////////////////////////////////////////////// //Description: Scans the registry for the given // signatures, storing any findings in // the passed-in matches structure. //Returns: none ///////////////////////////////////////////////////// internal void ScanForRegistrySignatures(CwXML.RegistrySignature[] signatures, CwXML.RegistryGuidSignature[] guidSignatures, ref CwXML.RegistrySignatureMatch[] matches) { string keyName, valueName, valueData, action, hive, keyWithoutHive; int firstSlashInKeyName = 0; RegistryKey key; Regex filePathValidator = new Regex(@"^(([a-zA-Z]\:)|(\\))(\\{1}|((\\{1})[^\\]([^/:*?<>""|]*))+)$"); string[] expandedKeys; ArrayList matchList = new ArrayList(); //loop through all registry indicators - admin and user foreach (CwXML.RegistrySignature signature in signatures) { //extract values from object keyName = signature.KeyName; valueName = signature.ValueName; valueData = signature.ValueData; action = signature.Action; firstSlashInKeyName = keyName.IndexOf('\\'); hive = keyName.Substring(0, firstSlashInKeyName); keyWithoutHive = keyName.Substring(firstSlashInKeyName, keyName.Length - firstSlashInKeyName); if (hive == "HKLM") key = Registry.LocalMachine; else if (hive == "HKCR") key = Registry.ClassesRoot; else if (hive == "HKU") key = Registry.Users; else if (hive == "HKCC") key = Registry.CurrentConfig; else { RegistryHelperLog.AppendLine("WARNING: Invalid hive detected in registry indicator:"); RegistryHelperLog.AppendLine(" Key: '" + keyName + "'"); RegistryHelperLog.AppendLine(" Parsed hive: '" + hive + "'"); RegistryHelperLog.AppendLine("WARNING: Skipping this indicator..."); continue; //skip if bad hive } RegistryHelperLog.AppendLine("SCAN: Using hive '" + hive + "'."); //expand any {<var>} expandable values in registry key string expandedKeys = ExpandRegistryKey(keyWithoutHive, guidSignatures); //only returns null if there was a malformed var, so skip that check if (expandedKeys == null) continue; //loop through the record/checks we built, or didn't build - if there was no var //to expand, we just got the same record back. foreach (string expandedKey in expandedKeys) { if (expandedKey == null) continue; //remove leading and trailing slashes keyName = expandedKey.Trim(new char[] { ' ', '\\' }); RegistryHelperLog.AppendLine("SCAN: Scanning for signature '" + hive + "\\" + keyName + "\\" + valueName + "'..."); RegistryKey parentKey = key.OpenSubKey(keyName, true); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // SIGNATURE HIT //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //if the key exists, we have a match. if (parentKey != null) { try { ArrayList valnames = new ArrayList(); //build an arraylist of value names to look for //if the valueName supplied in the signature is empty, we will copy //all valueName's in this registry key. if (valueName == "" || valueName == null) { foreach (string valname in parentKey.GetValueNames()) valnames.Add(valname); //if there are no value names, add the (Default) one, represented by "" in .net if (valnames.Count == 0) valnames.Add(""); } else { //otherwise we just want a single value name underneath this key valnames.Add(valueName); } //loop thru all value names to look for and add a new match record foreach (string v in valnames) { //get the value name object obj = parentKey.GetValue(v); //parse the value data - binary, expand string, etc... if (obj != null) { string displayData = ""; string valdata = ""; RegistryHelperLog.AppendLine("SCAN: Signature matched on host!"); //create a new RegistrySignatureMatch object CwXML.RegistrySignatureMatch matchRecord = new CwXML.RegistrySignatureMatch(); matchRecord.RegistryKeyName = hive+"\\"+keyName; //the expanded registry key name plus hive matchRecord.RegistryValueName = v; matchRecord.Action = action; //get the value data of this value name based on type if (parentKey.GetValueKind(v) == RegistryValueKind.Binary) { StringBuilder str = GetEncodingsFromBinaryRegData((byte[])parentKey.GetValue(v)); valdata = str.ToString(); displayData = valdata; } //handle DWORD and QWORD reg data else if (parentKey.GetValueKind(v) == RegistryValueKind.DWord || parentKey.GetValueKind(v) == RegistryValueKind.QWord) { valdata = parentKey.GetValue(v).ToString(); //first value will be in decimal, hex in parenthesis displayData = "'" + int.Parse(valdata).ToString() + "' (0x" + int.Parse(valdata).ToString("x") + ")"; } else { valdata = parentKey.GetValue(v).ToString(); displayData = "'" + valdata + "'"; } matchRecord.RegistryValueData = valdata; //if it's a file, mark the appropriate field in the registry signature entry. //later on , these files will be deleted if settings dictate it. if (filePathValidator.IsMatch(valdata)) matchRecord.IsFileOnDisk = true; else matchRecord.IsFileOnDisk = false; //log it in pretty format RegistryHelperLog.AppendLine(" " + v + " = '" + displayData + "'"); //add it to our result set matchList.Add(matchRecord); } //otherwise teh value name coudl not be retrieved, so no real match here. else { RegistryHelperLog.AppendLine("SCAN: The value name '" + keyName + "\\" + v + "' doesn't exist."); } } } catch (Exception e) { RegistryHelperLog.AppendLine("SCAN: Caught exception '" + e.Message + "', can't get this value name."); } } else { RegistryHelperLog.AppendLine("SCAN: The parent key '" + keyName + "' doesn't exist."); } } //end looping through expanded reg values for this reg indicator } // end looping through ALL registry indicators //re-initialize our return object to the number of items in arraylist int i = 0; matches = new CwXML.RegistrySignatureMatch[matchList.Count]; //add all registry findings in the arraylist to our matches object foreach (CwXML.RegistrySignatureMatch match in matchList) { matches[i] = new CwXML.RegistrySignatureMatch(); matches[i] = match; i++; } }
///////////////////////////////////////////////////// // // // ScanForRegistrySignatures() // // // ///////////////////////////////////////////////////// //Description: Scans the registry for the given // signatures, storing any findings in // the passed-in matches structure. //Returns: none ///////////////////////////////////////////////////// internal void ScanForRegistrySignatures(CwXML.RegistrySignature[] signatures, CwXML.RegistryGuidSignature[] guidSignatures, ref CwXML.RegistrySignatureMatch[] matches) { string keyName, valueName, valueData, action, hive, keyWithoutHive; int firstSlashInKeyName = 0; RegistryKey key; Regex filePathValidator = new Regex(@"^(([a-zA-Z]\:)|(\\))(\\{1}|((\\{1})[^\\]([^/:*?<>""|]*))+)$"); string[] expandedKeys; ArrayList matchList = new ArrayList(); //loop through all registry indicators - admin and user foreach (CwXML.RegistrySignature signature in signatures) { //extract values from object keyName = signature.KeyName; valueName = signature.ValueName; valueData = signature.ValueData; action = signature.Action; firstSlashInKeyName = keyName.IndexOf('\\'); hive = keyName.Substring(0, firstSlashInKeyName); keyWithoutHive = keyName.Substring(firstSlashInKeyName, keyName.Length - firstSlashInKeyName); if (hive == "HKLM") { key = Registry.LocalMachine; } else if (hive == "HKCR") { key = Registry.ClassesRoot; } else if (hive == "HKU") { key = Registry.Users; } else if (hive == "HKCC") { key = Registry.CurrentConfig; } else { RegistryHelperLog.AppendLine("WARNING: Invalid hive detected in registry indicator:"); RegistryHelperLog.AppendLine(" Key: '" + keyName + "'"); RegistryHelperLog.AppendLine(" Parsed hive: '" + hive + "'"); RegistryHelperLog.AppendLine("WARNING: Skipping this indicator..."); continue; //skip if bad hive } RegistryHelperLog.AppendLine("SCAN: Using hive '" + hive + "'."); //expand any {<var>} expandable values in registry key string expandedKeys = ExpandRegistryKey(keyWithoutHive, guidSignatures); //only returns null if there was a malformed var, so skip that check if (expandedKeys == null) { continue; } //loop through the record/checks we built, or didn't build - if there was no var //to expand, we just got the same record back. foreach (string expandedKey in expandedKeys) { if (expandedKey == null) { continue; } //remove leading and trailing slashes keyName = expandedKey.Trim(new char[] { ' ', '\\' }); RegistryHelperLog.AppendLine("SCAN: Scanning for signature '" + hive + "\\" + keyName + "\\" + valueName + "'..."); RegistryKey parentKey = key.OpenSubKey(keyName, true); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // SIGNATURE HIT //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //if the key exists, we have a match. if (parentKey != null) { try { ArrayList valnames = new ArrayList(); //build an arraylist of value names to look for //if the valueName supplied in the signature is empty, we will copy //all valueName's in this registry key. if (valueName == "" || valueName == null) { foreach (string valname in parentKey.GetValueNames()) { valnames.Add(valname); } //if there are no value names, add the (Default) one, represented by "" in .net if (valnames.Count == 0) { valnames.Add(""); } } else { //otherwise we just want a single value name underneath this key valnames.Add(valueName); } //loop thru all value names to look for and add a new match record foreach (string v in valnames) { //get the value name object obj = parentKey.GetValue(v); //parse the value data - binary, expand string, etc... if (obj != null) { string displayData = ""; string valdata = ""; RegistryHelperLog.AppendLine("SCAN: Signature matched on host!"); //create a new RegistrySignatureMatch object CwXML.RegistrySignatureMatch matchRecord = new CwXML.RegistrySignatureMatch(); matchRecord.RegistryKeyName = hive + "\\" + keyName; //the expanded registry key name plus hive matchRecord.RegistryValueName = v; matchRecord.Action = action; //get the value data of this value name based on type if (parentKey.GetValueKind(v) == RegistryValueKind.Binary) { StringBuilder str = GetEncodingsFromBinaryRegData((byte[])parentKey.GetValue(v)); valdata = str.ToString(); displayData = valdata; } //handle DWORD and QWORD reg data else if (parentKey.GetValueKind(v) == RegistryValueKind.DWord || parentKey.GetValueKind(v) == RegistryValueKind.QWord) { valdata = parentKey.GetValue(v).ToString(); //first value will be in decimal, hex in parenthesis displayData = "'" + int.Parse(valdata).ToString() + "' (0x" + int.Parse(valdata).ToString("x") + ")"; } else { valdata = parentKey.GetValue(v).ToString(); displayData = "'" + valdata + "'"; } matchRecord.RegistryValueData = valdata; //if it's a file, mark the appropriate field in the registry signature entry. //later on , these files will be deleted if settings dictate it. if (filePathValidator.IsMatch(valdata)) { matchRecord.IsFileOnDisk = true; } else { matchRecord.IsFileOnDisk = false; } //log it in pretty format RegistryHelperLog.AppendLine(" " + v + " = '" + displayData + "'"); //add it to our result set matchList.Add(matchRecord); } //otherwise teh value name coudl not be retrieved, so no real match here. else { RegistryHelperLog.AppendLine("SCAN: The value name '" + keyName + "\\" + v + "' doesn't exist."); } } } catch (Exception e) { RegistryHelperLog.AppendLine("SCAN: Caught exception '" + e.Message + "', can't get this value name."); } } else { RegistryHelperLog.AppendLine("SCAN: The parent key '" + keyName + "' doesn't exist."); } } //end looping through expanded reg values for this reg indicator } // end looping through ALL registry indicators //re-initialize our return object to the number of items in arraylist int i = 0; matches = new CwXML.RegistrySignatureMatch[matchList.Count]; //add all registry findings in the arraylist to our matches object foreach (CwXML.RegistrySignatureMatch match in matchList) { matches[i] = new CwXML.RegistrySignatureMatch(); matches[i] = match; i++; } }