Adds a little windows demo app (#230)

* Add AsaGenerator

Generates system changes for testing/demoing ASA.

* Fix #228 

* Fix #227
This commit is contained in:
Gabe Stocco 2019-06-04 13:18:07 -07:00 коммит произвёл GitHub
Родитель a54fbbe0f3
Коммит d1fc80d17d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
19 изменённых файлов: 994 добавлений и 57 удалений

Просмотреть файл

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Lib\AttackSurfaceAnalyzerLib.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,50 @@
using AttackSurfaceAnalyzer.Utils;
using System;
using System.Runtime.InteropServices;
using Serilog;
namespace AttackSurfaceAnalyzer
{
class AsaDemoGenerator
{
public static void Main(string[] args)
{
Logger.Setup(true,true);
try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (!Elevation.IsAdministrator())
{
Log.Fatal("Must run as administrator.");
Log.CloseAndFlush();
Environment.Exit(-1);
}
var user = System.Guid.NewGuid().ToString().Substring(0,10);
var password = System.Guid.NewGuid().ToString().Substring(0,10);
var cmd = string.Format("user /add {0} {1}", user, password);
ExternalCommandRunner.RunExternalCommand("net",cmd);
Log.Information("Created user {0} with password {1}", user, password);
var serviceName = System.Guid.NewGuid();
var exeName = "AsaDemoService.exe";
cmd = string.Format("create {0} binPath=\"{1}\"", serviceName, exeName);
ExternalCommandRunner.RunExternalCommand("sc.exe",cmd);
Log.Information("Created service {0} for not-present exe {1}", serviceName, exeName);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}
}

580
Cli/Output.cshtml Normal file
Просмотреть файл

@ -0,0 +1,580 @@
@using RazorLight
@using AttackSurfaceAnalyzer.ObjectTypes
@using Newtonsoft.Json;
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Attack Surface Analyzer</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" integrity="sha384-Zug+QiDoJOrZ5t4lssLdxGhVrurbmBWopoEl+M6BdEfwnCJZtKxi1KgxUyJq13dy" crossorigin="anonymous">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4">
<a class="navbar-brand" href="#">Attack Surface Analyzer</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">FAQ</a>
</li>
</ul>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<nav class="col-sm-3 col-md-2 d-none d-sm-block bg-light sidebar">
<ul class="nav nav-pills flex-column">
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_summary" role="button">Overview</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_file_system" role="button">File System</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_services" role="button">Services</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_open_ports" role="button">Open Ports</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_user_accounts" role="button">User Accounts</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_registry" role="button">Registry</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_certificates" role="button">Certificates</a>
</li>
</ul>
<ul class="nav nav-pills flex-column">
<li class="nav-item">
<a class="nav-link disabled" data-internal-link="replace" href="#export_sarif" role="button">Export SARIF</a>
</li>
</ul>
</nav>
<main role="main" class="col-sm-9 ml-sm-auto col-md-10 pt-3">
</main>
<div class="d-none">
<div id="section_summary">
<h1>Summary</h1>
<p>
<strong>This is the comparison between @Model["BeforeRunId"] and @Model["AfterRunId"].</strong>
</p>
</div>
<div id="section_file_system">
<h1>File System</h1>
The following files were changed between runs <strong>@Model["BeforeRunId"]</strong> and <strong>@Model["AfterRunId"]</strong>.
@{
if (Model.ContainsKey("files_remove"))
{
<div class="dropdown float-right show">
<a class="btn btn-sm btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Filter Results
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="#">Interesting</a>
<a class="dropdown-item" href="#">Uninteresting</a>
<a class="dropdown-item" href="#">Show All</a>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Path</th>
<th>Permissions</th>
<th>Size</th>
<th>Content Hash</th>
<th>Signature</th>
</tr>
</thead>
<tbody>
@foreach (FileSystemResult i in Model["files_remove"])
{
<tr>
<td>Deleted</td>
<td>@i.Base.Path</td>
<td>@i.Base.Permissions</td>
<td>@string.Format("{0:N0}", i.Base.Size)</td>
<td>@i.Base.ContentHash</td>
@*<td>@i.SignatureStatus</td>*@
</tr>
}
@foreach (FileSystemResult i in Model["files_add"])
{
<tr>
<td>New</td>
<td>@i.Compare.Path</td>
<td>@i.Compare.Permissions</td>
<td>@string.Format("{0:N0}", i.Compare.Size)</td>
<td>@i.Compare.ContentHash</td>
@*<td>@i.SignatureStatus</td>*@
</tr>
}
@foreach (FileSystemResult i in Model["files_modify"])
{
<tr>
<td>Modified:Before</td>
<td>@i.Base.Path</td>
<td>@i.Base.Permissions</td>
<td>@string.Format("{0:N0}", i.Base.Size)</td>
<td>@i.Base.ContentHash</td>
@*<td>@i.SignatureStatus</td>*@
</tr>
<tr>
<td>Modified:After</td>
<td>@i.Compare.Path</td>
<td>@i.Compare.Permissions</td>
<td>@string.Format("{0:N0}", i.Compare.Size)</td>
<td>@i.Compare.ContentHash</td>
@*<td>@i.SignatureStatus</td>*@
</tr>
}
</tbody>
</table>
</div>
}
}
</div>
<div id="section_services">
<h1>Services</h1>
The following services were changed between runs <strong>@Model["BeforeRunId"]</strong> and <strong>@Model["AfterRunId"]</strong>.
@{
if (Model.ContainsKey("services_remove"))
{
<div class="dropdown float-right show">
<a class="btn btn-sm btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Filter Results
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="#">Interesting</a>
<a class="dropdown-item" href="#">Uninteresting</a>
<a class="dropdown-item" href="#">Show All</a>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Service Name</th>
<th>Display Name</th>
<th>Start Type</th>
<th>Current State</th>
</tr>
</thead>
<tbody>
@foreach (ServiceResult i in Model["services_remove"])
{
<tr>
<td>Deleted</td>
<td>@i.Base.ServiceName</td>
<td>@i.Base.DisplayName</td>
<td>@i.Base.StartType</td>
<td>@i.Base.CurrentState</td>
</tr>
}
@foreach (ServiceResult i in Model["services_add"])
{
<tr>
<td>New</td>
<td>@i.Compare.ServiceName</td>
<td>@i.Compare.DisplayName</td>
<td>@i.Compare.StartType</td>
<td>@i.Compare.CurrentState</td>
</tr>
}
@foreach (ServiceResult i in Model["services_modify"])
{
<tr>
<td>Modified:Before</td>
<td>@i.Base.ServiceName</td>
<td>@i.Base.DisplayName</td>
<td>@i.Base.StartType</td>
<td>@i.Base.CurrentState</td>
</tr>
<tr>
<td>Modified:After</td>
<td>@i.Compare.ServiceName</td>
<td>@i.Compare.DisplayName</td>
<td>@i.Compare.StartType</td>
<td>@i.Compare.CurrentState</td>
</tr>
}
</tbody>
</table>
</div>
}
}
</div>
<div id="section_open_ports">
<h1>Open Network Ports</h1>
@{
if (Model.ContainsKey("ports_remove"))
{
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Family</th>
<th>Address</th>
<th>Port</th>
<th>Type</th>
</tr>
</thead>
<tbody>
@foreach (OpenPortResult i in Model["ports_remove"])
{
<tr>
<td>Deleted</td>
<td>@i.Base.family</td>
<td>@i.Base.address</td>
<td>@i.Base.port</td>
<td>@i.Base.type</td>
</tr>
}
@foreach (OpenPortResult i in Model["ports_add"])
{
<tr>
<td>New</td>
<td>@i.Compare.family</td>
<td>@i.Compare.address</td>
<td>@i.Compare.port</td>
<td>@i.Compare.type</td>
</tr>
}
</tbody>
</table>
</div>
}
}
</div>
<div id="section_user_accounts">
<h1>User Accounts</h1>
The following user accounts were changed between runs <strong>@Model["BeforeRunId"]</strong> and <strong>@Model["AfterRunId"]</strong>.
@{
if (Model.ContainsKey("users_remove"))
{
<div class="dropdown float-right show">
<a class="btn btn-sm btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Filter Results
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="#">Interesting</a>
<a class="dropdown-item" href="#">Uninteresting</a>
<a class="dropdown-item" href="#">Show All</a>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>AccountType</th>
<th>Caption</th>
<th>Description</th>
<th>Disabled</th>
<th>Domain</th>
<th>InstallDate</th>
<th>LocalAccount</th>
<th>Lockout</th>
<th>Name</th>
<th>FullName</th>
<th>PasswordChangeable</th>
<th>PasswordExpires</th>
<th>PasswordRequired</th>
<th>SID</th>
<th>UID</th>
<th>GID</th>
<th>Inactive</th>
<th>HomeDirectory</th>
<th>Shell</th>
<th>PasswordStorageAlgorithm</th>
</tr>
</thead>
<tbody>
@foreach (UserAccountResult i in Model["users_remove"])
{
<tr>
<td>Deleted</td>
<td>@i.Base.AccountType</td>
<td>@i.Base.Caption</td>
<td>@i.Base.Description</td>
<td>@i.Base.Disabled</td>
<td>@i.Base.Domain</td>
<td>@i.Base.InstallDate</td>
<td>@i.Base.LocalAccount</td>
<td>@i.Base.Lockout</td>
<td>@i.Base.Name</td>
<td>@i.Base.FullName</td>
<td>@i.Base.PasswordChangeable</td>
<td>@i.Base.PasswordExpires</td>
<td>@i.Base.PasswordRequired</td>
<td>@i.Base.SID</td>
<td>@i.Base.UID</td>
<td>@i.Base.GID</td>
<td>@i.Base.Inactive</td>
<td>@i.Base.HomeDirectory</td>
<td>@i.Base.Shell</td>
<td>@i.Base.PasswordStorageAlgorithm</td>
</tr>
}
@foreach (UserAccountResult i in Model["users_add"])
{
<tr>
<td>New</td>
<td>@i.Compare.AccountType</td>
<td>@i.Compare.Caption</td>
<td>@i.Compare.Description</td>
<td>@i.Compare.Disabled</td>
<td>@i.Compare.Domain</td>
<td>@i.Compare.InstallDate</td>
<td>@i.Compare.LocalAccount</td>
<td>@i.Compare.Lockout</td>
<td>@i.Compare.Name</td>
<td>@i.Compare.FullName</td>
<td>@i.Compare.PasswordChangeable</td>
<td>@i.Compare.PasswordExpires</td>
<td>@i.Compare.PasswordRequired</td>
<td>@i.Compare.SID</td>
<td>@i.Compare.UID</td>
<td>@i.Compare.GID</td>
<td>@i.Compare.Inactive</td>
<td>@i.Compare.HomeDirectory</td>
<td>@i.Compare.Shell</td>
<td>@i.Compare.PasswordStorageAlgorithm</td>
</tr>
}
@foreach (UserAccountResult i in Model["users_modify"])
{
<tr>
<td>Modified:Before</td>
<td>@i.Base.AccountType</td>
<td>@i.Base.Caption</td>
<td>@i.Base.Description</td>
<td>@i.Base.Disabled</td>
<td>@i.Base.Domain</td>
<td>@i.Base.InstallDate</td>
<td>@i.Base.LocalAccount</td>
<td>@i.Base.Lockout</td>
<td>@i.Base.Name</td>
<td>@i.Base.FullName</td>
<td>@i.Base.PasswordChangeable</td>
<td>@i.Base.PasswordExpires</td>
<td>@i.Base.PasswordRequired</td>
<td>@i.Base.SID</td>
<td>@i.Base.UID</td>
<td>@i.Base.GID</td>
<td>@i.Base.Inactive</td>
<td>@i.Base.HomeDirectory</td>
<td>@i.Base.Shell</td>
<td>@i.Base.PasswordStorageAlgorithm</td>
</tr>
<tr>
<td>Modified:After</td>
<td>@i.Compare.AccountType</td>
<td>@i.Compare.Caption</td>
<td>@i.Compare.Description</td>
<td>@i.Compare.Disabled</td>
<td>@i.Compare.Domain</td>
<td>@i.Compare.InstallDate</td>
<td>@i.Compare.LocalAccount</td>
<td>@i.Compare.Lockout</td>
<td>@i.Compare.Name</td>
<td>@i.Compare.FullName</td>
<td>@i.Compare.PasswordChangeable</td>
<td>@i.Compare.PasswordExpires</td>
<td>@i.Compare.PasswordRequired</td>
<td>@i.Compare.SID</td>
<td>@i.Compare.UID</td>
<td>@i.Compare.GID</td>
<td>@i.Compare.Inactive</td>
<td>@i.Compare.HomeDirectory</td>
<td>@i.Compare.Shell</td>
<td>@i.Compare.PasswordStorageAlgorithm</td>
</tr>
}
</tbody>
</table>
</div>
}
}
</div>
<div id="section_registry">
<h1>Registry values</h1>
The following registry keys and values were changed between runs <strong>@Model["BeforeRunId"]</strong> and <strong>@Model["AfterRunId"]</strong>.
@{
if (Model.ContainsKey("registry_remove"))
{
<div class="dropdown float-right show">
<a class="btn btn-sm btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Filter Results
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="#">Interesting</a>
<a class="dropdown-item" href="#">Uninteresting</a>
<a class="dropdown-item" href="#">Show All</a>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Key</th>
<th>Subkeys (if applicable)</th>
<th>Values (if a value)</th>
</tr>
</thead>
<tbody>
@foreach (RegistryResult i in Model["registry_remove"])
{
<tr>
<td>Deleted</td>
<td>@i.Base.Key</td>
<td>@JsonConvert.SerializeObject(i.Base.Subkeys)</td>
<td>@JsonConvert.SerializeObject(i.Base.Values)</td>
</tr>
}
@foreach (RegistryResult i in Model["registry_add"])
{
<tr>
<td>New</td>
<td>@i.Compare.Key</td>
<td>@JsonConvert.SerializeObject(i.Compare.Subkeys)</td>
<td>@JsonConvert.SerializeObject(i.Compare.Values)</td>
</tr>
}
@foreach (RegistryResult i in Model["registry_modify"])
{
<tr>
<td>Modified:Before</td>
<td>@i.Base.Key</td>
<td>@JsonConvert.SerializeObject(i.Base.Subkeys)</td>
<td>@JsonConvert.SerializeObject(i.Base.Values)</td>
</tr>
<tr>
<td>Modified:After</td>
<td>@i.Compare.Key</td>
<td>@JsonConvert.SerializeObject(i.Compare.Subkeys)</td>
<td>@JsonConvert.SerializeObject(i.Compare.Values)</td>
</tr>
}
</tbody>
</table>
</div>
}
}
</div>
<div id="section_certificates">
<h1>Certificate Store</h1>
The following Certificates were changed between runs <strong>@Model["BeforeRunId"]</strong> and <strong>@Model["AfterRunId"]</strong>.
@{
if (Model.ContainsKey("certs_remove"))
{
<div class="dropdown float-right show">
<a class="btn btn-sm btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Filter Results
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="#">Interesting</a>
<a class="dropdown-item" href="#">Uninteresting</a>
<a class="dropdown-item" href="#">Show All</a>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Store Location</th>
<th>Store Name</th>
<th>Subject Name</th>
<th>Certificate Hash</th>
</tr>
</thead>
<tbody>
@foreach (CertificateResult i in Model["certs_remove"])
{
<tr>
<td>Deleted</td>
<td>@i.Base.StoreLocation</td>
<td>@i.Base.StoreName</td>
<td>@i.Base.Subject</td>
<td>@i.Base.CertificateHashString</td>
</tr>
}
@foreach (CertificateResult i in Model["certs_add"])
{
<tr>
<td>Added</td>
<td>@i.Compare.StoreLocation</td>
<td>@i.Compare.StoreName</td>
<td>@i.Compare.Subject</td>
<td>@i.Compare.CertificateHashString</td>
</tr>
}
</tbody>
</table>
</div>
}
}
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/js/bootstrap.min.js" integrity="sha384-a5N7Y/aK3qNeh15eJKGWxsqtnX/wWdSZSKp+81YjTmS15nvnvxKHuzaWwXHDli+4" crossorigin="anonymous"></script>
<script type="text/javascript">$(document).ready(function () {
$('a[data-internal-link="replace"]').on('click', function (e) {
var href = $(e.target).attr('href'); // show this href
var $t = $('div' + href); // this element
if ($t) {
$('main').html($t.html());
}
});
})</script>
</body>
</html>

Просмотреть файл

@ -772,22 +772,28 @@ namespace AttackSurfaceAnalyzer
#else
Logger.Setup(opts.Debug, opts.Verbose);
#endif
AdminOrQuit();
DatabaseManager.SqliteFilename = opts.DatabaseFilename;
DatabaseManager.Setup();
CheckFirstRun();
Telemetry.Setup(Gui: false);
DatabaseManager.VerifySchemaVersion();
AdminOrQuit();
Filter.LoadFilters(opts.FilterLocation);
opts.RunId = opts.RunId.Trim();
if (opts.RunId.Equals("Timestamp"))
{
opts.RunId = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
Dictionary<string, string> StartEvent = new Dictionary<string, string>();
StartEvent.Add("Files", opts.EnableFileSystemMonitor.ToString());
StartEvent.Add("Admin", Helpers.IsAdmin().ToString());
Telemetry.TrackEvent("Begin monitoring", StartEvent);
CheckFirstRun();
DatabaseManager.VerifySchemaVersion();
Filter.LoadFilters(opts.FilterLocation);
opts.RunId = opts.RunId.Trim();
if (opts.RunId.Equals("Timestamp"))
{
opts.RunId = DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss");
}
if (opts.Overwrite)
{
@ -1217,6 +1223,7 @@ namespace AttackSurfaceAnalyzer
if (!Elevation.IsAdministrator())
{
Log.Fatal(Strings.Get("Err_RunAsAdmin"));
Log.CloseAndFlush();
Environment.Exit(1);
}
}
@ -1225,6 +1232,7 @@ namespace AttackSurfaceAnalyzer
if (!Elevation.IsRunningAsRoot())
{
Log.Fatal(Strings.Get("Err_RunAsRoot"));
Log.CloseAndFlush();
Environment.Exit(1);
}
}
@ -1233,6 +1241,7 @@ namespace AttackSurfaceAnalyzer
if (!Elevation.IsRunningAsRoot())
{
Log.Fatal(Strings.Get("Err_RunAsRoot"));
Log.CloseAndFlush();
Environment.Exit(1);
}
}
@ -1245,14 +1254,10 @@ namespace AttackSurfaceAnalyzer
#else
Logger.Setup(opts.Debug, opts.Verbose);
#endif
AdminOrQuit();
DatabaseManager.SqliteFilename = opts.DatabaseFilename;
DatabaseManager.Setup();
CheckFirstRun();
Telemetry.Setup(Gui: false);
DatabaseManager.VerifySchemaVersion();
int returnValue = (int)ERRORS.NONE;
opts.RunId = opts.RunId.Trim();
Dictionary<string, string> StartEvent = new Dictionary<string, string>();
StartEvent.Add("Files", opts.EnableAllCollectors ? "True" : opts.EnableFileSystemCollector.ToString());
StartEvent.Add("Ports", opts.EnableAllCollectors ? "True" : opts.EnableNetworkPortCollector.ToString());
@ -1260,8 +1265,19 @@ namespace AttackSurfaceAnalyzer
StartEvent.Add("Certificates", opts.EnableAllCollectors ? "True" : opts.EnableCertificateCollector.ToString());
StartEvent.Add("Registry", opts.EnableAllCollectors ? "True" : opts.EnableRegistryCollector.ToString());
StartEvent.Add("Service", opts.EnableAllCollectors ? "True" : opts.EnableServiceCollector.ToString());
StartEvent.Add("Admin", Helpers.IsAdmin().ToString());
Telemetry.TrackEvent("Run Command", StartEvent);
AdminOrQuit();
CheckFirstRun();
DatabaseManager.VerifySchemaVersion();
int returnValue = (int)ERRORS.NONE;
opts.RunId = opts.RunId.Trim();
if (opts.RunId.Equals("Timestamp"))
{
opts.RunId = DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss");

18
Cli/Properties/Resources.Designer.cs сгенерированный
Просмотреть файл

@ -438,6 +438,24 @@ namespace AttackSurfaceAnalyzer.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Attack Surface Analyzer must be run as Administrator..
/// </summary>
public static string Err_RunAsAdmin {
get {
return ResourceManager.GetString("Err_RunAsAdmin", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Attack Surace Analyzer must be run as root..
/// </summary>
public static string Err_RunAsRoot {
get {
return ResourceManager.GetString("Err_RunAsRoot", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to That runid was already used. Must use a unique runid for each run. Use --overwrite to discard previous run information..
/// </summary>

Просмотреть файл

@ -438,4 +438,10 @@
<data name="StartingN" xml:space="preserve">
<value>Starting {0} {1}.</value>
</data>
<data name="Err_RunAsAdmin" xml:space="preserve">
<value>Attack Surface Analyzer must be run as Administrator.</value>
</data>
<data name="Err_RunAsRoot" xml:space="preserve">
<value>Attack Surace Analyzer must be run as root.</value>
</data>
</root>

250
Cli/output.html Normal file
Просмотреть файл

@ -0,0 +1,250 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Attack Surface Analyzer</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" integrity="sha384-Zug+QiDoJOrZ5t4lssLdxGhVrurbmBWopoEl+M6BdEfwnCJZtKxi1KgxUyJq13dy" crossorigin="anonymous">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4">
<a class="navbar-brand" href="#">Attack Surface Analyzer</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">FAQ</a>
</li>
</ul>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<nav class="col-sm-3 col-md-2 d-none d-sm-block bg-light sidebar">
<ul class="nav nav-pills flex-column">
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_summary" role="button">Overview</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_file_system" role="button">File System</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_services" role="button">Services</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_open_ports" role="button">Open Ports</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_user_accounts" role="button">User Accounts</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_registry" role="button">Registry</a>
</li>
<li class="nav-item">
<a class="nav-link" data-internal-link="replace" href="#section_certificates" role="button">Certificates</a>
</li>
</ul>
<ul class="nav nav-pills flex-column">
<li class="nav-item">
<a class="nav-link disabled" data-internal-link="replace" href="#export_sarif" role="button">Export SARIF</a>
</li>
</ul>
</nav>
<main role="main" class="col-sm-9 ml-sm-auto col-md-10 pt-3">
</main>
<div class="d-none">
<div id="section_summary">
<h1>Summary</h1>
<p>
<strong>This is the comparison between 2019-06-04_09:24:54 and 2019-06-04_09:26:58.</strong>
</p>
</div>
<div id="section_file_system">
<h1>File System</h1>
The following files were changed between runs <strong>2019-06-04_09:24:54</strong> and <strong>2019-06-04_09:26:58</strong>.
</div>
<div id="section_services">
<h1>Services</h1>
The following services were changed between runs <strong>2019-06-04_09:24:54</strong> and <strong>2019-06-04_09:26:58</strong>.
<div class="dropdown float-right show">
<a class="btn btn-sm btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Filter Results
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="#">Interesting</a>
<a class="dropdown-item" href="#">Uninteresting</a>
<a class="dropdown-item" href="#">Show All</a>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Service Name</th>
<th>Display Name</th>
<th>Start Type</th>
<th>Current State</th>
</tr>
</thead>
<tbody>
<tr>
<td>New</td>
<td>1de224d3-a551-45af-bbc4-714b5ae5750a</td>
<td>1de224d3-a551-45af-bbc4-714b5ae5750a</td>
<td>Manual</td>
<td>Stopped</td>
</tr>
<tr>
<td>New</td>
<td>0c91bc9b-045a-47eb-a1ae-0bed720fc596</td>
<td>0c91bc9b-045a-47eb-a1ae-0bed720fc596</td>
<td>Manual</td>
<td>Stopped</td>
</tr>
<tr>
<td>Modified:Before</td>
<td>camsvc</td>
<td>Capability Access Manager Service</td>
<td>Manual</td>
<td>Stopped</td>
</tr>
<tr>
<td>Modified:After</td>
<td>camsvc</td>
<td>Capability Access Manager Service</td>
<td>Manual</td>
<td>Running</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="section_open_ports">
<h1>Open Network Ports</h1>
</div>
<div id="section_user_accounts">
<h1>User Accounts</h1>
The following user accounts were changed between runs <strong>2019-06-04_09:24:54</strong> and <strong>2019-06-04_09:26:58</strong>.
<div class="dropdown float-right show">
<a class="btn btn-sm btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Filter Results
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="#">Interesting</a>
<a class="dropdown-item" href="#">Uninteresting</a>
<a class="dropdown-item" href="#">Show All</a>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>AccountType</th>
<th>Caption</th>
<th>Description</th>
<th>Disabled</th>
<th>Domain</th>
<th>InstallDate</th>
<th>LocalAccount</th>
<th>Lockout</th>
<th>Name</th>
<th>FullName</th>
<th>PasswordChangeable</th>
<th>PasswordExpires</th>
<th>PasswordRequired</th>
<th>SID</th>
<th>UID</th>
<th>GID</th>
<th>Inactive</th>
<th>HomeDirectory</th>
<th>Shell</th>
<th>PasswordStorageAlgorithm</th>
</tr>
</thead>
<tbody>
<tr>
<td>New</td>
<td>512</td>
<td>OMNI\b5b83e6b-a</td>
<td></td>
<td>False</td>
<td>OMNI</td>
<td></td>
<td>True</td>
<td>False</td>
<td>b5b83e6b-a</td>
<td></td>
<td>True</td>
<td>True</td>
<td>True</td>
<td>S-1-5-21-2657022534-2149368671-1895623758-1004</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="section_registry">
<h1>Registry values</h1>
The following registry keys and values were changed between runs <strong>2019-06-04_09:24:54</strong> and <strong>2019-06-04_09:26:58</strong>.
</div>
<div id="section_certificates">
<h1>Certificate Store</h1>
The following Certificates were changed between runs <strong>2019-06-04_09:24:54</strong> and <strong>2019-06-04_09:26:58</strong>.
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/js/bootstrap.min.js" integrity="sha384-a5N7Y/aK3qNeh15eJKGWxsqtnX/wWdSZSKp+81YjTmS15nvnvxKHuzaWwXHDli+4" crossorigin="anonymous"></script>
<script type="text/javascript">$(document).ready(function () {
$('a[data-internal-link="replace"]').on('click', function (e) {
var href = $(e.target).attr('href'); // show this href
var $t = $('div' + href); // this element
if ($t) {
$('main').html($t.html());
}
});
})</script>
</body>
</html>

Просмотреть файл

@ -138,9 +138,9 @@ namespace AttackSurfaceAnalyzer.Collectors.Certificates
// We list all the certificates and then create a new X509Certificate2 object for each by filename.
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
var runner = new ExternalCommandRunner();
var result = runner.RunExternalCommand("ls", new string[] { "/etc/ssl/certs", "-A" });
var result = ExternalCommandRunner.RunExternalCommand("ls", new string[] { "/etc/ssl/certs", "-A" });
Log.Debug("{0}", result);
foreach (var _line in result.Split('\n'))
@ -165,14 +165,14 @@ namespace AttackSurfaceAnalyzer.Collectors.Certificates
// we import the pkcs12 with all our certs, delete the temp files and then iterate over it the certs
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
var runner = new ExternalCommandRunner();
var result = runner.RunExternalCommand("security", new string[] { "find-certificate", "-ap", "/System/Library/Keychains/SystemRootCertificates.keychain" });
var result = ExternalCommandRunner.RunExternalCommand("security", new string[] { "find-certificate", "-ap", "/System/Library/Keychains/SystemRootCertificates.keychain" });
string tmpPath = Path.Combine(Directory.GetCurrentDirectory(), "tmpcert.pem");
string pkPath = Path.Combine(Directory.GetCurrentDirectory(), "tmpcert.pk12");
File.WriteAllText(tmpPath, result);
_ = runner.RunExternalCommand("openssl", new string[] { "pkcs12", "-export", "-nokeys" , "-out", pkPath, "-passout pass:pass", "-in", tmpPath });
_ = ExternalCommandRunner.RunExternalCommand("openssl", new string[] { "pkcs12", "-export", "-nokeys" , "-out", pkPath, "-passout pass:pass", "-in", tmpPath });
X509Certificate2Collection xcert = new X509Certificate2Collection();
xcert.Import(pkPath,"pass",X509KeyStorageFlags.DefaultKeySet);

Просмотреть файл

@ -170,8 +170,8 @@ namespace AttackSurfaceAnalyzer.Collectors.OpenPorts
private void ExecuteLinux()
{
Log.Debug("ExecuteLinux()");
var runner = new ExternalCommandRunner();
var result = runner.RunExternalCommand("ss", "-ln");
var result = ExternalCommandRunner.RunExternalCommand("ss", "-ln");
foreach (var _line in result.Split('\n'))
{
@ -215,8 +215,8 @@ namespace AttackSurfaceAnalyzer.Collectors.OpenPorts
private void ExecuteOsX()
{
Log.Debug("ExecuteOsX()");
var runner = new ExternalCommandRunner();
var result = runner.RunExternalCommand("sudo", "lsof -Pn -i4 -i6");
var result = ExternalCommandRunner.RunExternalCommand("sudo", "lsof -Pn -i4 -i6");
foreach (var _line in result.Split('\n'))
{

Просмотреть файл

@ -26,10 +26,10 @@ namespace AttackSurfaceAnalyzer.Collectors.Registry
public override void Start()
{
var runner = new ExternalCommandRunner();
// backup the current auditpolicy
runner.RunExternalCommand("auditpol", String.Format("/backup /file:{0}", tmpFileName));
ExternalCommandRunner.RunExternalCommand("auditpol", String.Format("/backup /file:{0}", tmpFileName));
// start listening to the event log
log.EntryWritten += new EntryWrittenEventHandler(MyOnEntryWritten);
@ -38,19 +38,19 @@ namespace AttackSurfaceAnalyzer.Collectors.Registry
// Enable auditing for registry events
// GUID for Registry subcategory of audit policy
// https://msdn.microsoft.com/en-us/library/dd973928.aspx
runner.RunExternalCommand("auditpol", "/set /subcategory:{0CCE921E-69AE-11D9-BED3-505054503030} /success:enable /failure:enable");
ExternalCommandRunner.RunExternalCommand("auditpol", "/set /subcategory:{0CCE921E-69AE-11D9-BED3-505054503030} /success:enable /failure:enable");
}
public override void Stop()
{
var runner = new ExternalCommandRunner();
// restore the old auditpolicy
runner.RunExternalCommand("auditpol", String.Format("/restore /file:{0}", tmpFileName));
ExternalCommandRunner.RunExternalCommand("auditpol", String.Format("/restore /file:{0}", tmpFileName));
//delete temporary file
runner.RunExternalCommand("del", tmpFileName);
ExternalCommandRunner.RunExternalCommand("del", tmpFileName);
log.EnableRaisingEvents = false;
}

Просмотреть файл

@ -100,12 +100,12 @@ namespace AttackSurfaceAnalyzer.Collectors.Service
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
var runner = new ExternalCommandRunner();
// Get the user processes
// run "launchtl dumpstate" for the super detailed view
// However, dumpstate is difficult to parse
var result = runner.RunExternalCommand("launchctl", "list");
var result = ExternalCommandRunner.RunExternalCommand("launchctl", "list");
Dictionary<string, ServiceObject> outDict = new Dictionary<string, ServiceObject>();
foreach (var _line in result.Split('\n'))
{
@ -133,7 +133,7 @@ namespace AttackSurfaceAnalyzer.Collectors.Service
}
// Then get the system processes
result = runner.RunExternalCommand("sudo", "launchctl list");
result = ExternalCommandRunner.RunExternalCommand("sudo", "launchctl list");
foreach (var _line in result.Split('\n'))
{
@ -164,9 +164,9 @@ namespace AttackSurfaceAnalyzer.Collectors.Service
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
var runner = new ExternalCommandRunner();
var result = runner.RunExternalCommand("systemctl", "list-units --type service");
var result = ExternalCommandRunner.RunExternalCommand("systemctl", "list-units --type service");
//Split lines and remove header
var lines = result.Split('\n').Skip(1);
@ -189,7 +189,7 @@ namespace AttackSurfaceAnalyzer.Collectors.Service
}
}
result = runner.RunExternalCommand("ls", "/etc/init.d/ -l");
result = ExternalCommandRunner.RunExternalCommand("ls", "/etc/init.d/ -l");
lines = result.Split('\n').Skip(1);
String pattern = @".*\s(.*)";

Просмотреть файл

@ -192,7 +192,7 @@ using (ManagementObjectCollection users = result.GetRelationships("Win32_GroupUs
private void ExecuteLinux()
{
Log.Debug("ExecuteLinux()");
var runner = new ExternalCommandRunner();
var etc_passwd_lines = File.ReadAllLines("/etc/passwd");
var etc_shadow_lines = File.ReadAllLines("/etc/shadow");
@ -257,10 +257,10 @@ using (ManagementObjectCollection users = result.GetRelationships("Win32_GroupUs
{
Log.Debug("ExecuteOsX()");
var runner = new ExternalCommandRunner();
// Admin user details
var result = runner.RunExternalCommand("dscacheutil", "-q group -a name admin");
var result = ExternalCommandRunner.RunExternalCommand("dscacheutil", "-q group -a name admin");
var lines = result.Split('\n');
@ -269,7 +269,7 @@ using (ManagementObjectCollection users = result.GetRelationships("Win32_GroupUs
var admins = (lines[3].Split(':')[1]).Split(' ');
// details for all users
result = runner.RunExternalCommand("dscacheutil", "-q user");
result = ExternalCommandRunner.RunExternalCommand("dscacheutil", "-q user");
var accountDetails = new Dictionary<string, UserAccountObject>();

Просмотреть файл

@ -82,11 +82,8 @@ namespace AttackSurfaceAnalyzer.Utils
public static bool Setup()
{
Log.Warning("Before Conn Check");
if (Connection == null)
{
Log.Warning("After Conn Check");
Connection = new SqliteConnection($"Filename=" + _SqliteFilename);
Connection.Open();
@ -198,11 +195,9 @@ namespace AttackSurfaceAnalyzer.Utils
cmd.ExecuteNonQuery();
}
Console.WriteLine("Set up database.");
Commit();
return true;
}
Log.Warning("Failed to set up database");
return false;
}

Просмотреть файл

@ -439,8 +439,8 @@ namespace AttackSurfaceAnalyzer.Utils
// Does this cover sudo?
public static bool IsRunningAsRoot()
{
var runner = new ExternalCommandRunner();
var username = runner.RunExternalCommand("whoami");
var username = ExternalCommandRunner.RunExternalCommand("whoami");
return username != null ? username.Contains("root") : false;
}

Просмотреть файл

@ -4,10 +4,10 @@ using System.Diagnostics;
namespace AttackSurfaceAnalyzer.Utils
{
class ExternalCommandRunner
public static class ExternalCommandRunner
{
public string RunExternalCommand(string command, params string[] args)
public static string RunExternalCommand(string command, params string[] args)
{
var process = new Process()
{

Просмотреть файл

@ -26,6 +26,11 @@ namespace AttackSurfaceAnalyzer.Utils
}
}
public static bool IsAdmin()
{
return Elevation.IsAdministrator() || Elevation.IsRunningAsRoot();
}
public static string MakeValidFileName(string name)
{
string invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars()));
@ -87,8 +92,7 @@ namespace AttackSurfaceAnalyzer.Utils
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
ExternalCommandRunner runner = new ExternalCommandRunner();
return runner.RunExternalCommand("uname", "-r");
return ExternalCommandRunner.RunExternalCommand("uname", "-r");
}
return "";
}
@ -101,8 +105,7 @@ namespace AttackSurfaceAnalyzer.Utils
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
ExternalCommandRunner runner = new ExternalCommandRunner();
return runner.RunExternalCommand("uname", "-s");
return ExternalCommandRunner.RunExternalCommand("uname", "-s");
}
return "";
}

Просмотреть файл

@ -21,7 +21,7 @@ namespace AttackSurfaceAnalyzer.Utils
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.File("asa.log.txt")
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Verbose)
.WriteTo.Console()
.CreateLogger();
}
else if (debug)

Просмотреть файл

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Serilog;
namespace AttackSurfaceAnalyzer.Utils
@ -95,8 +96,8 @@ namespace AttackSurfaceAnalyzer.Utils
{
if(!Tokens[3].Equals("LISTENING")) { continue; }
ProcessPorts.Add(new ProcessPort(
GetProcessName(Convert.ToInt16(Tokens[4])),
Convert.ToInt16(Tokens[4]),
GetProcessName(Convert.ToInt32(Tokens[4])),
Convert.ToInt32(Tokens[4]),
IpAddress.Contains("1.1.1.1") ? String.Format("{0}v6", Tokens[1]) : String.Format("{0}v4", Tokens[1]),
Convert.ToInt32(IpAddress.Split(':')[1])
));
@ -105,8 +106,8 @@ namespace AttackSurfaceAnalyzer.Utils
else if (Tokens.Length == 4 && (Tokens[0].Equals("UDP")))
{
ProcessPorts.Add(new ProcessPort(
GetProcessName(Convert.ToInt16(Tokens[3])),
Convert.ToInt16(Tokens[3]),
GetProcessName(Convert.ToInt32(Tokens[3])),
Convert.ToInt32(Tokens[3]),
IpAddress.Contains("1.1.1.1") ? String.Format("{0}v6", Tokens[1]) : String.Format("{0}v4", Tokens[1]),
Convert.ToInt32(IpAddress.Split(':')[1])
));

6
NuGet.Config Normal file
Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>