This is a template project for easy control of remote personal computers/servers/workstations via a graphical interface based on the ASP.NET Model-View-Controller (MVC) web server. Designed to log in with the local machine account and a custom password generated by the user when running the program, which remains hidden in memory, it is currently possible to send operating system terminal commands and capture responses (interactive support not yet available). In the future, it will also be possible to access and add/view and delete files from the logged-in user and the system (if administrator).
Designed to run on a local account (not as a pre-login process or system service). Permission limitations are assigned to the local user running the web server.
Access and control the remote machine with less bureaucratic infrastructure.
- Tech Stack
- Prerequisites
- NuGet Packages
- Usage
- Local Setup
- Project structure
- Security
- Testing
- Contribute
--Command line
for login attempts and IP bans.- Local user login with identity authentication
CookieAuthenticationDefaults
. - Stacking the password created with
SecureString
(security layer). - Error handling with error screen (anonymous and authenticated variants).
- Security layer basics (The highest level is restricting non-administrator users who run this web server).
- Executes system terminal commands, inspects search box search.
- Localization through pages (English, Chinese, Russian).
AppResources.resx
- Bootstrap and basic integration in js.
- Language: C# (target .NET
8.0
) - Framework:
ASP.NET Core MVC
- .NET SDK
8.0
or later - OS:
Windows
orLinux
System.CommandLine
Use dotnet restore
to recover the packages.
dotnet run
--login_attempts 5
Maximum login attempts per IP address within a given time interval.
--time_out 90
IP ban time after exhausting login attempts (in seconds).
--sess-time_out 360
Time before the user session expires (in seconds).
..
When you start the program, the terminal will be blank, displaying only ..
This means that it is waiting for the user to enter a password to create the Web App password, than press ENTER. The characters are not displayed on the terminal to prevent them from being exploited in memory. The username
will always be the local username
of the operating system running the web server.
Username
: To obtain the local username used, type whoami
in the Linux terminal or echo %USERNAME%
in Windows CMD. This is the username used to log in to the host.
Change the server's IP and port by modifying the “Url
” Kestrel keys in appsettings.json
.
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://127.0.0.1:5000"
},
"Https": {
"Url": "https://127.0.0.1:5001"
}
}
}
Change basic and public information displayed when accessing the Web App Login screen.
"Basic": {
"AppName": "GUI-Based Server Management",
"CompanyName": "My Company ™"
},
├── wwwroot/
│ └── content/ # assets
├── Common/ # program Source
│ ├── Logging/ # Logger
│ ├── Security/ # Auth Service and password system
├── Controllers/ # ...
├── Models/ # ...
│ ├── Messaging/ # Widget models
│ ├── Nativization/ # Static translation accessor model
| ├── Options/ # Accessible information on anonymous routes.
| ├── Security/ # Models for mediating logins and entries
| ├── Static/ # For the error screen
├── Resources/ # ...AppResources.resx
│ ├── Languages/ # Contains translations from the App
├── Runtime/ # Interaction with the computer
| ├── HighLevel/ # Terminal command executor
├── Views/ # ...
| ├── Widgets/ # Partial HTML widgets
└── appsettings.json # ini settings
-
Only the HTTPs protocol is permitted.
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
-
All routes require authentication, except when specified
[AllowAnonymous]
. Anonymous routes should use the base layout_LoginLayout.cshtml
, which does not expose sensitive information.`builder.Services.AddControllersWithViews(options => { options.Filters.Add(new AuthorizeFilter()); } );
-
Basic way to evade attempts to track the password saved in memory by attempting to log in with an incorrect username.
if (username == LocalUserInfo.username) { if (PasswordInput.SecureEquals(PasswordInput.ConvertString(password))) { if (!remoteAttempts[ipAddress]._TokenSource.IsCancellationRequested) { remoteAttempts[ipAddress]._TokenSource.Cancel(); } remoteAttempts.Remove(ipAddress); return Task.FromResult((Int16)2); } }
-
Exception messages are only displayed on the Error screen if the user is logged in.
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [AllowAnonymous] public IActionResult Error() { HttpContext context = HttpContext; System.Security.Principal.IIdentity? identity = context.User.Identity; int status_code = context.Response.StatusCode; if (identity is not null) { if (identity.IsAuthenticated) { IExceptionHandlerPathFeature? exceptionHandlerPathMessage = context.Features.Get<IExceptionHandlerPathFeature>(); if (exceptionHandlerPathMessage?.Error is not null) { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? context.TraceIdentifier, ErrorCode = status_code, ErrorDescription = ReasonPhrases.GetReasonPhrase(status_code), ErrorMessage = exceptionHandlerPathMessage.Error.Message }); } } } return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? context.TraceIdentifier, ErrorCode = status_code, ErrorDescription = ReasonPhrases.GetReasonPhrase(status_code)}); }
- The static
PasswordInput
class manages all user password validation and creation.
- Example of use case with
/Tools/Console
. Basic CMD commands andhighlighting
words in the search box.
- The
CommandRunner
class is only instantiated in the program and is not separated in cases of multiple users on the server. - Currently, it does not support interactivity, so typing
python
will not return a response. Although the process has been executed, the terminal will be blocked, and it will be necessary to callfreset
to reinitiateCommandRunner
.
- Feel free to add features.