public void PrepDomainUserRules() { try { if (MyOptions.DomainUsersWordlistRules.Count >= 1) { foreach (string ruleName in MyOptions.DomainUsersWordlistRules) { ClassifierRule configClassifierRule = MyOptions.ClassifierRules.First(thing => thing.RuleName == ruleName); foreach (string user in MyOptions.DomainUsersToMatch) { string pattern = "( |'|\")" + Regex.Escape(user) + "( |'|\")"; Regex regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.CultureInvariant); configClassifierRule.Regexes.Add(regex); } } } } catch (Exception) { Mq.Error("Something went wrong adding domain users to rules."); } }
public void PrepDomainUserRules() { try { if (MyOptions.DomainUsersWordlistRules.Count >= 1) { foreach (string ruleName in MyOptions.DomainUsersWordlistRules) { ClassifierRule configClassifierRule = MyOptions.ClassifierRules.First(thing => thing.RuleName == ruleName); foreach (string user in MyOptions.DomainUsersToMatch) { if (user.Length < MyOptions.DomainUserMinLen) { Mq.Trace(String.Format("Skipping regex for \"{0}\". Shorter than minimum chars: {1}", user, MyOptions.DomainUserMinLen)); continue; } // Use the null character to match begin and end of line string pattern = "(| |'|\")" + Regex.Escape(user) + "(| |'|\")"; Regex regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.CultureInvariant); configClassifierRule.Regexes.Add(regex); Mq.Trace(String.Format("Adding regex {0} to rule {1}", regex, ruleName)); } } } } catch (Exception) { Mq.Error("Something went wrong adding domain users to rules."); } }
public AdData() { Mq = BlockingMq.GetMq(); // figure out domain context if (MyOptions.TargetDomain == null && MyOptions.TargetDc == null) { try { DirectoryContext = new DirectoryContext(DirectoryContextType.Domain, Domain.GetCurrentDomain().Name); } catch (Exception e) { Mq.Error( "Problem figuring out DirectoryContext, you might need to define manually with -d and/or -c."); Mq.Degub(e.ToString()); Mq.Terminate(); } } else if (!String.IsNullOrEmpty(MyOptions.TargetDc)) { DirectoryContext = new DirectoryContext(DirectoryContextType.Domain, MyOptions.TargetDc); } else if (!String.IsNullOrEmpty(MyOptions.TargetDomain)) { DirectoryContext = new DirectoryContext(DirectoryContextType.Domain, MyOptions.TargetDomain); } SetDomainUsersAndComputers(); }
internal void GetComputerShares(string computer) { // find the shares HostShareInfo[] hostShareInfos = GetHostShareInfo(computer); foreach (HostShareInfo hostShareInfo in hostShareInfos) { string shareName = GetShareName(hostShareInfo, computer); if (!String.IsNullOrWhiteSpace(shareName)) { bool matched = false; // classify them foreach (ClassifierRule classifier in MyOptions.ShareClassifiers) { ShareClassifier shareClassifier = new ShareClassifier(classifier); if (shareClassifier.ClassifyShare(shareName)) { matched = true; break; } } // by default all shares should go on to TreeWalker unless the classifier pulls them out. // send them to TreeWalker if (!matched) { if (IsShareReadable(shareName)) { ShareResult shareResult = new ShareResult() { Listable = true, SharePath = shareName }; Mq.ShareResult(shareResult); Mq.Info("Creating a TreeWalker task for " + shareResult.SharePath); TreeTaskScheduler.New(() => { try { TreeWalker.WalkTree(shareResult.SharePath); } catch (Exception e) { Mq.Error("Exception in TreeWalker task for share " + shareResult.SharePath); Mq.Error(e.ToString()); } }); } } } } }
public override async Task EnqueueRequests(string ownerId, IEnumerable <Request> requests) { // 本机下载中心只会有一个下载代理 var agents = await DownloaderAgentStore.GetAllListAsync(ownerId); if (agents.Count <= 0) { Logger.LogError("未找到活跃的下载器代理"); } var agent = agents[0]; var json = JsonConvert.SerializeObject(requests); await Mq.PublishAsync(agent.Id, $"{Framework.DownloadCommand}|{json}"); }
public void ScanFile(string file) { try { FileInfo fileInfo = new FileInfo(file); // send the file to all the classifiers. foreach (ClassifierRule classifier in MyOptions.FileClassifiers) { // Don't send file to classifier if interest level is not high enough if ((classifier.Triage == Triage.Red && InterestLevel > 2) || (classifier.Triage == Triage.Yellow && InterestLevel > 1) || (classifier.Triage == Triage.Green && InterestLevel > 0) ) { continue; } FileClassifier fileClassifier = new FileClassifier(classifier); if (fileClassifier.ClassifyFile(fileInfo)) { return; } ; } } catch (FileNotFoundException e) { // If file was deleted by a separate application // or thread since the call to TraverseTree() // then just continue. Mq.Trace(e.ToString()); return; } catch (UnauthorizedAccessException e) { Mq.Trace(e.ToString()); return; } catch (PathTooLongException) { Mq.Trace(file + " path was too long for me to look at."); return; } catch (Exception e) { Mq.Trace(e.ToString()); return; } }
public TreeWalker(string shareRoot) { Mq = BlockingMq.GetMq(); FileTaskScheduler = SnaffCon.GetFileTaskScheduler(); if (shareRoot == null) { Mq.Trace("A null made it into TreeWalker. Wtf."); return; } Mq.Trace("About to start a TreeWalker on share " + shareRoot); WalkTree(shareRoot); Mq.Trace("Finished TreeWalking share " + shareRoot); }
private string GetShareName(HostShareInfo hostShareInfo, string computer) { // takes a HostShareInfo object and a computer name and turns it into a usable path. // first we want to throw away any errored out ones. string[] errors = { "ERROR=53", "ERROR=5" }; if (errors.Contains(hostShareInfo.shi1_netname)) { //Mq.Trace(hostShareInfo.shi1_netname + " on " + computer + //", but this is usually no cause for alarm."); return(null); } Mq.Degub("Share discovered: " + $"\\\\{computer}\\{hostShareInfo.shi1_netname}"); return($"\\\\{computer}\\{hostShareInfo.shi1_netname}"); }
public void Execute() { StartTime = DateTime.Now; // This is the main execution thread. Timer statusUpdateTimer = new Timer(TimeSpan.FromMinutes(1) .TotalMilliseconds) { AutoReset = true }; // Set the time (1 min in this case) statusUpdateTimer.Elapsed += TimedStatusUpdate; statusUpdateTimer.Start(); // if we haven't been told what dir or computer to target, we're going to need to do share discovery. that means finding computers from the domain. if (MyOptions.PathTargets == null && MyOptions.ComputerTargets == null) { DomainDiscovery(); } // if we've been told what computers to hit... else if (MyOptions.ComputerTargets != null) { ShareDiscovery(MyOptions.ComputerTargets); } // otherwise we should have a set of path targets... else if (MyOptions.PathTargets != null) { FileDiscovery(MyOptions.PathTargets); } // but if that hasn't been done, something has gone wrong. else { Mq.Error("OctoParrot says: AWK! I SHOULDN'T BE!"); } waitHandle.WaitOne(); StatusUpdate(); DateTime finished = DateTime.Now; TimeSpan runSpan = finished.Subtract(StartTime); Mq.Info("Finished at " + finished.ToLocalTime()); Mq.Info("Snafflin' took " + runSpan); Mq.Finish(); }
private void GetDomainControllers() { try { DomainControllerCollection dcCollection = DomainController.FindAll(DirectoryContext); foreach (DomainController dc in dcCollection) { DomainControllers.Add(dc.IPAddress); } } catch (Exception e) { Mq.Error( "Something went wrong trying to find domain controllers. Try defining manually with -c?"); Mq.Degub(e.ToString()); Mq.Terminate(); } }
private void DomainUserDiscovery() { Mq.Info("Getting interesting users from AD."); // We do this single threaded cos it's fast and not easily divisible. // The AdData class set/get semantics have gotten wonky here. Leaving as-is to minimize breakage/changes, but needs another look. AdData adData = new AdData(); adData.SetDomainUsers(); foreach (string user in adData.GetDomainUsers()) { MyOptions.DomainUsersToMatch.Add(user); } // build the regexes for use in the file scans PrepDomainUserRules(); }
private void DomainDfsDiscovery() { Dictionary <string, string> dfsSharesDict = null; AdData adData = null; Mq.Info("Getting DFS paths from AD."); adData = new AdData(); adData.SetDfsPaths(); dfsSharesDict = adData.GetDfsSharesDict(); // if we found some actual dfsshares if (dfsSharesDict.Count >= 1) { MyOptions.DfsSharesDict = dfsSharesDict; MyOptions.DfsNamespacePaths = adData.GetDfsNamespacePaths(); } }
private void DomainDiscovery() { Mq.Info("Getting users and computers from AD."); // We do this single threaded cos it's fast and not easily divisible. AdData adData = new ActiveDirectory.AdData(); List <string> targetComputers = adData.GetDomainComputers(); if (targetComputers == null) { Mq.Error( "Something f****d out finding stuff in the domain. You must be holding it wrong."); while (true) { Mq.Terminate(); } } string numTargetComputers = targetComputers.Count.ToString(); Mq.Info("Got " + numTargetComputers + " computers from AD."); if (targetComputers.Count == 0) { Mq.Error("Didn't find any domain computers. Seems weird. Try pouring water on it."); while (true) { Mq.Terminate(); } } // Push list of fun users to Options if (MyOptions.DomainUserRules) { foreach (string user in adData.GetDomainUsers()) { MyOptions.DomainUsersToMatch.Add(user); } PrepDomainUserRules(); } // immediately call ShareDisco which should handle the rest. ShareDiscovery(targetComputers.ToArray()); }
private void FileDiscovery(string[] pathTargets) { foreach (string pathTarget in pathTargets) { // ShareScanner Task Creation - this kicks off the rest of the flow Mq.Info("Creating a TreeWalker task for " + pathTarget); TreeTaskScheduler.New(() => { try { TreeWalker.WalkTree(pathTarget); } catch (Exception e) { Mq.Error("Exception in TreeWalker task for path " + pathTarget); Mq.Error(e.ToString()); } }); } Mq.Info("Created all TreeWalker tasks."); }
public override async Task <bool> AllocateAsync(AllotDownloaderMessage allotDownloaderMessage) { List <DownloaderAgent> agents = null; for (int i = 0; i < 50; ++i) { agents = await DownloaderAgentStore.GetAllListAsync(); if (agents.Count <= 0) { Thread.Sleep(100); } else { break; } } if (agents == null) { Logger.LogError("未找到活跃的下载器代理"); return(false); } // 保存节点选取信息 await DownloaderAgentStore.AllocateAsync(allotDownloaderMessage.OwnerId, new[] { agents[0].Id }); Logger.LogInformation("下载器代理分配成功"); // 发送消息让下载代理器分配好下载器 var message = $"{Framework.AllocateDownloaderCommand}|{JsonConvert.SerializeObject(allotDownloaderMessage)}"; foreach (var agent in agents) { await Mq.PublishAsync(agent.Id, message); } return(true); }
private void ShareDiscovery(string[] computerTargets) { Mq.Info("Starting to look for readable shares..."); foreach (string computer in computerTargets) { // ShareFinder Task Creation - this kicks off the rest of the flow Mq.Trace("Creating a sharefinder task for " + computer); ShareTaskScheduler.New(() => { try { ShareFinder shareFinder = new ShareFinder(); shareFinder.GetComputerShares(computer); } catch (Exception e) { Mq.Error("Exception in ShareFinder task for host " + computer); Mq.Error(e.ToString()); } }); } Mq.Info("Created all sharefinder tasks."); }
private DirectorySearch GetDirectorySearcher() { Mq = BlockingMq.GetMq(); // target domain and dc set if ((!string.IsNullOrEmpty(MyOptions.TargetDomain)) && (!string.IsNullOrEmpty(MyOptions.TargetDc))) { Mq.Trace("Target DC and Domain specified: " + MyOptions.TargetDomain + " + " + MyOptions.TargetDc); _targetDc = MyOptions.TargetDc; _targetDomain = MyOptions.TargetDomain; } // no target DC or domain set else { Mq.Trace("Getting current domain from user context."); _currentDomain = Domain.GetCurrentDomain(); _targetDomain = _currentDomain.Name; _targetDc = _targetDomain; } _targetDomainNetBIOSName = GetNetBiosDomainName(); return(new DirectorySearch(_targetDomain, _targetDc)); }
/// <summary> /// 单机模式只有一个下载器代理 /// </summary> /// <param name="allotDownloaderMessage">分配下载器代理的选项</param> /// <returns></returns> protected override async Task <bool> AllocateAsync(AllotDownloaderMessage allotDownloaderMessage) { var agent = Agents.Values.FirstOrDefault(); if (agent == null) { Logger.LogInformation($"任务 {allotDownloaderMessage.OwnerId} 未找到可用的下载器代理"); return(false); } // 保存节点选取信息 await DownloaderAgentStore.AllocateAsync(allotDownloaderMessage.OwnerId, new[] { agent.Id }); // 发送消息让下载代理器分配好下载器 var message = $"|{Framework.AllocateDownloaderCommand}|{JsonConvert.SerializeObject(allotDownloaderMessage)}"; await Mq.PublishAsync(agent.Id, message); Logger.LogInformation( $"任务 {allotDownloaderMessage.OwnerId} 分配下载代理器成功: {JsonConvert.SerializeObject(agent)}"); return(true); }
private void ClassifyArchive(FileInfo fileInfo) { // look inside archives for files we like. try { IArchive archive = ArchiveFactory.Open(fileInfo.FullName); foreach (IArchiveEntry entry in archive.Entries) { if (!entry.IsDirectory) { try { FileScanner.ScanFile(entry.Key); } catch (Exception e) { Mq.Trace(e.ToString()); } } } } catch (CryptographicException) { Mq.FileResult(new FileResult(fileInfo) { MatchedRule = new ClassifierRule() { Triage = Triage.Black, RuleName = "EncryptedArchive" } }); } catch (Exception e) { Mq.Trace(e.ToString()); } }
private void ParseLogLevelString(string logLevelString) { switch (logLevelString.ToLower()) { case "debug": LogLevel = LogLevel.Debug; Mq.Degub("Set verbosity level to degub."); break; case "degub": LogLevel = LogLevel.Debug; Mq.Degub("Set verbosity level to degub."); break; case "trace": LogLevel = LogLevel.Trace; Mq.Degub("Set verbosity level to trace."); break; case "data": LogLevel = LogLevel.Warn; Mq.Degub("Set verbosity level to data."); break; case "info": LogLevel = LogLevel.Info; Mq.Degub("Set verbosity level to info."); break; default: LogLevel = LogLevel.Info; Mq.Error("Invalid verbosity level " + logLevelString + " falling back to default level (info)."); break; } }
public void SetDomainComputers(string LdapFilter) { DirectorySearch ds = GetDirectorySearcher(); List <string> domainComputers = new List <string>(); try { if (!MyOptions.DfsOnly) { // if we aren't limiting the scan to DFS shares then let's get some computer targets. List <string> ldapPropertiesList = new List <string> { "name", "dNSHostName", "lastLogonTimeStamp" }; string ldapFilter = LdapFilter; // extremely dirty hack to break a sig I once saw for Snaffler's LDAP queries. ;-) int num = random.Next(1, 5); while (num > 0) { Guid guid = Guid.NewGuid(); ldapPropertiesList.Add(guid.ToString()); --num; } string[] ldapProperties = ldapPropertiesList.ToArray(); IEnumerable <SearchResultEntry> searchResultEntries = ds.QueryLdap(ldapFilter, ldapProperties, System.DirectoryServices.Protocols.SearchScope.Subtree); // set a window of "the last 4 months" - if a computer hasn't logged in to the domain in 4 months it's probably gone. DateTime validLltsWindow = DateTime.Now.AddMonths(-4); foreach (SearchResultEntry resEnt in searchResultEntries) { int uacFlags; bool success = int.TryParse(resEnt.GetProperty("userAccountControl"), out uacFlags); UserAccountControlFlags userAccFlags = (UserAccountControlFlags)uacFlags; if (userAccFlags.HasFlag(UserAccountControlFlags.AccountDisabled)) { continue; } try { // get the last logon timestamp value as a datetime string lltsString = resEnt.GetProperty("lastlogontimestamp"); long lltsLong; long.TryParse(lltsString, out lltsLong); DateTime lltsDateTime = DateTime.FromFileTime(lltsLong); // compare it to our window, and if lltsDateTime is older, skip the computer acct. if (lltsDateTime <= validLltsWindow) { continue; } } catch (Exception e) { Mq.Error("Error calculating lastLogonTimeStamp for computer account " + resEnt.DistinguishedName); } if (!String.IsNullOrEmpty(resEnt.GetProperty("dNSHostName"))) { string computerName = resEnt.GetProperty("dNSHostName"); domainComputers.Add(computerName); } } } } catch (Exception e) { Mq.Trace(e.ToString()); } this._domainComputers = domainComputers; }
private void SetDomainUsersAndComputers() { if (!String.IsNullOrEmpty(MyOptions.TargetDc)) { DomainControllers.Add(MyOptions.TargetDc); } else { GetDomainControllers(); } List <string> domainComputers = new List <string>(); List <string> domainUsers = new List <string>(); // we do this so if the first one fails we keep trying til we find a DC we can talk to. foreach (string domainController in DomainControllers) { try { // TODO add support for user defined creds here. using (DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainController)) { using (DirectorySearcher mySearcher = new DirectorySearcher(entry)) { mySearcher.Filter = ("(objectClass=computer)"); // No size limit, reads all objects mySearcher.SizeLimit = 0; // Read data in pages of 250 objects. Make sure this value is below the limit configured in your AD domain (if there is a limit) mySearcher.PageSize = 250; // Let searcher know which properties are going to be used, and only load those mySearcher.PropertiesToLoad.Add("name"); mySearcher.PropertiesToLoad.Add("dNSHostName"); mySearcher.PropertiesToLoad.Add("lastLogonTimeStamp"); foreach (SearchResult resEnt in mySearcher.FindAll()) { // Note: Properties can contain multiple values. if (resEnt.Properties["dNSHostName"].Count > 0) { string computerName = (string)resEnt.Properties["dNSHostName"][0]; domainComputers.Add(computerName); } } } this._domainComputers = domainComputers; if (MyOptions.DomainUserRules) { // now users using (DirectorySearcher mySearcher = new DirectorySearcher(entry)) { mySearcher.Filter = ("(objectClass=user)"); // No size limit, reads all objects mySearcher.SizeLimit = 0; // Read data in pages of 250 objects. Make sure this value is below the limit configured in your AD domain (if there is a limit) mySearcher.PageSize = 250; // Let searcher know which properties are going to be used, and only load those mySearcher.PropertiesToLoad.Add("name"); mySearcher.PropertiesToLoad.Add("adminCount"); mySearcher.PropertiesToLoad.Add("sAMAccountName"); mySearcher.PropertiesToLoad.Add("userAccountControl"); foreach (SearchResult resEnt in mySearcher.FindAll()) { try { //busted account name if (resEnt.Properties["sAMAccountName"].Count == 0) { continue; } int uacFlags; bool succes = int.TryParse(resEnt.Properties["userAccountControl"][0].ToString(), out uacFlags); UserAccountControlFlags userAccFlags = (UserAccountControlFlags)uacFlags; if (userAccFlags.HasFlag(UserAccountControlFlags.AccountDisabled)) { continue; } string userName = (string)resEnt.Properties["sAMAccountName"][0]; // skip computer accounts if (userName.EndsWith("$")) { continue; } if (userName.IndexOf("mailbox", StringComparison.OrdinalIgnoreCase) >= 0) { continue; } if (userName.IndexOf("mbx", StringComparison.OrdinalIgnoreCase) >= 0) { continue; } // if it's got adminCount, keep it if (resEnt.Properties["adminCount"].Count != 0) { if (resEnt.Properties["adminCount"][0].ToString() == "1") { Mq.Trace("Adding " + userName + " to target list because it had adminCount=1."); domainUsers.Add(userName); continue; } } // if the password doesn't expire it's probably a service account if (userAccFlags.HasFlag(UserAccountControlFlags.PasswordDoesNotExpire)) { Mq.Trace("Adding " + userName + " to target list because I think it's a service account."); domainUsers.Add(userName); continue; } if (userAccFlags.HasFlag(UserAccountControlFlags.DontRequirePreauth)) { Mq.Trace("Adding " + userName + " to target list because I think it's a service account."); domainUsers.Add(userName); continue; } if (userAccFlags.HasFlag(UserAccountControlFlags.TrustedForDelegation)) { Mq.Trace("Adding " + userName + " to target list because I think it's a service account."); domainUsers.Add(userName); continue; } if (userAccFlags.HasFlag(UserAccountControlFlags .TrustedToAuthenticateForDelegation)) { Mq.Trace("Adding " + userName + " to target list because I think it's a service account."); domainUsers.Add(userName); continue; } // if it matches a string we like, keep it foreach (string str in MyOptions.DomainUserMatchStrings) { if (userName.ToLower().Contains(str.ToLower())) { Mq.Trace("Adding " + userName + " to target list because it contained " + str + "."); domainUsers.Add(userName); break; } } } catch (Exception e) { Mq.Trace(e.ToString()); continue; } } } } this._domainUsers = domainUsers; } break; } catch (Exception e) { Mq.Trace(e.ToString()); throw; } } }
private void StatusUpdate() { //lock (StatusObjectLocker) //{ // get memory usage for status update string memorynumber; using (Process proc = Process.GetCurrentProcess()) { long memorySize64 = proc.PrivateMemorySize64; memorynumber = BytesToString(memorySize64); } TaskCounters shareTaskCounters = ShareTaskScheduler.Scheduler.GetTaskCounters(); TaskCounters treeTaskCounters = TreeTaskScheduler.Scheduler.GetTaskCounters(); TaskCounters fileTaskCounters = FileTaskScheduler.Scheduler.GetTaskCounters(); StringBuilder updateText = new StringBuilder("Status Update: \n"); updateText.Append("ShareFinder Tasks Completed: " + shareTaskCounters.CompletedTasks + "\n"); updateText.Append("ShareFinder Tasks Remaining: " + shareTaskCounters.CurrentTasksRemaining + "\n"); updateText.Append("ShareFinder Tasks Running: " + shareTaskCounters.CurrentTasksRunning + "\n"); updateText.Append("TreeWalker Tasks Completed: " + treeTaskCounters.CompletedTasks + "\n"); updateText.Append("TreeWalker Tasks Remaining: " + treeTaskCounters.CurrentTasksRemaining + "\n"); updateText.Append("TreeWalker Tasks Running: " + treeTaskCounters.CurrentTasksRunning + "\n"); updateText.Append("FileScanner Tasks Completed: " + fileTaskCounters.CompletedTasks + "\n"); updateText.Append("FileScanner Tasks Remaining: " + fileTaskCounters.CurrentTasksRemaining + "\n"); updateText.Append("FileScanner Tasks Running: " + fileTaskCounters.CurrentTasksRunning + "\n"); updateText.Append(memorynumber + " RAM in use." + "\n"); updateText.Append("\n"); // if all share tasks have finished, reduce max parallelism to 0 and reassign capacity to file scheduler. if (ShareTaskScheduler.Done() && (shareTaskCounters.MaxParallelism >= 1)) { // get the current number of sharetask threads int transferVal = shareTaskCounters.MaxParallelism; // set it to zero ShareTaskScheduler.Scheduler._maxDegreeOfParallelism = 0; // add 1 to the other FileTaskScheduler.Scheduler._maxDegreeOfParallelism = FileTaskScheduler.Scheduler._maxDegreeOfParallelism + transferVal; updateText.Append("ShareScanner queue finished, rebalancing workload." + "\n"); } // do other rebalancing if (fileTaskCounters.CurrentTasksQueued <= (MyOptions.MaxFileQueue / 20)) { // but only if one side isn't already at minimum if (FileTaskScheduler.Scheduler._maxDegreeOfParallelism > 1) { updateText.Append("Insufficient FileScanner queue size, rebalancing workload." + "\n"); --FileTaskScheduler.Scheduler._maxDegreeOfParallelism; ++TreeTaskScheduler.Scheduler._maxDegreeOfParallelism; } } if (fileTaskCounters.CurrentTasksQueued == MyOptions.MaxFileQueue) { if (TreeTaskScheduler.Scheduler._maxDegreeOfParallelism > 1) { updateText.Append("Max FileScanner queue size reached, rebalancing workload." + "\n"); ++FileTaskScheduler.Scheduler._maxDegreeOfParallelism; --TreeTaskScheduler.Scheduler._maxDegreeOfParallelism; } } updateText.Append("Max ShareFinder Threads: " + ShareTaskScheduler.Scheduler._maxDegreeOfParallelism + "\n"); updateText.Append("Max TreeWalker Threads: " + TreeTaskScheduler.Scheduler._maxDegreeOfParallelism + "\n"); updateText.Append("Max FileScanner Threads: " + FileTaskScheduler.Scheduler._maxDegreeOfParallelism + "\n"); DateTime now = DateTime.Now; TimeSpan runSpan = now.Subtract(StartTime); updateText.Append("Been Snafflin' for " + runSpan + " and we ain't done yet..." + "\n"); Mq.Info(updateText.ToString()); if (FileTaskScheduler.Done() && ShareTaskScheduler.Done() && TreeTaskScheduler.Done()) { waitHandle.Set(); } //} }
public bool Parse(string[] args) { Mq.Info("Parsing args..."); var success = false; // define args var outFileArg = new ValueArgument <string>('o', "outfile", "Path for output file. You probably want this if you're not using -s."); var verboseArg = new ValueArgument <string>('v', "verbosity", "Controls verbosity level, options are Trace (most verbose), Debug (less verbose), Info (less verbose still, default), and Data (results only). e.g '-v debug' "); var helpArg = new SwitchArgument('h', "help", "Displays this help.", false); //var extMatchArg = new ValueArgument<string>('e', "extmatch", // "Path to wordlist for searching by exact extension match."); //var nameMatchArg = new ValueArgument<string>('n', "namematch", // "Path to wordlist for searching by exact filename match."); //var grepMatchArg = new ValueArgument<string>('g', "grepmatch", // "Path to wordlist for searching by grepping the contents of files with \"interesting\" extensions."); //var partialMatchArg = new ValueArgument<string>('p', "partialmatch", // "Path to wordlist for searching by partial filename match."); //var pathMatchArg = new ValueArgument<string>('a', "pathmatch", // "Path to wordlist for searching by partial path match."); //var extSkipMatchArg = new ValueArgument<string>('x', "extskipmatch", // "Path to wordlist for extensions that should be skipped."); var stdOutArg = new SwitchArgument('s', "stdout", "Enables outputting results to stdout as soon as they're found. You probably want this if you're not using -o.", false); var mirrorArg = new ValueArgument <string>('m', "mirror", "Enables and assigns an output dir for snaffler to automatically take a copy of any found files."); var fileHuntArg = new SwitchArgument('f', "filehuntoff", "Disables file discovery, will only perform computer and share discovery.", false); var dirTargetArg = new ValueArgument <string>('i', "dirtarget", "Disables computer and share discovery, requires a path to a directory in which to perform file discovery."); var maxThreadsArg = new ValueArgument <int>('t', "threads", "Maximum number of threads. Default 30."); var domainArg = new ValueArgument <string>('d', "domain", "Domain to search for computers to search for shares on to search for files in. Easy."); var adminshareArg = new SwitchArgument('a', "cdolla", "Enables scanning of C$ shares if found. Can be prone to false positives but more thorough.", false); var domainControllerArg = new ValueArgument <string>('c', "domaincontroller", "Domain controller to query for a list of domain computers."); var maxGrepSizeArg = new ValueArgument <long>('r', "maxgrepsize", "The maximum size file (in bytes) to search inside for interesting strings. Defaults to 500k."); var grepContextArg = new ValueArgument <int>('j', "grepcontext", "How many bytes of context either side of found strings in files to show, e.g. -j 200"); // list of letters i haven't used yet: bklquwyz var parser = new CommandLineParser.CommandLineParser(); parser.Arguments.Add(outFileArg); parser.Arguments.Add(helpArg); //parser.Arguments.Add(extMatchArg); //parser.Arguments.Add(nameMatchArg); //parser.Arguments.Add(grepMatchArg); //parser.Arguments.Add(extSkipMatchArg); //parser.Arguments.Add(partialMatchArg); parser.Arguments.Add(stdOutArg); parser.Arguments.Add(mirrorArg); parser.Arguments.Add(fileHuntArg); parser.Arguments.Add(dirTargetArg); parser.Arguments.Add(maxThreadsArg); parser.Arguments.Add(domainArg); parser.Arguments.Add(verboseArg); parser.Arguments.Add(adminshareArg); parser.Arguments.Add(domainControllerArg); parser.Arguments.Add(maxGrepSizeArg); parser.Arguments.Add(grepContextArg); // extra check to handle builtin behaviour from cmd line arg parser if ((args.Contains("--help") || args.Contains("/?") || args.Contains("help") || args.Contains("-h") || args.Length == 0)) { parser.ShowUsage(); Environment.Exit(0); } try { parser.ParseCommandLine(args); // get the args into our config // output args if (outFileArg.Parsed && (outFileArg.Value != null)) { LogToFile = true; LogFilePath = outFileArg.Value; Mq.Degub("Logging to file at " + LogFilePath); } // Set loglevel. if (verboseArg.Parsed) { var logLevelString = verboseArg.Value; switch (logLevelString.ToLower()) { case "debug": LogLevel = LogLevel.Debug; Mq.Degub("Set verbosity level to degub."); break; case "degub": LogLevel = LogLevel.Debug; Mq.Degub("Set verbosity level to degub."); break; case "trace": LogLevel = LogLevel.Trace; Mq.Degub("Set verbosity level to trace."); break; case "data": LogLevel = LogLevel.Warn; Mq.Degub("Set verbosity level to data."); break; default: LogLevel = LogLevel.Info; Mq.Error("Invalid verbosity level " + logLevelString + " falling back to default level (info)."); break; } } // if enabled, display findings to the console LogToConsole = stdOutArg.Parsed; Mq.Degub("Enabled logging to stdout."); if (maxThreadsArg.Parsed) { MaxThreads = maxThreadsArg.Value; Mq.Degub("Max threads set to " + maxThreadsArg.Value); } // args that tell us about targeting if ((domainArg.Parsed) && (domainArg.Value != null)) { TargetDomain = domainArg.Value; Mq.Degub("Target domain is " + domainArg.Value); } if ((domainControllerArg.Parsed) && (domainControllerArg.Value != null)) { TargetDc = domainControllerArg.Value; Mq.Degub("Target DC is " + domainControllerArg.Value); } if (dirTargetArg.Parsed) { ShareFinderEnabled = false; DirTarget = dirTargetArg.Value; Mq.Degub("Disabled finding shares."); Mq.Degub("Target path is " + dirTargetArg.Value); } if (adminshareArg.Parsed) { ScanCDollarShares = true; Mq.Degub("Scanning of C$ shares enabled."); } // if the user passes the various MatchArgs with no value, that disables them. // Otherwise load their wordlist into the appropriate config item. /* * if (extMatchArg.Parsed) * { * if (extMatchArg.Value.Length <= 0) * { * ExactExtensionCheck = false; * Mq.Degub("Disabled matching based on exact file extension match."); * } * else * { * ExtensionsToKeep = File.ReadAllLines(extMatchArg.Value); * Mq.Degub("Using file at " + extMatchArg.Value + " for exact file extension matching."); * } * } * * if (pathMatchArg.Parsed) * { * if (pathMatchArg.Value.Length <= 0) * { * PartialPathCheck = false; * Mq.Degub("Disabled matching based on partial file path."); * } * else * { * PathsToKeep = File.ReadAllLines(pathMatchArg.Value); * Mq.Degub("Using file at " + pathMatchArg.Value + " for partial file path matching."); * } * } * * if (extSkipMatchArg.Parsed) * { * if (extSkipMatchArg.Value.Length <= 0) * { * ExactExtensionSkipCheck = false; * Mq.Degub("Disabled skipping files with extensions on skip-list."); * } * else * { * ExtSkipList = File.ReadAllLines(extSkipMatchArg.Value); * Mq.Degub("Using file at " + extSkipMatchArg.Value + " for extension skip-list."); * } * } * * if (nameMatchArg.Parsed) * { * if (nameMatchArg.Value.Length <= 0) * { * ExactNameCheck = false; * Mq.Degub("Disabled matching based on exact file name"); * } * else * { * FileNamesToKeep = File.ReadAllLines(nameMatchArg.Value); * Mq.Degub("Using file at " + nameMatchArg.Value + " for exact file name matching."); * } * } * * if (grepMatchArg.Parsed) * { * if (grepMatchArg.Value.Length <= 0) * { * GrepByExtensionCheck = false; * Mq.Degub("Disabled matching based on file contents."); * } * else * { * GrepStrings = File.ReadAllLines(grepMatchArg.Value); * Mq.Degub("Using file at " + grepMatchArg.Value + " for file contents matching."); * } * } * * if (partialMatchArg.Parsed) * { * if (partialMatchArg.Value.Length <= 0) * { * PartialNameCheck = false; * Mq.Degub("Disabled partial file name matching."); * } * else * { * NameStringsToKeep = File.ReadAllLines(partialMatchArg.Value); * Mq.Degub("Using file at " + partialMatchArg.Value + " for partial file name matching."); * } * } */ if (maxGrepSizeArg.Parsed) { MaxSizeToGrep = maxGrepSizeArg.Value; Mq.Degub("We won't bother looking inside files if they're bigger than " + MaxSizeToGrep + " bytes"); } // how many bytes if (grepContextArg.Parsed) { GrepContextBytes = grepContextArg.Value; Mq.Degub( "We'll show you " + grepContextArg.Value + " bytes of context around matches inside files."); } // if enabled, grab a copy of files that we like. if (mirrorArg.Parsed) { if (mirrorArg.Value.Length <= 0) { Mq.Error("-m or -mirror arg requires a path value."); throw new ArgumentException("Invalid argument combination."); } EnableMirror = true; MirrorPath = mirrorArg.Value.TrimEnd('\\'); Mq.Degub("Mirroring matched files to path " + MirrorPath); } if (!LogToConsole && !LogToFile) { Mq.Error( "\nYou didn't enable output to file or to the console so you won't see any results or debugs or anything. Your l0ss."); throw new ArgumentException("Pointless argument combination."); } } catch (Exception e) { Mq.Error(e.ToString()); throw; } success = true; return(success); }
public void WalkTree(string currentDir) { // Walks a tree checking files and generating results as it goes. if (!Directory.Exists(currentDir)) { return; } try { string[] files = Directory.GetFiles(currentDir); // check if we actually like the files foreach (string file in files) { FileTaskScheduler.New(() => { try { FileScanner.ScanFile(file); } catch (Exception e) { Mq.Error("Exception in FileScanner task for file " + file); Mq.Trace(e.ToString()); } }); } } catch (UnauthorizedAccessException) { //Mq.Trace(e.ToString()); //continue; } catch (DirectoryNotFoundException) { //Mq.Trace(e.ToString()); //continue; } catch (IOException) { //Mq.Trace(e.ToString()); //continue; } catch (Exception e) { Mq.Degub(e.ToString()); //continue; } try { string[] subDirs = Directory.GetDirectories(currentDir); // Create a new treewalker task for each subdir. if (subDirs.Length >= 1) { foreach (string dirStr in subDirs) { bool scanDir = true; foreach (ClassifierRule classifier in MyOptions.DirClassifiers) { try { DirClassifier dirClassifier = new DirClassifier(classifier); DirResult dirResult = dirClassifier.ClassifyDir(dirStr); if (dirResult.ScanDir == false) { scanDir = false; break; } } catch (Exception e) { Mq.Trace(e.ToString()); continue; } } if (scanDir == true) { TreeTaskScheduler.New(() => { try { WalkTree(dirStr); } catch (Exception e) { Mq.Error("Exception in TreeWalker task for dir " + dirStr); Mq.Error(e.ToString()); } }); } else { Mq.Trace("Skipped scanning on " + dirStr + " due to Discard rule match."); } } } } catch (UnauthorizedAccessException) { //Mq.Trace(e.ToString()); //continue; } catch (DirectoryNotFoundException) { //Mq.Trace(e.ToString()); //continue; } catch (IOException) { //Mq.Trace(e.ToString()); //continue; } catch (Exception e) { Mq.Trace(e.ToString()); //continue; } }
public void WalkTree(string shareRoot) { try { // Walks a tree checking files and generating results as it goes. Stack <string> dirs = new Stack <string>(20); if (!Directory.Exists(shareRoot)) { return; } dirs.Push(shareRoot); while (dirs.Count > 0) { string currentDir = dirs.Pop(); string[] subDirs; try { subDirs = Directory.GetDirectories(currentDir); } catch (UnauthorizedAccessException) { //Mq.Trace(e.ToString()); continue; } catch (DirectoryNotFoundException) { //Mq.Trace(e.ToString()); continue; } catch (Exception e) { Mq.Trace(e.ToString()); continue; } string[] files = null; try { files = Directory.GetFiles(currentDir); } catch (UnauthorizedAccessException) { //Mq.Trace(e.ToString()); continue; } catch (DirectoryNotFoundException) { //Mq.Trace(e.ToString()); continue; } catch (Exception e) { Mq.Trace(e.ToString()); continue; } // check if we actually like the files foreach (string file in files) { FileTaskScheduler.New(() => { try { FileScanner fileScanner = new FileScanner(file); } catch (Exception e) { Mq.Trace(e.ToString()); } }); } // Push the subdirectories onto the stack for traversal if they aren't on any discard-lists etc. foreach (string dirStr in subDirs) { foreach (ClassifierRule classifier in MyOptions.DirClassifiers) { try { DirClassifier dirClassifier = new DirClassifier(classifier); DirResult dirResult = dirClassifier.ClassifyDir(dirStr); // TODO: concurrency uplift: when there is a pooled concurrency queue, just add the dir as a job to the queue if (dirResult.ScanDir) { dirs.Push(dirStr); } } catch (Exception e) { Mq.Trace(e.ToString()); continue; } } } } } catch (Exception e) { Mq.Error(e.ToString()); } }
public void SetDomainUsers() { DirectorySearch ds = GetDirectorySearcher(); List <string> domainUsers = new List <string>(); string[] ldapProperties = new string[] { "name", "adminCount", "sAMAccountName", "userAccountControl", "servicePrincipalName", "userPrincipalName" }; string ldapFilter = "(&(objectClass=user)(objectCategory=person))"; IEnumerable <SearchResultEntry> searchResultEntries = ds.QueryLdap(ldapFilter, ldapProperties, System.DirectoryServices.Protocols.SearchScope.Subtree); foreach (SearchResultEntry resEnt in searchResultEntries) { bool keepUser = false; try { //busted account name if (String.IsNullOrEmpty(resEnt.GetProperty("sAMAccountName"))) { continue; } int uacFlags; bool success = int.TryParse(resEnt.GetProperty("userAccountControl"), out uacFlags); UserAccountControlFlags userAccFlags = (UserAccountControlFlags)uacFlags; if (userAccFlags.HasFlag(UserAccountControlFlags.AccountDisabled)) { continue; } string userName = resEnt.GetProperty("sAMAccountName"); if (userName.EndsWith("$")) { Mq.Trace("Skipping " + userName + " because it appears to be a computer or trust account."); continue; } //skip mailboxy accounts - domains always have a billion of these. if (userName.IndexOf("mailbox", StringComparison.OrdinalIgnoreCase) >= 0) { Mq.Trace("Skipping " + userName + " because it appears to be a mailbox."); continue; } if (userName.IndexOf("mbx", StringComparison.OrdinalIgnoreCase) >= 0) { Mq.Trace("Skipping " + userName + " because it appears to be a mailbox."); continue; } // if has an SPN, keep it if (!keepUser && resEnt.GetProperty("servicePrincipalName") != null) { Mq.Trace("Adding " + userName + " to target list because it has an SPN"); keepUser = true; } // if it's got adminCount, keep it if (!keepUser && resEnt.GetProperty("adminCount") == "1") { Mq.Trace("Adding " + userName + " to target list because it had adminCount=1."); keepUser = true; } // if the password doesn't expire it's probably a service account if (!keepUser && userAccFlags.HasFlag(UserAccountControlFlags.PasswordDoesNotExpire)) { Mq.Trace("Adding " + userName + " to target list because password does not expire, probably service account."); keepUser = true; } if (!keepUser && userAccFlags.HasFlag(UserAccountControlFlags.DontRequirePreauth)) { Mq.Trace("Adding " + userName + " to target list because it doesn't require Kerberos pre-auth."); keepUser = true; } if (!keepUser && userAccFlags.HasFlag(UserAccountControlFlags.TrustedForDelegation)) { Mq.Trace("Adding " + userName + " to target list because it is trusted for delegation."); keepUser = true; } if (!keepUser && userAccFlags.HasFlag(UserAccountControlFlags .TrustedToAuthenticateForDelegation)) { Mq.Trace("Adding " + userName + " to target list because it is trusted for delegation."); keepUser = true; } // Included patterns if (!keepUser) { foreach (string str in MyOptions.DomainUserMatchStrings) { if (userName.ToLower().Contains(str.ToLower())) { Mq.Trace("Adding " + userName + " to target list because it contained " + str + "."); keepUser = true; break; } } } // Finished testing if (!keepUser) { continue; } // Must have matched something // For common/frequent names, force fully-qualified strict formats if (MyOptions.DomainUserStrictStrings.Contains(userName, StringComparer.OrdinalIgnoreCase)) { Mq.Trace("Using strict formats for " + userName + "."); domainUsers.Add(String.Format(@"{0}\{1}", _targetDomainNetBIOSName, userName)); if (!string.IsNullOrEmpty(resEnt.GetProperty("userPrincipalName"))) { domainUsers.Add(resEnt.GetProperty("userPrincipalName")); } continue; } // Otherwise, go with the format preference from the config file foreach (DomainUserNamesFormat dnuf in MyOptions.DomainUserNameFormats) { switch (dnuf) { case DomainUserNamesFormat.NetBIOS: domainUsers.Add(String.Format(@"{0}\{1}", _targetDomainNetBIOSName, userName)); break; case DomainUserNamesFormat.UPN: if (!string.IsNullOrEmpty(resEnt.GetProperty("userPrincipalName"))) { domainUsers.Add(resEnt.GetProperty("userPrincipalName")); } else { Mq.Trace("Adding " + userName + " with simple sAMAccountName because UPN is missing."); domainUsers.Add(userName); } break; case DomainUserNamesFormat.sAMAccountName: domainUsers.Add(userName); break; } } } catch (Exception e) { Mq.Trace(e.ToString()); continue; } } this._domainUsers = domainUsers; }
internal void GetComputerShares(string computer) { // find the shares HostShareInfo[] hostShareInfos = GetHostShareInfo(computer); foreach (HostShareInfo hostShareInfo in hostShareInfos) { string shareName = GetShareName(hostShareInfo, computer); if (!String.IsNullOrWhiteSpace(shareName)) { bool matched = false; // SYSVOL and NETLOGON shares are replicated so they have special logic - do not use Classifiers for these switch (hostShareInfo.shi1_netname.ToUpper()) { case "SYSVOL": if (MyOptions.ScanSysvol == true) { // leave matched as false so that we don't suppress the TreeWalk for the first SYSVOL replica we see // toggle the flag so that any other shares replica will be skipped MyOptions.ScanSysvol = false; break; } matched = true; break; case "NETLOGON": if (MyOptions.ScanNetlogon == true) { // same as SYSVOL above MyOptions.ScanNetlogon = false; break; } matched = true; break; default: // classify them foreach (ClassifierRule classifier in MyOptions.ShareClassifiers) { ShareClassifier shareClassifier = new ShareClassifier(classifier); if (shareClassifier.ClassifyShare(shareName)) { matched = true; break; } } break; } // by default all shares should go on to TreeWalker unless the classifier pulls them out. // send them to TreeWalker if (!matched) { if (IsShareReadable(shareName)) { ShareResult shareResult = new ShareResult() { Listable = true, SharePath = shareName }; Mq.ShareResult(shareResult); Mq.Info("Creating a TreeWalker task for " + shareResult.SharePath); TreeTaskScheduler.New(() => { try { TreeWalker.WalkTree(shareResult.SharePath); } catch (Exception e) { Mq.Error("Exception in TreeWalker task for share " + shareResult.SharePath); Mq.Error(e.ToString()); } }); } } } } }
internal void GetComputerShares(string computer) { // find the shares HostShareInfo[] hostShareInfos = GetHostShareInfo(computer); foreach (HostShareInfo hostShareInfo in hostShareInfos) { // skip IPC$ and PRINT$ shares for #OPSEC!!! List <string> neverScan = new List <string> { "ipc$", "print$" }; if (neverScan.Contains(hostShareInfo.shi1_netname.ToLower())) { continue; } string shareName = GetShareName(hostShareInfo, computer); if (!String.IsNullOrWhiteSpace(shareName)) { bool matched = false; // SYSVOL and NETLOGON shares are replicated so they have special logic - do not use Classifiers for these switch (hostShareInfo.shi1_netname.ToUpper()) { case "SYSVOL": if (MyOptions.ScanSysvol == true) { // Leave matched as false so that we don't suppress the TreeWalk for the first SYSVOL replica we see. // Toggle the flag so that any other shares replica will be skipped MyOptions.ScanSysvol = false; break; } matched = true; break; case "NETLOGON": if (MyOptions.ScanNetlogon == true) { // Same logic as SYSVOL above MyOptions.ScanNetlogon = false; break; } matched = true; break; default: // classify them foreach (ClassifierRule classifier in MyOptions.ShareClassifiers) { ShareClassifier shareClassifier = new ShareClassifier(classifier); if (shareClassifier.ClassifyShare(shareName)) { // in this instance 'matched' means 'matched a discard rule, so don't send to treewalker'. matched = true; break; } } break; } // by default all shares should go on to TreeWalker unless the classifier pulls them out. // send them to TreeWalker if (!matched) { // At least one classifier was matched so we will return this share to the results ShareResult shareResult = new ShareResult() { Listable = true, SharePath = shareName, ShareComment = hostShareInfo.shi1_remark.ToString() }; // Try to find this computer+share in the list of DFS targets /* * foreach (DFSShare dfsShare in MyOptions.DfsShares) * { * ///TODO: Add some logic to match cases where short hostnames is used in DFS target list * if (dfsShare.RemoteServerName.Equals(computer, StringComparison.OrdinalIgnoreCase) && * dfsShare.Name.Equals(hostShareInfo.shi1_netname, StringComparison.OrdinalIgnoreCase)) * { * // why the not operator? if (!MyOptions.DfsNamespacePaths.Contains(dfsShare.DfsNamespacePath)) * if (MyOptions.DfsNamespacePaths.Contains(dfsShare.DfsNamespacePath)) * { * // remove the namespace path to make sure we don't kick it off again. * MyOptions.DfsNamespacePaths.Remove(dfsShare.DfsNamespacePath); * // sub out the \\computer\share path for the dfs namespace path. this makes sure we hit the most efficient endpoint. * shareName = dfsShare.DfsNamespacePath; * } * else // if that dfs namespace has already been removed from our list, skip further scanning of that share. * { * skip = true; * } * * // Found DFS target matching this computer+share - no further comparisons needed * break; * } * } */ // If this path can be accessed via DFS if (MyOptions.DfsSharesDict.ContainsKey(shareName)) { string dfsUncPath = MyOptions.DfsSharesDict[shareName]; Mq.Degub(String.Format("Matched host path {0} to DFS {1}", shareName, dfsUncPath)); // and if we haven't already scanned this share if (MyOptions.DfsNamespacePaths.Contains(dfsUncPath)) { Mq.Degub(String.Format("Will scan {0} using DFS referral instead of explicit host", dfsUncPath)); // sub out the \\computer\share path for the dfs namespace path. this makes sure we hit the most efficient endpoint. shareResult.SharePath = dfsUncPath; // remove the namespace path to make sure we don't kick it off again. MyOptions.DfsNamespacePaths.Remove(dfsUncPath); } else // if that dfs path has already been removed from our list, skip further scanning of that share. { // Do we want to report a gray share result for these? I think not. // Mq.ShareResult(shareResult); break; } } // If the share is readable then dig deeper. if (IsShareReadable(shareResult.SharePath)) { // Share is readable, report as green (the old default/min of the Triage enum ) shareResult.Triage = Triage.Green; try { DirectoryInfo dirInfo = new DirectoryInfo(shareResult.SharePath); //EffectivePermissions.RwStatus rwStatus = effectivePermissions.CanRw(dirInfo); shareResult.RootModifyable = false; shareResult.RootWritable = false; shareResult.RootReadable = true; /* * if (rwStatus.CanWrite || rwStatus.CanModify) * { * triage = Triage.Yellow; * } */ } catch (System.UnauthorizedAccessException e) { Mq.Error("Failed to get permissions on " + shareResult.SharePath); } if (MyOptions.ScanFoundShares) { Mq.Trace("Creating a TreeWalker task for " + shareResult.SharePath); TreeTaskScheduler.New(() => { try { TreeWalker.WalkTree(shareResult.SharePath); } catch (Exception e) { Mq.Error("Exception in TreeWalker task for share " + shareResult.SharePath); Mq.Error(e.ToString()); } }); } Mq.ShareResult(shareResult); } else if (MyOptions.LogDeniedShares == true) { Mq.ShareResult(shareResult); } } } } }
public void SetDfsPaths() { DirectorySearch ds = GetDirectorySearcher(); try { Mq.Degub("Starting DFS Enumeration."); DfsFinder dfsFinder = new DfsFinder(); List <DFSShare> dfsShares = dfsFinder.FindDfsShares(ds); _dfsSharesDict = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase); _dfsNamespacePaths = new List <string>(); string realPath; foreach (DFSShare dfsShare in dfsShares) { // Construct the UNC path to this DFS share and add it to the list. // We use this structure as a to-do list in the ShareFinder code, skipping DFS shares that have already been processed string dfsShareNamespacePath = @"\\" + _targetDomain + @"\" + dfsShare.DFSNamespace; List <string> hostnames = new List <string>(); if (!_dfsNamespacePaths.Contains(dfsShareNamespacePath)) { _dfsNamespacePaths.Add(dfsShareNamespacePath); } // Calculate a long and a short name version for each "real" share path in lowercase. Admins can set either in AD and // we may get either for our scan (depending on how we got our computer list. // This simplifies the cross-referencing of actual server shares back to DFS paths in the ShareFinder code. hostnames.Add(dfsShare.RemoteServerName); if (dfsShare.RemoteServerName.EndsWith(_targetDomain, StringComparison.OrdinalIgnoreCase)) { // share path has FQDN so crack out the short hostname hostnames.Add(dfsShare.RemoteServerName.Split('.')[0]); } else { // share path has short name so append domain for FQDN hostnames.Add(String.Format("{0}.{1}", dfsShare.RemoteServerName, _targetDomain)); } // Add these paths as keys in the dictionary foreach (string h in hostnames) { realPath = String.Format(@"\\{0}\{1}", h, dfsShare.Name); if (!_dfsSharesDict.ContainsKey(realPath)) { _dfsSharesDict.Add(realPath, dfsShareNamespacePath); } } } Mq.Info("Found " + _dfsSharesDict.Count.ToString() + " DFS Shares in " + _dfsNamespacePaths.Count.ToString() + " namespaces."); Mq.Degub("Finished DFS Enumeration."); } catch (Exception e) { Mq.Trace(e.ToString()); } }