public static JObject GetFileDaclJObject(string filePathString) { JObject fileDaclsJObject = new JObject(); FileSecurity filePathSecObj = new FileSecurity(); try { filePathSecObj = File.GetAccessControl(filePathString); } catch (System.ArgumentException e) { Console.WriteLine("Tried to check file permissions on invalid path: " + filePathString.ToString()); return(fileDaclsJObject); } AuthorizationRuleCollection fileAccessRules = filePathSecObj.GetAccessRules(true, true, typeof(SecurityIdentifier)); foreach (FileSystemAccessRule fileAccessRule in fileAccessRules) { // get inheritance and access control type values string isInheritedString = "False"; if (fileAccessRule.IsInherited) { isInheritedString = "True"; } string accessControlTypeString = "Allow"; if (fileAccessRule.AccessControlType == AccessControlType.Deny) { accessControlTypeString = "Deny"; } // get the user's SID string identityReferenceString = fileAccessRule.IdentityReference.ToString(); string displayNameString = LDAPstuff.GetUserFromSid(identityReferenceString); // get the rights string fileSystemRightsString = fileAccessRule.FileSystemRights.ToString(); // strip spaces fileSystemRightsString = fileSystemRightsString.Replace(" ", ""); // turn them into an array string[] fileSystemRightsArray = fileSystemRightsString.Split(','); // then into a JArray JArray fileSystemRightsJArray = new JArray(); foreach (string x in fileSystemRightsArray) { fileSystemRightsJArray.Add(x); } JObject fileDaclJObject = new JObject(); fileDaclJObject.Add("Display Name", displayNameString); fileDaclJObject.Add("Allow or Deny?", accessControlTypeString); fileDaclJObject.Add("Inherited?", isInheritedString); fileDaclJObject.Add("Rights", fileSystemRightsJArray); fileDaclsJObject.Add(identityReferenceString, fileDaclJObject); } return(fileDaclsJObject); }
private JObject GetAssessedGroupMember(JToken member) { JObject assessedMember = new JObject(); assessedMember.Add("Name", Utility.GetSafeString(member, "@name")); assessedMember.Add("Action", Utility.GetSafeString(member, "@action")); string memberSid = Utility.GetSafeString(member, "@sid"); if (memberSid.Length > 0) { assessedMember.Add("SID", memberSid); if (GlobalVar.OnlineChecks) { string resolvedSID = LDAPstuff.GetUserFromSid(memberSid); assessedMember.Add("Display Name From SID", resolvedSID); } } return(assessedMember); }
private static void Main(string[] args) { DateTime grouper2StartTime = DateTime.Now; CommandLineParser.CommandLineParser parser = new CommandLineParser.CommandLineParser(); ValueArgument <string> htmlArg = new ValueArgument <string>('f', "html", "Path for html output file."); SwitchArgument debugArg = new SwitchArgument('v', "verbose", "Enables debug mode. Probably quite noisy and rarely necessary. Will also show you the names of any categories of policies" + " that Grouper saw but didn't have any means of processing. I eagerly await your pull request.", false); SwitchArgument offlineArg = new SwitchArgument('o', "offline", "Disables checks that require LDAP comms with a DC or SMB comms with file shares found in policy settings. Requires that you define a value for -s.", false); ValueArgument <string> sysvolArg = new ValueArgument <string>('s', "sysvol", "Set the path to a domain SYSVOL directory."); ValueArgument <int> intlevArg = new ValueArgument <int>('i', "interestlevel", "The minimum interest level to display. i.e. findings with an interest level lower than x will not be seen in output. Defaults to 1, i.e. show " + "everything except some extremely dull defaults. If you want to see those too, do -i 0."); ValueArgument <int> threadsArg = new ValueArgument <int>('t', "threads", "Max number of threads. Defaults to 10."); ValueArgument <string> domainArg = new ValueArgument <string>('d', "domain", "Domain to query for Group Policy Goodies."); ValueArgument <string> passwordArg = new ValueArgument <string>('p', "password", "Password to use for LDAP operations."); ValueArgument <string> usernameArg = new ValueArgument <string>('u', "username", "Username to use for LDAP operations."); SwitchArgument helpArg = new SwitchArgument('h', "help", "Displays this help.", false); SwitchArgument prettyArg = new SwitchArgument('g', "pretty", "Switches output from the raw Json to a prettier format.", false); SwitchArgument noMessArg = new SwitchArgument('m', "nomess", "Avoids file writes at all costs. May find less stuff.", false); SwitchArgument currentPolOnlyArg = new SwitchArgument('c', "currentonly", "Only checks current policies, ignoring stuff in those " + "Policies_NTFRS_* directories that result from replication failures.", false); SwitchArgument noGrepScriptsArg = new SwitchArgument('n', "nogrepscripts", "Don't grep through the files in the \"Scripts\" subdirectory", false); SwitchArgument quietModeArg = new SwitchArgument('q', "quiet", "Enables quiet mode. Turns off progress counter.", false); parser.Arguments.Add(usernameArg); parser.Arguments.Add(passwordArg); parser.Arguments.Add(debugArg); parser.Arguments.Add(intlevArg); parser.Arguments.Add(sysvolArg); parser.Arguments.Add(offlineArg); parser.Arguments.Add(threadsArg); parser.Arguments.Add(helpArg); parser.Arguments.Add(prettyArg); parser.Arguments.Add(noMessArg); parser.Arguments.Add(currentPolOnlyArg); parser.Arguments.Add(noGrepScriptsArg); parser.Arguments.Add(domainArg); parser.Arguments.Add(htmlArg); parser.Arguments.Add(quietModeArg); // set a few defaults string sysvolDir = ""; GlobalVar.OnlineChecks = true; int maxThreads = 10; bool prettyOutput = false; GlobalVar.NoMess = false; bool noNtfrs = false; bool noGrepScripts = false; string userDefinedDomain = ""; bool htmlOut = false; string htmlOutPath = ""; // extra checks to handle builtin behaviour from cmd line arg parser if ((args.Contains("--help") || args.Contains("/?") || args.Contains("help"))) { parser.ShowUsage(); Environment.Exit(0); } try { parser.ParseCommandLine(args); if (helpArg.Parsed) { foreach (Argument arg in parser.Arguments) { Console.Error.Write("-"); Console.Error.Write(arg.ShortName); Console.Error.Write(" " + arg.LongName); Console.Error.WriteLine(" - " + arg.Description); } Environment.Exit(0); } if (offlineArg.Parsed && offlineArg.Value && sysvolArg.Parsed) { // args config for valid offline run. GlobalVar.OnlineChecks = false; sysvolDir = sysvolArg.Value; } if (offlineArg.Parsed && offlineArg.Value && !sysvolArg.Parsed) { // handle someone trying to run in offline mode without giving a value for sysvol Console.Error.WriteLine( "\nOffline mode requires you to provide a value for -s, the path where Grouper2 can find the domain SYSVOL share, or a copy of it at least."); Environment.Exit(1); } if (intlevArg.Parsed) { // handle interest level parsing Console.Error.WriteLine("\nRoger. Everything with an Interest Level lower than " + intlevArg.Value.ToString() + " is getting thrown on the floor."); GlobalVar.IntLevelToShow = intlevArg.Value; } else { GlobalVar.IntLevelToShow = 1; } if (htmlArg.Parsed) { htmlOut = true; htmlOutPath = htmlArg.Value; } if (debugArg.Parsed) { Console.Error.WriteLine("\nVerbose debug mode enabled. Hope you like yellow."); GlobalVar.DebugMode = true; } if (threadsArg.Parsed) { Console.Error.WriteLine("\nMaximum threads set to: " + threadsArg.Value); maxThreads = threadsArg.Value; } if (sysvolArg.Parsed) { Console.Error.WriteLine("\nYou specified that I should assume SYSVOL is here: " + sysvolArg.Value); sysvolDir = sysvolArg.Value; } if (prettyArg.Parsed) { Console.Error.WriteLine("\nSwitching output to pretty mode. Nice."); prettyOutput = true; } if (noMessArg.Parsed) { Console.Error.WriteLine("\nNo Mess mode enabled. Good for OPSEC, maybe bad for finding all the vulns? All \"Directory Is Writable\" checks will return false."); GlobalVar.NoMess = true; } if (quietModeArg.Parsed) { GlobalVar.QuietMode = true; } if (currentPolOnlyArg.Parsed) { Console.Error.WriteLine("\nOnly looking at current policies and scripts, not checking any of those weird old NTFRS dirs."); noNtfrs = true; } if (domainArg.Parsed) { Console.Error.Write("\nYou told me to talk to domain " + domainArg.Value + " so I'm gonna do that."); if (!(usernameArg.Parsed) || !(passwordArg.Parsed)) { Console.Error.Write("\nIf you specify a domain you need to specify a username and password too using -u and -p."); } userDefinedDomain = domainArg.Value; string[] splitDomain = userDefinedDomain.Split('.'); StringBuilder sb = new StringBuilder(); int pi = splitDomain.Length; int ind = 1; foreach (string piece in splitDomain) { sb.Append("DC=" + piece); if (pi != ind) { sb.Append(","); } ind++; } GlobalVar.UserDefinedDomain = userDefinedDomain; GlobalVar.UserDefinedDomainDn = sb.ToString(); GlobalVar.UserDefinedPassword = passwordArg.Value; GlobalVar.UserDefinedUsername = usernameArg.Value; } if (noGrepScriptsArg.Parsed) { Console.Error.WriteLine("\nNot gonna look through scripts in SYSVOL for goodies."); noGrepScripts = true; } } catch (CommandLineException e) { Console.WriteLine(e.Message); } if (GlobalVar.UserDefinedDomain != null) { Console.Error.WriteLine("\nRunning as user: "******"\\" + GlobalVar.UserDefinedUsername); } else { Console.Error.WriteLine("\nRunning as user: "******"\\" + Environment.UserName); } Console.Error.WriteLine("\nAll online checks will be performed in the context of this user."); if (!prettyOutput) { Output.PrintBanner(); } // Ask the DC for GPO details string currentDomainString = ""; if (GlobalVar.OnlineChecks) { if (userDefinedDomain != "") { currentDomainString = userDefinedDomain; } else { Console.Error.WriteLine("\nTrying to figure out what AD domain we're working with."); try { currentDomainString = Domain.GetCurrentDomain().ToString(); } catch (ActiveDirectoryOperationException e) { Console.Error.WriteLine("\nCouldn't talk to the domain properly. If you're trying to run offline you should use the -o switch. Failing that, try rerunning with -d to specify a domain or -v to get more information about the error."); Utility.Output.DebugWrite(e.ToString()); Environment.Exit(1); } } Console.WriteLine("\nCurrent AD Domain is: " + currentDomainString); // if we're online, get a bunch of metadata about the GPOs via LDAP JObject domainGpos = new JObject(); if (GlobalVar.OnlineChecks) { domainGpos = GetDomainGpoData.DomainGpoData; } Console.WriteLine(""); if (sysvolDir == "") { sysvolDir = @"\\" + currentDomainString + @"\sysvol\" + currentDomainString + @"\"; Console.Error.WriteLine("Targeting SYSVOL at: " + sysvolDir); } } else if ((GlobalVar.OnlineChecks == false) && sysvolDir.Length > 1) { Console.Error.WriteLine("\nTargeting SYSVOL at: " + sysvolDir); } else { Console.Error.WriteLine("\nSomething went wrong with parsing the path to sysvol and I gave up."); Environment.Exit(1); } // get all the dirs with Policies and scripts in an array. string[] sysvolDirs = Directory.GetDirectories(sysvolDir); Console.Error.WriteLine( "\nI found all these directories in SYSVOL..."); Console.Error.WriteLine("#########################################"); foreach (string line in sysvolDirs) { Console.Error.WriteLine(line); } Console.Error.WriteLine("#########################################"); List <string> sysvolPolDirs = new List <string>(); List <string> sysvolScriptDirs = new List <string>(); if (noNtfrs) { Console.Error.WriteLine("... but I'm not going to look in any of them except .\\Policies and .\\Scripts because you told me not to."); sysvolPolDirs.Add(sysvolDir + "Policies\\"); sysvolScriptDirs.Add(sysvolDir + "Scripts\\"); } else { Console.Error.WriteLine("... and I'm going to find all the goodies I can in all of them."); foreach (string dir in sysvolDirs) { if (dir.ToLower().Contains("scripts")) { sysvolScriptDirs.Add(dir); } if (dir.ToLower().Contains("policies")) { sysvolPolDirs.Add(dir); } } } // get all the policy dirs List <string> gpoPaths = new List <string>(); foreach (string policyPath in sysvolPolDirs) { try { gpoPaths = Directory.GetDirectories(policyPath).ToList(); } catch (Exception e) { Console.Error.WriteLine("I had a problem with " + policyPath + ". I guess you could try to fix it?"); Output.DebugWrite(e.ToString()); } } JObject gpoPackageData = new JObject(); // Grab Packages from LDAP if (GlobalVar.OnlineChecks) { gpoPackageData = LDAPstuff.GetGpoPackages(Environment.UserDomainName.ToString()); } // create a JObject to put all our output goodies in. JObject grouper2Output = new JObject(); // so for each uid directory (including ones with that dumb broken domain replication condition) // we're going to gather up all our goodies and put them into that dict we just created. // Create a TaskScheduler LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(maxThreads); List <Task> gpoTasks = new List <Task>(); // create a TaskFactory TaskFactory gpoFactory = new TaskFactory(lcts); CancellationTokenSource gpocts = new CancellationTokenSource(); Console.Error.WriteLine("\n" + gpoPaths.Count.ToString() + " GPOs to process."); Console.Error.WriteLine("\nStarting processing GPOs with " + maxThreads.ToString() + " threads."); JObject taskErrors = new JObject(); // Create a task for each GPO foreach (string gpoPath in gpoPaths) { // skip PolicyDefinitions directory if (gpoPath.Contains("PolicyDefinitions")) { continue; } Task t = gpoFactory.StartNew(() => { try { JObject matchedPackages = new JObject(); if (GlobalVar.OnlineChecks) { // figure out the gpo UID from the path so we can see which packages need to be processed here. string[] gpoPathArr = gpoPath.Split('{'); string gpoPathBackString = gpoPathArr[1]; string[] gpoPathBackArr = gpoPathBackString.Split('}'); string gpoUid = gpoPathBackArr[0].ToString().ToLower(); // see if we have any appropriate matching packages and construct a little bundle foreach (KeyValuePair <string, JToken> gpoPackage in gpoPackageData) { string packageParentGpoUid = gpoPackage.Value["ParentGPO"].ToString().ToLower() .Trim('{', '}'); if (packageParentGpoUid == gpoUid) { JProperty assessedPackage = PackageAssess.AssessPackage(gpoPackage); if (assessedPackage != null) { matchedPackages.Add(assessedPackage); } } } } JObject gpoFindings = ProcessGpo(gpoPath, matchedPackages); if (gpoFindings != null) { if (gpoFindings.HasValues) { lock (grouper2Output) { if (!(gpoPath.Contains("NTFRS"))) { grouper2Output.Add(("Current Policy - " + gpoPath), gpoFindings); } else { grouper2Output.Add(gpoPath, gpoFindings); } } } } } catch (Exception e) { taskErrors.Add(gpoPath, e.ToString()); } }, gpocts.Token); gpoTasks.Add(t); } // put 'em all in a happy little array Task[] gpoTaskArray = gpoTasks.ToArray(); // create a little counter to provide status updates int totalGpoTasksCount = gpoTaskArray.Length; int incompleteTaskCount = gpoTaskArray.Length; int remainingTaskCount = gpoTaskArray.Length; while (remainingTaskCount > 0) { Task[] incompleteTasks = Array.FindAll(gpoTaskArray, element => element.Status != TaskStatus.RanToCompletion); incompleteTaskCount = incompleteTasks.Length; Task[] faultedTasks = Array.FindAll(gpoTaskArray, element => element.Status == TaskStatus.Faulted); int faultedTaskCount = faultedTasks.Length; int completeTaskCount = totalGpoTasksCount - incompleteTaskCount - faultedTaskCount; int percentage = (int)Math.Round((double)(100 * completeTaskCount) / totalGpoTasksCount); string percentageString = percentage.ToString(); if (GlobalVar.QuietMode != true) { Console.Error.Write(""); Console.Error.Write("\r" + completeTaskCount.ToString() + "/" + totalGpoTasksCount.ToString() + " GPOs processed. " + percentageString + "% complete. "); if (faultedTaskCount > 0) { Console.Error.Write(faultedTaskCount.ToString() + " GPOs failed to process."); } } remainingTaskCount = incompleteTaskCount - faultedTaskCount; } // make double sure tasks all finished Task.WaitAll(gpoTasks.ToArray()); gpocts.Dispose(); // do the script grepping if (!(noGrepScripts)) { Console.Error.Write("\n\nProcessing SYSVOL script dirs.\n\n"); JObject processedScriptDirs = ProcessScripts(sysvolScriptDirs); if ((processedScriptDirs != null) && (processedScriptDirs.HasValues)) { grouper2Output.Add("Scripts", processedScriptDirs); } } Console.Error.WriteLine("Errors in processing GPOs:"); Console.Error.WriteLine(taskErrors.ToString()); // Final output is finally happening finally here: if (prettyOutput || htmlOut) { // gotta add a line feed to make sure we're clear to write the nice output. Console.Error.WriteLine("\n"); if (htmlOut) { try { // gotta add a line feed to make sure we're clear to write the nice output. Document htmlDoc = new Document(); htmlDoc.Children.Add(Output.GetG2BannerDocument()); foreach (KeyValuePair <string, JToken> gpo in grouper2Output) { htmlDoc.Children.Add(Output.GetAssessedGpoOutput(gpo)); } ConsoleRenderer.RenderDocument(htmlDoc, new HtmlRenderTarget(File.Create(htmlOutPath), new UTF8Encoding(false))); } catch (UnauthorizedAccessException) { Console.Error.WriteLine("Tried to write html output file but I'm not allowed."); } } if (prettyOutput) { Document prettyDoc = new Document(); prettyDoc.Children.Add(Output.GetG2BannerDocument()); foreach (KeyValuePair <string, JToken> gpo in grouper2Output) { prettyDoc.Children.Add(Output.GetAssessedGpoOutput(gpo)); } ConsoleRenderer.RenderDocument(prettyDoc); } } else { Console.WriteLine(grouper2Output); Console.Error.WriteLine("If you find yourself thinking 'wtf this is very ugly and hard to read', consider trying the -g argument."); } // get the time it took to do the thing and give to user DateTime grouper2EndTime = DateTime.Now; TimeSpan grouper2RunTime = grouper2EndTime.Subtract(grouper2StartTime); string grouper2RunTimeString = $"{grouper2RunTime.Hours}:{grouper2RunTime.Minutes}:{grouper2RunTime.Seconds}:{grouper2RunTime.Milliseconds}"; Console.WriteLine("Grouper2 took " + grouper2RunTimeString + " to run."); if (GlobalVar.CleanupList != null) { List <string> cleanupList = Util.DedupeList(GlobalVar.CleanupList); if (cleanupList.Count >= 1) { Console.WriteLine("\n\nGrouper2 tried to create these files. It probably failed, but just in case it didn't, you might want to check and clean them up.\n"); foreach (string path in cleanupList) { Console.WriteLine(path); } } } // FINISHED! bool isDebuggerAttached = System.Diagnostics.Debugger.IsAttached; if (isDebuggerAttached) { Console.Error.WriteLine("Press any key to Exit"); Console.ReadKey(); } Environment.Exit(0); }
public static JObject AssessPrivRights(JToken privRights) { JObject jsonData = JankyDb.Instance; JArray intPrivRights = (JArray)jsonData["privRights"]["item"]; // create an object to put the results in Dictionary <string, Dictionary <string, string> > matchedPrivRights = new Dictionary <string, Dictionary <string, string> >(); //set an intentionally non-matchy domainSid value unless we doing online checks. string domainSid = "X"; if (GlobalVar.OnlineChecks) { domainSid = LDAPstuff.GetDomainSid(); } foreach (JProperty privRight in privRights.Children <JProperty>()) { foreach (JToken intPrivRight in intPrivRights) { // if the priv is interesting if ((string)intPrivRight["privRight"] == privRight.Name) { //create a dict to put the trustees into Dictionary <string, string> trusteesDict = new Dictionary <string, string>(); //then for each trustee it's granted to foreach (string trustee in privRight.Value) { string displayName = "unknown"; // clean up the trustee SID string trusteeClean = trustee.Trim('*'); JToken checkedSid = Utility.CheckSid(trusteeClean); // display some info if they match. if (checkedSid != null) { displayName = (string)checkedSid["displayName"]; } // if they don't match, handle that. else { if (GlobalVar.OnlineChecks) { try { if (trusteeClean.StartsWith(domainSid)) { string resolvedSid = LDAPstuff.GetUserFromSID(trusteeClean); displayName = resolvedSid; } } catch (IdentityNotMappedException e) { displayName = "Failed to resolve SID"; } //LDAPStuff.ResolveSID? //TODO: look up unknown SIDS in the domain if we can. } } trusteesDict.Add(trusteeClean, displayName); } // add the results to our dictionary of trustees string matchedPrivRightName = privRight.Name; matchedPrivRights.Add(matchedPrivRightName, trusteesDict); } } } // cast our dict to a jobject and return it. JObject matchedPrivRightsJson = (JObject)JToken.FromObject(matchedPrivRights); return(matchedPrivRightsJson); }
public static JObject GetFileDaclJObject(string filePathString) { if (!GlobalVar.OnlineChecks) { return(new JObject()); } JObject fileDaclsJObject = new JObject(); FileSecurity filePathSecObj; try { filePathSecObj = File.GetAccessControl(filePathString); } catch (ArgumentException) { Console.WriteLine("Tried to check file permissions on invalid path: " + filePathString); return(null); } catch (UnauthorizedAccessException e) { if (GlobalVar.DebugMode) { DebugWrite(e.ToString()); } return(null); } AuthorizationRuleCollection fileAccessRules = filePathSecObj.GetAccessRules(true, true, typeof(SecurityIdentifier)); foreach (FileSystemAccessRule fileAccessRule in fileAccessRules) { // get inheritance and access control type values string isInheritedString = "False"; if (fileAccessRule.IsInherited) { isInheritedString = "True"; } string accessControlTypeString = "Allow"; if (fileAccessRule.AccessControlType == AccessControlType.Deny) { accessControlTypeString = "Deny"; } // get the user's SID string identityReferenceString = fileAccessRule.IdentityReference.ToString(); string displayNameString = LDAPstuff.GetUserFromSid(identityReferenceString); // get the rights string fileSystemRightsString = fileAccessRule.FileSystemRights.ToString(); // strip spaces fileSystemRightsString = fileSystemRightsString.Replace(" ", ""); // turn them into an array string[] fileSystemRightsArray = fileSystemRightsString.Split(','); // then into a JArray JArray fileSystemRightsJArray = new JArray(); foreach (string x in fileSystemRightsArray) { fileSystemRightsJArray.Add(x); } JObject fileDaclJObject = new JObject { { accessControlTypeString, displayNameString }, { "Inherited?", isInheritedString }, { "Rights", fileSystemRightsJArray } }; try { fileDaclsJObject.Merge(fileDaclJObject, new JsonMergeSettings { // union array values together to avoid duplicates MergeArrayHandling = MergeArrayHandling.Union }); //fileDaclsJObject.Add((identityReferenceString + " - " + accessControlTypeString), fileDaclJObject); } catch (ArgumentException e) { if (GlobalVar.DebugMode) { DebugWrite(e.ToString()); DebugWrite("\n" + "Trying to Add:"); DebugWrite(fileDaclJObject.ToString()); DebugWrite("\n" + "To:"); DebugWrite(fileDaclsJObject.ToString()); } } } return(fileDaclsJObject); }
private static void Main(string[] args) { Utility.PrintBanner(); string sysvolPolDir = ""; JObject domainGpos = new JObject(); // Ask the DC for GPO details if (args.Length == 0) { Console.WriteLine("Trying to figure out what AD domain we're working with."); string currentDomainString = Domain.GetCurrentDomain().ToString(); Console.WriteLine("Current AD Domain is: " + currentDomainString); sysvolPolDir = @"\\" + currentDomainString + @"\sysvol\" + currentDomainString + @"\Policies\"; Utility.DebugWrite("SysvolPolDir is " + sysvolPolDir); GlobalVar.OnlineChecks = true; } // or if the user gives a path argument, just look for policies in there if (args.Length == 1) { Console.WriteLine("OK, I trust you know where you're aiming me."); sysvolPolDir = args[0]; } Console.WriteLine("We gonna look at the policies in: " + sysvolPolDir); if (GlobalVar.OnlineChecks) { domainGpos = LDAPstuff.GetDomainGpos(); } string[] gpoPaths = Directory.GetDirectories(sysvolPolDir); // create a dict to put all our output goodies in. Dictionary <string, JObject> grouper2OutputDict = new Dictionary <string, JObject>(); foreach (var gpoPath in gpoPaths) { // create a dict to put the stuff we find for this GPO into. Dictionary <string, JObject> gpoResultDict = new Dictionary <string, JObject>(); // // Get the UID of the GPO from the file path. string[] splitPath = gpoPath.Split(Path.DirectorySeparatorChar); string gpoUid = splitPath[splitPath.Length - 1]; // Make a JObject for GPO metadata JObject gpoPropsJson = new JObject(); // If we're online and talking to the domain, just use that data if (GlobalVar.OnlineChecks) { JToken domainGpo = domainGpos[gpoUid]; gpoPropsJson = (JObject)JToken.FromObject(domainGpo); } // otherwise do what we can with what we have else { Dictionary <string, string> gpoPropsDict = new Dictionary <string, string>(); gpoPropsDict.Add("GPO UID", gpoUid); gpoPropsDict.Add("GPO Path", gpoPath); gpoPropsJson = (JObject)JToken.FromObject(gpoPropsDict); } // TODO (and put in GPOProps) // get the policy owner // get whether it's linked and where // get whether it's enabled // Get the paths for the machine policy and user policy dirs string machinePolPath = Path.Combine(gpoPath, "Machine"); string userPolPath = Path.Combine(gpoPath, "User"); // Process Inf and Xml Policy data for machine and user JObject machinePolInfResults = ProcessInf(machinePolPath); JObject userPolInfResults = ProcessInf(userPolPath); JObject machinePolGppResults = ProcessGpXml(machinePolPath); JObject userPolGppResults = ProcessGpXml(userPolPath); // Add all this crap into a dict gpoResultDict.Add("GPOProps", gpoPropsJson); //gpoResultDict.Add("Machine Policy from GPP XML files", machinePolGppResults); //gpoResultDict.Add("User Policy from GPP XML files", userPolGppResults); gpoResultDict.Add("Machine Policy from Inf files", machinePolInfResults); gpoResultDict.Add("User Policy from Inf files", userPolInfResults); // turn dict of data for this gpo into jobj JObject gpoResultJson = (JObject)JToken.FromObject(gpoResultDict); // put into final jobj grouper2OutputDict.Add(gpoPath, gpoResultJson); // TODO // Parse other inf sections: // System Access // Kerberos Policy // Event Audit // Registry Values // Registry Keys // Group Membership // Service General Setting // Parse XML files // Parse ini files // Grep scripts for creds. // File permissions for referenced files. } // Final output is finally happening finally here: Utility.DebugWrite("Final Output:"); JObject grouper2OutputJson = (JObject)JToken.FromObject(grouper2OutputDict); Console.WriteLine(""); Console.WriteLine(grouper2OutputJson); Console.WriteLine(""); Console.WriteLine("This"); Console.WriteLine(Utility.CanIWrite("C:\\temp\\thing.txt").ToString()); // wait for 'anykey' Console.ReadKey(); }
static void Main(string[] args) { Utility.PrintBanner(); JObject JSonData = JankyDB.Instance; JObject JSonData2 = JankyDB.Instance; string SysvolPolDir = ""; JObject DomainGPOs = new JObject(); // Ask the DC for GPO details if (args.Length == 0) { Console.WriteLine("Trying to figure out what AD domain we're workin with."); Domain CurrentDomain = Domain.GetCurrentDomain(); string CurrentDomainString = CurrentDomain.ToString(); Console.WriteLine("Current AD Domain is: " + CurrentDomainString); SysvolPolDir = @"\\" + CurrentDomainString + @"\sysvol\" + CurrentDomainString + @"\Policies\"; Utility.DebugWrite("SysvolPolDir is " + SysvolPolDir); GlobalVar.OnlineChecks = true; } if (args.Length == 1) { Console.WriteLine("OK, I trust you know where you're aiming me."); SysvolPolDir = args[0]; } Console.WriteLine("We gonna look at the policies in: " + SysvolPolDir); if (GlobalVar.OnlineChecks) { DomainGPOs = LDAPstuff.GetDomainGPOs(); } string[] GPOPaths = Directory.GetDirectories(SysvolPolDir); // create a dict to put all our output goodies in. Dictionary <string, JObject> Grouper2OutputDict = new Dictionary <string, JObject>(); foreach (string GPOPath in GPOPaths) { // create a dict to put the stuff we find for this GPO into. Dictionary <string, JObject> GPOResultDict = new Dictionary <string, JObject>(); Dictionary <string, string> GPOPropsDict = new Dictionary <string, string>(); // Get the UID of the GPO from the file path. char DirSeparator = Path.DirectorySeparatorChar; char[] SplitChars = new char[] { DirSeparator }; string[] SplitPath = GPOPath.Split(SplitChars); string GPOUID = SplitPath[(SplitPath.Length - 1)]; // Set some properties of the GPO we're looking at in our output file. GPOPropsDict.Add("GPO UID", GPOUID); GPOPropsDict.Add("GPO Path", GPOPath); if (GlobalVar.OnlineChecks) { JToken DomainGPO = DomainGPOs[GPOUID]; GPOPropsDict.Add("Display Name", DomainGPO["DisplayName"].ToString()); GPOPropsDict.Add("Distinguished Name", DomainGPO["DistinguishedName"].ToString()); GPOPropsDict.Add("GPO SDDL", DomainGPO["SDDL"].ToString()); } // TODO (and put in GPOProps) // look up the friendly name of the policy // get the policy ACLs // get the policy owner // get whether it's linked and where // get whether it's enabled // start processing files string[] MachinePolPathArray = { GPOPath, "Machine" }; string[] UserPolPathArray = { GPOPath, "User" }; string MachinePolPath = Path.Combine(MachinePolPathArray); string UserPolPath = Path.Combine(UserPolPathArray); JObject MachinePolInfResults = ProcessInf(MachinePolPath); JObject UserPolInfResults = ProcessInf(UserPolPath); JObject MachinePolGPPResults = ProcessGPXml(MachinePolPath); JObject UserPolGPPResults = ProcessGPXml(UserPolPath); JObject GPOPropsJson = (JObject)JToken.FromObject(GPOPropsDict); GPOResultDict.Add("GPOProps", GPOPropsJson); GPOResultDict.Add("Machine Policy from GPP XML files", MachinePolGPPResults); GPOResultDict.Add("User Policy from GPP XML files", UserPolGPPResults); GPOResultDict.Add("Machine Policy from Inf files", MachinePolInfResults); GPOResultDict.Add("User Policy from Inf files", MachinePolInfResults); JObject GPOResultJson = (JObject)JToken.FromObject(GPOResultDict); Grouper2OutputDict.Add(GPOPath, GPOResultJson); // TODO // Parse other inf sections: // System Access // Kerberos Policy // Event Audit // Registry Values // Registry Keys // Group Membership // Service General Setting // Parse XML files // Parse ini files // Grep scripts for creds. // File permissions for referenced files. } // Final output is finally happening here: Utility.DebugWrite("Final Output:"); JObject Grouper2OutputJson = (JObject)JToken.FromObject(Grouper2OutputDict); Console.WriteLine(Grouper2OutputJson.ToString()); Console.ReadKey(); }
private static void Main(string[] args) { Utility.PrintBanner(); CommandLineParser.CommandLineParser parser = new CommandLineParser.CommandLineParser(); SwitchArgument debugArg = new SwitchArgument('d', "debug", "Enables debug mode. Will also show you the names of any categories of policies that Grouper saw but didn't have any means of processing. I eagerly await your pull request.", false); SwitchArgument offlineArg = new SwitchArgument('o', "offline", "Disables checks that require LDAP comms with a DC or SMB comms with file shares found in policy settings. Requires that you define a value for --sysvol.", false); ValueArgument <string> sysvolArg = new ValueArgument <string>('s', "sysvol", "Set the path to a domain SYSVOL directory."); ValueArgument <int> intlevArg = new ValueArgument <int>('i', "interestlevel", "The minimum interest level to display. i.e. findings with an interest level lower than x will not be seen in output. Defaults to 1, i.e. show everything except some extremely dull defaults. If you want to see those too, do -i 0."); //ValueArgument<string> domainArg = new ValueArgument<string>('d', "domain", "The domain to connect to. If not specified, connects to current user context domain."); //ValueArgument<string> usernameArg = new ValueArgument<string>('u', "username", "Username to authenticate as. SMB permissions checks will be run from this user's perspective."); //ValueArgument<string> passwordArg = new ValueArgument<string>('p', "password", "Password to use for authentication."); //parser.Arguments.Add(domainArg); //parser.Arguments.Add(usernameArg); //parser.Arguments.Add(passwordArg); parser.Arguments.Add(debugArg); parser.Arguments.Add(intlevArg); parser.Arguments.Add(sysvolArg); parser.Arguments.Add(offlineArg); // set a couple of defaults string sysvolPolDir = ""; GlobalVar.OnlineChecks = true; try { parser.ParseCommandLine(args); //parser.ShowParsedArguments(); if (debugArg.Parsed && debugArg.Value) { GlobalVar.DebugMode = true; } if (offlineArg.Parsed && offlineArg.Value && sysvolArg.Parsed) { // args config for valid offline run. GlobalVar.OnlineChecks = false; sysvolPolDir = sysvolArg.Value; } if (offlineArg.Parsed && offlineArg.Value && !sysvolArg.Parsed) { // handle someone trying to run in offline mode without giving a value for sysvol Console.WriteLine("Offline mode requires you to provide a value for -s, the path where Grouper2 can find the domain SYSVOL share, or a copy of it at least."); Environment.Exit(1); } if (intlevArg.Parsed) { // handle interest level parsing Console.WriteLine("Roger. Everything with an Interest Level lower than " + intlevArg.Value.ToString() + " is getting thrown on the floor."); GlobalVar.IntLevelToShow = intlevArg.Value; } else { GlobalVar.IntLevelToShow = 1; } if (sysvolArg.Parsed) { sysvolPolDir = sysvolArg.Value; } //if (domainArg.Parsed || usernameArg.Parsed || passwordArg.Parsed) //{ // Console.WriteLine("I haven't set up anything to handle the domain/password stuff yet, so it won't work"); // Environment.Exit(1); //} } catch (CommandLineException e) { Console.WriteLine(e.Message); } JObject domainGpos = new JObject(); // Ask the DC for GPO details if (GlobalVar.OnlineChecks) { Console.WriteLine("Trying to figure out what AD domain we're working with."); string currentDomainString = Domain.GetCurrentDomain().ToString(); Console.WriteLine("Current AD Domain is: " + currentDomainString); if (sysvolPolDir == "") { sysvolPolDir = @"\\" + currentDomainString + @"\sysvol\" + currentDomainString + @"\Policies\"; } } Console.WriteLine("Targeting SYSVOL at: " + sysvolPolDir); // if we're online, get a bunch of metadata about the GPOs via LDAP if (GlobalVar.OnlineChecks) { domainGpos = LDAPstuff.GetDomainGpos(); } string[] gpoPaths = new string[0]; try { gpoPaths = Directory.GetDirectories(sysvolPolDir); } catch { Console.WriteLine("Sysvol path is broken. You should fix it."); Environment.Exit(1); } // create a JObject to put all our output goodies in. JObject grouper2Output = new JObject(); // so for each uid directory (including ones with that dumb broken domain replication condition) // we're going to gather up all our goodies and put them into that dict we just created. foreach (var gpoPath in gpoPaths) { // create a dict to put the stuff we find for this GPO into. JObject gpoResult = new JObject(); // Get the UID of the GPO from the file path. string[] splitPath = gpoPath.Split(Path.DirectorySeparatorChar); string gpoUid = splitPath[splitPath.Length - 1]; // Make a JObject for GPO metadata JObject gpoProps = new JObject(); // If we're online and talking to the domain, just use that data if (GlobalVar.OnlineChecks) { JToken domainGpo = domainGpos[gpoUid]; gpoProps = (JObject)JToken.FromObject(domainGpo); } // otherwise do what we can with what we have else { gpoProps = new JObject() { { "gpoUID", gpoUid }, { "gpoPath", gpoPath } }; } // TODO (and put in GPOProps) // get the policy owner // get whether it's linked and where // get whether it's enabled // Add all this crap into a dict, if we found anything of interest. gpoResult.Add("GPOProps", gpoProps); // turn dict of data for this gpo into jobj JObject gpoResultJson = (JObject)JToken.FromObject(gpoResult); // if I were smarter I would have done this shit with the machine and user dirs inside the Process methods instead of calling each one twice out here. // @liamosaur you reckon you can see how to clean it up after the fact? // Get the paths for the machine policy and user policy dirs string machinePolPath = Path.Combine(gpoPath, "Machine"); string userPolPath = Path.Combine(gpoPath, "User"); // Process Inf and Xml Policy data for machine and user JArray machinePolInfResults = ProcessInf(machinePolPath); JArray userPolInfResults = ProcessInf(userPolPath); JArray machinePolGppResults = ProcessGpXml(machinePolPath); JArray userPolGppResults = ProcessGpXml(userPolPath); JArray machinePolScriptResults = ProcessScriptsIni(machinePolPath); JArray userPolScriptResults = ProcessScriptsIni(userPolPath); // add all our findings to a JArray in what seems a very inefficient manner. JArray userFindings = new JArray(); JArray machineFindings = new JArray(); if (machinePolGppResults != null && machinePolGppResults.HasValues) { foreach (JObject finding in machinePolGppResults) { machineFindings.Add(finding); } } if (userPolGppResults != null && userPolGppResults.HasValues) { foreach (JObject finding in userPolGppResults) { userFindings.Add(finding); } } if (machinePolGppResults != null && machinePolInfResults.HasValues) { foreach (JObject finding in machinePolInfResults) { machineFindings.Add(finding); } } if (userPolInfResults != null && userPolInfResults.HasValues) { foreach (JObject finding in userPolInfResults) { userFindings.Add(finding); } } if (machinePolScriptResults != null && machinePolScriptResults.HasValues) { foreach (JObject finding in machinePolScriptResults) { machineFindings.Add(finding); } } if (userPolScriptResults != null && userPolScriptResults.HasValues) { foreach (JObject finding in userPolScriptResults) { userFindings.Add(finding); } } // if there are any Findings, add it to the final output. if (userFindings.HasValues) { JProperty userFindingsJProp = new JProperty("Findings in User Policy", userFindings); gpoResultJson.Add(userFindingsJProp); } if (machineFindings.HasValues) { JProperty machineFindingsJProp = new JProperty("Findings in Machine Policy", machineFindings); gpoResultJson.Add(machineFindingsJProp); } // put into final output if (userFindings.HasValues || machineFindings.HasValues) { grouper2Output.Add(gpoPath, gpoResultJson); } } // Final output is finally happening finally here: Console.WriteLine("RESULT!"); Console.WriteLine(""); Console.WriteLine(grouper2Output); Console.WriteLine(""); // wait for 'anykey' Console.ReadKey(); }