forked from p15670423/monkey
Merge pull request #1439 from guardicore/remove-standard-environment
Remove standard environment (insecure access feature)
This commit is contained in:
commit
6740812f4b
|
@ -18,6 +18,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- "Back door user" post-breach action. #1410
|
||||
- Stale code in the Windows system info collector that collected installed
|
||||
packages and WMI info. #1389
|
||||
- Remove insecure access feature in the Monkey Island. #1418
|
||||
|
||||
### Fixed
|
||||
- Misaligned buttons and input fields on exploiter and network configuration
|
||||
|
|
|
@ -52,12 +52,11 @@ Monkey in the newly created folder.
|
|||
## Reset/enable the Monkey Island password
|
||||
|
||||
When you first access the Monkey Island server, you'll be prompted to create an account.
|
||||
To reset the credentials or enable/disable the authentication,
|
||||
edit the `server_config.json` file manually
|
||||
To reset the credentials, edit the `server_config.json` file manually
|
||||
(located in the [data directory](/reference/data_directory)).
|
||||
|
||||
In order to reset the credentials, the following edits need to be made:
|
||||
1. Delete the `user` field if one exists. It will look like this:
|
||||
1. Delete the `user` field. It will look like this:
|
||||
```json
|
||||
{
|
||||
...
|
||||
|
@ -65,7 +64,7 @@ In order to reset the credentials, the following edits need to be made:
|
|||
...
|
||||
}
|
||||
```
|
||||
1. Delete the `password_hash` field if one exists. It will look like this:
|
||||
1. Delete the `password_hash` field. It will look like this:
|
||||
```json
|
||||
{
|
||||
...
|
||||
|
|
|
@ -11,8 +11,6 @@ tags: ["usage", "password"]
|
|||
|
||||
The first time you launch Monkey Island (the Infection Monkey C&C server), you'll be prompted to create an account and secure your island. After account creation, the server will only be accessible via the credentials you entered.
|
||||
|
||||
If you want an island to be accessible without credentials, press *I want anyone to access the island*. Please note that this option is insecure, and you should only use it in development environments.
|
||||
|
||||
## Resetting your account credentials
|
||||
|
||||
This procedure is documented in [the FAQ]({{< ref "/faq/#how-do-i-reset-the-monkey-island-password" >}}).
|
||||
|
|
|
@ -23,7 +23,6 @@ from monkey_island.cc.resources.client_run import ClientRun
|
|||
from monkey_island.cc.resources.configuration_export import ConfigurationExport
|
||||
from monkey_island.cc.resources.configuration_import import ConfigurationImport
|
||||
from monkey_island.cc.resources.edge import Edge
|
||||
from monkey_island.cc.resources.environment import Environment
|
||||
from monkey_island.cc.resources.exploitations.manual_exploitation import ManualExploitation
|
||||
from monkey_island.cc.resources.exploitations.monkey_exploitation import MonkeyExploitation
|
||||
from monkey_island.cc.resources.island_configuration import IslandConfiguration
|
||||
|
@ -125,7 +124,6 @@ def init_api_resources(api):
|
|||
api.add_resource(Root, "/api")
|
||||
api.add_resource(Registration, "/api/registration")
|
||||
api.add_resource(Authenticate, "/api/auth")
|
||||
api.add_resource(Environment, "/api/environment")
|
||||
api.add_resource(Monkey, "/api/monkey", "/api/monkey/", "/api/monkey/<string:guid>")
|
||||
api.add_resource(Bootloader, "/api/bootloader/<string:os>")
|
||||
api.add_resource(LocalRun, "/api/local-monkey", "/api/local-monkey/")
|
||||
|
|
|
@ -77,9 +77,6 @@ class Environment(object, metaclass=ABCMeta):
|
|||
def testing(self, value):
|
||||
self._testing = value
|
||||
|
||||
def save_config(self):
|
||||
self._config.save_to_file()
|
||||
|
||||
def get_config(self) -> EnvironmentConfig:
|
||||
return self._config
|
||||
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
import logging
|
||||
|
||||
import monkey_island.cc.resources.auth.user_store as user_store
|
||||
from monkey_island.cc.environment import EnvironmentConfig, aws, password, standard
|
||||
from monkey_island.cc.environment import EnvironmentConfig, aws, password
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
AWS = "aws"
|
||||
STANDARD = "standard"
|
||||
PASSWORD = "password"
|
||||
|
||||
ENV_DICT = {
|
||||
STANDARD: standard.StandardEnvironment,
|
||||
AWS: aws.AwsEnvironment,
|
||||
PASSWORD: password.PasswordEnvironment,
|
||||
}
|
||||
|
@ -24,16 +21,6 @@ def set_env(env_type: str, env_config: EnvironmentConfig):
|
|||
env = ENV_DICT[env_type](env_config)
|
||||
|
||||
|
||||
def set_to_standard():
|
||||
global env
|
||||
if env:
|
||||
env_config = env.get_config()
|
||||
env_config.server_config = "standard"
|
||||
set_env("standard", env_config)
|
||||
env.save_config()
|
||||
user_store.UserStore.set_users(env.get_auth_users())
|
||||
|
||||
|
||||
def initialize_from_file(file_path):
|
||||
try:
|
||||
config = EnvironmentConfig(file_path)
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
from monkey_island.cc.environment import Environment
|
||||
from monkey_island.cc.resources.auth.auth_user import User
|
||||
|
||||
|
||||
class StandardEnvironment(Environment):
|
||||
_credentials_required = False
|
||||
|
||||
NO_AUTH_USER = "1234567890!@#$%^&*()_nothing_up_my_sleeve_1234567890!@#$%^&*()"
|
||||
NO_AUTH_SECRET = "$2b$12$frH7uEwV3jkDNGgReW6j2udw8hy/Yw1SWAqytrcBYK48kn1V5lQIa"
|
||||
|
||||
def get_auth_users(self):
|
||||
return [User(1, StandardEnvironment.NO_AUTH_USER, StandardEnvironment.NO_AUTH_SECRET)]
|
|
@ -1,22 +0,0 @@
|
|||
import json
|
||||
import logging
|
||||
|
||||
import flask_restful
|
||||
from flask import request
|
||||
|
||||
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Environment(flask_restful.Resource):
|
||||
def patch(self):
|
||||
env_data = json.loads(request.data)
|
||||
if env_data["server_config"] == "standard":
|
||||
if env_singleton.env.needs_registration():
|
||||
env_singleton.set_to_standard()
|
||||
logger.warning(
|
||||
"No user registered, Island on standard mode - no credentials required to "
|
||||
"access."
|
||||
)
|
||||
return {}
|
|
@ -67,7 +67,6 @@ class AppComponent extends AuthComponent {
|
|||
loading: true,
|
||||
completedSteps: completedSteps,
|
||||
islandMode: undefined,
|
||||
noAuthLoginAttempted: undefined
|
||||
};
|
||||
this.interval = undefined;
|
||||
this.setMode();
|
||||
|
@ -77,45 +76,44 @@ class AppComponent extends AuthComponent {
|
|||
if (this.state.isLoggedIn === false) {
|
||||
return
|
||||
}
|
||||
this.auth.loggedIn()
|
||||
.then(res => {
|
||||
if (this.state.isLoggedIn !== res) {
|
||||
this.setState({
|
||||
isLoggedIn: res
|
||||
});
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
this.auth.needsRegistration()
|
||||
.then(result => {
|
||||
this.setState({
|
||||
needsRegistration: result
|
||||
});
|
||||
})
|
||||
}
|
||||
let res = this.auth.loggedIn();
|
||||
|
||||
if (res) {
|
||||
this.setMode()
|
||||
.then(() => {
|
||||
if (this.state.islandMode === null) {
|
||||
return
|
||||
}
|
||||
this.authFetch('/api')
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
let completedSteps = CompletedSteps.buildFromResponse(res.completed_steps);
|
||||
// This check is used to prevent unnecessary re-rendering
|
||||
if (_.isEqual(this.state.completedSteps, completedSteps)) {
|
||||
return;
|
||||
}
|
||||
this.setState({completedSteps: completedSteps});
|
||||
this.showInfectionDoneNotification();
|
||||
});
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
if (this.state.isLoggedIn !== res) {
|
||||
this.setState({
|
||||
isLoggedIn: res
|
||||
});
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
this.auth.needsRegistration()
|
||||
.then(result => {
|
||||
this.setState({
|
||||
needsRegistration: result
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
if (res) {
|
||||
this.setMode()
|
||||
.then(() => {
|
||||
if (this.state.islandMode === null) {
|
||||
return
|
||||
}
|
||||
this.authFetch('/api')
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
let completedSteps = CompletedSteps.buildFromResponse(res.completed_steps);
|
||||
// This check is used to prevent unnecessary re-rendering
|
||||
if (_.isEqual(this.state.completedSteps, completedSteps)) {
|
||||
return;
|
||||
}
|
||||
this.setState({completedSteps: completedSteps});
|
||||
this.showInfectionDoneNotification();
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
setMode = () => {
|
||||
|
|
|
@ -48,12 +48,11 @@ class LoginPageComponent extends React.Component {
|
|||
this.redirectToRegistration()
|
||||
}
|
||||
})
|
||||
this.auth.loggedIn()
|
||||
.then(res => {
|
||||
if (res) {
|
||||
this.redirectToHome();
|
||||
}
|
||||
});
|
||||
|
||||
if (this.auth.loggedIn()) {
|
||||
this.redirectToHome();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -7,8 +7,6 @@ import ParticleBackground from '../ui-components/ParticleBackground';
|
|||
|
||||
class RegisterPageComponent extends React.Component {
|
||||
|
||||
NO_AUTH_API_ENDPOINT = '/api/environment';
|
||||
|
||||
register = (event) => {
|
||||
event.preventDefault();
|
||||
this.auth.register(this.username, this.password).then(res => {
|
||||
|
@ -24,30 +22,6 @@ class RegisterPageComponent extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
setNoAuth = () => {
|
||||
let options = {};
|
||||
options['headers'] = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
options['method'] = 'PATCH';
|
||||
options['body'] = JSON.stringify({'server_config': 'standard'});
|
||||
|
||||
return fetch(this.NO_AUTH_API_ENDPOINT, options)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
this.auth.attemptNoAuthLogin().then(() => {
|
||||
this.redirectToHome();
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
failed: true,
|
||||
error: res['error']
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
updateUsername = (evt) => {
|
||||
this.username = evt.target.value;
|
||||
};
|
||||
|
@ -96,13 +70,6 @@ class RegisterPageComponent extends React.Component {
|
|||
<Button className={'monkey-submit-button'} type={'submit'} >
|
||||
Let's go!
|
||||
</Button>
|
||||
<Row>
|
||||
<Col>
|
||||
<a href='#' onClick={this.setNoAuth} className={'no-auth-link'}>
|
||||
I want anyone to access the island
|
||||
</a>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
{
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import StandardConfig from './StandardConfig';
|
||||
import AwsConfig from './AwsConfig';
|
||||
import PasswordConfig from './PasswordConfig';
|
||||
|
||||
|
@ -6,7 +5,6 @@ import SERVER_CONFIG_JSON from '../../../server_config.json';
|
|||
|
||||
const CONFIG_DICT =
|
||||
{
|
||||
'standard': StandardConfig,
|
||||
'aws': AwsConfig,
|
||||
'password': PasswordConfig
|
||||
};
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import BaseConfig from './BaseConfig';
|
||||
|
||||
class StandardConfig extends BaseConfig {
|
||||
|
||||
isAuthEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default StandardConfig;
|
|
@ -1,8 +1,6 @@
|
|||
import decode from 'jwt-decode';
|
||||
|
||||
export default class AuthService {
|
||||
NO_AUTH_CREDS = '1234567890!@#$%^&*()_nothing_up_my_sleeve_1234567890!@#$%^&*()';
|
||||
|
||||
SECONDS_BEFORE_JWT_EXPIRES = 20;
|
||||
AUTHENTICATION_API_ENDPOINT = '/api/auth';
|
||||
REGISTRATION_API_ENDPOINT = '/api/registration';
|
||||
|
@ -16,7 +14,7 @@ export default class AuthService {
|
|||
};
|
||||
|
||||
jwtHeader = () => {
|
||||
if (this._loggedIn()) {
|
||||
if (this.loggedIn()) {
|
||||
return 'Bearer ' + this._getToken();
|
||||
}
|
||||
};
|
||||
|
@ -68,7 +66,7 @@ export default class AuthService {
|
|||
'Content-Type': 'application/json'
|
||||
};
|
||||
|
||||
if (this._loggedIn()) {
|
||||
if (this.loggedIn()) {
|
||||
headers['Authorization'] = 'Bearer ' + this._getToken();
|
||||
}
|
||||
|
||||
|
@ -101,19 +99,7 @@ export default class AuthService {
|
|||
})
|
||||
};
|
||||
|
||||
async loggedIn() {
|
||||
let token = this._getToken();
|
||||
if ((token === null) || (this._isTokenExpired(token))) {
|
||||
await this.attemptNoAuthLogin();
|
||||
}
|
||||
return this._loggedIn();
|
||||
}
|
||||
|
||||
attemptNoAuthLogin() {
|
||||
return this._login(this.NO_AUTH_CREDS, this.NO_AUTH_CREDS);
|
||||
}
|
||||
|
||||
_loggedIn() {
|
||||
loggedIn() {
|
||||
const token = this._getToken();
|
||||
return ((token !== null) && !this._isTokenExpired(token));
|
||||
}
|
||||
|
|
|
@ -35,15 +35,3 @@
|
|||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.no-auth-link {
|
||||
margin-top: 10px;
|
||||
float: right;
|
||||
color: $monkey-black;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.no-auth-link:hover {
|
||||
float: right;
|
||||
color: $monkey-yellow;
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"environment" : {
|
||||
"server_config": "standard",
|
||||
"deployment": "develop"
|
||||
},
|
||||
"mongodb": {
|
||||
"start_mongodb": true
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"log_level": "NOTICE",
|
||||
"environment" : {
|
||||
"server_config": "standard",
|
||||
"deployment": "develop",
|
||||
"user": "test",
|
||||
"password_hash": "abcdef"
|
||||
},
|
||||
"mongodb": {
|
||||
"start_mongodb": true
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"log_level": "NOTICE",
|
||||
"environment" : {
|
||||
"server_config": "password",
|
||||
"deployment": "develop",
|
||||
|
|
|
@ -16,8 +16,3 @@ def no_credentials(server_configs_dir):
|
|||
@pytest.fixture(scope="module")
|
||||
def partial_credentials(server_configs_dir):
|
||||
return os.path.join(server_configs_dir, "server_config_partial_credentials.json")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def standard_with_credentials(server_configs_dir):
|
||||
return os.path.join(server_configs_dir, "server_config_standard_with_credentials.json")
|
||||
|
|
|
@ -17,8 +17,6 @@ from monkey_island.cc.environment import Environment, EnvironmentConfig, UserCre
|
|||
WITH_CREDENTIALS = None
|
||||
NO_CREDENTIALS = None
|
||||
PARTIAL_CREDENTIALS = None
|
||||
STANDARD_WITH_CREDENTIALS = None
|
||||
STANDARD_ENV = None
|
||||
|
||||
EMPTY_USER_CREDENTIALS = UserCreds("", "")
|
||||
FULL_USER_CREDENTIALS = UserCreds(username="test", password_hash="1231234")
|
||||
|
@ -31,16 +29,10 @@ def configure_resources(server_configs_dir):
|
|||
global WITH_CREDENTIALS
|
||||
global NO_CREDENTIALS
|
||||
global PARTIAL_CREDENTIALS
|
||||
global STANDARD_WITH_CREDENTIALS
|
||||
global STANDARD_ENV
|
||||
|
||||
WITH_CREDENTIALS = os.path.join(server_configs_dir, "server_config_with_credentials.json")
|
||||
NO_CREDENTIALS = os.path.join(server_configs_dir, "server_config_no_credentials.json")
|
||||
PARTIAL_CREDENTIALS = os.path.join(server_configs_dir, "server_config_partial_credentials.json")
|
||||
STANDARD_WITH_CREDENTIALS = os.path.join(
|
||||
server_configs_dir, "server_config_standard_with_credentials.json"
|
||||
)
|
||||
STANDARD_ENV = os.path.join(server_configs_dir, "server_config_standard_env.json")
|
||||
|
||||
|
||||
def get_tmp_file():
|
||||
|
@ -123,29 +115,18 @@ class TestEnvironment(TestCase):
|
|||
self._test_bool_env_method("needs_registration", env, NO_CREDENTIALS, True)
|
||||
self._test_bool_env_method("needs_registration", env, PARTIAL_CREDENTIALS, True)
|
||||
|
||||
env = TestEnvironment.EnvironmentCredentialsNotRequired()
|
||||
self._test_bool_env_method("needs_registration", env, STANDARD_ENV, False)
|
||||
self._test_bool_env_method("needs_registration", env, STANDARD_WITH_CREDENTIALS, False)
|
||||
|
||||
def test_is_registered(self):
|
||||
env = TestEnvironment.EnvironmentCredentialsRequired()
|
||||
self._test_bool_env_method("_is_registered", env, WITH_CREDENTIALS, True)
|
||||
self._test_bool_env_method("_is_registered", env, NO_CREDENTIALS, False)
|
||||
self._test_bool_env_method("_is_registered", env, PARTIAL_CREDENTIALS, False)
|
||||
|
||||
env = TestEnvironment.EnvironmentCredentialsNotRequired()
|
||||
self._test_bool_env_method("_is_registered", env, STANDARD_ENV, False)
|
||||
self._test_bool_env_method("_is_registered", env, STANDARD_WITH_CREDENTIALS, False)
|
||||
|
||||
def test_is_credentials_set_up(self):
|
||||
env = TestEnvironment.EnvironmentCredentialsRequired()
|
||||
self._test_bool_env_method("_is_credentials_set_up", env, NO_CREDENTIALS, False)
|
||||
self._test_bool_env_method("_is_credentials_set_up", env, WITH_CREDENTIALS, True)
|
||||
self._test_bool_env_method("_is_credentials_set_up", env, PARTIAL_CREDENTIALS, False)
|
||||
|
||||
env = TestEnvironment.EnvironmentCredentialsNotRequired()
|
||||
self._test_bool_env_method("_is_credentials_set_up", env, STANDARD_ENV, False)
|
||||
|
||||
def _test_bool_env_method(
|
||||
self, method_name: str, env: Environment, config: Dict, expected_result: bool
|
||||
):
|
||||
|
|
|
@ -40,8 +40,8 @@ def test_get_with_partial_credentials(partial_credentials):
|
|||
assert config_dict["user"] == "test"
|
||||
|
||||
|
||||
def test_save_to_file(config_file, standard_with_credentials):
|
||||
shutil.copyfile(standard_with_credentials, config_file)
|
||||
def test_save_to_file(config_file, with_credentials):
|
||||
shutil.copyfile(with_credentials, config_file)
|
||||
|
||||
environment_config = EnvironmentConfig(config_file)
|
||||
environment_config.aws = "test_aws"
|
||||
|
@ -53,8 +53,8 @@ def test_save_to_file(config_file, standard_with_credentials):
|
|||
assert environment_config.to_dict() == from_file["environment"]
|
||||
|
||||
|
||||
def test_save_to_file_preserve_log_level(config_file, standard_with_credentials):
|
||||
shutil.copyfile(standard_with_credentials, config_file)
|
||||
def test_save_to_file_preserve_log_level(config_file, with_credentials):
|
||||
shutil.copyfile(with_credentials, config_file)
|
||||
|
||||
environment_config = EnvironmentConfig(config_file)
|
||||
environment_config.aws = "test_aws"
|
||||
|
@ -67,12 +67,12 @@ def test_save_to_file_preserve_log_level(config_file, standard_with_credentials)
|
|||
assert from_file["log_level"] == "NOTICE"
|
||||
|
||||
|
||||
def test_add_user(config_file, standard_with_credentials):
|
||||
def test_add_user(config_file, with_credentials):
|
||||
new_user = "new_user"
|
||||
new_password_hash = "fedcba"
|
||||
new_user_creds = UserCreds(new_user, new_password_hash)
|
||||
|
||||
shutil.copyfile(standard_with_credentials, config_file)
|
||||
shutil.copyfile(with_credentials, config_file)
|
||||
|
||||
environment_config = EnvironmentConfig(config_file)
|
||||
environment_config.add_user(new_user_creds)
|
||||
|
@ -85,8 +85,8 @@ def test_add_user(config_file, standard_with_credentials):
|
|||
assert from_file["environment"]["password_hash"] == new_password_hash
|
||||
|
||||
|
||||
def test_get_users(standard_with_credentials):
|
||||
environment_config = EnvironmentConfig(standard_with_credentials)
|
||||
def test_get_users(with_credentials):
|
||||
environment_config = EnvironmentConfig(with_credentials)
|
||||
users = environment_config.get_users()
|
||||
|
||||
assert len(users) == 1
|
||||
|
|
Loading…
Reference in New Issue