-
Notifications
You must be signed in to change notification settings - Fork 293
/
RuntimeSettings.cs
486 lines (443 loc) · 17.2 KB
/
RuntimeSettings.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
using PingCastle.ADWS;
using PingCastle.Exports;
using PingCastle.Report;
using PingCastle.Scanners;
using PingCastle.Cloud.Common;
using PingCastle.Cloud.Credentials;
using PingCastle.Cloud.RESTServices.Azure;
using PingCastle.Cloud.Tokens;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Security;
using PingCastleCommon;
namespace PingCastle
{
public enum DisplayState
{
Exit,
MainMenu,
ScannerMenu,
Run,
AvancedMenu,
AskForScannerParameter,
ProtocolMenu,
ExportMenu,
}
public class RuntimeSettings
{
public bool InteractiveMode { get; set; }
public string Server { get; set; }
public int Port { get; set; }
public NetworkCredential Credential { get; set; }
// must exists
public string InputFile { get; set; }
// must exists
public string InputDirectory { get; set; }
public Type Scanner { get; set; }
public Type Export { get; set; }
public IAzureCredential AzureCredential { get; set; }
public string User { get; set; }
public string Userdomain { get; set; }
public SecureString Password { get; set; }
public string InitForExportAsGuest { get; set; }
public string sendXmlTo;
public string sendHtmlTo;
public string sendAllTo;
public string sharepointdirectory;
public string sharepointuser;
public string sharepointpassword;
public string CenterDomainForSimpliedGraph = null;
public bool ExploreTerminalDomains;
public bool ExploreForestTrust;
public List<string> DomainToNotExplore;
public bool EncryptReport = false;
public string mailNotification;
public string smtpLogin;
public string smtpPassword;
public DateTime FilterReportDate = DateTime.MaxValue;
public bool smtpTls;
public string apiEndpoint;
public string apiKey;
public bool AnalyzeReachableDomains;
public string botPipe;
internal string privateKey = null;
internal string tenantid = null;
internal string clientid = null;
internal string thumbprint = null;
internal string p12file = null;
internal string p12pass = null;
internal bool p12passSet = false;
internal bool usePrt = false;
private bool CheckCertificate()
{
if (!string.IsNullOrEmpty(thumbprint) || !string.IsNullOrEmpty(privateKey))
{
if (string.IsNullOrEmpty(thumbprint))
{
WriteInRed("--thumbprint must be completed when --private-key is set");
return false;
}
if (string.IsNullOrEmpty(privateKey))
{
WriteInRed("--private-key must be completed when --thumbprint is set");
return false;
}
if (string.IsNullOrEmpty(clientid))
{
WriteInRed("--clientid must be set when certificate authentication is configured");
return false;
}
if (string.IsNullOrEmpty(tenantid))
{
WriteInRed("--tenantid must be set when certificate authentication is configured");
return false;
}
if (!string.IsNullOrEmpty(p12file))
{
WriteInRed("--p12-file cannot be combined with --private-key");
return false;
}
}
return true;
}
public bool CheckArgs()
{
return true;
//return CheckCertificate();
}
#region display menu
public DisplayState EnsureDataCompleted(params string[] requirements)
{
if (requirements.Contains("Scanner"))
{
if (Scanner == null)
{
var state = DisplayScannerMenu();
if (state != DisplayState.Run)
return state;
}
}
if (requirements.Contains("Export"))
{
if (Export == null)
{
var state = DisplayExportMenu();
if (state != DisplayState.Run)
return state;
}
}
if (requirements.Contains("Server"))
{
if (InteractiveMode)
{
var state = DisplayAskServer();
if (state != DisplayState.Run)
return state;
}
if (string.IsNullOrEmpty(Server))
{
Server = IPGlobalProperties.GetIPGlobalProperties().DomainName;
}
if (string.IsNullOrEmpty(Server))
{
WriteInRed("This computer is not connected to a domain. The program couldn't guess the domain or server to connect.");
WriteInRed("Please run again this program with the flag --server <my.domain.com> or --server <mydomaincontroller.my.domain.com>");
return DisplayState.Exit;
}
if (!string.IsNullOrEmpty(User))
{
if (Password == null)
{
if (!AskCredential())
return DisplayState.Exit;
}
if (!string.IsNullOrEmpty(Userdomain))
{
Credential = new NetworkCredential(User, Password, Userdomain);
}
else
{
Credential = new NetworkCredential(User, Password);
}
}
}
if (requirements.Contains("AzureADCredential") || requirements.Contains("AzureADTenant"))
{
if (AzureCredential == null)
{
if (!string.IsNullOrEmpty(privateKey))
{
var key = File.ReadAllText(privateKey);
AzureCredential = CertificateCredential.LoadFromKeyFile(clientid, tenantid, key, thumbprint);
}
if (!string.IsNullOrEmpty(p12file))
{
AzureCredential = CertificateCredential.LoadFromP12(clientid, tenantid, p12file, p12pass);
}
if (usePrt)
{
AzureCredential = new PRTCredential(tenantid);
}
}
if (AzureCredential == null)
{
var state = DisplayAskAzureADCredential();
if (state != DisplayState.Run)
return state;
}
}
if (requirements.Contains("AzureADTenant"))
{
var state = DisplayAskAzureADTenant();
if (state != DisplayState.Run)
return state;
}
if (requirements.Contains("File"))
{
var state = DisplayAskForFile();
if (state != DisplayState.Run)
return state;
}
if (requirements.Contains("Directory"))
{
if (string.IsNullOrEmpty(InputDirectory))
{
InputDirectory = Directory.GetCurrentDirectory();
}
if (!Directory.Exists(InputDirectory))
{
WriteInRed("No input directory has been provided");
return DisplayState.Exit;
}
}
if (requirements.Contains("AzureADSeed"))
{
var state = DisplayAskForSeed();
if (state != DisplayState.Run)
return state;
}
return DisplayState.Run;
}
public DisplayState DisplayScannerMenu()
{
var scanners = PingCastleFactory.GetAllScanners();
var choices = new List<ConsoleMenuItem>();
foreach (var scanner in scanners)
{
Type scannerType = scanner.Value;
IScanner iscanner = PingCastleFactory.LoadScanner(scannerType);
string description = iscanner.Description;
choices.Add(new ConsoleMenuItem(scanner.Key, description));
}
choices.Sort((ConsoleMenuItem a, ConsoleMenuItem b)
=>
{
return String.Compare(a.Choice, b.Choice);
}
);
ConsoleMenu.Notice = "WARNING: Checking a lot of workstations may raise security alerts.";
ConsoleMenu.Title = "Select a scanner";
ConsoleMenu.Information = "What scanner whould you like to run ?";
int choice = ConsoleMenu.SelectMenuCompact(choices, 1);
if (choice == 0)
{
return DisplayState.Exit;
}
Scanner = scanners[choices[choice - 1].Choice];
return DisplayState.Run;
}
public DisplayState DisplayExportMenu()
{
var exports = PingCastleFactory.GetAllExport();
var choices = new List<ConsoleMenuItem>();
foreach (var export in exports)
{
Type exportType = export.Value;
IExport iexport = PingCastleFactory.LoadExport(exportType);
string description = iexport.Description;
choices.Add(new ConsoleMenuItem(export.Key, description));
}
choices.Sort((ConsoleMenuItem a, ConsoleMenuItem b)
=>
{
return String.Compare(a.Choice, b.Choice);
}
);
ConsoleMenu.Title = "Select an export";
ConsoleMenu.Information = "What export whould you like to run ?";
int choice = ConsoleMenu.SelectMenu(choices, 1);
if (choice == 0)
{
return DisplayState.Exit;
}
Export = exports[choices[choice - 1].Choice];
return DisplayState.Run;
}
DisplayState DisplayAskServer()
{
var defaultServer = IPGlobalProperties.GetIPGlobalProperties().DomainName;
while (true)
{
if (!String.IsNullOrEmpty(defaultServer) || string.Equals(defaultServer, "(None)", StringComparison.OrdinalIgnoreCase))
{
ConsoleMenu.Information = "Please specify the domain or server to investigate (default:" + defaultServer + ")";
}
else
{
ConsoleMenu.Information = "Please specify the domain or server to investigate:";
}
ConsoleMenu.Title = "Select a domain or server";
Server = ConsoleMenu.AskForString();
if (!String.IsNullOrEmpty(Server))
{
break;
}
if (!string.IsNullOrEmpty(defaultServer))
{
Server = defaultServer;
break;
}
}
return DisplayState.Run;
}
private DisplayState DisplayAskAzureADCredential()
{
List<ConsoleMenuItem> choices = new List<ConsoleMenuItem>() {
new ConsoleMenuItem("askcredential","Ask credentials", "The identity may be asked multiple times during the healthcheck."),
};
var tokens = TokenFactory.GetRegisteredPRTIdentities();
if (tokens.Count > 0)
{
choices.Insert(0, new ConsoleMenuItem("useprt", "Use SSO with the PRT stored on this computer", "Use the Primary Refresh Token available on this computer to connect automatically without credential prompting."));
}
ConsoleMenu.Title = "Which identity do you want to use?";
ConsoleMenu.Information = "The program will use the choosen identity to perform the operation on the Azure Tenant.";
int choice = ConsoleMenu.SelectMenu(choices);
if (choice == 0)
return DisplayState.Exit;
AzureCredential = null;
string whattodo = choices[choice - 1].Choice;
switch (whattodo)
{
default:
break;
case "askcredential":
AzureCredential = new UserCredential();
break;
case "useprt":
AzureCredential = new PRTCredential();
break;
}
return DisplayState.Run;
}
private DisplayState DisplayAskAzureADTenant()
{
HttpClientHelper.LogComment = "DisplayAskTenant";
ManagementApi.TenantListResponse p;
try
{
var graph = new ManagementApi(AzureCredential);
p = graph.ListTenants();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return DisplayState.Exit;
}
HttpClientHelper.LogComment = null;
List<ConsoleMenuItem> choices = new List<ConsoleMenuItem>();
foreach (var t in p.responses)
{
foreach (var t2 in t.content.value)
{
choices.Add(new ConsoleMenuItem(t2.tenantId, t2.displayName + " (" + t2.countryCode + ")"));
}
}
ConsoleMenu.Title = "Which tenant do you want to use?";
ConsoleMenu.Information = "The program will use the choosen tenant to perform the operation on the Azure Tenant.";
int choice = ConsoleMenu.SelectMenu(choices);
if (choice == 0)
return DisplayState.Exit;
string whattodo = choices[choice - 1].Choice;
AzureCredential.TenantidToQuery = whattodo;
return DisplayState.Run;
}
DisplayState DisplayAskForFile()
{
while (String.IsNullOrEmpty(InputFile) || !File.Exists(InputFile))
{
ConsoleMenu.Title = "Select an existing file";
ConsoleMenu.Information = "Please specify the file to open.";
InputFile = ConsoleMenu.AskForString();
ConsoleMenu.Notice = "The file " + InputFile + " was not found";
}
return DisplayState.Run;
}
DisplayState DisplayAskForDirectory()
{
while (String.IsNullOrEmpty(InputDirectory) || !Directory.Exists(InputDirectory))
{
ConsoleMenu.Title = "Select an existing directory";
ConsoleMenu.Information = "Please specify the directory to open.";
InputFile = ConsoleMenu.AskForString();
ConsoleMenu.Notice = "The directory " + InputFile + " was not found";
}
return DisplayState.Run;
}
DisplayState DisplayAskForSeed()
{
while (String.IsNullOrEmpty(InitForExportAsGuest))
{
ConsoleMenu.Title = "Select the seed";
ConsoleMenu.Information = @"To start the export, the program need to have a first user. It can be its objectId or its UPN ([email protected]). The program accept many values if there are separted by a comma.";
InitForExportAsGuest = ConsoleMenu.AskForString();
// error message in case the query is not complete
ConsoleMenu.Notice = "The seed cannot be empty";
}
return DisplayState.Run;
}
private bool AskCredential()
{
Password = new SecureString();
Console.WriteLine("Enter password: ");
ConsoleKeyInfo nextKey = Console.ReadKey(true);
while (nextKey.Key != ConsoleKey.Enter)
{
if (nextKey.Key == ConsoleKey.Backspace)
{
if (Password.Length > 0)
{
Password.RemoveAt(Password.Length - 1);
// erase the last * as well
Console.Write(nextKey.KeyChar);
Console.Write(" ");
Console.Write(nextKey.KeyChar);
}
}
else
{
Password.AppendChar(nextKey.KeyChar);
Console.Write("*");
}
nextKey = Console.ReadKey(true);
}
Console.WriteLine();
return true;
}
#endregion
private void WriteInRed(string data)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(data);
Trace.WriteLine("[Red]" + data);
Console.ResetColor();
}
}
}